diff --git a/src/ai/default/default.cpp b/src/ai/default/default.cpp index 8533e6eba1..80956386b4 100644 --- a/src/ai/default/default.cpp +++ b/src/ai/default/default.cpp @@ -2579,11 +2579,11 @@ static int32 AiDoBuildDefaultRoadBlock(TileIndex tile, const AiDefaultBlockData if (p->mode == 2) { if (IsTileType(c, MP_STREET) && GetRoadTileType(c) == ROAD_TILE_NORMAL && - (GetRoadBits(c) & p->attr) != 0) { + (GetRoadBits(c, ROADTYPE_ROAD) & p->attr) != 0) { roadflag |= 2; // all bits are already built? - if ((GetRoadBits(c) & p->attr) == p->attr) continue; + if ((GetRoadBits(c, ROADTYPE_ROAD) & p->attr) == p->attr) continue; } ret = DoCommand(c, p->attr, 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD); diff --git a/src/bridge_map.h b/src/bridge_map.h index 5f270dc1a2..062bfc0c81 100644 --- a/src/bridge_map.h +++ b/src/bridge_map.h @@ -211,7 +211,6 @@ static inline void SetBridgeMiddle(TileIndex t, Axis a) SETBIT(_m[t].m6, 6 + a); } - /** * Generic part to make a bridge ramp for both roads and rails. * @param t the tile to make a bridge ramp @@ -219,13 +218,15 @@ static inline void SetBridgeMiddle(TileIndex t, Axis a) * @param bridgetype the type of bridge this bridge ramp belongs to * @param d the direction this ramp must be facing * @param tt the transport type of the bridge + * @param rt the road or rail type * @note this function should not be called directly. */ -static inline void MakeBridgeRamp(TileIndex t, Owner o, uint bridgetype, DiagDirection d, TransportType tt) +static inline void MakeBridgeRamp(TileIndex t, Owner o, uint bridgetype, DiagDirection d, TransportType tt, uint rt) { SetTileType(t, MP_TUNNELBRIDGE); SetTileOwner(t, o); _m[t].m2 = bridgetype << 4; + _m[t].m3 = rt; _m[t].m4 = 0; _m[t].m5 = 1 << 7 | tt << 2 | d; } @@ -236,11 +237,11 @@ static inline void MakeBridgeRamp(TileIndex t, Owner o, uint bridgetype, DiagDir * @param o the new owner of the bridge ramp * @param bridgetype the type of bridge this bridge ramp belongs to * @param d the direction this ramp must be facing + * @param r the road type of the bridge */ -static inline void MakeRoadBridgeRamp(TileIndex t, Owner o, uint bridgetype, DiagDirection d) +static inline void MakeRoadBridgeRamp(TileIndex t, Owner o, uint bridgetype, DiagDirection d, RoadTypes r) { - MakeBridgeRamp(t, o, bridgetype, d, TRANSPORT_ROAD); - _m[t].m3 = 0; + MakeBridgeRamp(t, o, bridgetype, d, TRANSPORT_ROAD, r); } /** @@ -253,8 +254,7 @@ static inline void MakeRoadBridgeRamp(TileIndex t, Owner o, uint bridgetype, Dia */ static inline void MakeRailBridgeRamp(TileIndex t, Owner o, uint bridgetype, DiagDirection d, RailType r) { - MakeBridgeRamp(t, o, bridgetype, d, TRANSPORT_RAIL); - _m[t].m3 = r; + MakeBridgeRamp(t, o, bridgetype, d, TRANSPORT_RAIL, r); } diff --git a/src/openttd.cpp b/src/openttd.cpp index 26119e9e33..69cb5c0dee 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -1108,8 +1108,8 @@ static void ConvertTownOwner() for (tile = 0; tile != MapSize(); tile++) { switch (GetTileType(tile)) { case MP_STREET: - if (IsLevelCrossing(tile) && GetCrossingRoadOwner(tile) & 0x80) { - SetCrossingRoadOwner(tile, OWNER_TOWN); + if (GB(_m[tile].m5, 4, 2) == ROAD_TILE_CROSSING && HASBIT(_m[tile].m4, 7)) { + _m[tile].m4 = OWNER_TOWN; } /* FALLTHROUGH */ @@ -1414,6 +1414,70 @@ bool AfterLoadGame() } } + if (CheckSavegameVersion(48)) { + for (TileIndex t = 0; t < map_size; t++) { + switch (GetTileType(t)) { + case MP_RAILWAY: + if (IsPlainRailTile(t)) { + /* Swap ground type and signal type for plain rail tiles, so the + * ground type uses the same bits as for depots and waypoints. */ + uint tmp = GB(_m[t].m4, 0, 4); + SB(_m[t].m4, 0, 4, GB(_m[t].m2, 0, 4)); + SB(_m[t].m2, 0, 4, tmp); + } else if (HASBIT(_m[t].m5, 2)) { + /* Split waypoint and depot rail type and remove the subtype. */ + CLRBIT(_m[t].m5, 2); + CLRBIT(_m[t].m5, 6); + } + break; + + case MP_STREET: + /* Swap m3 and m4, so the track type for rail crossings is the + * same as for normal rail. */ + Swap(_m[t].m3, _m[t].m4); + break; + + default: break; + } + } + } + + if (CheckSavegameVersion(61)) { + /* Added the RoadType */ + for (TileIndex t = 0; t < map_size; t++) { + switch(GetTileType(t)) { + case MP_STREET: + SB(_m[t].m5, 6, 2, GB(_m[t].m5, 4, 2)); + switch (GetRoadTileType(t)) { + default: NOT_REACHED(); + case ROAD_TILE_NORMAL: + SB(_m[t].m4, 0, 4, GB(_m[t].m5, 0, 4)); + SB(_m[t].m4, 4, 4, 0); + SB(_m[t].m6, 2, 4, 0); + break; + case ROAD_TILE_CROSSING: + SB(_m[t].m4, 5, 2, GB(_m[t].m5, 2, 2)); + break; + case ROAD_TILE_DEPOT: break; + } + SetRoadTypes(t, ROADTYPES_ROAD); + break; + + case MP_STATION: + if (IsRoadStop(t)) SetRoadTypes(t, ROADTYPES_ROAD); + break; + + case MP_TUNNELBRIDGE: + if ((IsTunnel(t) ? GetTunnelTransportType(t) : GetBridgeTransportType(t)) == TRANSPORT_ROAD) { + SetRoadTypes(t, ROADTYPES_ROAD); + } + break; + + default: break; + } + } + } + if (CheckSavegameVersion(42)) { Vehicle* v; @@ -1436,9 +1500,10 @@ bool AfterLoadGame() MakeRoadNormal( t, - GetTileOwner(t), axis == AXIS_X ? ROAD_Y : ROAD_X, - town + ROADTYPES_ROAD, + town, + GetTileOwner(t), OWNER_NONE, OWNER_NONE ); } } else { @@ -1486,34 +1551,6 @@ bool AfterLoadGame() } } - if (CheckSavegameVersion(48)) { - for (TileIndex t = 0; t < map_size; t++) { - switch (GetTileType(t)) { - case MP_RAILWAY: - if (IsPlainRailTile(t)) { - /* Swap ground type and signal type for plain rail tiles, so the - * ground type uses the same bits as for depots and waypoints. */ - uint tmp = GB(_m[t].m4, 0, 4); - SB(_m[t].m4, 0, 4, GB(_m[t].m2, 0, 4)); - SB(_m[t].m2, 0, 4, tmp); - } else if (HASBIT(_m[t].m5, 2)) { - /* Split waypoint and depot rail type and remove the subtype. */ - CLRBIT(_m[t].m5, 2); - CLRBIT(_m[t].m5, 6); - } - break; - - case MP_STREET: - /* Swap m3 and m4, so the track type for rail crossings is the - * same as for normal rail. */ - Swap(_m[t].m3, _m[t].m4); - break; - - default: break; - } - } - } - /* Elrails got added in rev 24 */ if (CheckSavegameVersion(24)) { Vehicle *v; @@ -1772,8 +1809,6 @@ bool AfterLoadGame() * space for newhouses grf features. A new byte, m7, was also added. */ if (CheckSavegameVersion(53)) { for (TileIndex t = 0; t < map_size; t++) { - _me[t].m7 = 0; - if (IsTileType(t, MP_HOUSE)) { if (GB(_m[t].m3, 6, 2) != TOWN_HOUSE_COMPLETED) { /* Move the construction stage from m3[7..6] to m5[5..4]. diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index be0bbd93a7..3280b13cdf 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -295,10 +295,25 @@ int32 CmdBuildSingleRail(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) if (GetRoadTileType(tile) == ROAD_TILE_NORMAL) { if (HasRoadWorks(tile)) return_cmd_error(STR_ROAD_WORKS_IN_PROGRESS); - if ((track == TRACK_X && GetRoadBits(tile) == ROAD_Y) || - (track == TRACK_Y && GetRoadBits(tile) == ROAD_X)) { + RoadTypes roadtypes = GetRoadTypes(tile); + RoadBits road = GetRoadBits(tile, ROADTYPE_ROAD); + RoadBits tram = GetRoadBits(tile, ROADTYPE_TRAM); + switch (roadtypes) { + default: break; + case ROADTYPES_ROADTRAM: if (road == tram) break; + /* FALL THROUGH */ + case ROADTYPES_ROADHWAY: // Road and highway are incompatible in this case + case ROADTYPES_TRAMHWAY: // Tram and highway are incompatible in this case + case ROADTYPES_ALL: // Also incompatible + return CMD_ERROR; + } + + road |= tram | GetRoadBits(tile, ROADTYPE_HWAY); + + if ((track == TRACK_X && road == ROAD_Y) || + (track == TRACK_Y && road == ROAD_X)) { if (flags & DC_EXEC) { - MakeRoadCrossing(tile, GetTileOwner(tile), _current_player, (track == TRACK_X ? AXIS_Y : AXIS_X), railtype, GetTownIndex(tile)); + MakeRoadCrossing(tile, GetRoadOwner(tile, ROADTYPE_ROAD), GetRoadOwner(tile, ROADTYPE_TRAM), GetRoadOwner(tile, ROADTYPE_HWAY), _current_player, (track == TRACK_X ? AXIS_Y : AXIS_X), railtype, roadtypes, GetTownIndex(tile)); } break; } @@ -359,7 +374,7 @@ int32 CmdRemoveSingleRail(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) } if (flags & DC_EXEC) { - MakeRoadNormal(tile, GetCrossingRoadOwner(tile), GetCrossingRoadBits(tile), GetTownIndex(tile)); + MakeRoadNormal(tile, GetCrossingRoadBits(tile), GetRoadTypes(tile), GetTownIndex(tile), GetRoadOwner(tile, ROADTYPE_ROAD), GetRoadOwner(tile, ROADTYPE_TRAM), GetRoadOwner(tile, ROADTYPE_HWAY)); } break; } diff --git a/src/road.h b/src/road.h index 035ec8089f..4c875dce00 100644 --- a/src/road.h +++ b/src/road.h @@ -7,6 +7,68 @@ #include "helpers.hpp" +/** + * The different roadtypes we support + * @note currently only ROADTYPE_ROAD is supported. + */ +enum RoadType { + ROADTYPE_ROAD = 0, + ROADTYPE_TRAM = 1, + ROADTYPE_HWAY = 2, ///< Only a placeholder. Not sure what we are going to do with this road type. + ROADTYPE_END, + INVALID_ROADTYPE = 0xFF +}; +DECLARE_POSTFIX_INCREMENT(RoadType); + +/** + * The different roadtypes we support, but then a bitmask of them + * @note currently only ROADTYPES_ROAD is supported. + */ +enum RoadTypes { + ROADTYPES_NONE = 0, + ROADTYPES_ROAD = 1 << ROADTYPE_ROAD, + ROADTYPES_TRAM = 1 << ROADTYPE_TRAM, + ROADTYPES_HWAY = 1 << ROADTYPE_HWAY, + ROADTYPES_ROADTRAM = ROADTYPES_ROAD | ROADTYPES_TRAM, + ROADTYPES_ROADHWAY = ROADTYPES_ROAD | ROADTYPES_HWAY, + ROADTYPES_TRAMHWAY = ROADTYPES_TRAM | ROADTYPES_HWAY, + ROADTYPES_ALL = ROADTYPES_ROAD | ROADTYPES_TRAM | ROADTYPES_HWAY, +}; +DECLARE_ENUM_AS_BIT_SET(RoadTypes); + +/** + * Whether the given roadtype is valid. + * @param rt the roadtype to check for validness + * @return true if and only if valid + */ +static inline bool IsValidRoadType(RoadType rt) +{ + return rt == ROADTYPE_ROAD; +} + +/** + * Are the given bits pointing to valid roadtypes? + * @param rts the roadtypes to check for validness + * @return true if and only if valid + */ +static inline bool AreValidRoadTypes(RoadTypes rts) +{ + return rts == ROADTYPES_ROAD; +} + +/** + * Maps a RoadType to the corresponding RoadTypes value + */ +static inline RoadTypes RoadTypeToRoadTypes(RoadType rt) +{ + return (RoadTypes)(1 << rt); +} + +static inline RoadTypes ComplementRoadTypes(RoadTypes r) +{ + return (RoadTypes)(ROADTYPES_ALL ^ r); +} + enum RoadBits { ROAD_NONE = 0U, ROAD_NW = 1U, @@ -48,8 +110,9 @@ static inline bool IsStraightRoadTrackdir(Trackdir dir) * @param remove the roadbits that are going to be removed * @param owner the actual owner of the roadbits of the tile * @param edge_road are the removed bits from a town? + * @param rt the road type to remove the bits from * @return true when it is allowed to remove the road bits */ -bool CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, Owner owner, bool *edge_road); +bool CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, Owner owner, bool *edge_road, RoadType rt); #endif /* ROAD_H */ diff --git a/src/road_cmd.cpp b/src/road_cmd.cpp index 1ad5ce9e7c..636fed9a7a 100644 --- a/src/road_cmd.cpp +++ b/src/road_cmd.cpp @@ -41,13 +41,13 @@ static uint CountRoadBits(RoadBits r) } -bool CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, Owner owner, bool *edge_road) +bool CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, Owner owner, bool *edge_road, RoadType rt) { RoadBits present; RoadBits n; *edge_road = true; - if (_game_mode == GM_EDITOR) return true; + if (_game_mode == GM_EDITOR || remove == ROAD_NONE) return true; /* Only do the special processing for actual players. */ if (!IsValidPlayer(_current_player)) return true; @@ -60,11 +60,11 @@ bool CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, Owner owner, bool *ed /* Get a bitmask of which neighbouring roads has a tile */ n = ROAD_NONE; - present = GetAnyRoadBits(tile); - if (present & ROAD_NE && GetAnyRoadBits(TILE_ADDXY(tile, -1, 0)) & ROAD_SW) n |= ROAD_NE; - if (present & ROAD_SE && GetAnyRoadBits(TILE_ADDXY(tile, 0, 1)) & ROAD_NW) n |= ROAD_SE; - if (present & ROAD_SW && GetAnyRoadBits(TILE_ADDXY(tile, 1, 0)) & ROAD_NE) n |= ROAD_SW; - if (present & ROAD_NW && GetAnyRoadBits(TILE_ADDXY(tile, 0, -1)) & ROAD_SE) n |= ROAD_NW; + present = GetAnyRoadBits(tile, rt); + if (present & ROAD_NE && GetAnyRoadBits(TILE_ADDXY(tile, -1, 0), rt) & ROAD_SW) n |= ROAD_NE; + if (present & ROAD_SE && GetAnyRoadBits(TILE_ADDXY(tile, 0, 1), rt) & ROAD_NW) n |= ROAD_SE; + if (present & ROAD_SW && GetAnyRoadBits(TILE_ADDXY(tile, 1, 0), rt) & ROAD_NE) n |= ROAD_SW; + if (present & ROAD_NW && GetAnyRoadBits(TILE_ADDXY(tile, 0, -1), rt) & ROAD_SE) n |= ROAD_NW; /* If 0 or 1 bits are set in n, or if no bits that match the bits to remove, * then allow it */ @@ -84,15 +84,16 @@ bool CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, Owner owner, bool *ed return true; } -static bool CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, bool *edge_road) +static bool CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, bool *edge_road, RoadType rt) { - return CheckAllowRemoveRoad(tile, remove, IsLevelCrossingTile(tile) ? GetCrossingRoadOwner(tile) : GetTileOwner(tile), edge_road); + return CheckAllowRemoveRoad(tile, remove, GetRoadOwner(tile, rt), edge_road, rt); } /** Delete a piece of road. * @param tile tile where to remove road from * @param flags operation to perform * @param p1 bit 0..3 road pieces to remove (RoadBits) + * bit 4..5 road type * @param p2 unused */ int32 CmdRemoveRoad(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) @@ -100,7 +101,6 @@ int32 CmdRemoveRoad(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) /* cost for removing inner/edge -roads */ static const uint16 road_remove_cost[2] = {50, 18}; - Owner owner; Town *t; /* true if the roadpiece was always removeable, * false if it was a center piece. Affects town ratings drop */ @@ -108,9 +108,10 @@ int32 CmdRemoveRoad(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); - if (!IsTileType(tile, MP_STREET)) return CMD_ERROR; + RoadType rt = (RoadType)GB(p1, 4, 2); + if (!IsTileType(tile, MP_STREET) || !IsValidRoadType(rt)) return CMD_ERROR; - owner = IsLevelCrossingTile(tile) ? GetCrossingRoadOwner(tile) : GetTileOwner(tile); + Owner owner = GetRoadOwner(tile, rt); if (owner == OWNER_TOWN && _game_mode != GM_EDITOR) { t = GetTownByTile(tile); @@ -119,8 +120,11 @@ int32 CmdRemoveRoad(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) } RoadBits pieces = Extract(p1); + RoadTypes rts = GetRoadTypes(tile); + /* The tile doesn't have the given road type */ + if (!HASBIT(rts, rt)) return CMD_ERROR; - if (!CheckAllowRemoveRoad(tile, pieces, &edge_road)) return CMD_ERROR; + if (!CheckAllowRemoveRoad(tile, pieces, &edge_road, rt)) return CMD_ERROR; if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR; @@ -130,7 +134,7 @@ int32 CmdRemoveRoad(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) switch (GetRoadTileType(tile)) { case ROAD_TILE_NORMAL: { - RoadBits present = GetRoadBits(tile); + RoadBits present = GetRoadBits(tile, rt); RoadBits c = pieces; if (HasRoadWorks(tile)) return_cmd_error(STR_ROAD_WORKS_IN_PROGRESS); @@ -150,9 +154,14 @@ int32 CmdRemoveRoad(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) present ^= c; if (present == 0) { - DoClearSquare(tile); + RoadTypes rts = GetRoadTypes(tile) & ComplementRoadTypes(RoadTypeToRoadTypes(rt)); + if (rts == ROADTYPES_NONE) { + DoClearSquare(tile); + } else { + SetRoadTypes(tile, rts); + } } else { - SetRoadBits(tile, present); + SetRoadBits(tile, present, rt); MarkTileDirtyByTile(tile); } } @@ -165,9 +174,16 @@ int32 CmdRemoveRoad(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) } if (flags & DC_EXEC) { - ChangeTownRating(t, -road_remove_cost[(byte)edge_road], RATING_ROAD_MINIMUM); + if (rt == ROADTYPE_ROAD) { + ChangeTownRating(t, -road_remove_cost[(byte)edge_road], RATING_ROAD_MINIMUM); + } - MakeRailNormal(tile, GetTileOwner(tile), GetCrossingRailBits(tile), GetRailType(tile)); + RoadTypes rts = GetRoadTypes(tile) & ComplementRoadTypes(RoadTypeToRoadTypes(rt)); + if (rts == ROADTYPES_NONE) { + MakeRailNormal(tile, GetTileOwner(tile), GetCrossingRailBits(tile), GetRailType(tile)); + } else { + SetRoadTypes(tile, rts); + } MarkTileDirtyByTile(tile); YapfNotifyTrackLayoutChange(tile, FindFirstTrack(GetTrackBits(tile))); } @@ -255,6 +271,7 @@ static uint32 CheckRoadSlope(Slope tileh, RoadBits* pieces, RoadBits existing) * @param tile tile where to build road * @param flags operation to perform * @param p1 bit 0..3 road pieces to build (RoadBits) + * bit 4..5 road type * @param p2 the town that is building the road (0 if not applicable) */ int32 CmdBuildRoad(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) @@ -272,6 +289,9 @@ int32 CmdBuildRoad(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) RoadBits pieces = Extract(p1); + RoadType rt = (RoadType)GB(p1, 4, 2); + if (!IsValidRoadType(rt)) return CMD_ERROR; + tileh = GetTileSlope(tile, NULL); switch (GetTileType(tile)) { @@ -280,7 +300,7 @@ int32 CmdBuildRoad(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) case ROAD_TILE_NORMAL: if (HasRoadWorks(tile)) return_cmd_error(STR_ROAD_WORKS_IN_PROGRESS); - existing = GetRoadBits(tile); + existing = GetRoadBits(tile, rt); if ((existing & pieces) == pieces) { return_cmd_error(STR_1007_ALREADY_BUILT); } @@ -288,10 +308,9 @@ int32 CmdBuildRoad(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) break; case ROAD_TILE_CROSSING: - if (pieces != GetCrossingRoadBits(tile)) { // XXX is this correct? - return_cmd_error(STR_1007_ALREADY_BUILT); - } - goto do_clear; + if (HASBIT(GetRoadTypes(tile), rt)) return_cmd_error(STR_1007_ALREADY_BUILT); + if (pieces & ComplementRoadBits(GetCrossingRoadBits(tile))) goto do_clear; + break; default: case ROAD_TILE_DEPOT: @@ -332,7 +351,7 @@ int32 CmdBuildRoad(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) if (flags & DC_EXEC) { YapfNotifyTrackLayoutChange(tile, FindFirstTrack(GetTrackBits(tile))); - MakeRoadCrossing(tile, _current_player, GetTileOwner(tile), roaddir, GetRailType(tile), p2); + MakeRoadCrossing(tile, _current_player, _current_player, _current_player, GetTileOwner(tile), roaddir, GetRailType(tile), RoadTypeToRoadTypes(rt), p2); MarkTileDirtyByTile(tile); } return _price.build_road * 2; @@ -362,9 +381,13 @@ do_clear:; if (flags & DC_EXEC) { if (IsTileType(tile, MP_STREET)) { - SetRoadBits(tile, existing | pieces); + if (existing == 0) { + SetRoadTypes(tile, GetRoadTypes(tile) | RoadTypeToRoadTypes(rt)); + SetRoadOwner(tile, rt, _current_player); + } + SetRoadBits(tile, existing | pieces, rt); } else { - MakeRoadNormal(tile, _current_player, pieces, p2); + MakeRoadNormal(tile, pieces, RoadTypeToRoadTypes(rt), p2, _current_player, _current_player, _current_player); } MarkTileDirtyByTile(tile); @@ -411,6 +434,7 @@ int32 DoConvertStreetRail(TileIndex tile, RailType totype, bool exec) * - p2 = (bit 0) - start tile starts in the 2nd half of tile (p2 & 1) * - p2 = (bit 1) - end tile starts in the 2nd half of tile (p2 & 2) * - p2 = (bit 2) - direction: 0 = along x-axis, 1 = along y-axis (p2 & 4) + * - p2 = (bit 3) - road type */ int32 CmdBuildLongRoad(TileIndex end_tile, uint32 flags, uint32 p1, uint32 p2) { @@ -422,6 +446,7 @@ int32 CmdBuildLongRoad(TileIndex end_tile, uint32 flags, uint32 p1, uint32 p2) if (p1 >= MapSize()) return CMD_ERROR; start_tile = p1; + RoadType rt = (RoadType)HASBIT(p2, 3); /* Only drag in X or Y direction dictated by the direction variable */ if (!HASBIT(p2, 2) && TileY(start_tile) != TileY(end_tile)) return CMD_ERROR; // x-axis @@ -444,7 +469,7 @@ int32 CmdBuildLongRoad(TileIndex end_tile, uint32 flags, uint32 p1, uint32 p2) if (tile == end_tile && !HASBIT(p2, 1)) bits &= ROAD_NW | ROAD_NE; if (tile == start_tile && HASBIT(p2, 0)) bits &= ROAD_SE | ROAD_SW; - ret = DoCommand(tile, bits, 0, flags, CMD_BUILD_ROAD); + ret = DoCommand(tile, rt << 4 | bits, 0, flags, CMD_BUILD_ROAD); if (CmdFailed(ret)) { if (_error_message != STR_1007_ALREADY_BUILT) return CMD_ERROR; _error_message = INVALID_STRING_ID; @@ -468,6 +493,7 @@ int32 CmdBuildLongRoad(TileIndex end_tile, uint32 flags, uint32 p1, uint32 p2) * - p2 = (bit 0) - start tile starts in the 2nd half of tile (p2 & 1) * - p2 = (bit 1) - end tile starts in the 2nd half of tile (p2 & 2) * - p2 = (bit 2) - direction: 0 = along x-axis, 1 = along y-axis (p2 & 4) + * - p2 = (bit 3) - road type */ int32 CmdRemoveLongRoad(TileIndex end_tile, uint32 flags, uint32 p1, uint32 p2) { @@ -479,6 +505,7 @@ int32 CmdRemoveLongRoad(TileIndex end_tile, uint32 flags, uint32 p1, uint32 p2) if (p1 >= MapSize()) return CMD_ERROR; start_tile = p1; + RoadType rt = (RoadType)HASBIT(p2, 3); /* Only drag in X or Y direction dictated by the direction variable */ if (!HASBIT(p2, 2) && TileY(start_tile) != TileY(end_tile)) return CMD_ERROR; // x-axis @@ -503,7 +530,7 @@ int32 CmdRemoveLongRoad(TileIndex end_tile, uint32 flags, uint32 p1, uint32 p2) /* try to remove the halves. */ if (bits != 0) { - ret = DoCommand(tile, bits, 0, flags, CMD_REMOVE_ROAD); + ret = DoCommand(tile, rt << 4 | bits, 0, flags, CMD_REMOVE_ROAD); if (!CmdFailed(ret)) cost += ret; } @@ -519,6 +546,7 @@ int32 CmdRemoveLongRoad(TileIndex end_tile, uint32 flags, uint32 p1, uint32 p2) * @param tile tile where to build the depot * @param flags operation to perform * @param p1 bit 0..1 entrance direction (DiagDirection) + * bit 2 road type * @param p2 unused * * @todo When checking for the tile slope, @@ -533,6 +561,7 @@ int32 CmdBuildRoadDepot(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); DiagDirection dir = Extract(p1); + RoadType rt = (RoadType)HASBIT(p1, 2); tileh = GetTileSlope(tile, NULL); if (tileh != SLOPE_FLAT && ( @@ -555,7 +584,7 @@ int32 CmdBuildRoadDepot(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) dep->xy = tile; dep->town_index = ClosestTownFromTile(tile, (uint)-1)->index; - MakeRoadDepot(tile, _current_player, dir); + MakeRoadDepot(tile, _current_player, dir, rt); MarkTileDirtyByTile(tile); } return cost + _price.build_road_depot; @@ -577,7 +606,7 @@ static int32 ClearTile_Road(TileIndex tile, byte flags) { switch (GetRoadTileType(tile)) { case ROAD_TILE_NORMAL: { - RoadBits b = GetRoadBits(tile); + RoadBits b = GetAllRoadBits(tile); #define M(x) (1 << (x)) /* Clear the road if only one piece is on the tile OR the AI tries @@ -685,7 +714,7 @@ static bool AlwaysDrawUnpavedRoads(TileIndex tile, Roadside roadside) */ static void DrawRoadBits(TileInfo* ti) { - RoadBits road = GetRoadBits(ti->tile); + RoadBits road = GetRoadBits(ti->tile, ROADTYPE_ROAD); const DrawRoadTileStruct *drts; SpriteID image = 0; SpriteID pal = PAL_NONE; @@ -836,7 +865,7 @@ static uint GetSlopeZ_Road(TileIndex tile, uint x, uint y) if (tileh == SLOPE_FLAT) return z; if (GetRoadTileType(tile) == ROAD_TILE_NORMAL) { - uint f = GetRoadFoundation(tileh, GetRoadBits(tile)); + uint f = GetRoadFoundation(tileh, GetAllRoadBits(tile)); if (f != 0) { if (IsSteepSlope(tileh)) { @@ -856,7 +885,7 @@ static Slope GetSlopeTileh_Road(TileIndex tile, Slope tileh) { if (tileh == SLOPE_FLAT) return SLOPE_FLAT; if (GetRoadTileType(tile) == ROAD_TILE_NORMAL) { - uint f = GetRoadFoundation(tileh, GetRoadBits(tile)); + uint f = GetRoadFoundation(tileh, GetAllRoadBits(tile)); if (f == 0) return tileh; if (f < 15) return SLOPE_FLAT; // leveled foundation @@ -924,7 +953,7 @@ static void TileLoop_Road(TileIndex tile) /* Show an animation to indicate road work */ if (t->road_build_months != 0 && (DistanceManhattan(t->xy, tile) < 8 || grp != 0) && - GetRoadTileType(tile) == ROAD_TILE_NORMAL && (GetRoadBits(tile) == ROAD_X || GetRoadBits(tile) == ROAD_Y)) { + GetRoadTileType(tile) == ROAD_TILE_NORMAL && (GetAllRoadBits(tile) == ROAD_X || GetAllRoadBits(tile) == ROAD_Y)) { if (GetTileSlope(tile, NULL) == SLOPE_FLAT && EnsureNoVehicleOnGround(tile) && CHANCE16(1, 20)) { StartRoadWorks(tile); @@ -978,15 +1007,18 @@ static const byte _road_trackbits[16] = { static uint32 GetTileTrackStatus_Road(TileIndex tile, TransportType mode) { + RoadType rt = ROADTYPE_ROAD; + switch (mode) { case TRANSPORT_RAIL: if (!IsLevelCrossing(tile)) return 0; return GetCrossingRailBits(tile) * 0x101; case TRANSPORT_ROAD: + if (!HASBIT(GetRoadTypes(tile), rt)) return 0; switch (GetRoadTileType(tile)) { case ROAD_TILE_NORMAL: - return HasRoadWorks(tile) ? 0 : _road_trackbits[GetRoadBits(tile)] * 0x101; + return HasRoadWorks(tile) ? 0 : _road_trackbits[GetRoadBits(tile, rt)] * 0x101; case ROAD_TILE_CROSSING: { uint32 r = AxisToTrackBits(GetCrossingRoadAxis(tile)) * 0x101; @@ -1060,30 +1092,26 @@ static uint32 VehicleEnter_Road(Vehicle *v, TileIndex tile, int x, int y) static void ChangeTileOwner_Road(TileIndex tile, PlayerID old_player, PlayerID new_player) { - if (IsLevelCrossing(tile) && GetCrossingRoadOwner(tile) == old_player) { - SetCrossingRoadOwner(tile, new_player == PLAYER_SPECTATOR ? OWNER_NONE : new_player); + if (GetRoadTileType(tile) == ROAD_TILE_DEPOT) { + DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR); + return; } - if (!IsTileOwner(tile, old_player)) return; + for (RoadType rt = ROADTYPE_ROAD; rt < ROADTYPE_END; rt++) { + if (!HASBIT(GetRoadTypes(tile), rt)) continue; - if (new_player != PLAYER_SPECTATOR) { - SetTileOwner(tile, new_player); - } else { - switch (GetRoadTileType(tile)) { - case ROAD_TILE_NORMAL: - SetTileOwner(tile, OWNER_NONE); - break; + if (GetRoadOwner(tile, rt) == old_player) { + SetRoadOwner(tile, rt, new_player == PLAYER_SPECTATOR ? OWNER_NONE : new_player); - case ROAD_TILE_CROSSING: - MakeRoadNormal(tile, GetCrossingRoadOwner(tile), GetCrossingRoadBits(tile), GetTownIndex(tile)); - break; - - default: - case ROAD_TILE_DEPOT: - DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR); - break; + if (rt == ROADTYPE_TRAM) { + DoCommand(tile, ROADTYPE_TRAM << 4 | GetRoadBits(tile, ROADTYPE_ROAD), 0, DC_EXEC, CMD_REMOVE_ROAD); + } } } + + if (IsLevelCrossing(tile)) { + MakeRoadNormal(tile, GetCrossingRoadBits(tile), GetRoadTypes(tile), GetTownIndex(tile), GetRoadOwner(tile, ROADTYPE_ROAD), GetRoadOwner(tile, ROADTYPE_TRAM), GetRoadOwner(tile, ROADTYPE_HWAY)); + } } diff --git a/src/road_gui.cpp b/src/road_gui.cpp index 381d85c323..3b21fef41a 100644 --- a/src/road_gui.cpp +++ b/src/road_gui.cpp @@ -69,7 +69,7 @@ void CcBuildRoadTunnel(bool success, TileIndex tile, uint32 p1, uint32 p2) static void PlaceRoad_Tunnel(TileIndex tile) { - DoCommandP(tile, 0x200, 0, CcBuildRoadTunnel, CMD_BUILD_TUNNEL | CMD_AUTO | CMD_MSG(STR_5016_CAN_T_BUILD_TUNNEL_HERE)); + DoCommandP(tile, 0x200 | ROADTYPES_ROAD, 0, CcBuildRoadTunnel, CMD_BUILD_TUNNEL | CMD_AUTO | CMD_MSG(STR_5016_CAN_T_BUILD_TUNNEL_HERE)); } static void BuildRoadOutsideStation(TileIndex tile, DiagDirection direction) @@ -113,7 +113,7 @@ static void PlaceRoad_BusStation(TileIndex tile) if (_remove_button_clicked) { DoCommandP(tile, 0, RoadStop::BUS, CcPlaySound1D, CMD_REMOVE_ROAD_STOP | CMD_MSG(STR_CAN_T_REMOVE_BUS_STATION)); } else { - PlaceRoadStop(tile, RoadStop::BUS, CMD_BUILD_ROAD_STOP | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1808_CAN_T_BUILD_BUS_STATION)); + PlaceRoadStop(tile, ROADTYPES_ROAD << 2 | RoadStop::BUS, CMD_BUILD_ROAD_STOP | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1808_CAN_T_BUILD_BUS_STATION)); } } @@ -122,7 +122,7 @@ static void PlaceRoad_TruckStation(TileIndex tile) if (_remove_button_clicked) { DoCommandP(tile, 0, RoadStop::TRUCK, CcPlaySound1D, CMD_REMOVE_ROAD_STOP | CMD_MSG(STR_CAN_T_REMOVE_TRUCK_STATION)); } else { - PlaceRoadStop(tile, RoadStop::TRUCK, CMD_BUILD_ROAD_STOP | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1809_CAN_T_BUILD_TRUCK_STATION)); + PlaceRoadStop(tile, ROADTYPES_ROAD << 2 | RoadStop::TRUCK, CMD_BUILD_ROAD_STOP | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1809_CAN_T_BUILD_TRUCK_STATION)); } } @@ -297,7 +297,7 @@ static void BuildRoadToolbWndProc(Window *w, WindowEvent *e) if (e->we.place.userdata == 0) { ResetObjectToPlace(); - ShowBuildBridgeWindow(start_tile, end_tile, 0x80); + ShowBuildBridgeWindow(start_tile, end_tile, 0x80 | ROADTYPES_ROAD); } else if (e->we.place.userdata != 4) { DoCommandP(end_tile, start_tile, _place_road_flag, CcPlaySound1D, _remove_button_clicked ? @@ -312,7 +312,7 @@ static void BuildRoadToolbWndProc(Window *w, WindowEvent *e) case WE_PLACE_PRESIZE: { TileIndex tile = e->we.place.tile; - DoCommand(tile, 0x200, 0, DC_AUTO, CMD_BUILD_TUNNEL); + DoCommand(tile, 0x200 | ROADTYPES_ROAD, 0, DC_AUTO, CMD_BUILD_TUNNEL); VpSetPresizeRange(tile, _build_tunnel_endtile == 0 ? tile : _build_tunnel_endtile); break; } diff --git a/src/road_map.cpp b/src/road_map.cpp index 98a893490e..0c40d5d4aa 100644 --- a/src/road_map.cpp +++ b/src/road_map.cpp @@ -14,13 +14,15 @@ #include "depot.h" -RoadBits GetAnyRoadBits(TileIndex tile) +RoadBits GetAnyRoadBits(TileIndex tile, RoadType rt) { + if (!HASBIT(GetRoadTypes(tile), rt)) return ROAD_NONE; + switch (GetTileType(tile)) { case MP_STREET: switch (GetRoadTileType(tile)) { default: - case ROAD_TILE_NORMAL: return GetRoadBits(tile); + case ROAD_TILE_NORMAL: return GetRoadBits(tile, rt); case ROAD_TILE_CROSSING: return GetCrossingRoadBits(tile); case ROAD_TILE_DEPOT: return DiagDirToRoadBits(GetRoadDepotDirection(tile)); } @@ -44,15 +46,16 @@ RoadBits GetAnyRoadBits(TileIndex tile) } -TrackBits GetAnyRoadTrackBits(TileIndex tile) +TrackBits GetAnyRoadTrackBits(TileIndex tile, RoadType rt) { uint32 r; /* Don't allow local authorities to build roads through road depots or road stops. */ - if ((IsTileType(tile, MP_STREET) && IsTileDepotType(tile, TRANSPORT_ROAD)) || (IsTileType(tile, MP_STATION) && !IsDriveThroughStopTile(tile))) { + if ((IsTileType(tile, MP_STREET) && IsTileDepotType(tile, TRANSPORT_ROAD)) || (IsTileType(tile, MP_STATION) && !IsDriveThroughStopTile(tile)) || !HASBIT(GetRoadTypes(tile), rt)) { return TRACK_BIT_NONE; } r = GetTileTrackStatus(tile, TRANSPORT_ROAD); + return (TrackBits)(byte)(r | (r >> 8)); } diff --git a/src/road_map.h b/src/road_map.h index 88e0a0295d..15edb8e434 100644 --- a/src/road_map.h +++ b/src/road_map.h @@ -18,9 +18,9 @@ enum RoadTileType { }; static inline RoadTileType GetRoadTileType(TileIndex t) -{ + { assert(IsTileType(t, MP_STREET)); - return (RoadTileType)GB(_m[t].m5, 4, 4); + return (RoadTileType)GB(_m[t].m5, 6, 2); } static inline bool IsLevelCrossing(TileIndex t) @@ -33,23 +33,104 @@ static inline bool IsLevelCrossingTile(TileIndex t) return IsTileType(t, MP_STREET) && IsLevelCrossing(t); } -static inline RoadBits GetRoadBits(TileIndex t) +static inline RoadBits GetRoadBits(TileIndex t, RoadType rt) { assert(GetRoadTileType(t) == ROAD_TILE_NORMAL); - return (RoadBits)GB(_m[t].m5, 0, 4); + switch (rt) { + default: NOT_REACHED(); + case ROADTYPE_ROAD: return (RoadBits)GB(_m[t].m4, 0, 4); + case ROADTYPE_TRAM: return (RoadBits)GB(_m[t].m4, 4, 4); + case ROADTYPE_HWAY: return (RoadBits)GB(_m[t].m6, 2, 4); + } } -static inline void SetRoadBits(TileIndex t, RoadBits r) +static inline RoadBits GetAllRoadBits(TileIndex tile) +{ + return GetRoadBits(tile, ROADTYPE_ROAD) | GetRoadBits(tile, ROADTYPE_TRAM) | GetRoadBits(tile, ROADTYPE_HWAY); +} + +static inline void SetRoadBits(TileIndex t, RoadBits r, RoadType rt) { assert(GetRoadTileType(t) == ROAD_TILE_NORMAL); // XXX incomplete - SB(_m[t].m5, 0, 4, r); + switch (rt) { + default: NOT_REACHED(); + case ROADTYPE_ROAD: SB(_m[t].m4, 0, 4, r); break; + case ROADTYPE_TRAM: SB(_m[t].m4, 4, 4, r); break; + case ROADTYPE_HWAY: SB(_m[t].m6, 2, 4, r); break; + } } +static inline RoadTypes GetRoadTypes(TileIndex t) +{ + if (IsTileType(t, MP_STREET)) { + return (RoadTypes)GB(_me[t].m7, 5, 3); + } else { + return (RoadTypes)GB(_m[t].m3, 0, 3); + } +} + +static inline void SetRoadTypes(TileIndex t, RoadTypes rt) +{ + if (IsTileType(t, MP_STREET)) { + SB(_me[t].m7, 5, 3, rt); + } else { + assert(IsTileType(t, MP_STATION) || IsTileType(t, MP_TUNNELBRIDGE)); + SB(_m[t].m3, 0, 2, rt); + } +} + +static inline Owner GetRoadOwner(TileIndex t, RoadType rt) +{ + if (!IsTileType(t, MP_STREET)) return GetTileOwner(t); + + switch (GetRoadTileType(t)) { + default: NOT_REACHED(); + case ROAD_TILE_NORMAL: + switch (rt) { + default: NOT_REACHED(); + case ROADTYPE_ROAD: return (Owner)GB( _m[t].m1, 0, 5); + case ROADTYPE_TRAM: return (Owner)GB( _m[t].m5, 0, 5); + case ROADTYPE_HWAY: return (Owner)GB(_me[t].m7, 0, 5); + } + case ROAD_TILE_CROSSING: + switch (rt) { + default: NOT_REACHED(); + case ROADTYPE_ROAD: return (Owner)GB( _m[t].m4, 0, 5); + case ROADTYPE_TRAM: return (Owner)GB( _m[t].m5, 0, 5); + case ROADTYPE_HWAY: return (Owner)GB(_me[t].m7, 0, 5); + } + case ROAD_TILE_DEPOT: return GetTileOwner(t); + } +} + +static inline void SetRoadOwner(TileIndex t, RoadType rt, Owner o) +{ + if (!IsTileType(t, MP_STREET)) return SetTileOwner(t, o); + + switch (GetRoadTileType(t)) { + default: NOT_REACHED(); + case ROAD_TILE_NORMAL: + switch (rt) { + default: NOT_REACHED(); + case ROADTYPE_ROAD: SB( _m[t].m1, 0, 5, o); break; + case ROADTYPE_TRAM: SB( _m[t].m5, 0, 5, o); break; + case ROADTYPE_HWAY: SB(_me[t].m7, 0, 5, o); break; + } + case ROAD_TILE_CROSSING: + switch (rt) { + default: NOT_REACHED(); + case ROADTYPE_ROAD: SB( _m[t].m4, 0, 5, o); break; + case ROADTYPE_TRAM: SB( _m[t].m5, 0, 5, o); break; + case ROADTYPE_HWAY: SB(_me[t].m7, 0, 5, o); break; + } + case ROAD_TILE_DEPOT: return SetTileOwner(t, o); + } +} static inline Axis GetCrossingRoadAxis(TileIndex t) { assert(GetRoadTileType(t) == ROAD_TILE_CROSSING); - return (Axis)GB(_m[t].m5, 3, 1); + return (Axis)GB(_m[t].m4, 6, 1); } static inline RoadBits GetCrossingRoadBits(TileIndex tile) @@ -63,35 +144,22 @@ static inline TrackBits GetCrossingRailBits(TileIndex tile) } -// TODO swap owner of road and rail -static inline Owner GetCrossingRoadOwner(TileIndex t) -{ - assert(GetRoadTileType(t) == ROAD_TILE_CROSSING); - return (Owner)_m[t].m4; -} - -static inline void SetCrossingRoadOwner(TileIndex t, Owner o) -{ - assert(GetRoadTileType(t) == ROAD_TILE_CROSSING); - _m[t].m4 = o; -} - static inline void UnbarCrossing(TileIndex t) { assert(GetRoadTileType(t) == ROAD_TILE_CROSSING); - CLRBIT(_m[t].m5, 2); + CLRBIT(_m[t].m4, 5); } static inline void BarCrossing(TileIndex t) { assert(GetRoadTileType(t) == ROAD_TILE_CROSSING); - SETBIT(_m[t].m5, 2); + SETBIT(_m[t].m4, 5); } static inline bool IsCrossingBarred(TileIndex t) { assert(GetRoadTileType(t) == ROAD_TILE_CROSSING); - return HASBIT(_m[t].m5, 2); + return HASBIT(_m[t].m4, 5); } #define IsOnDesert IsOnSnow @@ -174,9 +242,10 @@ static inline DiagDirection GetRoadDepotDirection(TileIndex t) * - bridge ramps: start of the ramp is treated as road piece * - bridge middle parts: bridge itself is ignored * @param tile the tile to get the road bits for + * @param rt the road type to get the road bits form * @return the road bits of the given tile */ -RoadBits GetAnyRoadBits(TileIndex tile); +RoadBits GetAnyRoadBits(TileIndex tile, RoadType rt); /** * Get the accessible track bits for the given tile. @@ -186,39 +255,45 @@ RoadBits GetAnyRoadBits(TileIndex tile); * @param tile the tile to get the track bits for * @return the track bits for the given tile */ -TrackBits GetAnyRoadTrackBits(TileIndex tile); +TrackBits GetAnyRoadTrackBits(TileIndex tile, RoadType rt); -static inline void MakeRoadNormal(TileIndex t, Owner owner, RoadBits bits, TownID town) +static inline void MakeRoadNormal(TileIndex t, RoadBits bits, RoadTypes rot, TownID town, Owner road, Owner tram, Owner hway) { SetTileType(t, MP_STREET); - SetTileOwner(t, owner); + SetTileOwner(t, road); _m[t].m2 = town; - _m[t].m3 = 0 << 7 | 0 << 4 | 0; - _m[t].m4 = 0; - _m[t].m5 = ROAD_TILE_NORMAL << 4 | bits; + _m[t].m3 = 0; + _m[t].m4 = (HASBIT(rot, ROADTYPE_ROAD) ? bits : 0) << 4 | HASBIT(rot, ROADTYPE_TRAM) ? bits : 0; + _m[t].m5 = ROAD_TILE_NORMAL << 6 | tram; + SB(_m[t].m6, 2, 4, HASBIT(rot, ROADTYPE_HWAY) ? bits : 0); + _me[t].m7 = rot << 5 | hway; } -static inline void MakeRoadCrossing(TileIndex t, Owner road, Owner rail, Axis roaddir, RailType rt, uint town) +static inline void MakeRoadCrossing(TileIndex t, Owner road, Owner tram, Owner hway, Owner rail, Axis roaddir, RailType rat, RoadTypes rot, uint town) { SetTileType(t, MP_STREET); SetTileOwner(t, rail); _m[t].m2 = town; - _m[t].m3 = 0 << 7 | 0 << 4 | rt; - _m[t].m4 = road; - _m[t].m5 = ROAD_TILE_CROSSING << 4 | roaddir << 3 | 0 << 2; + _m[t].m3 = rat; + _m[t].m4 = roaddir << 6 | road; + _m[t].m5 = ROAD_TILE_CROSSING << 6 | tram; + SB(_m[t].m6, 2, 4, 0); + _me[t].m7 = rot << 5 | hway; } -static inline void MakeRoadDepot(TileIndex t, Owner owner, DiagDirection dir) +static inline void MakeRoadDepot(TileIndex t, Owner owner, DiagDirection dir, RoadType rt) { SetTileType(t, MP_STREET); SetTileOwner(t, owner); _m[t].m2 = 0; _m[t].m3 = 0; _m[t].m4 = 0; - _m[t].m5 = ROAD_TILE_DEPOT << 4 | dir; + _m[t].m5 = ROAD_TILE_DEPOT << 6 | dir; + SB(_m[t].m6, 2, 4, 0); + _me[t].m7 = RoadTypeToRoadTypes(rt) << 5; } #endif /* ROAD_MAP_H */ diff --git a/src/saveload.cpp b/src/saveload.cpp index 6550fdfdd1..971b0eb4f2 100644 --- a/src/saveload.cpp +++ b/src/saveload.cpp @@ -29,7 +29,7 @@ #include #include -extern const uint16 SAVEGAME_VERSION = 60; +extern const uint16 SAVEGAME_VERSION = 61; uint16 _sl_version; ///< the major savegame version identifier byte _sl_minor_version; ///< the minor savegame version, DO NOT USE! diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index 74547ef2b4..d331dd870d 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -1214,6 +1214,7 @@ static RoadStop **FindRoadStopSpot(bool truck_station, Station* st) * @param p1 entrance direction (DiagDirection) * @param p2 bit 0: 0 for Bus stops, 1 for truck stops * bit 1: 0 for normal, 1 for drive-through + * bit 2..4: the roadtypes */ int32 CmdBuildRoadStop(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) { @@ -1222,17 +1223,23 @@ int32 CmdBuildRoadStop(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) bool build_over_road = is_drive_through && IsTileType(tile, MP_STREET) && GetRoadTileType(tile) == ROAD_TILE_NORMAL; bool town_owned_road = build_over_road && IsTileOwner(tile, OWNER_TOWN); Owner cur_owner = _current_player; + RoadTypes rts = (RoadTypes)GB(p2, 2, 3); + + if (rts == ROADTYPES_NONE || HASBIT(rts, ROADTYPE_HWAY)) return CMD_ERROR; /* Saveguard the parameters */ if (!IsValidDiagDirection((DiagDirection)p1)) return CMD_ERROR; /* If it is a drive-through stop check for valid axis */ if (is_drive_through && !IsValidAxis((Axis)p1)) return CMD_ERROR; /* Road bits in the wrong direction */ - if (build_over_road && (GetRoadBits(tile) & ((Axis)p1 == AXIS_X ? ROAD_Y : ROAD_X)) != 0) return_cmd_error(STR_DRIVE_THROUGH_ERROR_DIRECTION); + if (build_over_road && (GetAllRoadBits(tile) & ((Axis)p1 == AXIS_X ? ROAD_Y : ROAD_X)) != 0) return_cmd_error(STR_DRIVE_THROUGH_ERROR_DIRECTION); /* Not allowed to build over this road */ if (build_over_road) { if (IsTileOwner(tile, OWNER_TOWN) && !_patches.road_stop_on_town_road) return_cmd_error(STR_DRIVE_THROUGH_ERROR_ON_TOWN_ROAD); - if (!IsTileOwner(tile, OWNER_TOWN) && !CheckOwnership(GetTileOwner(tile))) return CMD_ERROR; + if (GetRoadTileType(tile) != ROAD_TILE_NORMAL) return CMD_ERROR; + if (!IsTileOwner(tile, OWNER_TOWN) && !CheckOwnership(GetRoadOwner(tile, ROADTYPE_ROAD)) && !CheckOwnership(GetRoadOwner(tile, ROADTYPE_TRAM))) return CMD_ERROR; + /* Do not remove roadtypes! */ + if (rts != GetRoadTypes(tile) && rts != ROADTYPES_ROADTRAM) return CMD_ERROR; } SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); @@ -1311,9 +1318,9 @@ int32 CmdBuildRoadStop(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) RoadStop::Type rs_type = type ? RoadStop::TRUCK : RoadStop::BUS; if (is_drive_through) { - MakeDriveThroughRoadStop(tile, st->owner, st->index, rs_type, (Axis)p1, town_owned_road); + MakeDriveThroughRoadStop(tile, st->owner, st->index, rs_type, rts, (Axis)p1, town_owned_road); } else { - MakeRoadStop(tile, st->owner, st->index, rs_type, (DiagDirection)p1); + MakeRoadStop(tile, st->owner, st->index, rs_type, rts, (DiagDirection)p1); } UpdateStationVirtCoordDirty(st); @@ -1389,7 +1396,8 @@ int32 CmdRemoveRoadStop(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) Station *st = GetStationByTile(tile); /* Save the stop info before it is removed */ bool is_drive_through = IsDriveThroughStopTile(tile); - RoadBits road_bits = GetAnyRoadBits(tile); + RoadTypes rts = GetRoadTypes(tile); + RoadBits road_bits = GetAnyRoadBits(tile, HASBIT(rts, ROADTYPE_ROAD) ? ROADTYPE_ROAD : ROADTYPE_TRAM); bool is_towns_road = is_drive_through && GetStopBuiltOnTownRoad(tile); int32 ret = RemoveRoadStop(st, flags, tile); @@ -1403,7 +1411,12 @@ int32 CmdRemoveRoadStop(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) index = ClosestTownFromTile(tile, (uint)-1)->index; _current_player = OWNER_TOWN; } - DoCommand(tile, road_bits, index, DC_EXEC, CMD_BUILD_ROAD); + if (HASBIT(rts, ROADTYPE_ROAD)) { + DoCommand(tile, ROADTYPE_ROAD << 4 | road_bits, index, DC_EXEC, CMD_BUILD_ROAD); + } + if (HASBIT(rts, ROADTYPE_TRAM)) { + DoCommand(tile, ROADTYPE_TRAM << 4 | road_bits, index, DC_EXEC, CMD_BUILD_ROAD); + } _current_player = cur_owner; } @@ -2676,7 +2689,8 @@ static bool CanRemoveRoadWithStop(TileIndex tile) if (!GetStopBuiltOnTownRoad(tile)) return true; bool edge_road; - return CheckAllowRemoveRoad(tile, GetAnyRoadBits(tile), OWNER_TOWN, &edge_road); + return CheckAllowRemoveRoad(tile, GetAnyRoadBits(tile, ROADTYPE_ROAD), OWNER_TOWN, &edge_road, ROADTYPE_ROAD) && + CheckAllowRemoveRoad(tile, GetAnyRoadBits(tile, ROADTYPE_TRAM), OWNER_TOWN, &edge_road, ROADTYPE_TRAM); } static int32 ClearTile_Station(TileIndex tile, byte flags) diff --git a/src/station_map.h b/src/station_map.h index 6a4cb6d6b1..e35b5d8b51 100644 --- a/src/station_map.h +++ b/src/station_map.h @@ -6,6 +6,7 @@ #define STATION_MAP_H #include "rail_map.h" +#include "road_map.h" #include "station.h" typedef byte StationGfx; @@ -309,15 +310,17 @@ static inline void MakeRailStation(TileIndex t, Owner o, StationID sid, Axis a, SetRailType(t, rt); } -static inline void MakeRoadStop(TileIndex t, Owner o, StationID sid, RoadStop::Type rst, DiagDirection d) +static inline void MakeRoadStop(TileIndex t, Owner o, StationID sid, RoadStop::Type rst, RoadTypes rt, DiagDirection d) { MakeStation(t, o, sid, (rst == RoadStop::BUS ? GFX_BUS_BASE : GFX_TRUCK_BASE) + d); + SetRoadTypes(t, rt); } -static inline void MakeDriveThroughRoadStop(TileIndex t, Owner o, StationID sid, RoadStop::Type rst, Axis a, bool on_town_road) +static inline void MakeDriveThroughRoadStop(TileIndex t, Owner o, StationID sid, RoadStop::Type rst, RoadTypes rt, Axis a, bool on_town_road) { MakeStation(t, o, sid, (rst == RoadStop::BUS ? GFX_BUS_BASE_EXT : GFX_TRUCK_BASE_EXT) + a); SB(_m[t].m6, 3, 1, on_town_road); + SetRoadTypes(t, rt); } static inline void MakeAirport(TileIndex t, Owner o, StationID sid, byte section) diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp index 03248a9bbf..39765e25dc 100644 --- a/src/town_cmd.cpp +++ b/src/town_cmd.cpp @@ -636,7 +636,7 @@ void OnTick_Town() static RoadBits GetTownRoadMask(TileIndex tile) { - TrackBits b = GetAnyRoadTrackBits(tile); + TrackBits b = GetAnyRoadTrackBits(tile, ROADTYPE_ROAD); RoadBits r = ROAD_NONE; if (b & TRACK_BIT_X) r |= ROAD_X; @@ -676,7 +676,7 @@ static bool IsRoadAllowedHere(TileIndex tile, int dir) for (;;) { /* Check if there already is a road at this point? */ - if (GetAnyRoadTrackBits(tile) == 0) { + if (GetAnyRoadTrackBits(tile, ROADTYPE_ROAD) == 0) { /* No, try to build one in the direction. * if that fails clear the land, and if that fails exit. * This is to make sure that we can build a road here later. */ @@ -1221,7 +1221,7 @@ static bool GrowTown(Town *t) /* Find a road that we can base the construction on. */ tile = t->xy; for (ptr = _town_coord_mod; ptr != endof(_town_coord_mod); ++ptr) { - if (GetAnyRoadTrackBits(tile) != 0) { + if (GetAnyRoadTrackBits(tile, ROADTYPE_ROAD) != 0) { int r = GrowTownAtRoad(t, tile); _current_player = old_player; return r != 0; @@ -2208,7 +2208,7 @@ Town *ClosestTownFromTile(TileIndex tile, uint threshold) { if (IsTileType(tile, MP_HOUSE) || ( IsTileType(tile, MP_STREET) && - (IsLevelCrossing(tile) ? GetCrossingRoadOwner(tile) : GetTileOwner(tile)) == OWNER_TOWN + GetRoadOwner(tile, ROADTYPE_ROAD) == OWNER_TOWN )) { return GetTownByTile(tile); } else { diff --git a/src/tunnel_map.h b/src/tunnel_map.h index dde7bac63f..66d5bcd106 100644 --- a/src/tunnel_map.h +++ b/src/tunnel_map.h @@ -9,6 +9,7 @@ #include "macros.h" #include "map.h" #include "rail.h" +#include "road.h" /** * Is this a tunnel (entrance)? @@ -93,13 +94,14 @@ bool IsTunnelInWay(TileIndex, uint z); * @param t the entrance of the tunnel * @param o the owner of the entrance * @param d the direction facing out of the tunnel + * @param r the road type used in the tunnel */ -static inline void MakeRoadTunnel(TileIndex t, Owner o, DiagDirection d) +static inline void MakeRoadTunnel(TileIndex t, Owner o, DiagDirection d, RoadTypes r) { SetTileType(t, MP_TUNNELBRIDGE); SetTileOwner(t, o); _m[t].m2 = 0; - _m[t].m3 = 0; + _m[t].m3 = r; _m[t].m4 = 0; _m[t].m5 = TRANSPORT_ROAD << 2 | d; } diff --git a/src/tunnelbridge_cmd.cpp b/src/tunnelbridge_cmd.cpp index 771cb3f52d..26aafc65de 100644 --- a/src/tunnelbridge_cmd.cpp +++ b/src/tunnelbridge_cmd.cpp @@ -172,12 +172,14 @@ bool CheckBridge_Stuff(byte bridge_type, uint bridge_len) * @param p1 packed start tile coords (~ dx) * @param p2 various bitstuffed elements * - p2 = (bit 0- 7) - bridge type (hi bh) - * - p2 = (bit 8-..) - rail type. bit15 ((x>>8)&0x80) means road bridge. + * - p2 = (bit 8-..) - rail type or road types. + * - p2 = (bit 15 ) - set means road bridge. */ int32 CmdBuildBridge(TileIndex end_tile, uint32 flags, uint32 p1, uint32 p2) { uint bridge_type; RailType railtype; + RoadTypes roadtypes; uint x; uint y; uint sx; @@ -207,6 +209,8 @@ int32 CmdBuildBridge(TileIndex end_tile, uint32 flags, uint32 p1, uint32 p2) /* type of bridge */ if (HASBIT(p2, 15)) { railtype = INVALID_RAILTYPE; // road bridge + roadtypes = (RoadTypes)GB(p2, 8, 2); + if (roadtypes > ROADTYPES_ALL || roadtypes == ROADTYPES_NONE) return CMD_ERROR; } else { if (!ValParamRailtype(GB(p2, 8, 8))) return CMD_ERROR; railtype = (RailType)GB(p2, 8, 8); @@ -352,8 +356,8 @@ int32 CmdBuildBridge(TileIndex end_tile, uint32 flags, uint32 p1, uint32 p2) MakeRailBridgeRamp(tile_start, owner, bridge_type, dir, railtype); MakeRailBridgeRamp(tile_end, owner, bridge_type, ReverseDiagDir(dir), railtype); } else { - MakeRoadBridgeRamp(tile_start, owner, bridge_type, dir); - MakeRoadBridgeRamp(tile_end, owner, bridge_type, ReverseDiagDir(dir)); + MakeRoadBridgeRamp(tile_start, owner, bridge_type, dir, roadtypes); + MakeRoadBridgeRamp(tile_end, owner, bridge_type, ReverseDiagDir(dir), roadtypes); } MarkTileDirtyByTile(tile_start); MarkTileDirtyByTile(tile_end); @@ -442,7 +446,7 @@ not_valid_below:; /** Build Tunnel. * @param start_tile start tile of tunnel * @param flags type of operation - * @param p1 railtype, 0x200 for road tunnel + * @param p1 railtype or roadtypes. bit 9 set means road tunnel * @param p2 unused */ int32 CmdBuildTunnel(TileIndex start_tile, uint32 flags, uint32 p1, uint32 p2) @@ -459,7 +463,11 @@ int32 CmdBuildTunnel(TileIndex start_tile, uint32 flags, uint32 p1, uint32 p2) _build_tunnel_endtile = 0; - if (p1 != 0x200 && !ValParamRailtype(p1)) return CMD_ERROR; + if (HASBIT(p1, 9)) { + if (!ValParamRailtype(p1)) return CMD_ERROR; + } else if (GB(p1, 0, 4) > ROADTYPES_ALL || GB(p1, 0, 4) == ROADTYPES_NONE) { + return CMD_ERROR; + } start_tileh = GetTileSlope(start_tile, &start_z); @@ -519,8 +527,8 @@ int32 CmdBuildTunnel(TileIndex start_tile, uint32 flags, uint32 p1, uint32 p2) UpdateSignalsOnSegment(start_tile, direction); YapfNotifyTrackLayoutChange(start_tile, AxisToTrack(DiagDirToAxis(direction))); } else { - MakeRoadTunnel(start_tile, _current_player, direction); - MakeRoadTunnel(end_tile, _current_player, ReverseDiagDir(direction)); + MakeRoadTunnel(start_tile, _current_player, direction, (RoadTypes)GB(p1, 0, 4)); + MakeRoadTunnel(end_tile, _current_player, ReverseDiagDir(direction), (RoadTypes)GB(p1, 0, 4)); } }