diff options
-rw-r--r-- | bin/data/oneway.grf | bin | 0 -> 581 bytes | |||
-rw-r--r-- | docs/landscape.html | 5 | ||||
-rw-r--r-- | docs/landscape_grid.html | 2 | ||||
-rw-r--r-- | src/gfxinit.cpp | 3 | ||||
-rw-r--r-- | src/lang/english.txt | 1 | ||||
-rw-r--r-- | src/newgrf.cpp | 8 | ||||
-rw-r--r-- | src/road_cmd.cpp | 84 | ||||
-rw-r--r-- | src/road_gui.cpp | 2 | ||||
-rw-r--r-- | src/road_map.h | 55 | ||||
-rw-r--r-- | src/roadveh_cmd.cpp | 5 | ||||
-rw-r--r-- | src/table/files.h | 1 | ||||
-rw-r--r-- | src/table/sprites.h | 3 |
12 files changed, 151 insertions, 18 deletions
diff --git a/bin/data/oneway.grf b/bin/data/oneway.grf Binary files differnew file mode 100644 index 000000000..4c376e93a --- /dev/null +++ b/bin/data/oneway.grf diff --git a/docs/landscape.html b/docs/landscape.html index 142c94682..b876bb31b 100644 --- a/docs/landscape.html +++ b/docs/landscape.html @@ -534,7 +534,8 @@ </table> </li> <li>m4 bits 7..4: road layout road type #2 - <li>m5 bits 4..0: owner of road type #2 + <li>m5 bits 5..4: bits to disallow vehicles to go a specific direction + <li>m5 bits 3..0: owner of road type #2 <li>m6 bits 5..2: road layout road type #3 <li>m7 bits 7..5: road types <li>m7 bits 4..0: owner of road type #3 @@ -559,7 +560,7 @@ <li>m4 bit 6: clear - road in the X direction, set - road in the Y direction (railway track always perpendicular)</li> <li>m4 bit 5: set if crossing lights are on</li> <li>m4 bits 4..0: <a href="#OwnershipInfo">owner</a> of the road type #1</li> - <li>m5 bits 4..0: owner of road type #2 + <li>m5 bits 3..0: owner of road type #2 <li>m7 bits 7..5: road types <li>m7 bits 4..0: owner of road type #3 </ul> diff --git a/docs/landscape_grid.html b/docs/landscape_grid.html index 5a492458e..01a0ef1e2 100644 --- a/docs/landscape_grid.html +++ b/docs/landscape_grid.html @@ -125,7 +125,7 @@ the array so you can quickly see what is used and what is not. <td class="bits">XXXX XXXX XXXX XXXX</td> <td class="bits">XXXX XXXX</td> <td class="bits">XXXX XXXX</td> - <td class="bits">XX<span class="free">OO</span> XXXX</td> + <td class="bits">XXXX XXXX</td> <td class="bits">XXXX XXXX</td> <td class="bits">XXXX XXXX</td> </tr> diff --git a/src/gfxinit.cpp b/src/gfxinit.cpp index b1f6e4ab2..9abdd1679 100644 --- a/src/gfxinit.cpp +++ b/src/gfxinit.cpp @@ -399,6 +399,9 @@ static void LoadSpriteTables() assert(load_index == SPR_TRAMWAY_BASE); load_index += LoadGrfFile("tramtrkw.grf", load_index, i++); + assert(load_index == SPR_ONEWAY_BASE); + load_index += LoadGrfFile("oneway.grf", load_index, i++); + /* Initialize the unicode to sprite mapping table */ InitializeUnicodeGlyphMap(); diff --git a/src/lang/english.txt b/src/lang/english.txt index c3f9dc0cf..9a2d69353 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -1600,6 +1600,7 @@ STR_ROAD_WORKS_IN_PROGRESS :{WHITE}Road wor STR_1802_ROAD_CONSTRUCTION :{WHITE}Road Construction STR_1802_TRAMWAY_CONSTRUCTION :{WHITE}Tramway Construction STR_1803_SELECT_ROAD_BRIDGE :{WHITE}Select Road Bridge +STR_ERR_ONEWAY_ROADS_CAN_T_HAVE_JUNCTION :{WHITE}... one way roads can't have junctions STR_1804_CAN_T_BUILD_ROAD_HERE :{WHITE}Can't build road here... STR_1804_CAN_T_BUILD_TRAMWAY_HERE :{WHITE}Can't build tramway here... STR_1805_CAN_T_REMOVE_ROAD_FROM :{WHITE}Can't remove road from here... diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 0ba3aa846..cc44682d0 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -2897,6 +2897,14 @@ static void GraphicsNew(byte *buf, int len) replace = SPR_CANALS_BASE + 5; break; + case 0x09: // One way graphics + if (num != 6) { + grfmsg(1, "GraphicsNew: One way road graphics sprite count must be 6, skipping"); + return; + } + replace = SPR_ONEWAY_BASE; + break; + case 0x0A: // 2CC colour maps if (num != 256) { grfmsg(1, "GraphicsNew: 2CC colour maps sprite count must be 256, skipping"); diff --git a/src/road_cmd.cpp b/src/road_cmd.cpp index 5f4e6e538..6ab860502 100644 --- a/src/road_cmd.cpp +++ b/src/road_cmd.cpp @@ -218,6 +218,10 @@ int32 CmdRemoveRoad(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) SetRoadTypes(tile, rts); } } else { + /* When bits are removed, you *always* end up with something that + * is not a complete straight road tile. However, trams do not have + * onewayness, so they cannot remove it either. */ + if (rt != ROADTYPE_TRAM) SetDisallowedRoadDirections(tile, DRD_NONE); SetRoadBits(tile, present, rt); MarkTileDirtyByTile(tile); } @@ -333,6 +337,7 @@ static uint32 CheckRoadSlope(Slope tileh, RoadBits* pieces, RoadBits existing) * @param flags operation to perform * @param p1 bit 0..3 road pieces to build (RoadBits) * bit 4..5 road type + * bit 6..7 disallowed directions to toggle * @param p2 the town that is building the road (0 if not applicable) */ int32 CmdBuildRoad(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) @@ -354,12 +359,14 @@ int32 CmdBuildRoad(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) RoadType rt = (RoadType)GB(p1, 4, 2); if (!IsValidRoadType(rt)) return CMD_ERROR; + DisallowedRoadDirections toggle_drd = (DisallowedRoadDirections)GB(p1, 6, 2); + tileh = GetTileSlope(tile, NULL); switch (GetTileType(tile)) { case MP_STREET: switch (GetRoadTileType(tile)) { - case ROAD_TILE_NORMAL: + case ROAD_TILE_NORMAL: { if (HasRoadWorks(tile)) return_cmd_error(STR_ROAD_WORKS_IN_PROGRESS); if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR; @@ -367,10 +374,27 @@ int32 CmdBuildRoad(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) if (!HASBIT(GetRoadTypes(tile), rt)) break; existing = GetRoadBits(tile, rt); + RoadBits merged = existing | pieces; + bool crossing = (merged & ROAD_X) != ROAD_NONE && (merged & ROAD_Y) != ROAD_NONE; + if (GetDisallowedRoadDirections(tile) != DRD_NONE && crossing) { + /* Junctions cannot be one-way */ + return_cmd_error(STR_ERR_ONEWAY_ROADS_CAN_T_HAVE_JUNCTION); + } if ((existing & pieces) == pieces) { + /* We only want to set the (dis)allowed road directions */ + if (toggle_drd != DRD_NONE && rt != ROADTYPE_TRAM && GetRoadOwner(tile, ROADTYPE_ROAD) == _current_player) { + if (crossing) return_cmd_error(STR_ERR_ONEWAY_ROADS_CAN_T_HAVE_JUNCTION); + + /* Ignore half built tiles */ + if (flags & DC_EXEC && rt != ROADTYPE_TRAM && (existing == ROAD_X || existing == ROAD_Y)) { + SetDisallowedRoadDirections(tile, GetDisallowedRoadDirections(tile) ^ toggle_drd); + MarkTileDirtyByTile(tile); + } + return 0; + } return_cmd_error(STR_1007_ALREADY_BUILT); } - break; + } break; case ROAD_TILE_CROSSING: if (HASBIT(GetRoadTypes(tile), rt)) return_cmd_error(STR_1007_ALREADY_BUILT); @@ -504,6 +528,12 @@ do_clear:; break; } + if (rt != ROADTYPE_TRAM && IsTileType(tile, MP_STREET) && GetRoadTileType(tile) == ROAD_TILE_NORMAL) { + existing |= pieces; + SetDisallowedRoadDirections(tile, (existing == ROAD_X || existing == ROAD_Y) ? + GetDisallowedRoadDirections(tile) ^ toggle_drd : DRD_NONE); + } + MarkTileDirtyByTile(tile); } return cost; @@ -549,12 +579,15 @@ int32 DoConvertStreetRail(TileIndex tile, RailType totype, bool exec) * - 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 + 4) - road type + * - p2 = (bit 5) - set road direction */ int32 CmdBuildLongRoad(TileIndex end_tile, uint32 flags, uint32 p1, uint32 p2) { TileIndex start_tile, tile; int32 cost, ret; bool had_bridge = false; + bool had_success = false; + DisallowedRoadDirections drd = DRD_NORTHBOUND; SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); @@ -574,8 +607,16 @@ int32 CmdBuildLongRoad(TileIndex end_tile, uint32 flags, uint32 p1, uint32 p2) start_tile = end_tile; end_tile = t; p2 ^= IS_INT_INSIDE(p2 & 3, 1, 3) ? 3 : 0; + drd = DRD_SOUTHBOUND; } + /* On the X-axis, we have to swap the initial bits, so they + * will be interpreted correctly in the GTTS. Futhermore + * when you just 'click' on one tile to build them. */ + if (HASBIT(p2, 2) == (start_tile == end_tile)) drd ^= DRD_BOTH; + /* No disallowed direction bits have to be toggled */ + if (!HASBIT(p2, 5)) drd = DRD_NONE; + cost = 0; tile = start_tile; /* Start tile is the small number. */ @@ -585,11 +626,12 @@ 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, rt << 4 | bits, 0, flags, CMD_BUILD_ROAD); + ret = DoCommand(tile, drd << 6 | 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; } else { + had_success = true; /* Only pay for the upgrade on one side of the bridge */ if (IsBridgeTile(tile)) { if ((!had_bridge || GetBridgeRampDirection(tile) == DIAGDIR_SE || GetBridgeRampDirection(tile) == DIAGDIR_SW)) { @@ -606,7 +648,7 @@ int32 CmdBuildLongRoad(TileIndex end_tile, uint32 flags, uint32 p1, uint32 p2) tile += HASBIT(p2, 2) ? TileDiffXY(0, 1) : TileDiffXY(1, 0); } - return (cost == 0) ? CMD_ERROR : cost; + return !had_success ? CMD_ERROR : cost; } /** Remove a long piece of road. @@ -881,6 +923,23 @@ void DrawTramCatenary(TileInfo *ti, RoadBits tram) } /** + * Draws details on/around the road + * @param img the sprite to draw + * @param ti the tile to draw on + * @param dx the offset from the top of the BB of the tile + * @param dy the offset from the top of the BB of the tile + * @param h the height of the sprite to draw + */ +static void DrawRoadDetail(SpriteID img, TileInfo *ti, int dx, int dy, int h) +{ + int x = ti->x | dx; + int y = ti->y | dy; + byte z = ti->z; + if (ti->tileh != SLOPE_FLAT) z = GetSlopeZ(x, y); + AddSortableSpriteToDraw(img, PAL_NONE, x, y, 2, 2, h, z); +} + +/** * Draw ground sprite and road pieces * @param ti TileInfo */ @@ -921,6 +980,13 @@ static void DrawRoadBits(TileInfo* ti) DrawGroundSprite(image, pal); + if (road != ROAD_NONE) { + DisallowedRoadDirections drd = GetDisallowedRoadDirections(ti->tile); + if (drd != DRD_NONE) { + DrawRoadDetail(SPR_ONEWAY_BASE + drd - 1 + ((road == ROAD_X) ? 0 : 3), ti, 8, 8, 0); + } + } + /* For tram we overlay the road graphics with either tram tracks only * (when there is actual road beneath the trams) or with tram tracks * and some dirts which hides the road graphics */ @@ -947,11 +1013,7 @@ static void DrawRoadBits(TileInfo* ti) /* Draw extra details. */ for (drts = _road_display_table[roadside][road]; drts->image != 0; drts++) { - int x = ti->x | drts->subcoord_x; - int y = ti->y | drts->subcoord_y; - byte z = ti->z; - if (ti->tileh != SLOPE_FLAT) z = GetSlopeZ(x, y); - AddSortableSpriteToDraw(drts->image, PAL_NONE, x, y, 2, 2, 0x10, z); + DrawRoadDetail(drts->image, ti, drts->subcoord_x, drts->subcoord_y, 0x10); } } @@ -1216,7 +1278,9 @@ static uint32 GetTileTrackStatus_Road(TileIndex tile, TransportType mode, uint s switch (GetRoadTileType(tile)) { case ROAD_TILE_NORMAL: { RoadType rt = (RoadType)FindFirstBit(sub_mode); - return HasRoadWorks(tile) ? 0 : _road_trackbits[GetRoadBits(tile, rt)] * 0x101; + const uint drd_to_multiplier[DRD_END] = { 0x101, 0x100, 0x1, 0x0 }; + uint multiplier = drd_to_multiplier[rt == ROADTYPE_TRAM ? DRD_NONE : GetDisallowedRoadDirections(tile)]; + return HasRoadWorks(tile) ? 0 : _road_trackbits[GetRoadBits(tile, rt)] * multiplier; } case ROAD_TILE_CROSSING: { diff --git a/src/road_gui.cpp b/src/road_gui.cpp index 83e132ae6..ed15fe0b9 100644 --- a/src/road_gui.cpp +++ b/src/road_gui.cpp @@ -343,7 +343,7 @@ static void BuildRoadToolbWndProc(Window *w, WindowEvent *e) case DDSP_PLACE_ROAD_NE: case DDSP_PLACE_ROAD_NW: - DoCommandP(end_tile, start_tile, _place_road_flag | (_cur_roadtype << 3), CcPlaySound1D, + DoCommandP(end_tile, start_tile, _place_road_flag | (_cur_roadtype << 3) | _ctrl_pressed << 5, CcPlaySound1D, _remove_button_clicked ? CMD_REMOVE_LONG_ROAD | CMD_AUTO | CMD_NO_WATER | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_road) : CMD_BUILD_LONG_ROAD | CMD_AUTO | CMD_NO_WATER | CMD_MSG(_road_type_infos[_cur_roadtype].err_build_road)); diff --git a/src/road_map.h b/src/road_map.h index 4887e76d3..032febed6 100644 --- a/src/road_map.h +++ b/src/road_map.h @@ -89,14 +89,24 @@ static inline Owner GetRoadOwner(TileIndex t, RoadType rt) 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_TRAM: { + /* Trams don't need OWNER_TOWN, and remapping OWNER_NONE + * to OWNER_TOWN makes it use one bit less */ + Owner o = (Owner)GB( _m[t].m5, 0, 4); + return o == OWNER_TOWN ? OWNER_NONE : o; + } 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_TRAM: { + /* Trams don't need OWNER_TOWN, and remapping OWNER_NONE + * to OWNER_TOWN makes it use one bit less */ + Owner o = (Owner)GB( _m[t].m5, 0, 4); + return o == OWNER_TOWN ? OWNER_NONE : o; + } case ROADTYPE_HWAY: return (Owner)GB(_me[t].m7, 0, 5); } case ROAD_TILE_DEPOT: return GetTileOwner(t); @@ -113,7 +123,9 @@ static inline void SetRoadOwner(TileIndex t, RoadType rt, Owner o) 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; + /* Trams don't need OWNER_TOWN, and remapping OWNER_NONE + * to OWNER_TOWN makes it use one bit less */ + case ROADTYPE_TRAM: SB( _m[t].m5, 0, 4, o == OWNER_NONE ? OWNER_TOWN : o); break; case ROADTYPE_HWAY: SB(_me[t].m7, 0, 5, o); break; } break; @@ -121,7 +133,9 @@ static inline void SetRoadOwner(TileIndex t, RoadType rt, Owner o) 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; + /* Trams don't need OWNER_TOWN, and remapping OWNER_NONE + * to OWNER_TOWN makes it use one bit less */ + case ROADTYPE_TRAM: SB( _m[t].m5, 0, 4, o == OWNER_NONE ? OWNER_TOWN : o); break; case ROADTYPE_HWAY: SB(_me[t].m7, 0, 5, o); break; } break; @@ -129,6 +143,39 @@ static inline void SetRoadOwner(TileIndex t, RoadType rt, Owner o) } } +/** Which directions are disallowed ? */ +enum DisallowedRoadDirections { + DRD_NONE, ///< None of the directions are disallowed + DRD_SOUTHBOUND, ///< All southbound traffic is disallowed + DRD_NORTHBOUND, ///< All northbound traffic is disallowed + DRD_BOTH, ///< All directions are disallowed + DRD_END +}; +DECLARE_ENUM_AS_BIT_SET(DisallowedRoadDirections); + +/** + * Gets the disallowed directions + * @param t the tile to get the directions from + * @return the disallowed directions + */ +static inline DisallowedRoadDirections GetDisallowedRoadDirections(TileIndex t) +{ + assert(GetRoadTileType(t) == ROAD_TILE_NORMAL); + return (DisallowedRoadDirections)GB(_m[t].m5, 4, 2); +} + +/** + * Sets the disallowed directions + * @param t the tile to set the directions for + * @param drd the disallowed directions + */ +static inline void SetDisallowedRoadDirections(TileIndex t, DisallowedRoadDirections drd) +{ + assert(GetRoadTileType(t) == ROAD_TILE_NORMAL); + assert(drd < DRD_END); + SB(_m[t].m5, 4, 2, drd); +} + static inline Axis GetCrossingRoadAxis(TileIndex t) { assert(GetRoadTileType(t) == ROAD_TILE_CROSSING); diff --git a/src/roadveh_cmd.cpp b/src/roadveh_cmd.cpp index ba731b9e9..2cb240a76 100644 --- a/src/roadveh_cmd.cpp +++ b/src/roadveh_cmd.cpp @@ -485,6 +485,8 @@ int32 CmdTurnRoadVeh(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) return CMD_ERROR; } + if (GetDisallowedRoadDirections(v->tile) != DRD_NONE) return CMD_ERROR; + if (IsTunnelTile(v->tile) && DirToDiagDir(v->direction) == GetTunnelDirection(v->tile)) return CMD_ERROR; if (IsBridgeTile(v->tile) && DirToDiagDir(v->direction) == GetBridgeRampDirection(v->tile)) return CMD_ERROR; @@ -1415,6 +1417,9 @@ again: v->cur_speed = 0; return; } + } else if (GetDisallowedRoadDirections(v->tile) != DRD_NONE) { + v->cur_speed = 0; + return; } else { tile = v->tile; } diff --git a/src/table/files.h b/src/table/files.h index bd7b0a439..662b4c121 100644 --- a/src/table/files.h +++ b/src/table/files.h @@ -64,4 +64,5 @@ static MD5File files_openttd[] = { { "roadstops.grf", { 0x8c, 0xd9, 0x45, 0x21, 0x28, 0x82, 0x96, 0x45, 0x33, 0x22, 0x7a, 0xb9, 0x0d, 0xf3, 0x67, 0x4a } }, { "group.grf", { 0xe8, 0x52, 0x5f, 0x1c, 0x3e, 0xf9, 0x91, 0x9d, 0x0f, 0x70, 0x8c, 0x8a, 0x21, 0xa4, 0xc7, 0x02 } }, { "tramtrkw.grf", { 0x83, 0x0a, 0xf4, 0x9f, 0x29, 0x10, 0x48, 0xfd, 0x76, 0xe9, 0xda, 0xac, 0x5d, 0xa2, 0x30, 0x45 } }, + { "oneway.grf", { 0xbb, 0xc6, 0xa3, 0xb2, 0xb3, 0xa0, 0xc9, 0x3c, 0xc9, 0xee, 0x24, 0x7c, 0xb6, 0x51, 0x74, 0x63 } }, }; diff --git a/src/table/sprites.h b/src/table/sprites.h index c6257cdfe..77d87d3db 100644 --- a/src/table/sprites.h +++ b/src/table/sprites.h @@ -168,6 +168,9 @@ enum Sprites { SPR_TRAMWAY_TUNNEL_WIRES = SPR_TRAMWAY_BASE + 80, SPR_TRAMWAY_BRIDGE = SPR_TRAMWAY_BASE + 107, + /* One way road sprites */ + SPR_ONEWAY_BASE = SPR_TRAMWAY_BASE + 113, + /* Manager face sprites */ SPR_GRADIENT = 874, // background gradient behind manager face |