(svn r9999) -Feature: make it possible to disallow busses and lorries to go a specific way on straight pieces of road.
authorrubidium
Thu, 31 May 2007 15:15:00 +0000
changeset 6764 d09d8d618a07
parent 6763 87f1ed44eedb
child 6765 50903afa1a48
(svn r9999) -Feature: make it possible to disallow busses and lorries to go a specific way on straight pieces of road.
bin/data/oneway.grf
docs/landscape.html
docs/landscape_grid.html
src/gfxinit.cpp
src/lang/english.txt
src/newgrf.cpp
src/road_cmd.cpp
src/road_gui.cpp
src/road_map.h
src/roadveh_cmd.cpp
src/table/files.h
src/table/sprites.h
Binary file bin/data/oneway.grf has changed
--- a/docs/landscape.html	Thu May 31 14:29:19 2007 +0000
+++ b/docs/landscape.html	Thu May 31 15:15:00 2007 +0000
@@ -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>
--- a/docs/landscape_grid.html	Thu May 31 14:29:19 2007 +0000
+++ b/docs/landscape_grid.html	Thu May 31 15:15:00 2007 +0000
@@ -125,7 +125,7 @@
       <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>
--- a/src/gfxinit.cpp	Thu May 31 14:29:19 2007 +0000
+++ b/src/gfxinit.cpp	Thu May 31 15:15:00 2007 +0000
@@ -399,6 +399,9 @@
 	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();
 
--- a/src/lang/english.txt	Thu May 31 14:29:19 2007 +0000
+++ b/src/lang/english.txt	Thu May 31 15:15:00 2007 +0000
@@ -1600,6 +1600,7 @@
 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...
--- a/src/newgrf.cpp	Thu May 31 14:29:19 2007 +0000
+++ b/src/newgrf.cpp	Thu May 31 15:15:00 2007 +0000
@@ -2897,6 +2897,14 @@
 			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");
--- a/src/road_cmd.cpp	Thu May 31 14:29:19 2007 +0000
+++ b/src/road_cmd.cpp	Thu May 31 15:15:00 2007 +0000
@@ -218,6 +218,10 @@
 						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 @@
  * @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 @@
 	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 @@
 					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 @@
 				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 @@
  * - 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 @@
 		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 @@
 		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 @@
 		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 @@
 }
 
 /**
+ * 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 @@
 
 	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 @@
 
 	/* 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 @@
 			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: {
--- a/src/road_gui.cpp	Thu May 31 14:29:19 2007 +0000
+++ b/src/road_gui.cpp	Thu May 31 15:15:00 2007 +0000
@@ -343,7 +343,7 @@
 
 				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));
--- a/src/road_map.h	Thu May 31 14:29:19 2007 +0000
+++ b/src/road_map.h	Thu May 31 15:15:00 2007 +0000
@@ -89,14 +89,24 @@
 			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 @@
 			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 @@
 			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 @@
 	}
 }
 
+/** 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);
--- a/src/roadveh_cmd.cpp	Thu May 31 14:29:19 2007 +0000
+++ b/src/roadveh_cmd.cpp	Thu May 31 15:15:00 2007 +0000
@@ -485,6 +485,8 @@
 		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 @@
 					v->cur_speed = 0;
 					return;
 				}
+			} else if (GetDisallowedRoadDirections(v->tile) != DRD_NONE) {
+				v->cur_speed = 0;
+				return;
 			} else {
 				tile = v->tile;
 			}
--- a/src/table/files.h	Thu May 31 14:29:19 2007 +0000
+++ b/src/table/files.h	Thu May 31 15:15:00 2007 +0000
@@ -64,4 +64,5 @@
 	{ "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 } },
 };
--- a/src/table/sprites.h	Thu May 31 14:29:19 2007 +0000
+++ b/src/table/sprites.h	Thu May 31 15:15:00 2007 +0000
@@ -168,6 +168,9 @@
 	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