|
@@ -420,103 +420,97 @@ CommandCost CmdTurnRoadVeh(TileIndex til
|
|
|
v->state == RVSB_WORMHOLE ||
|
|
|
v->IsInDepot() ||
|
|
|
v->cur_speed < 5) {
|
|
|
return CMD_ERROR;
|
|
|
}
|
|
|
|
|
|
if (IsNormalRoadTile(v->tile) && GetDisallowedRoadDirections(v->tile) != DRD_NONE) return CMD_ERROR;
|
|
|
|
|
|
if (IsTileType(v->tile, MP_TUNNELBRIDGE) && DirToDiagDir(v->direction) == GetTunnelBridgeDirection(v->tile)) return CMD_ERROR;
|
|
|
|
|
|
if (flags & DC_EXEC) v->reverse_ctr = 180;
|
|
|
|
|
|
return CommandCost();
|
|
|
}
|
|
|
|
|
|
|
|
|
void RoadVehicle::MarkDirty()
|
|
|
{
|
|
|
for (Vehicle *v = this; v != NULL; v = v->Next()) {
|
|
|
v->UpdateViewport(false, false);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void RoadVehicle::UpdateDeltaXY(Direction direction)
|
|
|
{
|
|
|
#define MKIT(a, b, c, d) ((a & 0xFF) << 24) | ((b & 0xFF) << 16) | ((c & 0xFF) << 8) | ((d & 0xFF) << 0)
|
|
|
static const uint32 _delta_xy_table[8] = {
|
|
|
MKIT(3, 3, -1, -1),
|
|
|
MKIT(3, 7, -1, -3),
|
|
|
MKIT(3, 3, -1, -1),
|
|
|
MKIT(7, 3, -3, -1),
|
|
|
MKIT(3, 3, -1, -1),
|
|
|
MKIT(3, 7, -1, -3),
|
|
|
MKIT(3, 3, -1, -1),
|
|
|
MKIT(7, 3, -3, -1),
|
|
|
};
|
|
|
#undef MKIT
|
|
|
|
|
|
uint32 x = _delta_xy_table[direction];
|
|
|
this->x_offs = GB(x, 0, 8);
|
|
|
this->y_offs = GB(x, 8, 8);
|
|
|
this->x_extent = GB(x, 16, 8);
|
|
|
this->y_extent = GB(x, 24, 8);
|
|
|
this->z_extent = 6;
|
|
|
}
|
|
|
|
|
|
static void ClearCrashedStation(RoadVehicle *v)
|
|
|
{
|
|
|
RoadStop *rs = RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile));
|
|
|
|
|
|
/* Mark the station entrance as not busy */
|
|
|
rs->SetEntranceBusy(false);
|
|
|
|
|
|
/* Free the parking bay */
|
|
|
rs->FreeBay(HasBit(v->state, RVS_USING_SECOND_BAY));
|
|
|
RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile))->Leave(v);
|
|
|
}
|
|
|
|
|
|
static void DeleteLastRoadVeh(RoadVehicle *v)
|
|
|
{
|
|
|
Vehicle *u = v;
|
|
|
for (; v->Next() != NULL; v = v->Next()) u = v;
|
|
|
u->SetNext(NULL);
|
|
|
|
|
|
if (IsTileType(v->tile, MP_STATION)) ClearCrashedStation(v);
|
|
|
|
|
|
delete v;
|
|
|
}
|
|
|
|
|
|
static byte SetRoadVehPosition(RoadVehicle *v, int x, int y, bool turned)
|
|
|
{
|
|
|
byte new_z, old_z;
|
|
|
|
|
|
/* need this hint so it returns the right z coordinate on bridges. */
|
|
|
v->x_pos = x;
|
|
|
v->y_pos = y;
|
|
|
new_z = GetSlopeZ(x, y);
|
|
|
|
|
|
old_z = v->z_pos;
|
|
|
v->z_pos = new_z;
|
|
|
|
|
|
v->UpdateViewport(true, turned);
|
|
|
return old_z;
|
|
|
}
|
|
|
|
|
|
static void RoadVehSetRandomDirection(RoadVehicle *v)
|
|
|
{
|
|
|
static const DirDiff delta[] = {
|
|
|
DIRDIFF_45LEFT, DIRDIFF_SAME, DIRDIFF_SAME, DIRDIFF_45RIGHT
|
|
|
};
|
|
|
|
|
|
do {
|
|
|
uint32 r = Random();
|
|
|
|
|
|
v->direction = ChangeDir(v->direction, delta[r & 3]);
|
|
|
SetRoadVehPosition(v, v->x_pos, v->y_pos, true);
|
|
|
} while ((v = v->Next()) != NULL);
|
|
|
}
|
|
|
|
|
|
static bool RoadVehIsCrashed(RoadVehicle *v)
|
|
|
{
|
|
|
v->crashed_ctr++;
|
|
|
if (v->crashed_ctr == 2) {
|
|
|
CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
|
|
@@ -1272,107 +1266,97 @@ again:
|
|
|
tile = v->tile;
|
|
|
start_frame = RVC_TURN_AROUND_START_FRAME_SHORT_TRAM;
|
|
|
} else {
|
|
|
/* The company can build on the next tile, so wait till (s)he does. */
|
|
|
v->cur_speed = 0;
|
|
|
return false;
|
|
|
}
|
|
|
} else if (IsNormalRoadTile(v->tile) && GetDisallowedRoadDirections(v->tile) != DRD_NONE) {
|
|
|
v->cur_speed = 0;
|
|
|
return false;
|
|
|
} else {
|
|
|
tile = v->tile;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* Get position data for first frame on the new tile */
|
|
|
const RoadDriveEntry *rdp = _road_drive_data[v->roadtype][(dir + (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)) ^ v->overtaking];
|
|
|
|
|
|
int x = TileX(tile) * TILE_SIZE + rdp[start_frame].x;
|
|
|
int y = TileY(tile) * TILE_SIZE + rdp[start_frame].y;
|
|
|
|
|
|
Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
|
|
|
if (v->IsRoadVehFront()) {
|
|
|
Vehicle *u = RoadVehFindCloseTo(v, x, y, new_dir);
|
|
|
if (u != NULL) {
|
|
|
v->cur_speed = u->First()->cur_speed;
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
uint32 r = VehicleEnterTile(v, tile, x, y);
|
|
|
if (HasBit(r, VETS_CANNOT_ENTER)) {
|
|
|
if (!IsTileType(tile, MP_TUNNELBRIDGE)) {
|
|
|
v->cur_speed = 0;
|
|
|
return false;
|
|
|
}
|
|
|
/* Try an about turn to re-enter the previous tile */
|
|
|
dir = _road_reverse_table[rd.x & 3];
|
|
|
goto again;
|
|
|
}
|
|
|
|
|
|
if (IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) && IsTileType(v->tile, MP_STATION)) {
|
|
|
if (IsReversingRoadTrackdir(dir) && IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END)) {
|
|
|
/* New direction is trying to turn vehicle around.
|
|
|
* We can't turn at the exit of a road stop so wait.*/
|
|
|
v->cur_speed = 0;
|
|
|
return false;
|
|
|
}
|
|
|
if (IsRoadStop(v->tile)) {
|
|
|
RoadStop *rs = RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile));
|
|
|
|
|
|
/* Vehicle is leaving a road stop tile, mark bay as free
|
|
|
* For drive-through stops, only do it if the vehicle stopped here */
|
|
|
if (IsStandardRoadStopTile(v->tile) || HasBit(v->state, RVS_IS_STOPPING)) {
|
|
|
rs->FreeBay(HasBit(v->state, RVS_USING_SECOND_BAY));
|
|
|
ClrBit(v->state, RVS_IS_STOPPING);
|
|
|
}
|
|
|
if (IsStandardRoadStopTile(v->tile)) rs->SetEntranceBusy(false);
|
|
|
}
|
|
|
if (IsRoadStop(v->tile)) RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile))->Leave(v);
|
|
|
}
|
|
|
|
|
|
if (!HasBit(r, VETS_ENTERED_WORMHOLE)) {
|
|
|
v->tile = tile;
|
|
|
v->state = (byte)dir;
|
|
|
v->frame = start_frame;
|
|
|
}
|
|
|
if (new_dir != v->direction) {
|
|
|
v->direction = new_dir;
|
|
|
v->cur_speed -= v->cur_speed >> 2;
|
|
|
}
|
|
|
|
|
|
RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y, true));
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
if (rd.x & RDE_TURNED) {
|
|
|
/* Vehicle has finished turning around, it will now head back onto the same tile */
|
|
|
Trackdir dir;
|
|
|
uint turn_around_start_frame = RVC_TURN_AROUND_START_FRAME;
|
|
|
|
|
|
RoadBits tram;
|
|
|
if (v->roadtype == ROADTYPE_TRAM && !IsRoadDepotTile(v->tile) && CountBits(tram = GetAnyRoadBits(v->tile, ROADTYPE_TRAM, true)) == 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 (rd.x & 0x3) {
|
|
|
default: NOT_REACHED();
|
|
|
case DIAGDIR_NW: dir = TRACKDIR_RVREV_SE; break;
|
|
|
case DIAGDIR_NE: dir = TRACKDIR_RVREV_SW; break;
|
|
|
case DIAGDIR_SE: dir = TRACKDIR_RVREV_NW; break;
|
|
|
case DIAGDIR_SW: dir = TRACKDIR_RVREV_NE; break;
|
|
|
}
|
|
|
} else {
|
|
|
if (v->IsRoadVehFront()) {
|
|
|
/* 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);
|
|
|
}
|
|
|
}
|