diff --git a/Makefile b/Makefile --- a/Makefile +++ b/Makefile @@ -648,6 +648,7 @@ C_SOURCES += player_gui.c C_SOURCES += players.c C_SOURCES += pool.c C_SOURCES += queue.c +C_SOURCES += rail.c C_SOURCES += rail_cmd.c C_SOURCES += rail_gui.c C_SOURCES += rev.c diff --git a/depot.h b/depot.h --- a/depot.h +++ b/depot.h @@ -89,7 +89,7 @@ static inline bool IsTileDepotType(TileI /** * Returns the direction the exit of the depot on the given tile is facing. */ -static inline uint GetDepotDirection(TileIndex tile, TransportType type) +static inline DiagDirection GetDepotDirection(TileIndex tile, TransportType type) { assert(IsTileDepotType(tile, type)); @@ -102,13 +102,13 @@ static inline uint GetDepotDirection(Til case TRANSPORT_WATER: /* Water is stubborn, it stores the directions in a different order. */ switch (_map5[tile] & 3) { - case 0: return 0; - case 1: return 2; - case 2: return 3; - case 3: return 1; + case 0: return DIAGDIR_NE; + case 1: return DIAGDIR_SW; + case 2: return DIAGDIR_NW; + case 3: return DIAGDIR_SE; } default: - return 0; /* Not reached */ + return INVALID_DIAGDIR; /* Not reached */ } } diff --git a/map.h b/map.h --- a/map.h +++ b/map.h @@ -48,6 +48,13 @@ enum { INVALID_TILE = (uint32) -1 }; +enum { + TILE_SIZE = 16, /* Tiles are 16x16 "units" in size */ + TILE_PIXELS = 32, /* a tile is 32x32 pixels */ + TILE_HEIGHT = 8, /* The standard height-difference between tiles on two levels is 8 (z-diff 8) */ +}; + + static inline uint TileX(TileIndex tile) { return tile & MapMaxX(); diff --git a/npf.c b/npf.c --- a/npf.c +++ b/npf.c @@ -9,92 +9,8 @@ #include "tile.h" #include "depot.h" -AyStar _train_find_station; -AyStar _train_find_depot; -AyStar _road_find_station; -AyStar _road_find_depot; AyStar _npf_aystar; -/* Maps a trackdir to the bit that stores its status in the map arrays, in the - * direction along with the trackdir */ -const byte _signal_along_trackdir[14] = { - 0x80, 0x80, 0x80, 0x20, 0x40, 0x10, 0, 0, - 0x40, 0x40, 0x40, 0x10, 0x80, 0x20 -}; - -/* Maps a trackdir to the bit that stores its status in the map arrays, in the - * direction against the trackdir */ -const byte _signal_against_trackdir[14] = { - 0x40, 0x40, 0x40, 0x10, 0x80, 0x20, 0, 0, - 0x80, 0x80, 0x80, 0x20, 0x40, 0x10 -}; - -/* Maps a trackdir to the trackdirs that can be reached from it (ie, when - * entering the next tile */ -const uint16 _trackdir_reaches_trackdirs[14] = { - 0x1009, 0x0016, 0x1009, 0x0016, 0x0520, 0x0016, 0, 0, - 0x0520, 0x2A00, 0x2A00, 0x0520, 0x2A00, 0x1009 -}; - -const uint16 _next_trackdir[14] = { - 0, 1, 3, 2, 5, 4, 0, 0, - 8, 9, 11, 10, 13, 12 -}; - -/* Maps a trackdir to all trackdirs that make 90 deg turns with it. */ -const uint16 _trackdir_crosses_trackdirs[14] = { - 0x0202, 0x0101, 0x3030, 0x3030, 0x0C0C, 0x0C0C, 0, 0, - 0x0202, 0x0101, 0x3030, 0x3030, 0x0C0C, 0x0C0C -}; - -/* Maps a track to all tracks that make 90 deg turns with it. */ -const byte _track_crosses_tracks[6] = { - 0x2, /* Track 1 -> Track 2 */ - 0x1, /* Track 2 -> Track 1 */ - 0x30, /* Upper -> Left | Right */ - 0x30, /* Lower -> Left | Right */ - 0x0C, /* Left -> Upper | Lower */ - 0x0C, /* Right -> Upper | Lower */ -}; - -/* Maps a trackdir to the (4-way) direction the tile is exited when following - * that trackdir */ -const byte _trackdir_to_exitdir[14] = { - 0,1,0,1,2,1, 0,0, - 2,3,3,2,3,0, -}; - -const byte _track_exitdir_to_trackdir[6][4] = { - {0, 0xff, 8, 0xff}, - {0xff, 1, 0xff, 9}, - {2, 0xff, 0xff, 10}, - {0xff, 3, 11, 0xf}, - {0xff, 0xff, 4, 12}, - {13, 5, 0xff, 0xff} -}; - -const byte _track_direction_to_trackdir[6][8] = { - {0xff, 0, 0xff, 0xff, 0xff, 8, 0xff, 0xff}, - {0xff, 0xff, 0xff, 1, 0xff, 0xff, 0xff, 9}, - {0xff, 0xff, 2, 0xff, 0xff, 0xff, 10, 0xff}, - {0xff, 0xff, 3, 0xff, 0xff, 0xff, 11, 0xff}, - {12, 0xff, 0xff, 0xff, 4, 0xff, 0xff, 0xff}, - {13, 0xff, 0xff, 0xff, 5, 0xff, 0xff, 0xff} -}; - -const byte _dir_to_diag_trackdir[4] = { - 0, 1, 8, 9, -}; - -const byte _reverse_dir[4] = { - 2, 3, 0, 1 -}; - -const byte _reverse_trackdir[14] = { - 8, 9, 10, 11, 12, 13, 0xFF, 0xFF, - 0, 1, 2, 3, 4, 5 -}; - /* The cost of each trackdir. A diagonal piece is the full NPF_TILE_LENGTH, * the shorter piece is sqrt(2)/2*NPF_TILE_LENGTH =~ 0.7071 */ @@ -214,11 +130,11 @@ void NPFFillTrackdirChoice(AyStarNode* c uint NPFTunnelCost(AyStarNode* current) { byte exitdir = _trackdir_to_exitdir[current->direction]; TileIndex tile = current->tile; - if ( (uint)(_map5[tile] & 3) == _reverse_dir[exitdir]) { + if ( (uint)(_map5[tile] & 3) == ReverseDiagdir(exitdir)) { /* We just popped out if this tunnel, since were * facing the tunnel exit */ FindLengthOfTunnelResult flotr; - flotr = FindLengthOfTunnel(tile, _reverse_dir[exitdir]); + flotr = FindLengthOfTunnel(tile, ReverseDiagdir(exitdir)); return flotr.length * NPF_TILE_LENGTH; //TODO: Penalty for tunnels? } else { @@ -233,13 +149,15 @@ uint NPFSlopeCost(AyStarNode* current) { int x,y; int8 z1,z2; - x = TileX(current->tile) * 16; - y = TileY(current->tile) * 16; - z1 = GetSlopeZ(x+8, y+8); + x = TileX(current->tile) * TILE_SIZE; + y = TileY(current->tile) * TILE_SIZE; + /* get the height of the center of the current tile */ + z1 = GetSlopeZ(x+TILE_HEIGHT, y+TILE_HEIGHT); - x = TileX(next) * 16; - y = TileY(next) * 16; - z2 = GetSlopeZ(x+8, y+8); + x = TileX(next) * TILE_SIZE; + y = TileY(next) * TILE_SIZE; + /* get the height of the center of the next tile */ + z2 = GetSlopeZ(x+TILE_HEIGHT, y+TILE_HEIGHT); if ((z2 - z1) > 1) { /* Slope up */ @@ -499,7 +417,7 @@ static inline RailType GetTileRailType(T /* railway bridge ending */ if ((_map5[tile] & 0xC6) == 0x80) type = _map3_lo[tile] & RAILTYPE_MASK; /* on railway bridge */ - if ((_map5[tile] & 0xC6) == 0xC0 && (_map5[tile] & 0x1) == (_trackdir_to_exitdir[trackdir] & 0x1)) + if ((_map5[tile] & 0xC6) == 0xC0 && ((unsigned)(_map5[tile] & 0x1)) == (TrackdirToExitdir(trackdir) & 0x1)) type = (_map3_lo[tile] >> 4) & RAILTYPE_MASK; /* under bridge (any type) */ if ((_map5[tile] & 0xC0) == 0xC0 && (_map5[tile] & 0x1) != (trackdir & 0x1)) @@ -554,7 +472,7 @@ void NPFFollowTrack(AyStar* aystar, Open * otherwise (only for trains, since only with trains you can * (sometimes) reach tiles after reversing that you couldn't reach * without reversing. */ - if (src_trackdir == _dir_to_diag_trackdir[_reverse_dir[exitdir]] && type == TRANSPORT_RAIL) + if (src_trackdir == _dir_to_diag_trackdir[ReverseDiagdir(exitdir)] && type == TRANSPORT_RAIL) /* We are headed inwards. We can only reverse here, so we'll not * consider this direction, but jump ahead to the reverse direction. * It would be nicer to return one neighbour here (the reverse @@ -609,7 +527,7 @@ void NPFFollowTrack(AyStar* aystar, Open * orientation. They are only "inwards", since we are reaching this tile * from some other tile. This prevents vehicles driving into depots from * the back */ - ts = (1 << _dir_to_diag_trackdir[_reverse_dir[exitdir]]); + ts = TrackdirToTrackdirBits(DiagdirToDiagTrackdir(ReverseDiagdir(exitdir))); } else { ts = GetTileTrackStatus(dst_tile, type); } @@ -617,7 +535,7 @@ void NPFFollowTrack(AyStar* aystar, Open DEBUG(npf, 4)("Next node: (%d, %d) [%d], possible trackdirs: %#x", TileX(dst_tile), TileY(dst_tile), dst_tile, trackdirs); /* Select only trackdirs we can reach from our current trackdir */ - trackdirs &= _trackdir_reaches_trackdirs[src_trackdir]; + trackdirs &= TrackdirReachesTrackdirs(src_trackdir); if (_patches.forbid_90_deg && (type == TRANSPORT_RAIL || type == TRANSPORT_WATER)) /* Filter out trackdirs that would make 90 deg turns for trains */ trackdirs &= ~_trackdir_crosses_trackdirs[src_trackdir]; DEBUG(npf,6)("After filtering: (%d, %d), possible trackdirs: %#x", TileX(dst_tile), TileY(dst_tile), trackdirs); @@ -682,11 +600,11 @@ NPFFoundTargetData NPFRouteInternal(AySt assert(0); /* Initialize Start Node(s) */ - start1->user_data[NPF_TRACKDIR_CHOICE] = 0xff; + start1->user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR; start1->user_data[NPF_NODE_FLAGS] = 0; _npf_aystar.addstart(&_npf_aystar, start1, 0); if (start2) { - start2->user_data[NPF_TRACKDIR_CHOICE] = 0xff; + start2->user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR; start2->user_data[NPF_NODE_FLAGS] = 0; NPFSetFlag(start2, NPF_FLAG_REVERSE, true); _npf_aystar.addstart(&_npf_aystar, start2, reverse_penalty); @@ -695,7 +613,7 @@ NPFFoundTargetData NPFRouteInternal(AySt /* Initialize result */ result.best_bird_dist = (uint)-1; result.best_path_dist = (uint)-1; - result.best_trackdir = 0xff; + result.best_trackdir = INVALID_TRACKDIR; _npf_aystar.user_path = &result; /* Initialize target */ @@ -721,7 +639,7 @@ NPFFoundTargetData NPFRouteInternal(AySt return result; } -NPFFoundTargetData NPFRouteToStationOrTileTwoWay(TileIndex tile1, byte trackdir1, TileIndex tile2, byte trackdir2, NPFFindStationOrTileData* target, TransportType type, Owner owner) { +NPFFoundTargetData NPFRouteToStationOrTileTwoWay(TileIndex tile1, Trackdir trackdir1, TileIndex tile2, Trackdir trackdir2, NPFFindStationOrTileData* target, TransportType type, Owner owner) { AyStarNode start1; AyStarNode start2; @@ -729,19 +647,19 @@ NPFFoundTargetData NPFRouteToStationOrTi start2.tile = tile2; /* We set this in case the target is also the start tile, we will just * return a not found then */ - start1.user_data[NPF_TRACKDIR_CHOICE] = 0xff; + start1.user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR; start1.direction = trackdir1; start2.direction = trackdir2; - start2.user_data[NPF_TRACKDIR_CHOICE] = 0xff; + start2.user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR; return NPFRouteInternal(&start1, (IsValidTile(tile2) ? &start2 : NULL), target, NPFFindStationOrTile, NPFCalcStationOrTileHeuristic, type, owner, 0); } -NPFFoundTargetData NPFRouteToStationOrTile(TileIndex tile, byte trackdir, NPFFindStationOrTileData* target, TransportType type, Owner owner) { +NPFFoundTargetData NPFRouteToStationOrTile(TileIndex tile, Trackdir trackdir, NPFFindStationOrTileData* target, TransportType type, Owner owner) { return NPFRouteToStationOrTileTwoWay(tile, trackdir, INVALID_TILE, 0, target, type, owner); } -NPFFoundTargetData NPFRouteToDepotBreadthFirstTwoWay(TileIndex tile1, byte trackdir1, TileIndex tile2, byte trackdir2, TransportType type, Owner owner, uint reverse_penalty) { +NPFFoundTargetData NPFRouteToDepotBreadthFirstTwoWay(TileIndex tile1, Trackdir trackdir1, TileIndex tile2, Trackdir trackdir2, TransportType type, Owner owner, uint reverse_penalty) { AyStarNode start1; AyStarNode start2; @@ -749,21 +667,21 @@ NPFFoundTargetData NPFRouteToDepotBreadt start2.tile = tile2; /* We set this in case the target is also the start tile, we will just * return a not found then */ - start1.user_data[NPF_TRACKDIR_CHOICE] = 0xff; + start1.user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR; start1.direction = trackdir1; start2.direction = trackdir2; - start2.user_data[NPF_TRACKDIR_CHOICE] = 0xff; + start2.user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR; /* perform a breadth first search. Target is NULL, * since we are just looking for any depot...*/ return NPFRouteInternal(&start1, (IsValidTile(tile2) ? &start2 : NULL), NULL, NPFFindDepot, NPFCalcZero, type, owner, reverse_penalty); } -NPFFoundTargetData NPFRouteToDepotBreadthFirst(TileIndex tile, byte trackdir, TransportType type, Owner owner) { +NPFFoundTargetData NPFRouteToDepotBreadthFirst(TileIndex tile, Trackdir trackdir, TransportType type, Owner owner) { return NPFRouteToDepotBreadthFirstTwoWay(tile, trackdir, INVALID_TILE, 0, type, owner, 0); } -NPFFoundTargetData NPFRouteToDepotTrialError(TileIndex tile, byte trackdir, TransportType type, Owner owner) { +NPFFoundTargetData NPFRouteToDepotTrialError(TileIndex tile, Trackdir trackdir, TransportType type, Owner owner) { /* Okay, what we're gonna do. First, we look at all depots, calculate * the manhatten distance to get to each depot. We then sort them by * distance. We start by trying to plan a route to the closest, then @@ -836,14 +754,14 @@ NPFFoundTargetData NPFRouteToDepotTrialE /* Initialize Start Node */ /* We set this in case the target is also the start tile, we will just * return a not found then */ - start.user_data[NPF_TRACKDIR_CHOICE] = 0xff; + start.user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR; start.user_data[NPF_NODE_FLAGS] = 0; _npf_aystar.addstart(&_npf_aystar, &start, 0); /* Initialize result */ result.best_bird_dist = (uint)-1; result.best_path_dist = (uint)-1; - result.best_trackdir = 0xff; + result.best_trackdir = INVALID_TRACKDIR; /* Initialize target */ target.dest_coords = current->xy; @@ -871,52 +789,6 @@ void InitializeNPF(void) /* We will limit the number of nodes for now, until we have a better * solution to really fix performance */ _npf_aystar.max_search_nodes = _patches.npf_max_search_nodes; -#if 0 - init_AyStar(&_train_find_station, NTPHash, 1024); - init_AyStar(&_train_find_depot, NTPHash, 1024); - init_AyStar(&_road_find_station, NTPHash, 1024); - init_AyStar(&_road_find_depot, NTPHash, 1024); - - _train_find_station.loops_per_tick = 0; - _train_find_depot.loops_per_tick = 0; - _road_find_station.loops_per_tick = 0; - _road_find_depot.loops_per_tick = 0; - - _train_find_station.max_path_cost = 0; - _train_find_depot.max_path_cost = 0; - _road_find_station.max_path_cost = 0; - _road_find_depot.max_path_cost = 0; - - _train_find_station.max_search_nodes = 0; - _train_find_depot.max_search_nodes = 0; - _road_find_station.max_search_nodes = 0; - _road_find_depot.max_search_nodes = 0; - - _train_find_station.CalculateG = NPFRailPathCost; - _train_find_depot.CalculateG = NPFRailPathCost; - _road_find_station.CalculateG = NPFRoadPathCost; - _road_find_depot.CalculateG = NPFRoadPathCost; - - _train_find_station.CalculateH = NPFCalcStationHeuristic; - _train_find_depot.CalculateH = NPFCalcStationHeuristic; - _road_find_station.CalculateH = NPFCalcStationHeuristic; - _road_find_depot.CalculateH = NPFCalcStationHeuristic; - - _train_find_station.EndNodeCheck = NPFFindStationOrTile; - _train_find_depot.EndNodeCheck = NPFFindStationOrTile; - _road_find_station.EndNodeCheck = NPFFindStationOrTile; - _road_find_depot.EndNodeCheck = NPFFindStationOrTile; - - _train_find_station.FoundEndNode = NPFSaveTargetData; - _train_find_depot.FoundEndNode = NPFSaveTargetData; - _road_find_station.FoundEndNode = NPFSaveTargetData; - _road_find_depot.FoundEndNode = NPFSaveTargetData; - - _train_find_station.GetNeighbours = NPFFollowTrack; - _train_find_depot.GetNeighbours = NPFFollowTrack; - _road_find_station.GetNeighbours = NPFFollowTrack; - _road_find_depot.GetNeighbours = NPFFollowTrack; -#endif } void NPFFillWithOrderData(NPFFindStationOrTileData* fstd, Vehicle* v) { diff --git a/npf.h b/npf.h --- a/npf.h +++ b/npf.h @@ -1,11 +1,11 @@ #ifndef NPF_H #define NPF_H -/* Blaat */ - #include "openttd.h" #include "aystar.h" #include "vehicle.h" +#include "tile.h" +#include "rail.h" //mowing grass enum { @@ -50,7 +50,7 @@ typedef enum { /* Flags for AyStarNode.u typedef struct NPFFoundTargetData { /* Meant to be stored in AyStar.userpath */ uint best_bird_dist; /* The best heuristic found. Is 0 if the target was found */ uint best_path_dist; /* The shortest path. Is (uint)-1 if no path is found */ - byte best_trackdir; /* The trackdir that leads to the shortest path/closest birds dist */ + Trackdir best_trackdir; /* The trackdir that leads to the shortest path/closest birds dist */ AyStarNode node; /* The node within the target the search led us to */ } NPFFoundTargetData; @@ -59,27 +59,27 @@ typedef struct NPFFoundTargetData { /* M /* Will search from the given tile and direction, for a route to the given * station for the given transport type. See the declaration of * NPFFoundTargetData above for the meaning of the result. */ -NPFFoundTargetData NPFRouteToStationOrTile(TileIndex tile, byte trackdir, NPFFindStationOrTileData* target, TransportType type, Owner owner); +NPFFoundTargetData NPFRouteToStationOrTile(TileIndex tile, Trackdir trackdir, NPFFindStationOrTileData* target, TransportType type, Owner owner); /* Will search as above, but with two start nodes, the second being the * reverse. Look at the NPF_FLAG_REVERSE flag in the result node to see which * direction was taken (NPFGetBit(result.node, NPF_FLAG_REVERSE)) */ -NPFFoundTargetData NPFRouteToStationOrTileTwoWay(TileIndex tile1, byte trackdir1, TileIndex tile2, byte trackdir2, NPFFindStationOrTileData* target, TransportType type, Owner owner); +NPFFoundTargetData NPFRouteToStationOrTileTwoWay(TileIndex tile1, Trackdir trackdir1, TileIndex tile2, Trackdir trackdir2, NPFFindStationOrTileData* target, TransportType type, Owner owner); /* Will search a route to the closest depot. */ /* Search using breadth first. Good for little track choice and inaccurate * heuristic, such as railway/road.*/ -NPFFoundTargetData NPFRouteToDepotBreadthFirst(TileIndex tile, byte trackdir, TransportType type, Owner owner); +NPFFoundTargetData NPFRouteToDepotBreadthFirst(TileIndex tile, Trackdir trackdir, TransportType type, Owner owner); /* Same as above but with two start nodes, the second being the reverse. Call * NPFGetBit(result.node, NPF_FLAG_REVERSE) to see from which node the path * orginated. All pathfs from the second node will have the given * reverse_penalty applied (NPF_TILE_LENGTH is the equivalent of one full * tile). */ -NPFFoundTargetData NPFRouteToDepotBreadthFirstTwoWay(TileIndex tile1, byte trackdir1, TileIndex tile2, byte trackdir2, TransportType type, Owner owner, uint reverse_penalty); +NPFFoundTargetData NPFRouteToDepotBreadthFirstTwoWay(TileIndex tile1, Trackdir trackdir1, TileIndex tile2, Trackdir trackdir2, TransportType type, Owner owner, uint reverse_penalty); /* Search by trying each depot in order of Manhattan Distance. Good for lots * of choices and accurate heuristics, such as water. */ -NPFFoundTargetData NPFRouteToDepotTrialError(TileIndex tile, byte trackdir, TransportType type, Owner owner); +NPFFoundTargetData NPFRouteToDepotTrialError(TileIndex tile, Trackdir trackdir, TransportType type, Owner owner); void NPFFillWithOrderData(NPFFindStationOrTileData* fstd, Vehicle* v); @@ -107,95 +107,4 @@ static inline void NPFSetFlag(AyStarNode CLRBIT(node->user_data[NPF_NODE_FLAGS], flag); } -/* - * Some tables considering tracks, directions and signals. - * XXX: Better place to but these? - */ - -/** - * Maps a trackdir to the bit that stores its status in the map arrays, in the - * direction along with the trackdir. - */ -const byte _signal_along_trackdir[14]; - -/** - * Maps a trackdir to the bit that stores its status in the map arrays, in the - * direction against the trackdir. - */ -const byte _signal_against_trackdir[14]; - -/** - * Maps a trackdir to the trackdirs that can be reached from it (ie, when - * entering the next tile. - */ -const uint16 _trackdir_reaches_trackdirs[14]; - -/** - * Maps a trackdir to the trackdir that you will end up on if you go straight - * ahead. This will be the same trackdir for diagonal trackdirs, but a - * different (alternating) one for straight trackdirs */ -const uint16 _next_trackdir[14]; -/** - * Maps a trackdir to all trackdirs that make 90 deg turns with it. - */ -const uint16 _trackdir_crosses_trackdirs[14]; - -/** - * Maps a track to all tracks that make 90 deg turns with it. - */ -const byte _track_crosses_tracks[6]; - -/** - * Maps a trackdir to the (4-way) direction the tile is exited when following - * that trackdir. - */ -const byte _trackdir_to_exitdir[14]; - -/** - * Maps a track and an (4-way) dir to the trackdir that represents the track - * with the exit in the given direction. - */ -const byte _track_exitdir_to_trackdir[6][4]; - -/** - * Maps a track and a full (8-way) direction to the trackdir that represents - * the track running in the given direction. - */ -const byte _track_direction_to_trackdir[6][8]; - -/** - * Maps a (4-way) direction to the diagonal track that runs in that - * direction. - */ -const byte _dir_to_diag_trackdir[4]; - -/** - * Maps a (4-way) direction to the reverse. - */ -const byte _reverse_dir[4]; - -/** - * Maps a trackdir to the reverse trackdir. - */ -const byte _reverse_trackdir[14]; - -/* Returns the Track that a given Trackdir represents */ -static inline byte TrackdirToTrack(byte trackdir) { return trackdir & 0x7; } - -/* Returns a Trackdir for the given Track. Since every Track corresponds to - * two Trackdirs, we choose the one which points between N and SE. - * Note that the actual implementation is quite futile, but this might change - * in the future. - */ -static inline byte TrackToTrackdir(byte track) { return track; } - -/* Checks if a given Track is diagonal */ -static inline bool IsDiagonalTrack(byte track) { return track == 0x0 || track == 0x1; } - -/* Checks if a given Trackdir is diagonal. */ -static inline bool IsDiagonalTrackdir(byte trackdir) { return IsDiagonalTrack(TrackdirToTrack(trackdir)); } - - -#define REVERSE_TRACKDIR(trackdir) (trackdir ^ 0x8) - #endif // NPF_H diff --git a/rail.c b/rail.c new file mode 100644 --- /dev/null +++ b/rail.c @@ -0,0 +1,93 @@ +#include "rail.h" + +/* Maps a trackdir to the bit that stores its status in the map arrays, in the + * direction along with the trackdir */ +const byte _signal_along_trackdir[] = { + 0x80, 0x80, 0x80, 0x20, 0x40, 0x10, 0, 0, + 0x40, 0x40, 0x40, 0x10, 0x80, 0x20 +}; + +/* Maps a trackdir to the bit that stores its status in the map arrays, in the + * direction against the trackdir */ +const byte _signal_against_trackdir[] = { + 0x40, 0x40, 0x40, 0x10, 0x80, 0x20, 0, 0, + 0x80, 0x80, 0x80, 0x20, 0x40, 0x10 +}; + +/* Maps a Track to the bits that store the status of the two signals that can + * be present on the given track */ +const byte _signal_on_track[] = { + 0xC0, 0xC0, 0xC0, 0x30, 0xC0, 0x30 +}; + +/* Maps a diagonal direction to the all trackdirs that are connected to any + * track entering in this direction (including those making 90 degree turns) + */ +const TrackdirBits _exitdir_reaches_trackdirs[] = { + TRACKDIR_BIT_DIAG1_NE|TRACKDIR_BIT_LOWER_E|TRACKDIR_BIT_LEFT_N, /* DIAGDIR_NE */ + TRACKDIR_BIT_DIAG2_SE|TRACKDIR_BIT_LEFT_S |TRACKDIR_BIT_UPPER_E, /* DIAGDIR_SE */ + TRACKDIR_BIT_DIAG1_SW|TRACKDIR_BIT_UPPER_W|TRACKDIR_BIT_RIGHT_S, /* DIAGDIR_SW */ + TRACKDIR_BIT_DIAG2_NW|TRACKDIR_BIT_RIGHT_N|TRACKDIR_BIT_LOWER_W /* DIAGDIR_NW */ +}; + +/* TODO: Remove magic numbers from tables below just like + * _exitdir_reaches_trackdirs[] */ + +const Trackdir _next_trackdir[14] = { + 0, 1, 3, 2, 5, 4, 0, 0, + 8, 9, 11, 10, 13, 12 +}; + +/* Maps a trackdir to all trackdirs that make 90 deg turns with it. */ +const TrackdirBits _trackdir_crosses_trackdirs[] = { + 0x0202, 0x0101, 0x3030, 0x3030, 0x0C0C, 0x0C0C, 0, 0, + 0x0202, 0x0101, 0x3030, 0x3030, 0x0C0C, 0x0C0C +}; + +/* Maps a track to all tracks that make 90 deg turns with it. */ +const TrackBits _track_crosses_tracks[] = { + 0x2, /* Track 1 -> Track 2 */ + 0x1, /* Track 2 -> Track 1 */ + 0x30, /* Upper -> Left | Right */ + 0x30, /* Lower -> Left | Right */ + 0x0C, /* Left -> Upper | Lower */ + 0x0C, /* Right -> Upper | Lower */ +}; + +/* Maps a trackdir to the (4-way) direction the tile is exited when following + * that trackdir */ +const DiagDirection _trackdir_to_exitdir[] = { + 0,1,0,1,2,1, 0,0, + 2,3,3,2,3,0, +}; + +const Trackdir _track_exitdir_to_trackdir[][DIAGDIR_END] = { + {0, 0xff, 8, 0xff}, + {0xff, 1, 0xff, 9}, + {2, 0xff, 0xff, 10}, + {0xff, 3, 11, 0xf}, + {0xff, 0xff, 4, 12}, + {13, 5, 0xff, 0xff} +}; + +const Trackdir _track_direction_to_trackdir[][DIR_END] = { + {0xff, 0, 0xff, 0xff, 0xff, 8, 0xff, 0xff}, + {0xff, 0xff, 0xff, 1, 0xff, 0xff, 0xff, 9}, + {0xff, 0xff, 2, 0xff, 0xff, 0xff, 10, 0xff}, + {0xff, 0xff, 3, 0xff, 0xff, 0xff, 11, 0xff}, + {12, 0xff, 0xff, 0xff, 4, 0xff, 0xff, 0xff}, + {13, 0xff, 0xff, 0xff, 5, 0xff, 0xff, 0xff} +}; + +const Trackdir _dir_to_diag_trackdir[] = { + 0, 1, 8, 9, +}; + +const DiagDirection _reverse_diagdir[] = { + 2, 3, 0, 1 +}; + +const Trackdir _reverse_trackdir[] = { + 8, 9, 10, 11, 12, 13, 0xFF, 0xFF, + 0, 1, 2, 3, 4, 5 +}; diff --git a/rail.h b/rail.h new file mode 100644 --- /dev/null +++ b/rail.h @@ -0,0 +1,397 @@ +#ifndef RAIL_H +#define RAIL_H + +#include "stdafx.h" +#include "openttd.h" +#include "tile.h" + +/* + * Some enums for accesing the map bytes for rail tiles + */ + +/* These types are used in the map5 byte for rail tiles. Use GetRailTileType() to + * get these values */ +typedef enum RailTileTypes { + RAIL_TYPE_NORMAL = 0x0, + RAIL_TYPE_SIGNALS = 0x40, + RAIL_TYPE_UNUSED = 0x80, /* XXX: Maybe this could become waypoints? */ + RAIL_TYPE_DEPOT_WAYPOINT = 0xC0, /* Is really depots and waypoints... */ + RAIL_TILE_TYPE_MASK = 0xC0, +} RailTileType; + +enum { /* DEPRECATED TODO: Rewrite all uses of this */ + RAIL_TYPE_SPECIAL = 0x80, /* This used to say "If this bit is set, then it's + * not a regular track.", but currently, you + * should rather view map5[6..7] as one type, + * containing a value from RailTileTypes above. + * This value is only maintained for backwards + * compatibility */ + + /* There used to be RAIL_BIT_* enums here, they moved to (for now) npf.c as + * TRACK_BIT_* */ +}; + +/* These subtypes are used in the map5 byte when the main rail type is + * RAIL_TYPE_DEPOT_WAYPOINT */ +typedef enum { + RAIL_SUBTYPE_DEPOT = 0x00, + RAIL_SUBTYPE_WAYPOINT = 0x04, + RAIL_SUBTYPE_MASK = 0x3C, +} RailTileSubtype; + +typedef enum { + /* Stored in _map3_hi[0..1] for MP_RAILWAY */ + SIGTYPE_NORMAL = 0, // normal signal + SIGTYPE_ENTRY = 1, // presignal block entry + SIGTYPE_EXIT = 2, // presignal block exit + SIGTYPE_COMBO = 3, // presignal inter-block + SIGTYPE_END, + SIGTYPE_MASK = 3, +} SignalType; + +typedef enum { + RAILTYPE_RAIL = 0, + RAILTYPE_MONO = 1, + RAILTYPE_MAGLEV = 2, + RAILTYPE_END, + RAILTYPE_MASK = 0x3, + INVALID_RAILTYPE = 0xFF, +} RailType; + +enum { + SIG_SEMAPHORE_MASK = 4, +}; + +/* These are used to specify a single track. Can be translated to a trackbit + * with TrackToTrackbit */ +typedef enum { + TRACK_DIAG1 = 0, + TRACK_DIAG2 = 1, + TRACK_UPPER = 2, + TRACK_LOWER = 3, + TRACK_LEFT = 4, + TRACK_RIGHT = 5, + TRACK_END, + INVALID_TRACK = 0xFF, +} Track; + +/* These are the bitfield variants of the above */ +typedef enum { + TRACK_BIT_DIAG1 = 1, // 0 + TRACK_BIT_DIAG2 = 2, // 1 + TRACK_BIT_UPPER = 4, // 2 + TRACK_BIT_LOWER = 8, // 3 + TRACK_BIT_LEFT = 16, // 4 + TRACK_BIT_RIGHT = 32, // 5 + TRACK_BIT_MASK = 0x3F, +} TrackBits; + +/* 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. */ +typedef enum { + TRACKDIR_DIAG1_NE = 0, + TRACKDIR_DIAG2_SE = 1, + TRACKDIR_UPPER_E = 2, + TRACKDIR_LOWER_E = 3, + TRACKDIR_LEFT_S = 4, + TRACKDIR_RIGHT_S = 5, + /* Note the two missing values here. This enables trackdir -> track conversion by doing (trackdir & 7) */ + TRACKDIR_DIAG1_SW = 8, + TRACKDIR_DIAG2_NW = 9, + TRACKDIR_UPPER_W = 10, + TRACKDIR_LOWER_W = 11, + TRACKDIR_LEFT_N = 12, + TRACKDIR_RIGHT_N = 13, + TRACKDIR_END, + INVALID_TRACKDIR = 0xFF, +} Trackdir; + +/* 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. */ +typedef enum { + TRACKDIR_BIT_DIAG1_NE = 0x1, + TRACKDIR_BIT_DIAG2_SE = 0x2, + TRACKDIR_BIT_UPPER_E = 0x4, + TRACKDIR_BIT_LOWER_E = 0x8, + TRACKDIR_BIT_LEFT_S = 0x10, + TRACKDIR_BIT_RIGHT_S = 0x20, + /* Again, note the two missing values here. This enables trackdir -> track conversion by doing (trackdir & 0xFF) */ + TRACKDIR_BIT_DIAG1_SW = 0x0100, + TRACKDIR_BIT_DIAG2_NW = 0x0200, + TRACKDIR_BIT_UPPER_W = 0x0400, + TRACKDIR_BIT_LOWER_W = 0x0800, + TRACKDIR_BIT_LEFT_N = 0x1000, + TRACKDIR_BIT_RIGHT_N = 0x2000, + TRACKDIR_BIT_MASK = 0x3F3F, + INVALID_TRACKDIR_BIT = 0xFFFF, +} TrackdirBits; + +/* These are states in which a signal can be. Currently these are only two, so + * simple boolean logic will do. But do try to compare to this enum instead of + * normal boolean evaluation, since that will make future additions easier. + */ +typedef enum { + SIGNALSTATE_RED = 0, + SIGNALSTATE_GREEN = 1, +} SignalState; + + +/* + * These functions check the validity of Tracks and Trackdirs. assert against + * them when convenient. + */ +static inline bool IsValidTrack(Track track) { return track < TRACK_END; } +static inline bool IsValidTrackdir(Trackdir trackdir) { return trackdir < TRACKDIR_END; } + +/* + * Functions to map tracks to the corresponding bits in the signal + * presence/status bytes in the map. You should not use these directly, but + * wrapper functions below instead. XXX: Which are these? + */ + +/** + * Maps a trackdir to the bit that stores its status in the map arrays, in the + * direction along with the trackdir. + */ +const byte _signal_along_trackdir[TRACKDIR_END]; +static inline byte SignalAlongTrackdir(Trackdir trackdir) {return _signal_along_trackdir[trackdir];} + +/** + * Maps a trackdir to the bit that stores its status in the map arrays, in the + * direction against the trackdir. + */ +const byte _signal_against_trackdir[TRACKDIR_END]; +static inline byte SignalAgainstTrackdir(Trackdir trackdir) { return _signal_against_trackdir[trackdir]; } + +/** + * Maps a Track to the bits that store the status of the two signals that can + * be present on the given track. + */ +const byte _signal_on_track[TRACK_END]; +static inline byte SignalOnTrack(Track track) { return _signal_on_track[track]; } + +/* + * Some functions to query rail tiles + */ + +/** + * Returns the RailTileType of a given rail tile. (ie normal, with signals, + * depot, etc.) + */ +static inline RailTileType GetRailTileType(TileIndex tile) +{ + assert(IsTileType(tile, MP_RAILWAY)); + return (_map5[tile] & RAIL_TILE_TYPE_MASK); +} + +/** + * Returns the rail type of the given rail tile (ie rail, mono, maglev). + */ +static inline RailType GetRailType(TileIndex tile) { return _map3_lo[tile] & RAILTYPE_MASK; } + +/** + * Checks if a rail tile has signals. + */ +static inline bool HasSignals(TileIndex tile) +{ + return GetRailTileType(tile) == RAIL_TYPE_SIGNALS; +} + +/** + * Returns the RailTileSubtype of a given rail tile with type + * RAIL_TYPE_DEPOT_WAYPOINT + */ +static inline RailTileSubtype GetRailTileSubtype(TileIndex tile) +{ + assert(GetRailTileType(tile) == RAIL_TYPE_DEPOT_WAYPOINT); + return _map5[tile] & RAIL_SUBTYPE_MASK; +} + +/** + * Returns whether this is plain rails, with or without signals. Iow, if this + * tiles RailTileType is RAIL_TYPE_NORMAL or RAIL_TYPE_SIGNALS. + */ +static inline bool IsPlainRailTile(TileIndex tile) +{ + RailTileType rtt = GetRailTileType(tile); + return rtt == RAIL_TYPE_NORMAL || rtt == RAIL_TYPE_SIGNALS; +} + +/** + * Returns the tracks present on the given plain rail tile (IsPlainRailTile()) + */ +static inline TrackBits GetTrackBits(TileIndex tile) +{ + assert(GetRailTileType(tile) == RAIL_TYPE_NORMAL || GetRailTileType(tile) == RAIL_TYPE_SIGNALS); + return _map5[tile] & TRACK_BIT_MASK; +} + +/** + * Returns whether the given track is present on the given tile. Tile must be + * a plain rail tile (IsPlainRailTile()). + */ +static inline bool HasTrack(TileIndex tile, Track track) +{ + assert(IsValidTrack(track)); + return HASBIT(GetTrackBits(tile), track); +} + +/* + * Functions describing logical relations between Tracks, TrackBits, Trackdirs + * TrackdirBits, Direction and DiagDirections. + * + * TODO: Add #unndefs or something similar to remove the arrays used below + * from the global scope and expose direct uses of them. + */ + +/** + * Maps a trackdir to the trackdir that you will end up on if you go straight + * ahead. This will be the same trackdir for diagonal trackdirs, but a + * different (alternating) one for straight trackdirs + */ +const Trackdir _next_trackdir[TRACKDIR_END]; +static inline Trackdir NextTrackdir(Trackdir trackdir) { return _next_trackdir[trackdir]; } + +/** + * Maps a track to all tracks that make 90 deg turns with it. + */ +const TrackBits _track_crosses_tracks[TRACK_END]; +static inline TrackBits TrackCrossesTracks(Track track) { return _track_crosses_tracks[track]; } + +/** + * Maps a trackdir to the (4-way) direction the tile is exited when following + * that trackdir. + */ +const DiagDirection _trackdir_to_exitdir[TRACKDIR_END]; +static inline DiagDirection TrackdirToExitdir(Trackdir trackdir) { return _trackdir_to_exitdir[trackdir]; } + +/** + * Maps a track and an (4-way) dir to the trackdir that represents the track + * with the exit in the given direction. + */ +const Trackdir _track_exitdir_to_trackdir[TRACK_END][DIAGDIR_END]; +static inline Trackdir TrackExitdirToTrackdir(Track track, DiagDirection diagdir) { return _track_exitdir_to_trackdir[track][diagdir]; } + +/** + * Maps a track and a full (8-way) direction to the trackdir that represents + * the track running in the given direction. + */ +const Trackdir _track_direction_to_trackdir[TRACK_END][DIR_END]; +static inline Trackdir TrackDirectionToTrackdir(Track track, Direction dir) { return _track_direction_to_trackdir[track][dir]; } + +/** + * Maps a (4-way) direction to the diagonal trackdir that runs in that + * direction. + */ +const Trackdir _dir_to_diag_trackdir[DIAGDIR_END]; +static inline Trackdir DiagdirToDiagTrackdir(DiagDirection diagdir) { return _dir_to_diag_trackdir[diagdir]; } + +/** + * Maps a trackdir to the trackdirs that can be reached from it (ie, when + * entering the next tile. This + */ +const TrackdirBits _exitdir_reaches_trackdirs[DIAGDIR_END]; +/* Note that there is no direct table for this function (there used to be), + * but it uses two simpeler tables to achieve the result */ +static inline TrackdirBits TrackdirReachesTrackdirs(Trackdir trackdir) { return _exitdir_reaches_trackdirs[TrackdirToExitdir(trackdir)]; } + +/** + * Maps a trackdir to all trackdirs that make 90 deg turns with it. + */ +const TrackdirBits _trackdir_crosses_trackdirs[TRACKDIR_END]; +static inline TrackdirBits TrackdirCrossesTrackdirs(Trackdir trackdir) { return _trackdir_crosses_trackdirs[trackdir]; } + +/** + * Maps a (4-way) direction to the reverse. + */ +const DiagDirection _reverse_diagdir[DIAGDIR_END]; +static inline DiagDirection ReverseDiagdir(DiagDirection diagdir) { return _reverse_diagdir[diagdir]; } + +/** + * Maps a trackdir to the reverse trackdir. + */ +const Trackdir _reverse_trackdir[TRACKDIR_END]; +static inline Trackdir ReverseTrackdir(Trackdir trackdir) { return _reverse_trackdir[trackdir]; } + +/** + * Maps a Trackdir to the corresponding TrackdirBits value + */ +static inline TrackdirBits TrackdirToTrackdirBits(Trackdir trackdir) { return 1 << trackdir; } + +/* + * Maps a Track to the corresponding TrackBits value + */ +static inline TrackBits TrackToTrackBits(Track track) { return 1 << track; } + +/* Returns the Track that a given Trackdir represents */ +static inline Track TrackdirToTrack(Trackdir trackdir) { return trackdir & 0x7; } + +/* Returns a Trackdir for the given Track. Since every Track corresponds to + * two Trackdirs, we choose the one which points between N and SE. + * Note that the actual implementation is quite futile, but this might change + * in the future. + */ +static inline Trackdir TrackToTrackdir(Track track) { return track; } + +/* Checks if a given Track is diagonal */ +static inline bool IsDiagonalTrack(Track track) { return track == TRACK_DIAG1 || track == TRACK_DIAG2; } + +/* Checks if a given Trackdir is diagonal. */ +static inline bool IsDiagonalTrackdir(Trackdir trackdir) { return IsDiagonalTrack(TrackdirToTrack(trackdir)); } + +/* + * Functions quering signals on tiles. + */ + +/** + * Checks for the presence of signals on the given track on the given tile + */ +static inline bool HasSignalOnTrack(TileIndex tile, Track track) +{ + assert(IsValidTrack(track)); + return (GetRailTileType(tile) == RAIL_TYPE_SIGNALS && (_map3_lo[tile] & SignalOnTrack(track))); +} + +/** + * Gets the state of the signal along the given trackdir. + * + * Along meaning if you are currently driving on the given trackdir, this is + * the signal that is facing us (for which we stop when it's red). + */ +static inline SignalState GetSignalState(TileIndex tile, Trackdir trackdir) +{ + assert(IsValidTrackdir(trackdir)); + assert(HasSignalOnTrack(tile, TrackdirToTrack(trackdir))); + return ((_map2[tile] & SignalAlongTrackdir(trackdir))?SIGNALSTATE_GREEN:SIGNALSTATE_RED); +} + +/** + * Gets the type of signal on a given track on a given rail tile with signals. + * + * Note that currently, the track argument is not used, since + * signal types cannot be mixed. This function is trying to be + * future-compatible, though. + */ +static inline SignalType GetSignalType(TileIndex tile, Track track) +{ + assert(IsValidTrack(track)); + assert(GetRailTileType(tile) == RAIL_TYPE_SIGNALS); + return _map3_hi[tile] & SIGTYPE_MASK; +} + +/** + * Checks if this tile contains semaphores (returns true) or normal signals + * (returns false) on the given track. Does not check if there are actually + * signals on the track, you should use HasSignalsOnTrack() for that. + * + * Note that currently, the track argument is not used, since + * semaphores/electric signals cannot be mixed. This function is trying to be + * future-compatible, though. + */ +static inline bool HasSemaphores(TileIndex tile, Track track) +{ + assert(IsValidTrack(track)); + return _map3_hi[tile] & SIG_SEMAPHORE_MASK; +} + +#endif // RAIL_H diff --git a/rail_cmd.c b/rail_cmd.c --- a/rail_cmd.c +++ b/rail_cmd.c @@ -17,41 +17,12 @@ #include "sprite.h" #include "depot.h" #include "waypoint.h" +#include "rail.h" extern uint16 _custom_sprites_base; void ShowTrainDepotWindow(uint tile); -enum { /* These values are bitmasks for the map5 byte */ - RAIL_TYPE_NORMAL = 0, - RAIL_TYPE_SIGNALS = 0x40, - RAIL_TYPE_SPECIAL = 0x80, // If this bit is set, then it's not a regular track. - RAIL_TYPE_DEPOT = 0xC0, - RAIL_TYPE_MASK = 0xC0, - - RAIL_BIT_DIAG1 = 1, // 0 - RAIL_BIT_DIAG2 = 2, // 1 - RAIL_BIT_UPPER = 4, // 2 - RAIL_BIT_LOWER = 8, // 3 - RAIL_BIT_LEFT = 16, // 4 - RAIL_BIT_RIGHT = 32, // 5 - RAIL_BIT_MASK = 0x3F, - - RAIL_DEPOT_TRACK_MASK = 1, - RAIL_DEPOT_DIR = 3, - - RAIL_SUBTYPE_MASK = 0x3C, - RAIL_SUBTYPE_DEPOT = 0x00, - RAIL_SUBTYPE_WAYPOINT = 0x04 -}; - -static inline bool IsRailDepot(byte m5) -{ - return - (m5 & RAIL_TYPE_MASK) == RAIL_TYPE_DEPOT && - (m5 & RAIL_SUBTYPE_MASK) == RAIL_SUBTYPE_DEPOT; -} - /* Format of rail map5 byte. * 00 abcdef => Normal rail * 01 abcdef => Rail with signals @@ -111,40 +82,38 @@ enum RailMap2Lower4 { * 11uuuudd => rail depot */ -static bool CheckTrackCombination(uint map5, uint trackbits, uint flags) +static bool CheckTrackCombination(TileIndex tile, TrackBits to_build, uint flags) { + RailTileType type = GetRailTileType(tile); + TrackBits current; /* The current track layout */ + TrackBits future; /* The track layout we want to build */ _error_message = STR_1001_IMPOSSIBLE_TRACK_COMBINATION; - switch (map5 & RAIL_TYPE_MASK) { - case RAIL_TYPE_NORMAL: - if (map5 & trackbits) { - _error_message = STR_1007_ALREADY_BUILT; - return false; - } + if (type != RAIL_TYPE_NORMAL && type != RAIL_TYPE_SIGNALS) + return false; /* Cannot build anything on depots and checkpoints */ + + /* So, we have a tile with tracks on it (and possibly signals). Let's see + * what tracks first */ + current = GetTrackBits(tile); + future = current & to_build; - if (flags & DC_NO_RAIL_OVERLAP) { - // Computer players are not allowed to intersect pieces of rail. - map5 |= trackbits; - return - map5 == (RAIL_BIT_UPPER | RAIL_BIT_LOWER) || - map5 == (RAIL_BIT_LEFT | RAIL_BIT_RIGHT); - } else { - return true; - } + /* Are we really building something new? */ + if (current == future) { + /* Nothing new is being built */ + _error_message = STR_1007_ALREADY_BUILT; + return false; + } - case RAIL_TYPE_SIGNALS: - if (map5 & trackbits) { - _error_message = STR_1007_ALREADY_BUILT; - return false; - } - - map5 |= trackbits; - return - map5 == (RAIL_TYPE_SIGNALS | RAIL_BIT_UPPER | RAIL_BIT_LOWER) || - map5 == (RAIL_TYPE_SIGNALS | RAIL_BIT_LEFT | RAIL_BIT_RIGHT); - - default: - return false; + /* Let's see if we may build this */ + if ((flags & DC_NO_RAIL_OVERLAP) || type == RAIL_TYPE_SIGNALS) { + /* If we are not allowed to overlap (flag is on for ai players or we have + * signals on the tile), check that */ + return + future == (TRACK_BIT_UPPER | TRACK_BIT_LOWER) || + future == (TRACK_BIT_LEFT | TRACK_BIT_RIGHT); + } else { + /* Normally, we may overlap and any combination is valid */ + return true; } } @@ -153,68 +122,68 @@ static const byte _valid_tileh_slopes[4] // set of normal ones { - RAIL_BIT_DIAG1|RAIL_BIT_DIAG2|RAIL_BIT_UPPER|RAIL_BIT_LOWER|RAIL_BIT_LEFT|RAIL_BIT_RIGHT, - RAIL_BIT_RIGHT, - RAIL_BIT_UPPER, - RAIL_BIT_DIAG1, + TRACK_BIT_DIAG1|TRACK_BIT_DIAG2|TRACK_BIT_UPPER|TRACK_BIT_LOWER|TRACK_BIT_LEFT|TRACK_BIT_RIGHT, + TRACK_BIT_RIGHT, + TRACK_BIT_UPPER, + TRACK_BIT_DIAG1, - RAIL_BIT_LEFT, + TRACK_BIT_LEFT, 0, - RAIL_BIT_DIAG2, - RAIL_BIT_LOWER, + TRACK_BIT_DIAG2, + TRACK_BIT_LOWER, - RAIL_BIT_LOWER, - RAIL_BIT_DIAG2, + TRACK_BIT_LOWER, + TRACK_BIT_DIAG2, 0, - RAIL_BIT_LEFT, + TRACK_BIT_LEFT, - RAIL_BIT_DIAG1, - RAIL_BIT_UPPER, - RAIL_BIT_RIGHT, + TRACK_BIT_DIAG1, + TRACK_BIT_UPPER, + TRACK_BIT_RIGHT, }, // allowed rail for an evenly raised platform { 0, - RAIL_BIT_LEFT, - RAIL_BIT_LOWER, - RAIL_BIT_DIAG2 | RAIL_BIT_LOWER | RAIL_BIT_LEFT, + TRACK_BIT_LEFT, + TRACK_BIT_LOWER, + TRACK_BIT_DIAG2 | TRACK_BIT_LOWER | TRACK_BIT_LEFT, - RAIL_BIT_RIGHT, - RAIL_BIT_DIAG1|RAIL_BIT_DIAG2|RAIL_BIT_UPPER|RAIL_BIT_LOWER|RAIL_BIT_LEFT|RAIL_BIT_RIGHT, - RAIL_BIT_DIAG1 | RAIL_BIT_LOWER | RAIL_BIT_RIGHT, - RAIL_BIT_DIAG1|RAIL_BIT_DIAG2|RAIL_BIT_UPPER|RAIL_BIT_LOWER|RAIL_BIT_LEFT|RAIL_BIT_RIGHT, + TRACK_BIT_RIGHT, + TRACK_BIT_DIAG1|TRACK_BIT_DIAG2|TRACK_BIT_UPPER|TRACK_BIT_LOWER|TRACK_BIT_LEFT|TRACK_BIT_RIGHT, + TRACK_BIT_DIAG1 | TRACK_BIT_LOWER | TRACK_BIT_RIGHT, + TRACK_BIT_DIAG1|TRACK_BIT_DIAG2|TRACK_BIT_UPPER|TRACK_BIT_LOWER|TRACK_BIT_LEFT|TRACK_BIT_RIGHT, - RAIL_BIT_UPPER, - RAIL_BIT_DIAG1 | RAIL_BIT_UPPER | RAIL_BIT_LEFT, - RAIL_BIT_DIAG1|RAIL_BIT_DIAG2|RAIL_BIT_UPPER|RAIL_BIT_LOWER|RAIL_BIT_LEFT|RAIL_BIT_RIGHT, - RAIL_BIT_DIAG1|RAIL_BIT_DIAG2|RAIL_BIT_UPPER|RAIL_BIT_LOWER|RAIL_BIT_LEFT|RAIL_BIT_RIGHT, + TRACK_BIT_UPPER, + TRACK_BIT_DIAG1 | TRACK_BIT_UPPER | TRACK_BIT_LEFT, + TRACK_BIT_DIAG1|TRACK_BIT_DIAG2|TRACK_BIT_UPPER|TRACK_BIT_LOWER|TRACK_BIT_LEFT|TRACK_BIT_RIGHT, + TRACK_BIT_DIAG1|TRACK_BIT_DIAG2|TRACK_BIT_UPPER|TRACK_BIT_LOWER|TRACK_BIT_LEFT|TRACK_BIT_RIGHT, - RAIL_BIT_DIAG2 | RAIL_BIT_UPPER | RAIL_BIT_RIGHT, - RAIL_BIT_DIAG1|RAIL_BIT_DIAG2|RAIL_BIT_UPPER|RAIL_BIT_LOWER|RAIL_BIT_LEFT|RAIL_BIT_RIGHT, - RAIL_BIT_DIAG1|RAIL_BIT_DIAG2|RAIL_BIT_UPPER|RAIL_BIT_LOWER|RAIL_BIT_LEFT|RAIL_BIT_RIGHT, + TRACK_BIT_DIAG2 | TRACK_BIT_UPPER | TRACK_BIT_RIGHT, + TRACK_BIT_DIAG1|TRACK_BIT_DIAG2|TRACK_BIT_UPPER|TRACK_BIT_LOWER|TRACK_BIT_LEFT|TRACK_BIT_RIGHT, + TRACK_BIT_DIAG1|TRACK_BIT_DIAG2|TRACK_BIT_UPPER|TRACK_BIT_LOWER|TRACK_BIT_LEFT|TRACK_BIT_RIGHT, }, // allowed rail on coast tile { 0, - RAIL_BIT_LEFT, - RAIL_BIT_LOWER, - RAIL_BIT_DIAG2|RAIL_BIT_LEFT|RAIL_BIT_LOWER, + TRACK_BIT_LEFT, + TRACK_BIT_LOWER, + TRACK_BIT_DIAG2|TRACK_BIT_LEFT|TRACK_BIT_LOWER, - RAIL_BIT_RIGHT, - RAIL_BIT_DIAG1|RAIL_BIT_DIAG2|RAIL_BIT_UPPER|RAIL_BIT_LOWER|RAIL_BIT_LEFT|RAIL_BIT_RIGHT, - RAIL_BIT_DIAG1|RAIL_BIT_RIGHT|RAIL_BIT_LOWER, - RAIL_BIT_DIAG1|RAIL_BIT_DIAG2|RAIL_BIT_UPPER|RAIL_BIT_LOWER|RAIL_BIT_LEFT|RAIL_BIT_RIGHT, + TRACK_BIT_RIGHT, + TRACK_BIT_DIAG1|TRACK_BIT_DIAG2|TRACK_BIT_UPPER|TRACK_BIT_LOWER|TRACK_BIT_LEFT|TRACK_BIT_RIGHT, + TRACK_BIT_DIAG1|TRACK_BIT_RIGHT|TRACK_BIT_LOWER, + TRACK_BIT_DIAG1|TRACK_BIT_DIAG2|TRACK_BIT_UPPER|TRACK_BIT_LOWER|TRACK_BIT_LEFT|TRACK_BIT_RIGHT, - RAIL_BIT_UPPER, - RAIL_BIT_DIAG1|RAIL_BIT_LEFT|RAIL_BIT_UPPER, - RAIL_BIT_DIAG1|RAIL_BIT_DIAG2|RAIL_BIT_UPPER|RAIL_BIT_LOWER|RAIL_BIT_LEFT|RAIL_BIT_RIGHT, - RAIL_BIT_DIAG1|RAIL_BIT_DIAG2|RAIL_BIT_UPPER|RAIL_BIT_LOWER|RAIL_BIT_LEFT|RAIL_BIT_RIGHT, + TRACK_BIT_UPPER, + TRACK_BIT_DIAG1|TRACK_BIT_LEFT|TRACK_BIT_UPPER, + TRACK_BIT_DIAG1|TRACK_BIT_DIAG2|TRACK_BIT_UPPER|TRACK_BIT_LOWER|TRACK_BIT_LEFT|TRACK_BIT_RIGHT, + TRACK_BIT_DIAG1|TRACK_BIT_DIAG2|TRACK_BIT_UPPER|TRACK_BIT_LOWER|TRACK_BIT_LEFT|TRACK_BIT_RIGHT, - RAIL_BIT_DIAG2|RAIL_BIT_RIGHT|RAIL_BIT_UPPER, - RAIL_BIT_DIAG1|RAIL_BIT_DIAG2|RAIL_BIT_UPPER|RAIL_BIT_LOWER|RAIL_BIT_LEFT|RAIL_BIT_RIGHT, - RAIL_BIT_DIAG1|RAIL_BIT_DIAG2|RAIL_BIT_UPPER|RAIL_BIT_LOWER|RAIL_BIT_LEFT|RAIL_BIT_RIGHT, + TRACK_BIT_DIAG2|TRACK_BIT_RIGHT|TRACK_BIT_UPPER, + TRACK_BIT_DIAG1|TRACK_BIT_DIAG2|TRACK_BIT_UPPER|TRACK_BIT_LOWER|TRACK_BIT_LEFT|TRACK_BIT_RIGHT, + TRACK_BIT_DIAG1|TRACK_BIT_DIAG2|TRACK_BIT_UPPER|TRACK_BIT_LOWER|TRACK_BIT_LEFT|TRACK_BIT_RIGHT, }, // valid railway crossings on slopes @@ -237,14 +206,14 @@ uint GetRailFoundation(uint tileh, uint if ((~_valid_tileh_slopes[1][tileh] & bits) == 0) return tileh; - if ( ((i=0, tileh == 1) || (i+=2, tileh == 2) || (i+=2, tileh == 4) || (i+=2, tileh == 8)) && (bits == RAIL_BIT_DIAG1 || (i++, bits == RAIL_BIT_DIAG2))) + if ( ((i=0, tileh == 1) || (i+=2, tileh == 2) || (i+=2, tileh == 4) || (i+=2, tileh == 8)) && (bits == TRACK_BIT_DIAG1 || (i++, bits == TRACK_BIT_DIAG2))) return i + 15; return 0; } // -static uint32 CheckRailSlope(uint tileh, uint rail_bits, uint existing, TileIndex tile) +static uint32 CheckRailSlope(uint tileh, TrackBits rail_bits, TrackBits existing, TileIndex tile) { // never allow building on top of steep tiles if (!(tileh & 0x10)) { @@ -261,7 +230,7 @@ static uint32 CheckRailSlope(uint tileh, return 0; if ((~_valid_tileh_slopes[1][tileh] & rail_bits) == 0 || ( // whole tile is leveled up - (rail_bits == RAIL_BIT_DIAG1 || rail_bits == RAIL_BIT_DIAG2) && + (rail_bits == TRACK_BIT_DIAG1 || rail_bits == TRACK_BIT_DIAG2) && (tileh == 1 || tileh == 2 || tileh == 4 || tileh == 8) )) { // partly up if (existing != 0) { @@ -278,42 +247,43 @@ static uint32 CheckRailSlope(uint tileh, } /* Validate functions for rail building */ -static inline bool ValParamTrackOrientation(uint32 rail) {return rail <= 5;} +static inline bool ValParamTrackOrientation(Track track) {return IsValidTrack(track);} /** Build a single piece of rail * @param x,y coordinates on where to build * @param p1 railtype of being built piece (normal, mono, maglev) - * @param p2 rail combination to build + * @param p2 rail track to build */ int32 CmdBuildSingleRail(int x, int y, uint32 flags, uint32 p1, uint32 p2) { TileIndex tile; uint tileh; - uint m5; - uint rail_bit; + uint m5; /* XXX: Used only as a cache, should probably be removed? */ + Track track = (Track)p2; + TrackBits trackbit; int32 cost = 0; int32 ret; - if (!ValParamRailtype(p1) || !ValParamTrackOrientation(p2)) return CMD_ERROR; + if (!ValParamRailtype(p1) || !ValParamTrackOrientation(track)) return CMD_ERROR; tile = TILE_FROM_XY(x, y); tileh = GetTileSlope(tile, NULL); m5 = _map5[tile]; - rail_bit = 1 << p2; + trackbit = TrackToTrackBits(track); SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); switch (GetTileType(tile)) { case MP_TUNNELBRIDGE: if ((m5 & 0xC0) != 0xC0 || // not bridge middle part? - (m5 & 0x01 ? 1 : 2) != rail_bit) { // wrong direction? + (m5 & 0x01 ? 1 : 2) != trackbit) { // wrong direction? // Get detailed error message return DoCommandByTile(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); } switch (m5 & 0x38) { // what's under the bridge? case 0x00: // clear land - ret = CheckRailSlope(tileh, rail_bit, 0, tile); + ret = CheckRailSlope(tileh, trackbit, 0, tile); if (CmdFailed(ret)) return ret; cost += ret; @@ -335,7 +305,7 @@ int32 CmdBuildSingleRail(int x, int y, u break; case MP_RAILWAY: - if (!CheckTrackCombination(m5, rail_bit, flags) || + if (!CheckTrackCombination(tile, trackbit, flags) || !EnsureNoVehicle(tile)) { return CMD_ERROR; } @@ -346,13 +316,13 @@ int32 CmdBuildSingleRail(int x, int y, u return DoCommandByTile(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); } - ret = CheckRailSlope(tileh, rail_bit, m5 & RAIL_BIT_MASK, tile); + ret = CheckRailSlope(tileh, trackbit, GetTrackBits(tile), tile); if (CmdFailed(ret)) return ret; cost += ret; if (flags & DC_EXEC) { _map2[tile] &= ~RAIL_MAP2LO_GROUND_MASK; // Bare land - _map5[tile] = m5 | rail_bit; + _map5[tile] = m5 | trackbit; } break; @@ -362,24 +332,24 @@ int32 CmdBuildSingleRail(int x, int y, u if (!EnsureNoVehicle(tile)) return CMD_ERROR; if ((m5 & 0xF0) == 0 && ( // normal road? - (rail_bit == 1 && m5 == 0x05) || - (rail_bit == 2 && m5 == 0x0A) // correct direction? + (track == TRACK_DIAG1 && m5 == 0x05) || + (track == TRACK_DIAG2 && m5 == 0x0A) // correct direction? )) { if (flags & DC_EXEC) { _map3_lo[tile] = GetTileOwner(tile); SetTileOwner(tile, _current_player); _map3_hi[tile] = p1; - _map5[tile] = 0x10 | (rail_bit == 1 ? 0x08 : 0x00); // level crossing + _map5[tile] = 0x10 | (track == TRACK_DIAG1 ? 0x08 : 0x00); // level crossing } break; } - if (IsLevelCrossing(tile) && (m5 & 0x08 ? 1 : 2) == rail_bit) + if (IsLevelCrossing(tile) && (m5 & 0x08 ? TRACK_DIAG1 : TRACK_DIAG2) == track) return_cmd_error(STR_1007_ALREADY_BUILT); /* FALLTHROUGH */ default: - ret = CheckRailSlope(tileh, rail_bit, 0, tile); + ret = CheckRailSlope(tileh, trackbit, 0, tile); if (CmdFailed(ret)) return ret; cost += ret; @@ -392,14 +362,14 @@ int32 CmdBuildSingleRail(int x, int y, u SetTileOwner(tile, _current_player); _map2[tile] = 0; // Bare land _map3_lo[tile] = p1; // No signals, rail type - _map5[tile] = rail_bit; + _map5[tile] = trackbit; } break; } if (flags & DC_EXEC) { MarkTileDirtyByTile(tile); - SetSignalsOnBothDir(tile, p2); + SetSignalsOnBothDir(tile, track); } return cost + _price.build_rail; @@ -428,89 +398,101 @@ static const byte _signals_table_both[] */ int32 CmdRemoveSingleRail(int x, int y, uint32 flags, uint32 p1, uint32 p2) { - TileInfo ti; + Track track = (Track)p2; + TrackBits trackbit; + uint tileh; TileIndex tile; - byte rail_bit = 1 << p2; + byte m5; if (!ValParamTrackOrientation(p2)) return CMD_ERROR; + trackbit = TrackToTrackBits(track); SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); - FindLandscapeHeight(&ti, x, y); + tile = TILE_FROM_XY(x, y); + tileh = GetTileSlope(tile, NULL); - tile = ti.tile; - - if (!((1< 0)) || ((trdx >= 0) && (dx < 0)) || ((trdy <= 0) && (dy > 0)) || ((trdy >= 0) && (dy < 0))) { - if (!HASBIT(*railbit, 3)) { // first direction is invalid, try the other - SETBIT(*railbit, 3); // reverse the direction + if (!HASBIT(*trackdir, 3)) { // first direction is invalid, try the other + SETBIT(*trackdir, 3); // reverse the direction trdx = -trdx; trdy = -trdy; } else // other direction is invalid too, invalid drag @@ -567,9 +549,9 @@ static int32 ValidateAutoDrag(byte *rail // (for diagonal tracks, this is already made sure of by above test), but: // for non-diagonal tracks, check if the start and end tile are on 1 line - if (*railbit & 0x6) { - trdx = _railbit.xinc[*railbit]; - trdy = _railbit.yinc[*railbit]; + if (!IsDiagonalTrackdir(*trackdir)) { + trdx = _railbit.xinc[*trackdir]; + trdy = _railbit.yinc[*trackdir]; if ((abs(dx) != abs(dy)) && (abs(dx) + abs(trdy) != abs(dy) + abs(trdx))) return CMD_ERROR; } @@ -582,31 +564,33 @@ static int32 ValidateAutoDrag(byte *rail * @param p1 end tile of drag * @param p2 various bitstuffed elements * - p2 = (bit 0-3) - railroad type normal/maglev (0 = normal, 1 = mono, 2 = maglev) - * - p2 = (bit 4-6) - track-orientation, valid values: 0-5 + * - p2 = (bit 4-6) - track-orientation, valid values: 0-5 (Track enum) * - p2 = (bit 7) - 0 = build, 1 = remove tracks */ static int32 CmdRailTrackHelper(int x, int y, uint32 flags, uint32 p1, uint32 p2) { int ex, ey; int32 ret, total_cost = 0; - byte railbit = (p2 >> 4) & 7; + Track track = (Track)((p2 >> 4) & 7); + Trackdir trackdir; byte mode = HASBIT(p2, 7); - if (!ValParamRailtype(p2 & 0x3) || !ValParamTrackOrientation(railbit)) return CMD_ERROR; + if (!ValParamRailtype(p2 & 0x3) || !ValParamTrackOrientation(track)) return CMD_ERROR; if (p1 > MapSize()) return CMD_ERROR; + trackdir = TrackToTrackdir(track); /* unpack end point */ - ex = TileX(p1) * 16; - ey = TileY(p1) * 16; + ex = TileX(p1) * TILE_SIZE; + ey = TileY(p1) * TILE_SIZE; SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); - if (CmdFailed(ValidateAutoDrag(&railbit, x, y, ex, ey))) return CMD_ERROR; + if (CmdFailed(ValidateAutoDrag(&trackdir, x, y, ex, ey))) return CMD_ERROR; if (flags & DC_EXEC) SndPlayTileFx(SND_20_SPLAT_2, TILE_FROM_XY(x,y)); for(;;) { - ret = DoCommand(x, y, p2 & 0x3, railbit & 7, flags, (mode == 0) ? CMD_BUILD_SINGLE_RAIL : CMD_REMOVE_SINGLE_RAIL); + ret = DoCommand(x, y, p2 & 0x3, TrackdirToTrack(trackdir), flags, (mode == 0) ? CMD_BUILD_SINGLE_RAIL : CMD_REMOVE_SINGLE_RAIL); if (CmdFailed(ret)) { if ((_error_message != STR_1007_ALREADY_BUILT) && (mode == 0)) @@ -617,11 +601,11 @@ static int32 CmdRailTrackHelper(int x, i if (x == ex && y == ey) break; - x += _railbit.xinc[railbit]; - y += _railbit.yinc[railbit]; + x += _railbit.xinc[trackdir]; + y += _railbit.yinc[trackdir]; // toggle railbit for the non-diagonal tracks - if (railbit & 0x6) railbit ^= 1; + if (!IsDiagonalTrackdir(trackdir)) trackdir ^= 1; } return (total_cost == 0) ? CMD_ERROR : total_cost; @@ -685,7 +669,7 @@ int32 CmdBuildTrainDepot(int x, int y, u MP_SETTYPE(MP_RAILWAY) | MP_MAP3LO | MP_MAPOWNER_CURRENT | MP_MAP5, p1, /* map3_lo */ - p2 | RAIL_TYPE_DEPOT /* map5 */ + p2 | RAIL_TYPE_DEPOT_WAYPOINT /* map5 */ ); d->xy = tile; @@ -702,59 +686,55 @@ int32 CmdBuildTrainDepot(int x, int y, u * pre/exit/combo-signals, and what-else not * @param x,y coordinates where signals is being built * @param p1 various bitstuffed elements - * - p1 = (bit 0-2) - track-orientation, valid values: 0-5 + * - p1 = (bit 0-2) - track-orientation, valid values: 0-5 (Track enum) * - p1 = (bit 3) - choose semaphores/signals or cycle normal/pre/exit/combo depending on context - * @param p2 used for CmdBuildManySignals() to copy style of first signal + * @param p2 used for CmdBuildManySignals() to copy direction of first signal + * TODO: p2 should be replaced by two bits for "along" and "against" the track. */ int32 CmdBuildSingleSignal(int x, int y, uint32 flags, uint32 p1, uint32 p2) { TileIndex tile = TILE_FROM_XY(x, y); bool semaphore; bool pre_signal; - uint track = p1 & 0x7; + Track track = (Track)(p1 & 0x7); byte m5; int32 cost; + // Same bit, used in different contexts + semaphore = pre_signal = HASBIT(p1, 3); + if (!ValParamTrackOrientation(track) || !IsTileType(tile, MP_RAILWAY) || !EnsureNoVehicle(tile)) return CMD_ERROR; /* Protect against invalid signal copying */ - if (p2 != 0 && (p2 & _signals_table_both[track]) == 0) return CMD_ERROR; + if (p2 != 0 && (p2 & SignalOnTrack(track)) == 0) return CMD_ERROR; m5 = _map5[tile]; - /* You can't build signals in a depot, and the selected track must exist */ - if (m5 & 0x80 || !HASBIT(m5, track)) return CMD_ERROR; + /* You can only build signals on plain rail tiles, and the selected track must exist */ + if (!IsPlainRailTile(tile) || !HasTrack(tile, track)) return CMD_ERROR; if (!CheckTileOwnership(tile)) return CMD_ERROR; _error_message = STR_1005_NO_SUITABLE_RAILROAD_TRACK; { - byte m = m5 & RAIL_BIT_MASK; - if (m != RAIL_BIT_DIAG1 && - m != RAIL_BIT_DIAG2 && - m != RAIL_BIT_UPPER && - m != RAIL_BIT_LOWER && - m != RAIL_BIT_LEFT && - m != RAIL_BIT_RIGHT && - m != (RAIL_BIT_UPPER | RAIL_BIT_LOWER) && - m != (RAIL_BIT_LEFT | RAIL_BIT_RIGHT)) + /* See if this is a valid track combination for signals, (ie, no overlap) */ + TrackBits trackbits = GetTrackBits(tile); + if (KILL_FIRST_BIT(trackbits) != 0 && /* More than one track present */ + trackbits != (TRACK_BIT_UPPER | TRACK_BIT_LOWER) && /* Horizontal parallel, non-intersecting tracks */ + trackbits != (TRACK_BIT_LEFT | TRACK_BIT_RIGHT) /* Vertical parallel, non-intersecting tracks */ + ) return CMD_ERROR; } SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); - // Same bit, used in different contexts - semaphore = pre_signal = HASBIT(p1, 3); - - if ((_map3_lo[tile] & _signals_table_both[track]) == 0) { + if (!HasSignalOnTrack(tile, track)) { // build new signals cost = _price.build_signals; } else { - if (p2 != 0 && - ((semaphore && !HASBIT(_map3_hi[tile], 2)) || - (!semaphore && HASBIT(_map3_hi[tile], 2)))) { + if (p2 != 0 && semaphore != HasSemaphores(tile, track)) { // convert signals <-> semaphores cost = _price.build_signals + _price.remove_signals; } else { @@ -764,7 +744,7 @@ int32 CmdBuildSingleSignal(int x, int y, } if (flags & DC_EXEC) { - if (!(m5 & RAIL_TYPE_SIGNALS)) { + if (GetRailTileType(tile) != RAIL_TYPE_SIGNALS) { // there are no signals at all on this tile yet _map5[tile] |= RAIL_TYPE_SIGNALS; // change into signals _map2[tile] |= 0xF0; // all signals are on @@ -773,20 +753,21 @@ int32 CmdBuildSingleSignal(int x, int y, } if (p2 == 0) { - if ((_map3_lo[tile] & _signals_table_both[track]) == 0) { + if (!HasSignalOnTrack(tile, track)) { // build new signals - _map3_lo[tile] |= _signals_table_both[track]; + _map3_lo[tile] |= SignalOnTrack(track); } else { if (pre_signal) { // cycle between normal -> pre -> exit -> combo -> ... - byte type = (_map3_hi[tile] + 1) & 0x03; + byte type = (GetSignalType(tile, track) + 1) & 0x03; _map3_hi[tile] &= ~0x03; _map3_hi[tile] |= type; } else { // cycle between two-way -> one-way -> one-way -> ... + /* TODO: Rewrite switch into something more general */ switch (track) { - case 3: - case 5: { + case TRACK_LOWER: + case TRACK_RIGHT: { byte signal = (_map3_lo[tile] - 0x10) & 0x30; if (signal == 0) signal = 0x30; _map3_lo[tile] &= ~0x30; @@ -806,9 +787,9 @@ int32 CmdBuildSingleSignal(int x, int y, } } else { /* If CmdBuildManySignals is called with copying signals, just copy the - * style of the first signal given as parameter by CmdBuildManySignals */ - _map3_lo[tile] &= ~_signals_table_both[track]; - _map3_lo[tile] |= p2 & _signals_table_both[track]; + * direction of the first signal given as parameter by CmdBuildManySignals */ + _map3_lo[tile] &= ~SignalOnTrack(track); + _map3_lo[tile] |= p2 & SignalOnTrack(track); // convert between signal<->semaphores when dragging if (semaphore) SETBIT(_map3_hi[tile], 2); @@ -829,7 +810,7 @@ int32 CmdBuildSingleSignal(int x, int y, * @param p2 various bitstuffed elements * - p2 = (bit 0) - 0 = build, 1 = remove signals * - p2 = (bit 3) - 0 = signals, 1 = semaphores - * - p2 = (bit 4- 6) - track-orientation, valid values: 0-5 + * - p2 = (bit 4- 6) - track-orientation, valid values: 0-5 (Track enum) * - p2 = (bit 24-31) - user defined signals_density */ static int32 CmdSignalTrackHelper(int x, int y, uint32 flags, uint32 p1, uint32 p2) @@ -841,8 +822,9 @@ static int32 CmdSignalTrackHelper(int x, bool error = true; int mode = p2 & 0x1; + Track track = (p2 >> 4) & 7; + Trackdir trackdir = TrackToTrackdir(track); byte semaphores = (HASBIT(p2, 3)) ? 8 : 0; - byte railbit = (p2 >> 4) & 0x7; byte signal_density = (p2 >> 24); if (p1 > MapSize()) return CMD_ERROR; @@ -852,37 +834,40 @@ static int32 CmdSignalTrackHelper(int x, /* for vertical/horizontal tracks, double the given signals density * since the original amount will be too dense (shorter tracks) */ - if (railbit & 0x6) signal_density *= 2; + if (!IsDiagonalTrack(track)) + signal_density *= 2; // unpack end tile - ex = TileX(p1) * 16; - ey = TileY(p1) * 16; + ex = TileX(p1) * TILE_SIZE; + ey = TileY(p1) * TILE_SIZE; - if (CmdFailed(ValidateAutoDrag(&railbit, x, y, ex, ey))) return CMD_ERROR; + if (CmdFailed(ValidateAutoDrag(&trackdir, x, y, ex, ey))) return CMD_ERROR; + + track = TrackdirToTrack(trackdir); /* trackdir might have changed, keep track in sync */ // copy the signal-style of the first rail-piece if existing m5 = _map5[tile]; - if (!(m5 & RAIL_TYPE_SPECIAL) && (m5 & RAIL_BIT_MASK) && (m5 & RAIL_TYPE_SIGNALS)) { - signals = _map3_lo[tile] & _signals_table_both[railbit]; - if (signals == 0) signals = _signals_table_both[railbit]; + if (GetRailTileType(tile) == RAIL_TYPE_SIGNALS && GetTrackBits(tile) != 0) { /* XXX: GetTrackBits check useless? */ + signals = _map3_lo[tile] & SignalOnTrack(track); + if (signals == 0) signals = SignalOnTrack(track); /* Can this actually occur? */ - semaphores = (_map3_hi[tile] & ~3) ? 8 : 0; // copy signal/semaphores style (independent of CTRL) + semaphores = (HasSemaphores(tile, track) ? 8 : 0); // copy signal/semaphores style (independent of CTRL) } else // no signals exist, drag a two-way signal stretch - signals = _signals_table_both[railbit]; + signals = SignalOnTrack(track); - /* signal_density_ctr - amount of tiles already processed - * signals_density - patch setting to put signal on every Nth tile (double space on |, -- tracks) + /* signal_ctr - amount of tiles already processed + * signals_density - patch setting to put signal on every Nth tile (double space on |, -- tracks) ********** - * railbit - direction of autorail + * trackdir - trackdir to build with autorail * semaphores - semaphores or signals - * signals - is there a signal/semaphore on the first tile, copy its style (two-way/single-way) - and convert all others to semaphore/signal + * signals - is there a signal/semaphore on the first tile, copy its style (two-way/single-way) + and convert all others to semaphore/signal * mode - 1 remove signals, 0 build signals */ signal_ctr = total_cost = 0; for (;;) { // only build/remove signals with the specified density if ((signal_ctr % signal_density) == 0 ) { - ret = DoCommand(x, y, (railbit & 7) | semaphores, signals, flags, (mode == 1) ? CMD_REMOVE_SIGNALS : CMD_BUILD_SIGNALS); + ret = DoCommand(x, y, TrackdirToTrack(trackdir) | semaphores, signals, flags, (mode == 1) ? CMD_REMOVE_SIGNALS : CMD_BUILD_SIGNALS); /* Abort placement for any other error than NOT_SUITABLE_TRACK * This includes vehicles on track, competitor's tracks, etc. */ @@ -896,12 +881,12 @@ static int32 CmdSignalTrackHelper(int x, if (ex == x && ey == y) break; // reached end of drag - x += _railbit.xinc[railbit]; - y += _railbit.yinc[railbit]; + x += _railbit.xinc[trackdir]; + y += _railbit.yinc[trackdir]; signal_ctr++; // toggle railbit for the non-diagonal tracks (|, -- tracks) - if (railbit & 0x6) railbit ^= 1; + if (!IsDiagonalTrackdir(trackdir)) trackdir ^= 1; } return (error) ? CMD_ERROR : total_cost; @@ -918,18 +903,17 @@ int32 CmdBuildSignalTrack(int x, int y, /** Remove signals * @param x,y coordinates where signal is being deleted from - * @param p1 track combination to remove signal from + * @param p1 track to remove signal from (Track enum) */ int32 CmdRemoveSingleSignal(int x, int y, uint32 flags, uint32 p1, uint32 p2) { TileIndex tile = TILE_FROM_XY(x, y); - uint track = p1 & 0x7; + Track track = (Track)(p1 & 0x7); if (!ValParamTrackOrientation(track) || !IsTileType(tile, MP_RAILWAY) || !EnsureNoVehicle(tile)) return CMD_ERROR; - if ((_map5[tile] & RAIL_TYPE_MASK) != RAIL_TYPE_SIGNALS || - (_map3_lo[tile] & _signals_table_both[track]) == 0) // signals on track? + if (!HasSignalOnTrack(tile, track)) // no signals on track? return CMD_ERROR; /* Only water can remove signals from anyone */ @@ -939,7 +923,7 @@ int32 CmdRemoveSingleSignal(int x, int y /* Do it? */ if (flags & DC_EXEC) { - _map3_lo[tile] &= ~_signals_table_both[track]; + _map3_lo[tile] &= ~SignalOnTrack(track); /* removed last signal from tile? */ if ((_map3_lo[tile] & 0xF0) == 0) { @@ -973,7 +957,7 @@ static int32 DoConvertRail(uint tile, ui return CMD_ERROR; // tile is already of requested type? - if ( (uint)(_map3_lo[tile] & 0xF) == totype) + if ( GetRailType(tile) == totype) return CMD_ERROR; // change type. @@ -982,7 +966,7 @@ static int32 DoConvertRail(uint tile, ui MarkTileDirtyByTile(tile); } - return _price.build_rail >> 1; + return _price.build_rail / 2; } extern int32 DoConvertStationRail(uint tile, uint totype, bool exec); @@ -1006,16 +990,16 @@ int32 CmdConvertRail(int ex, int ey, uin if (p1 > MapSize()) return CMD_ERROR; // make sure sx,sy are smaller than ex,ey - sx = TileX(p1) * 16; - sy = TileY(p1) * 16; + sx = TileX(p1) * TILE_SIZE; + sy = TileY(p1) * TILE_SIZE; if (ex < sx) intswap(ex, sx); if (ey < sy) intswap(ey, sy); money = GetAvailableMoneyForCommand(); cost = 0; - for (x = sx; x <= ex; x += 16) { - for (y = sy; y <= ey; y += 16) { + for (x = sx; x <= ex; x += TILE_SIZE) { + for (y = sy; y <= ey; y += TILE_SIZE) { TileIndex tile = TILE_FROM_XY(x,y); DoConvertRailProc *proc; @@ -1048,7 +1032,7 @@ static int32 RemoveTrainDepot(uint tile, return CMD_ERROR; if (flags & DC_EXEC) { - int track = _map5[tile] & RAIL_DEPOT_TRACK_MASK; + int track = TrackdirToTrack(DiagdirToDiagTrackdir(GetDepotDirection(tile, TRANSPORT_RAIL))); DoDeleteDepot(tile); SetSignalsOnBothDir(tile, track); @@ -1077,7 +1061,7 @@ static int32 ClearTile_Track(TileIndex t cost = 0; - switch (m5 & RAIL_TYPE_MASK) { + switch (GetRailTileType(tile)) { case RAIL_TYPE_SIGNALS: if (_map3_lo[tile] & _signals_table_both[0]) { ret = DoCommandByTile(tile, 0, 0, flags, CMD_REMOVE_SIGNALS); @@ -1090,7 +1074,7 @@ static int32 ClearTile_Track(TileIndex t cost += ret; } - m5 &= RAIL_BIT_MASK; + m5 &= TRACK_BIT_MASK; if (!(flags & DC_EXEC)) { for (; m5 != 0; m5 >>= 1) if (m5 & 1) cost += _price.remove_rail; return cost; @@ -1110,7 +1094,7 @@ static int32 ClearTile_Track(TileIndex t return cost; } - case RAIL_TYPE_DEPOT: + case RAIL_TYPE_DEPOT_WAYPOINT: switch (m5 & RAIL_SUBTYPE_MASK) { case RAIL_SUBTYPE_DEPOT: return RemoveTrainDepot(tile, flags); @@ -1334,28 +1318,28 @@ static void DrawTile_Track(TileInfo *ti) if (!(m5 & RAIL_TYPE_SPECIAL)) { bool special; - m5 &= RAIL_BIT_MASK; + m5 &= TRACK_BIT_MASK; special = false; // select the sprite to use based on the map5 byte. - (image = 0x3F3, m5 == RAIL_BIT_DIAG2) || - (image++, m5 == RAIL_BIT_DIAG1) || - (image++, m5 == RAIL_BIT_UPPER) || - (image++, m5 == RAIL_BIT_LOWER) || - (image++, m5 == RAIL_BIT_RIGHT) || - (image++, m5 == RAIL_BIT_LEFT) || - (image++, m5 == (RAIL_BIT_DIAG1|RAIL_BIT_DIAG2)) || + (image = 0x3F3, m5 == TRACK_BIT_DIAG2) || + (image++, m5 == TRACK_BIT_DIAG1) || + (image++, m5 == TRACK_BIT_UPPER) || + (image++, m5 == TRACK_BIT_LOWER) || + (image++, m5 == TRACK_BIT_RIGHT) || + (image++, m5 == TRACK_BIT_LEFT) || + (image++, m5 == (TRACK_BIT_DIAG1|TRACK_BIT_DIAG2)) || - (image = 0x40B, m5 == (RAIL_BIT_UPPER|RAIL_BIT_LOWER)) || - (image++, m5 == (RAIL_BIT_LEFT|RAIL_BIT_RIGHT)) || + (image = 0x40B, m5 == (TRACK_BIT_UPPER|TRACK_BIT_LOWER)) || + (image++, m5 == (TRACK_BIT_LEFT|TRACK_BIT_RIGHT)) || (special=true, false) || - (image = 0x3FA, !(m5 & (RAIL_BIT_RIGHT|RAIL_BIT_UPPER|RAIL_BIT_DIAG1))) || - (image++, !(m5 & (RAIL_BIT_LEFT|RAIL_BIT_LOWER|RAIL_BIT_DIAG1))) || - (image++, !(m5 & (RAIL_BIT_LEFT|RAIL_BIT_UPPER|RAIL_BIT_DIAG2))) || - (image++, !(m5 & (RAIL_BIT_RIGHT|RAIL_BIT_LOWER|RAIL_BIT_DIAG2))) || + (image = 0x3FA, !(m5 & (TRACK_BIT_RIGHT|TRACK_BIT_UPPER|TRACK_BIT_DIAG1))) || + (image++, !(m5 & (TRACK_BIT_LEFT|TRACK_BIT_LOWER|TRACK_BIT_DIAG1))) || + (image++, !(m5 & (TRACK_BIT_LEFT|TRACK_BIT_UPPER|TRACK_BIT_DIAG2))) || + (image++, !(m5 & (TRACK_BIT_RIGHT|TRACK_BIT_LOWER|TRACK_BIT_DIAG2))) || (image++, true); if (ti->tileh != 0) { @@ -1374,12 +1358,12 @@ static void DrawTile_Track(TileInfo *ti) DrawGroundSprite(image + tracktype_offs); if (special) { - if (m5 & RAIL_BIT_DIAG1) DrawGroundSprite(0x3ED + tracktype_offs); - if (m5 & RAIL_BIT_DIAG2) DrawGroundSprite(0x3EE + tracktype_offs); - if (m5 & RAIL_BIT_UPPER) DrawGroundSprite(0x3EF + tracktype_offs); - if (m5 & RAIL_BIT_LOWER) DrawGroundSprite(0x3F0 + tracktype_offs); - if (m5 & RAIL_BIT_LEFT) DrawGroundSprite(0x3F2 + tracktype_offs); - if (m5 & RAIL_BIT_RIGHT) DrawGroundSprite(0x3F1 + tracktype_offs); + if (m5 & TRACK_BIT_DIAG1) DrawGroundSprite(0x3ED + tracktype_offs); + if (m5 & TRACK_BIT_DIAG2) DrawGroundSprite(0x3EE + tracktype_offs); + if (m5 & TRACK_BIT_UPPER) DrawGroundSprite(0x3EF + tracktype_offs); + if (m5 & TRACK_BIT_LOWER) DrawGroundSprite(0x3F0 + tracktype_offs); + if (m5 & TRACK_BIT_LEFT) DrawGroundSprite(0x3F2 + tracktype_offs); + if (m5 & TRACK_BIT_RIGHT) DrawGroundSprite(0x3F1 + tracktype_offs); } if (_display_opt & DO_FULL_DETAIL) { @@ -1399,21 +1383,21 @@ static void DrawTile_Track(TileInfo *ti) #define ISON_SIGNAL(x) (m23 & (byte)(0x10 << (x))) #define MAYBE_DRAW_SIGNAL(x,y,z) if (HAS_SIGNAL(x)) DrawSignalHelper(ti, ISON_SIGNAL(x), ((y-0x4FB) << 4)|(z)) - if (!(m5 & RAIL_BIT_DIAG2)) { - if (!(m5 & RAIL_BIT_DIAG1)) { - if (m5 & RAIL_BIT_LEFT) { + if (!(m5 & TRACK_BIT_DIAG2)) { + if (!(m5 & TRACK_BIT_DIAG1)) { + if (m5 & TRACK_BIT_LEFT) { MAYBE_DRAW_SIGNAL(2, 0x509, 0); MAYBE_DRAW_SIGNAL(3, 0x507, 1); } - if (m5 & RAIL_BIT_RIGHT) { + if (m5 & TRACK_BIT_RIGHT) { MAYBE_DRAW_SIGNAL(0, 0x509, 2); MAYBE_DRAW_SIGNAL(1, 0x507, 3); } - if (m5 & RAIL_BIT_UPPER) { + if (m5 & TRACK_BIT_UPPER) { MAYBE_DRAW_SIGNAL(3, 0x505, 4); MAYBE_DRAW_SIGNAL(2, 0x503, 5); } - if (m5 & RAIL_BIT_LOWER) { + if (m5 & TRACK_BIT_LOWER) { MAYBE_DRAW_SIGNAL(1, 0x505, 6); MAYBE_DRAW_SIGNAL(0, 0x503, 7); } @@ -1431,8 +1415,11 @@ static void DrawTile_Track(TileInfo *ti) const DrawTrackSeqStruct *drss; byte type = m5 & 0x3F; // 0-3: depots, 4-5: waypoints - if (!(m5 & (RAIL_TYPE_MASK&~RAIL_TYPE_SPECIAL))) - return; + if (!(m5 & (RAIL_TILE_TYPE_MASK&~RAIL_TYPE_SPECIAL))) + /* XXX: There used to be "return;" here, but since I could not find out + * why this would ever occur, I put assert(0) here. Let's see if someone + * complains about it. If not, we'll remove this check. (Matthijs). */ + assert(0); if (ti->tileh != 0) { DrawFoundation(ti, ti->tileh); } @@ -1551,32 +1538,28 @@ static bool SetSignalsEnumProc(uint tile { // the tile has signals? if (IsTileType(tile, MP_RAILWAY)) { - if ((_map5[tile]&RAIL_TYPE_MASK) == RAIL_TYPE_SIGNALS) { - if ((_map3_lo[tile] & _signals_table_both[track]) != 0) { - - // is the signal pointing in to the segment existing? - if ((_map3_lo[tile] & _signals_table[track]) != 0) { - // yes, add the signal to the list of signals - if (ssd->cur != NUM_SSD_ENTRY) { - ssd->tile[ssd->cur] = tile; // remember the tile index - ssd->bit[ssd->cur] = track; // and the controlling bit number - ssd->cur++; - } - - // remember if this block has a presignal. - ssd->has_presignal |= (_map3_hi[tile]&1); + if (HasSignalOnTrack(tile, TrackdirToTrack(track))) { + if ((_map3_lo[tile] & _signals_table[track]) != 0) { + // yes, add the signal to the list of signals + if (ssd->cur != NUM_SSD_ENTRY) { + ssd->tile[ssd->cur] = tile; // remember the tile index + ssd->bit[ssd->cur] = track; // and the controlling bit number + ssd->cur++; } - // is this an exit signal that points out from the segment? - if ((_map3_hi[tile]&2) && _map3_lo[tile]&_signals_table_other[track]) { - ssd->presignal_exits++; - if ((_map2[tile]&_signals_table_other[track]) != 0) - ssd->presignal_exits_free++; - } + // remember if this block has a presignal. + ssd->has_presignal |= (_map3_hi[tile]&1); + } - return true; + // is this an exit signal that points out from the segment? + if ((_map3_hi[tile]&2) && _map3_lo[tile]&_signals_table_other[track]) { + ssd->presignal_exits++; + if ((_map2[tile]&_signals_table_other[track]) != 0) + ssd->presignal_exits_free++; } - } else if (IsRailDepot(_map5[tile])) + + return true; + } else if (IsTileDepotType(tile, TRANSPORT_RAIL)) return true; // don't look further if the tile is a depot } return false; @@ -1891,44 +1874,44 @@ static void TileLoop_Track(uint tile) if (m2 != RAIL_GROUND_BROWN) { /* wait until bottom is green */ /* determine direction of fence */ - rail = _map5[tile] & RAIL_BIT_MASK; + rail = _map5[tile] & TRACK_BIT_MASK; - if (rail == RAIL_BIT_UPPER) { + if (rail == TRACK_BIT_UPPER) { a2 = RAIL_GROUND_FENCE_HORIZ1; - } else if (rail == RAIL_BIT_LOWER) { + } else if (rail == TRACK_BIT_LOWER) { a2 = RAIL_GROUND_FENCE_HORIZ2; - } else if (rail == RAIL_BIT_LEFT) { + } else if (rail == TRACK_BIT_LEFT) { a2 = RAIL_GROUND_FENCE_VERT1; - } else if (rail == RAIL_BIT_RIGHT) { + } else if (rail == TRACK_BIT_RIGHT) { a2 = RAIL_GROUND_FENCE_VERT2; } else { owner = GetTileOwner(tile); - if ( (!(rail&(RAIL_BIT_DIAG2|RAIL_BIT_UPPER|RAIL_BIT_LEFT)) && (rail&RAIL_BIT_DIAG1)) || rail==(RAIL_BIT_LOWER|RAIL_BIT_RIGHT)) { + if ( (!(rail&(TRACK_BIT_DIAG2|TRACK_BIT_UPPER|TRACK_BIT_LEFT)) && (rail&TRACK_BIT_DIAG1)) || rail==(TRACK_BIT_LOWER|TRACK_BIT_RIGHT)) { if (!IsTileType(tile + TILE_XY(0,-1), MP_RAILWAY) || !IsTileOwner(tile + TILE_XY(0, -1), owner) || - (_map5[tile + TILE_XY(0,-1)]==RAIL_BIT_UPPER || _map5[tile + TILE_XY(0,-1)]==RAIL_BIT_LEFT)) + (_map5[tile + TILE_XY(0,-1)]==TRACK_BIT_UPPER || _map5[tile + TILE_XY(0,-1)]==TRACK_BIT_LEFT)) a2 = RAIL_GROUND_FENCE_NW; } - if ( (!(rail&(RAIL_BIT_DIAG2|RAIL_BIT_LOWER|RAIL_BIT_RIGHT)) && (rail&RAIL_BIT_DIAG1)) || rail==(RAIL_BIT_UPPER|RAIL_BIT_LEFT)) { + if ( (!(rail&(TRACK_BIT_DIAG2|TRACK_BIT_LOWER|TRACK_BIT_RIGHT)) && (rail&TRACK_BIT_DIAG1)) || rail==(TRACK_BIT_UPPER|TRACK_BIT_LEFT)) { if (!IsTileType(tile + TILE_XY(0,1), MP_RAILWAY) || !IsTileOwner(tile + TILE_XY(0, 1), owner) || - (_map5[tile + TILE_XY(0,1)]==RAIL_BIT_LOWER || _map5[tile + TILE_XY(0,1)]==RAIL_BIT_RIGHT)) + (_map5[tile + TILE_XY(0,1)]==TRACK_BIT_LOWER || _map5[tile + TILE_XY(0,1)]==TRACK_BIT_RIGHT)) a2 = (a2 == RAIL_GROUND_FENCE_NW) ? RAIL_GROUND_FENCE_SENW : RAIL_GROUND_FENCE_SE; } - if ( (!(rail&(RAIL_BIT_DIAG1|RAIL_BIT_UPPER|RAIL_BIT_RIGHT)) && (rail&RAIL_BIT_DIAG2)) || rail==(RAIL_BIT_LOWER|RAIL_BIT_LEFT)) { + if ( (!(rail&(TRACK_BIT_DIAG1|TRACK_BIT_UPPER|TRACK_BIT_RIGHT)) && (rail&TRACK_BIT_DIAG2)) || rail==(TRACK_BIT_LOWER|TRACK_BIT_LEFT)) { if (!IsTileType(tile + TILE_XY(-1,0), MP_RAILWAY) || !IsTileOwner(tile + TILE_XY(-1, 0), owner) || - (_map5[tile + TILE_XY(-1,0)]==RAIL_BIT_UPPER || _map5[tile + TILE_XY(-1,0)]==RAIL_BIT_RIGHT)) + (_map5[tile + TILE_XY(-1,0)]==TRACK_BIT_UPPER || _map5[tile + TILE_XY(-1,0)]==TRACK_BIT_RIGHT)) a2 = RAIL_GROUND_FENCE_NE; } - if ( (!(rail&(RAIL_BIT_DIAG1|RAIL_BIT_LOWER|RAIL_BIT_LEFT)) && (rail&RAIL_BIT_DIAG2)) || rail==(RAIL_BIT_UPPER|RAIL_BIT_RIGHT)) { + if ( (!(rail&(TRACK_BIT_DIAG1|TRACK_BIT_LOWER|TRACK_BIT_LEFT)) && (rail&TRACK_BIT_DIAG2)) || rail==(TRACK_BIT_UPPER|TRACK_BIT_RIGHT)) { if (!IsTileType(tile + TILE_XY(1,0), MP_RAILWAY) || !IsTileOwner(tile + TILE_XY(1, 0), owner) || - (_map5[tile + TILE_XY(1,0)]==RAIL_BIT_LOWER || _map5[tile + TILE_XY(1,0)]==RAIL_BIT_LEFT)) + (_map5[tile + TILE_XY(1,0)]==TRACK_BIT_LOWER || _map5[tile + TILE_XY(1,0)]==TRACK_BIT_LEFT)) a2 = (a2 == RAIL_GROUND_FENCE_NE) ? RAIL_GROUND_FENCE_NESW : RAIL_GROUND_FENCE_SW; } } @@ -1990,7 +1973,7 @@ static uint32 GetTileTrackStatus_Track(u static void ClickTile_Track(uint tile) { - if (IsRailDepot(_map5[tile])) + if (IsTileDepotType(tile, TRANSPORT_RAIL)) ShowTrainDepotWindow(tile); else if (IsRailWaypoint(_map5[tile])) ShowRenameWaypointWindow(GetWaypointByTile(tile)); @@ -2000,7 +1983,7 @@ static void ClickTile_Track(uint tile) static void GetTileDesc_Track(TileIndex tile, TileDesc *td) { td->owner = GetTileOwner(tile); - switch (_map5[tile] & RAIL_TYPE_MASK) { + switch (GetRailTileType(tile)) { case RAIL_TYPE_NORMAL: td->str = STR_1021_RAILROAD_TRACK; break; @@ -2017,7 +2000,7 @@ static void GetTileDesc_Track(TileIndex break; } - case RAIL_TYPE_DEPOT: + case RAIL_TYPE_DEPOT_WAYPOINT: default: td->str = ((_map5[tile] & RAIL_SUBTYPE_MASK) == RAIL_SUBTYPE_DEPOT) ? STR_1023_RAILROAD_TRAIN_DEPOT : STR_LANDINFO_WAYPOINT; @@ -2054,11 +2037,11 @@ static uint32 VehicleEnter_Track(Vehicle int length; // this routine applies only to trains in depot tiles - if (v->type != VEH_Train || !IsRailDepot(_map5[tile])) + if (v->type != VEH_Train || !IsTileDepotType(tile, TRANSPORT_RAIL)) return 0; /* depot direction */ - dir = _map5[tile] & RAIL_DEPOT_DIR; + dir = GetDepotDirection(tile, TRANSPORT_RAIL); /* calculate the point where the following wagon should be activated */ /* this depends on the length of the current vehicle */ diff --git a/road_cmd.c b/road_cmd.c --- a/road_cmd.c +++ b/road_cmd.c @@ -9,7 +9,6 @@ #include "player.h" #include "town.h" #include "gfx.h" -#include "npf.h" #include "sound.h" #include "depot.h" diff --git a/roadveh_cmd.c b/roadveh_cmd.c --- a/roadveh_cmd.c +++ b/roadveh_cmd.c @@ -317,7 +317,7 @@ static Depot *FindClosestRoadDepot(Vehic if (_patches.new_pathfinding_all) { NPFFoundTargetData ftd; /* See where we are now */ - byte trackdir = GetVehicleTrackdir(v); + Trackdir trackdir = GetVehicleTrackdir(v); ftd = NPFRouteToDepotBreadthFirst(v->tile, trackdir, TRANSPORT_ROAD, v->owner); if (ftd.best_bird_dist == 0) @@ -1101,7 +1101,7 @@ static int RoadFindPathToDest(Vehicle *v byte trackdir; NPFFillWithOrderData(&fstd, v); - trackdir = _dir_to_diag_trackdir[enterdir]; + trackdir = DiagdirToDiagTrackdir(enterdir); //debug("Finding path. Enterdir: %d, Trackdir: %d", enterdir, trackdir); ftd = NPFRouteToStationOrTile(tile - TileOffsByDir(enterdir), trackdir, &fstd, TRANSPORT_ROAD, v->owner); diff --git a/ship_cmd.c b/ship_cmd.c --- a/ship_cmd.c +++ b/ship_cmd.c @@ -568,7 +568,7 @@ static int ChooseShipTrack(Vehicle *v, u if (_patches.new_pathfinding_all) { NPFFindStationOrTileData fstd; NPFFoundTargetData ftd; - uint src_tile = TILE_ADD(tile, TileOffsByDir(_reverse_dir[enterdir])); + uint src_tile = TILE_ADD(tile, TileOffsByDir(ReverseDiagdir(enterdir))); byte trackdir = GetVehicleTrackdir(v); assert (trackdir != 0xFF); /* Check that we are not in a depot */ @@ -594,9 +594,9 @@ static int ChooseShipTrack(Vehicle *v, u tot_dist = (uint)-1; /* Let's find out how far it would be if we would reverse first */ - b = GetTileShipTrackStatus(tile2) & _ship_sometracks[_reverse_dir[enterdir]] & v->u.ship.state; + b = GetTileShipTrackStatus(tile2) & _ship_sometracks[ReverseDiagdir(enterdir)] & v->u.ship.state; if (b != 0) { - dist = FindShipTrack(v, tile2, _reverse_dir[enterdir], b, tile, &track); + dist = FindShipTrack(v, tile2, ReverseDiagdir(enterdir), b, tile, &track); if (dist != (uint)-1) tot_dist = dist + 1; } diff --git a/station_cmd.c b/station_cmd.c --- a/station_cmd.c +++ b/station_cmd.c @@ -18,7 +18,6 @@ #include "player.h" #include "airport.h" #include "sprite.h" -#include "npf.h" #include "depot.h" enum { diff --git a/tile.h b/tile.h --- a/tile.h +++ b/tile.h @@ -18,17 +18,30 @@ typedef enum TileType { MP_UNMOVABLE } TileType; -/* XXX: This should be moved out to a new file (rail.h) along with some other - * cleanups. I'll do that after 0.4) */ -typedef enum { - RAILTYPE_RAIL = 0, - RAILTYPE_MONO = 1, - RAILTYPE_MAGLEV = 2, - RAILTYPE_END, - RAILTYPE_MASK = 0x3, - INVALID_RAILTYPE = 0xFF, -} RailType; +/* TODO: Find out values */ +/* Direction as commonly used in v->direction, 8 way. */ +typedef enum Directions { + DIR_N = 0, + DIR_NE = 1, /* Northeast, upper right on your monitor */ + DIR_E = 2, + DIR_SE = 3, + DIR_S = 4, + DIR_SW = 5, + DIR_W = 6, + DIR_NW = 7, + DIR_END, + INVALID_DIR = 0xFF, +} Direction; +/* Direction commonly used as the direction of entering and leaving tiles, 4-way */ +typedef enum DiagonalDirections { + DIAGDIR_NE = 0, /* Northeast, upper right on your monitor */ + DIAGDIR_SE = 1, + DIAGDIR_SW = 2, + DIAGDIR_NW = 3, + DIAGDIR_END, + INVALID_DIAGDIR = 0xFF, +} DiagDirection; void SetMapExtraBits(TileIndex tile, byte flags); uint GetMapExtraBits(TileIndex tile); diff --git a/train_cmd.c b/train_cmd.c --- a/train_cmd.c +++ b/train_cmd.c @@ -459,8 +459,8 @@ static int32 CmdBuildRailWagon(uint engi v->direction = (byte)(dir*2+1); v->tile = (TileIndex)tile; - x = TileX(tile) * 16 | _vehicle_initial_x_fract[dir]; - y = TileY(tile) * 16 | _vehicle_initial_y_fract[dir]; + x = TileX(tile) * TILE_SIZE | _vehicle_initial_x_fract[dir]; + y = TileY(tile) * TILE_SIZE | _vehicle_initial_y_fract[dir]; v->x_pos = x; v->y_pos = y; @@ -694,6 +694,9 @@ static bool IsTunnelTile(TileIndex tile) } +/* Check if all the wagons of the given train are in a depot, returns the + * number of cars (including loco) then. If not, sets the error message to + * STR_881A_TRAINS_CAN_ONLY_BE_ALTERED and returns -1 */ int CheckTrainStoppedInDepot(const Vehicle *v) { int count; @@ -1525,7 +1528,7 @@ static bool TrainFindDepotEnumProc(uint // make sure the train doesn't run against a oneway signal if ((_map5[tile] & 0xC0) == 0x40) { - if (!(_map3_lo[tile] & _signal_along_trackdir[track]) && _map3_lo[tile] & _signal_against_trackdir[track]) + if (!(_map3_lo[tile] & SignalAlongTrackdir(track)) && _map3_lo[tile] & SignalAgainstTrackdir(track)) return true; } } @@ -1559,10 +1562,10 @@ static TrainFindDepotData FindClosestTra if (_patches.new_pathfinding_all) { NPFFoundTargetData ftd; Vehicle* last = GetLastVehicleInChain(v); - byte trackdir = GetVehicleTrackdir(v); - byte trackdir_rev = REVERSE_TRACKDIR(GetVehicleTrackdir(last)); - - assert (trackdir != 0xFF); + Trackdir trackdir = GetVehicleTrackdir(v); + Trackdir trackdir_rev = ReverseTrackdir(GetVehicleTrackdir(last)); + + assert (trackdir != INVALID_TRACKDIR); ftd = NPFRouteToDepotBreadthFirstTwoWay(v->tile, trackdir, last->tile, trackdir_rev, TRANSPORT_RAIL, v->owner, NPF_INFINITE_PENALTY); if (ftd.best_bird_dist == 0) { /* Found target */ @@ -1808,14 +1811,14 @@ static bool TrainTrackFollower(uint tile if (IsTileType(tile, MP_RAILWAY) && (_map5[tile]&0xC0) == 0x40) { // the tile has a signal byte m3 = _map3_lo[tile]; - if (!(m3 & _signal_along_trackdir[track])) { + if (!(m3 & SignalAlongTrackdir(track))) { // if one way signal not pointing towards us, stop going in this direction. - if (m3 & _signal_against_trackdir[track]) + if (m3 & SignalAgainstTrackdir(track)) return true; - } else if (_map2[tile] & _signal_along_trackdir[track]) { + } else if (_map2[tile] & SignalAlongTrackdir(track)) { // green signal in our direction. either one way or two way. *state = true; - } else if (m3 & _signal_against_trackdir[track]) { + } else if (m3 & SignalAgainstTrackdir(track)) { // two way signal. unless we passed another green signal on the way, // stop going in this direction. if (!*state) return true; @@ -1904,26 +1907,25 @@ unsigned int rdtsc() /* choose a track */ -static byte ChooseTrainTrack(Vehicle *v, uint tile, int enterdir, byte trackbits) +static byte ChooseTrainTrack(Vehicle *v, uint tile, int enterdir, TrackdirBits trackdirbits) { TrainTrackFollowerData fd; - int bits = trackbits; uint best_track; #if PF_BENCHMARK int time = rdtsc(); static float f; #endif - assert( (bits & ~0x3F) == 0); + assert( (trackdirbits & ~0x3F) == 0); /* quick return in case only one possible track is available */ - if (KILL_FIRST_BIT(bits) == 0) - return FIND_FIRST_BIT(bits); + if (KILL_FIRST_BIT(trackdirbits) == 0) + return FIND_FIRST_BIT(trackdirbits); if (_patches.new_pathfinding_all) { /* Use a new pathfinding for everything */ NPFFindStationOrTileData fstd; NPFFoundTargetData ftd; - byte trackdir; + Trackdir trackdir; NPFFillWithOrderData(&fstd, v); /* The enterdir for the new tile, is the exitdir for the old tile */ @@ -1936,7 +1938,7 @@ static byte ChooseTrainTrack(Vehicle *v, /* We are already at our target. Just do something */ //TODO: maybe display error? //TODO: go straight ahead if possible? - best_track = FIND_FIRST_BIT(bits); + best_track = FIND_FIRST_BIT(trackdirbits); } else { /* If ftd.best_bird_dist is 0, we found our target and ftd.best_trackdir contains the direction we need to take to get there, if ftd.best_bird_dist is not 0, @@ -1960,7 +1962,7 @@ static byte ChooseTrainTrack(Vehicle *v, if (fd.best_track == 0xff) { // blaha - best_track = FIND_FIRST_BIT(bits); + best_track = FIND_FIRST_BIT(trackdirbits); } else { best_track = fd.best_track & 7; } @@ -1975,8 +1977,8 @@ static byte ChooseTrainTrack(Vehicle *v, best_track = (uint)-1; do { - i = FIND_FIRST_BIT(bits); - bits = KILL_FIRST_BIT(bits); + i = FIND_FIRST_BIT(trackdirbits); + trackdirbits = KILL_FIRST_BIT(trackdirbits); fd.best_bird_dist = (uint)-1; fd.best_track_dist = (uint)-1; @@ -2016,7 +2018,7 @@ static byte ChooseTrainTrack(Vehicle *v, best_bird_dist = fd.best_bird_dist; best_track_dist = fd.best_track_dist; bad:; - } while (bits != 0); + } while (trackdirbits != 0); // printf("Train %d %s\n", v->unitnumber, best_track_dist == -1 ? "NOTFOUND" : "FOUND"); assert(best_track != (uint)-1); } @@ -2064,7 +2066,7 @@ static bool CheckReverseTrain(Vehicle *v NPFFillWithOrderData(&fstd, v); trackdir = GetVehicleTrackdir(v); - trackdir_rev = REVERSE_TRACKDIR(GetVehicleTrackdir(last)); + trackdir_rev = ReverseTrackdir(GetVehicleTrackdir(last)); assert(trackdir != 0xff); assert(trackdir_rev != 0xff); @@ -2704,7 +2706,7 @@ static void TrainController(Vehicle *v) if (_patches.new_pathfinding_all && _patches.forbid_90_deg && prev == NULL) /* We allow wagons to make 90 deg turns, because forbid_90_deg * can be switched on halfway a turn */ - bits &= ~_track_crosses_tracks[FIND_FIRST_BIT(v->u.rail.track)]; + bits &= ~TrackCrossesTracks(FIND_FIRST_BIT(v->u.rail.track)); if ( bits == 0) { //debug("%x == 0", bits); @@ -2821,13 +2823,13 @@ red_light: { * FIND_FIRST_BIT only handles 6 bits at a time. */ i = FindFirstBit2x64(ts); - if (!(_map3_lo[gp.new_tile] & _signal_against_trackdir[i])) { + if (!(_map3_lo[gp.new_tile] & SignalAgainstTrackdir(i))) { v->cur_speed = 0; v->subspeed = 0; v->progress = 255-100; if (++v->load_unload_time_rem < _patches.wait_oneway_signal * 20) return; - } else if (_map3_lo[gp.new_tile] & _signal_along_trackdir[i]){ + } else if (_map3_lo[gp.new_tile] & SignalAlongTrackdir(i)){ v->cur_speed = 0; v->subspeed = 0; v->progress = 255-10; diff --git a/vehicle.c b/vehicle.c --- a/vehicle.c +++ b/vehicle.c @@ -15,10 +15,10 @@ #include "engine.h" #include "sound.h" #include "debug.h" -#include "npf.h" #include "vehicle_gui.h" #include "depot.h" #include "station.h" +#include "rail.h" #define INVALID_COORD (-0x8000) #define GEN_HASH(x,y) (((x & 0x1F80)>>7) + ((y & 0xFC0))) @@ -1752,7 +1752,8 @@ byte GetVehicleTrackdir(const Vehicle* v return _track_direction_to_trackdir[FIND_FIRST_BIT(v->u.rail.track)][v->direction]; break; case VEH_Ship: - if (v->u.ship.state == 0x80) /* We'll assume the ship is facing outwards */ + if (v->u.ship.state == 0x80) /* Inside a depot? */ + /* We'll assume the ship is facing outwards */ return _dir_to_diag_trackdir[GetDepotDirection(v->tile, TRANSPORT_WATER)]; /* Ship in depot */ return _track_direction_to_trackdir[FIND_FIRST_BIT(v->u.ship.state)][v->direction];