(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.

This commit is contained in:
rubidium 2007-11-17 12:42:15 +00:00
parent fd9e2887b2
commit ef6c4c1cdf
2 changed files with 107 additions and 18 deletions

View File

@ -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 FollowPreviousRoadVehicle(const Vehicle *v, const Vehicle *prev,
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 IndividualRoadVehicleController(Vehicle *v, const Vehicle *prev)
}
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;

View File

@ -1099,6 +1099,7 @@ static const RoadDriveEntry _roadveh_tram_turn_ne_0[] = {
{ 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_tram_turn_ne_1[] = {
{ 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_tram_turn_se_0[] = {
{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_tram_turn_se_1[] = {
{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_tram_turn_sw_0[] = {
{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_tram_turn_sw_1[] = {
{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_tram_turn_nw_0[] = {
{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_tram_turn_nw_1[] = {
{7, 0},
{8, 0},
{9, 0},
{RDE_TURNED | DIAGDIR_SE, 0},
{9, 1},
{9, 2},
{9, 3},