Changeset - r7898:c4cded9d8731
[Not reviewed]
master
0 2 0
rubidium - 17 years ago 2007-11-17 12:42:15
rubidium@openttd.org
(svn r11449) -Fix [FS#1160]: trams could deadlock themselves. As of now trams will turn as roadvehicles do when the player cannot build a tram track piece on the next tile without destroying anything. It will not turn when the player can build the before mentioned track piece on the 'next' tile.
2 files changed with 107 insertions and 18 deletions:
0 comments (0 inline, 0 general)
src/roadveh_cmd.cpp
Show inline comments
 
@@ -1325,12 +1325,16 @@ enum {
 

	
 
	/* Start frames for when a vehicle enters a tile/changes its state.
 
	 * The start frame is different for vehicles that turned around or
 
	 * are leaving the depot as the do not start at the edge of the tile */
 
	RVC_DEFAULT_START_FRAME      = 0,
 
	RVC_TURN_AROUND_START_FRAME  = 1,
 
	RVC_DEPOT_START_FRAME        = 6,
 
	 * are leaving the depot as the do not start at the edge of the tile.
 
	 * For trams there are a few different start frames as there are two
 
	 * places where trams can turn. */
 
	RVC_DEFAULT_START_FRAME                =  0,
 
	RVC_TURN_AROUND_START_FRAME            =  1,
 
	RVC_DEPOT_START_FRAME                  =  6,
 
	RVC_START_FRAME_AFTER_LONG_TRAM        = 22,
 
	RVC_TURN_AROUND_START_FRAME_SHORT_TRAM = 16,
 
	/* Stop frame for a vehicle in a drive-through stop */
 
	RVC_DRIVE_THROUGH_STOP_FRAME = 7
 
	RVC_DRIVE_THROUGH_STOP_FRAME           =  7
 
};
 

	
 
struct RoadDriveEntry {
 
@@ -1456,6 +1460,29 @@ static Trackdir FollowPreviousRoadVehicl
 
	return dir;
 
}
 

	
 
/**
 
 * Can a tram track build without destruction on the given tile?
 
 * @param t the tile to build on.
 
 * @return true when a track track can be build on 't'
 
 */
 
static bool CanBuildTramTrackOnTile(TileIndex t)
 
{
 
	switch (GetTileType(t)) {
 
		case MP_CLEAR:
 
		case MP_TREES:
 
			return true;
 

	
 
		case MP_ROAD:
 
			return GetRoadTileType(t) == ROAD_TILE_NORMAL;
 

	
 
		case MP_WATER:
 
			return IsCoast(t);
 

	
 
		default:
 
			return false;
 
	}
 
}
 

	
 
static bool IndividualRoadVehicleController(Vehicle *v, const Vehicle *prev)
 
{
 
	Direction new_dir;
 
@@ -1535,10 +1562,13 @@ static bool IndividualRoadVehicleControl
 
		}
 

	
 
again:
 
		uint start_frame = RVC_DEFAULT_START_FRAME;
 
		if (IsReversingRoadTrackdir(dir)) {
 
			/* Turning around */
 
			if (v->u.road.roadtype == ROADTYPE_TRAM) {
 
				RoadBits needed; // The road bits the tram needs to be able to turn around
 
				/* Determine the road bits the tram needs to be able to turn around
 
				 * using the 'big' corner loop. */
 
				RoadBits needed;
 
				switch (dir) {
 
					default: NOT_REACHED();
 
					case TRACKDIR_RVREV_NE: needed = ROAD_SW; break;
 
@@ -1546,8 +1576,36 @@ again:
 
					case TRACKDIR_RVREV_SW: needed = ROAD_NE; break;
 
					case TRACKDIR_RVREV_NW: needed = ROAD_SE; break;
 
				}
 
				if (!IsTileType(tile, MP_ROAD) || GetRoadTileType(tile) != ROAD_TILE_NORMAL || HasRoadWorks(tile) || (needed & GetRoadBits(tile, ROADTYPE_TRAM)) == ROAD_NONE) {
 
					/* The tram cannot turn here */
 
				if ((v->Previous() != NULL && v->Previous()->tile == tile) ||
 
						(IsRoadVehFront(v) && IsTileType(tile, MP_ROAD) &&
 
							GetRoadTileType(tile) == ROAD_TILE_NORMAL && !HasRoadWorks(tile) &&
 
							(needed & GetRoadBits(tile, ROADTYPE_TRAM)) != ROAD_NONE)) {
 
					/*
 
					 * Taking the 'big' corner for trams only happens when:
 
					 * - The previous vehicle in this (articulated) tram chain is
 
					 *   already on the 'next' tile, we just follow them regardless of
 
					 *   anything. When it is NOT on the 'next' tile, the tram started
 
					 *   doing a reversing turn when the piece of tram track on the next
 
					 *   tile did not exist yet. Do not use the big tram loop as that is
 
					 *   going to cause the tram to split up.
 
					 * - Or the front of the tram can drive over the next tile.
 
					 */
 
				} else if (!IsRoadVehFront(v) || !CanBuildTramTrackOnTile(tile)) {
 
					/*
 
					 * Taking the 'small' corner for trams only happens when:
 
					 * - We are not the from vehicle of an articulated tram.
 
					 * - Or when the player cannot build on the next tile.
 
					 *
 
					 * The 'small' corner means that the vehicle is on the end of a
 
					 * tram track and needs to start turning there. To do this properly
 
					 * the tram needs to start at an offset in the tram turning 'code'
 
					 * for 'big' corners. It furthermore does not go to the next tile,
 
					 * so that needs to be fixed too.
 
					 */
 
					tile = v->tile;
 
					start_frame = RVC_TURN_AROUND_START_FRAME_SHORT_TRAM;
 
				} else {
 
					/* The player can build on the next tile, so wait till (s)he does. */
 
					v->cur_speed = 0;
 
					return false;
 
				}
 
@@ -1562,8 +1620,8 @@ again:
 
		/* Get position data for first frame on the new tile */
 
		rdp = _road_drive_data[v->u.road.roadtype][(dir + (_opt.road_side << RVS_DRIVE_SIDE)) ^ v->u.road.overtaking];
 

	
 
		x = TileX(tile) * TILE_SIZE + rdp[RVC_DEFAULT_START_FRAME].x;
 
		y = TileY(tile) * TILE_SIZE + rdp[RVC_DEFAULT_START_FRAME].y;
 
		x = TileX(tile) * TILE_SIZE + rdp[start_frame].x;
 
		y = TileY(tile) * TILE_SIZE + rdp[start_frame].y;
 

	
 
		newdir = RoadVehGetSlidingDirection(v, x, y);
 
		if (IsRoadVehFront(v) && RoadVehFindCloseTo(v, x, y, newdir) != NULL) return false;
 
@@ -1602,7 +1660,7 @@ again:
 
		if (!HASBIT(r, VETS_ENTERED_WORMHOLE)) {
 
			v->tile = tile;
 
			v->u.road.state = (byte)dir;
 
			v->u.road.frame = RVC_DEFAULT_START_FRAME;
 
			v->u.road.frame = start_frame;
 
		}
 
		if (newdir != v->direction) {
 
			v->direction = newdir;
 
@@ -1622,11 +1680,34 @@ again:
 
		Direction newdir;
 
		const RoadDriveEntry *rdp;
 

	
 
		if (IsRoadVehFront(v)) {
 
			/* If this is the front engine, look for the right path. */
 
			dir = RoadFindPathToDest(v, v->tile, (DiagDirection)(rd.x & 3));
 
		uint turn_around_start_frame = RVC_TURN_AROUND_START_FRAME;
 

	
 
		RoadBits tram = GetRoadBits(v->tile, ROADTYPE_TRAM);
 
		if (v->u.road.roadtype == ROADTYPE_TRAM && CountBits(tram) == 1) {
 
			/*
 
			 * The tram is turning around with one tram 'roadbit'. This means that
 
			 * it is using the 'big' corner 'drive data'. However, to support the
 
			 * trams to take a small corner, there is a 'turned' marker in the middle
 
			 * of the turning 'drive data'. When the tram took the long corner, we
 
			 * will still use the 'big' corner drive data, but we advance it one
 
			 * frame. We furthermore set the driving direction so the turning is
 
			 * going to be properly shown.
 
			 */
 
			turn_around_start_frame = RVC_START_FRAME_AFTER_LONG_TRAM;
 
			switch (tram) {
 
				default: NOT_REACHED();
 
				case ROAD_SW: dir = TRACKDIR_RVREV_NE; break;
 
				case ROAD_NW: dir = TRACKDIR_RVREV_SE; break;
 
				case ROAD_NE: dir = TRACKDIR_RVREV_SW; break;
 
				case ROAD_SE: dir = TRACKDIR_RVREV_NW; break;
 
			}
 
		} else {
 
			dir = FollowPreviousRoadVehicle(v, prev, v->tile, (DiagDirection)(rd.x & 3), true);
 
			if (IsRoadVehFront(v)) {
 
				/* If this is the front engine, look for the right path. */
 
				dir = RoadFindPathToDest(v, v->tile, (DiagDirection)(rd.x & 3));
 
			} else {
 
				dir = FollowPreviousRoadVehicle(v, prev, v->tile, (DiagDirection)(rd.x & 3), true);
 
			}
 
		}
 

	
 
		if (dir == INVALID_TRACKDIR) {
 
@@ -1636,8 +1717,8 @@ again:
 

	
 
		rdp = _road_drive_data[v->u.road.roadtype][(_opt.road_side << RVS_DRIVE_SIDE) + dir];
 

	
 
		x = TileX(v->tile) * TILE_SIZE + rdp[RVC_TURN_AROUND_START_FRAME].x;
 
		y = TileY(v->tile) * TILE_SIZE + rdp[RVC_TURN_AROUND_START_FRAME].y;
 
		x = TileX(v->tile) * TILE_SIZE + rdp[turn_around_start_frame].x;
 
		y = TileY(v->tile) * TILE_SIZE + rdp[turn_around_start_frame].y;
 

	
 
		newdir = RoadVehGetSlidingDirection(v, x, y);
 
		if (IsRoadVehFront(v) && RoadVehFindCloseTo(v, x, y, newdir) != NULL) return false;
 
@@ -1649,7 +1730,7 @@ again:
 
		}
 

	
 
		v->u.road.state = dir;
 
		v->u.road.frame = RVC_TURN_AROUND_START_FRAME;
 
		v->u.road.frame = turn_around_start_frame;
 

	
 
		if (newdir != v->direction) {
 
			v->direction = newdir;
src/table/roadveh.h
Show inline comments
 
@@ -1099,6 +1099,7 @@ static const RoadDriveEntry _roadveh_tra
 
	{ 0, 7},
 
	{ 0, 8},
 
	{ 0, 9},
 
	{RDE_TURNED | DIAGDIR_SW, 0},
 
	{ 1, 9},
 
	{ 2, 9},
 
	{ 3, 9},
 
@@ -1138,6 +1139,7 @@ static const RoadDriveEntry _roadveh_tra
 
	{ 0, 7},
 
	{ 0, 6},
 
	{ 0, 5},
 
	{RDE_TURNED | DIAGDIR_SW, 0},
 
	{ 1, 5},
 
	{ 2, 5},
 
	{ 3, 5},
 
@@ -1177,6 +1179,7 @@ static const RoadDriveEntry _roadveh_tra
 
	{7, 15},
 
	{8, 15},
 
	{9, 15},
 
	{RDE_TURNED | DIAGDIR_NW, 0},
 
	{9, 14},
 
	{9, 13},
 
	{9, 12},
 
@@ -1216,6 +1219,7 @@ static const RoadDriveEntry _roadveh_tra
 
	{7, 15},
 
	{6, 15},
 
	{5, 15},
 
	{RDE_TURNED | DIAGDIR_NW, 0},
 
	{5, 14},
 
	{5, 13},
 
	{5, 12},
 
@@ -1255,6 +1259,7 @@ static const RoadDriveEntry _roadveh_tra
 
	{15, 7},
 
	{15, 6},
 
	{15, 5},
 
	{RDE_TURNED | DIAGDIR_SW, 0},
 
	{14, 5},
 
	{13, 5},
 
	{12, 5},
 
@@ -1293,6 +1298,7 @@ static const RoadDriveEntry _roadveh_tra
 
	{15, 7},
 
	{15, 8},
 
	{15, 9},
 
	{RDE_TURNED | DIAGDIR_NE, 0},
 
	{14, 9},
 
	{13, 9},
 
	{12, 9},
 
@@ -1332,6 +1338,7 @@ static const RoadDriveEntry _roadveh_tra
 
	{7,  0},
 
	{6,  0},
 
	{5,  0},
 
	{RDE_TURNED | DIAGDIR_SE, 0},
 
	{5,  1},
 
	{5,  2},
 
	{5,  3},
 
@@ -1370,6 +1377,7 @@ static const RoadDriveEntry _roadveh_tra
 
	{7,  0},
 
	{8,  0},
 
	{9,  0},
 
	{RDE_TURNED | DIAGDIR_SE, 0},
 
	{9,  1},
 
	{9,  2},
 
	{9,  3},
0 comments (0 inline, 0 general)