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

pull/155/head
rubidium 17 years ago
parent 0bba49b413
commit 2245094822

@ -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;

@ -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},

Loading…
Cancel
Save