roadveh_cmd.cpp

Go to the documentation of this file.
00001 /* $Id$ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
00008  */
00009 
00012 #include "stdafx.h"
00013 #include "roadveh.h"
00014 #include "command_func.h"
00015 #include "news_func.h"
00016 #include "pathfinder/npf/npf_func.h"
00017 #include "station_base.h"
00018 #include "company_func.h"
00019 #include "vehicle_gui.h"
00020 #include "articulated_vehicles.h"
00021 #include "newgrf_sound.h"
00022 #include "pathfinder/yapf/yapf.h"
00023 #include "strings_func.h"
00024 #include "tunnelbridge_map.h"
00025 #include "window_func.h"
00026 #include "date_func.h"
00027 #include "vehicle_func.h"
00028 #include "sound_func.h"
00029 #include "ai/ai.hpp"
00030 #include "depot_map.h"
00031 #include "effectvehicle_func.h"
00032 #include "roadstop_base.h"
00033 #include "spritecache.h"
00034 #include "core/random_func.hpp"
00035 #include "company_base.h"
00036 #include "core/backup_type.hpp"
00037 #include "newgrf.h"
00038 #include "zoom_func.h"
00039 
00040 #include "table/strings.h"
00041 
00042 static const uint16 _roadveh_images[63] = {
00043   0xCD4, 0xCDC, 0xCE4, 0xCEC, 0xCF4, 0xCFC, 0xD0C, 0xD14,
00044   0xD24, 0xD1C, 0xD2C, 0xD04, 0xD1C, 0xD24, 0xD6C, 0xD74,
00045   0xD7C, 0xC14, 0xC1C, 0xC24, 0xC2C, 0xC34, 0xC3C, 0xC4C,
00046   0xC54, 0xC64, 0xC5C, 0xC6C, 0xC44, 0xC5C, 0xC64, 0xCAC,
00047   0xCB4, 0xCBC, 0xD94, 0xD9C, 0xDA4, 0xDAC, 0xDB4, 0xDBC,
00048   0xDCC, 0xDD4, 0xDE4, 0xDDC, 0xDEC, 0xDC4, 0xDDC, 0xDE4,
00049   0xE2C, 0xE34, 0xE3C, 0xC14, 0xC1C, 0xC2C, 0xC3C, 0xC4C,
00050   0xC5C, 0xC64, 0xC6C, 0xC74, 0xC84, 0xC94, 0xCA4
00051 };
00052 
00053 static const uint16 _roadveh_full_adder[63] = {
00054    0,  88,   0,   0,   0,   0,  48,  48,
00055   48,  48,   0,   0,  64,  64,   0,  16,
00056   16,   0,  88,   0,   0,   0,   0,  48,
00057   48,  48,  48,   0,   0,  64,  64,   0,
00058   16,  16,   0,  88,   0,   0,   0,   0,
00059   48,  48,  48,  48,   0,   0,  64,  64,
00060    0,  16,  16,   0,   8,   8,   8,   8,
00061    0,   0,   0,   8,   8,   8,   8
00062 };
00063 
00065 static const TrackdirBits _road_enter_dir_to_reachable_trackdirs[DIAGDIR_END] = {
00066   TRACKDIR_BIT_LEFT_N  | TRACKDIR_BIT_LOWER_E | TRACKDIR_BIT_X_NE,    // Enter from north east
00067   TRACKDIR_BIT_LEFT_S  | TRACKDIR_BIT_UPPER_E | TRACKDIR_BIT_Y_SE,    // Enter from south east
00068   TRACKDIR_BIT_UPPER_W | TRACKDIR_BIT_X_SW    | TRACKDIR_BIT_RIGHT_S, // Enter from south west
00069   TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_LOWER_W | TRACKDIR_BIT_Y_NW     // Enter from north west
00070 };
00071 
00072 static const Trackdir _road_reverse_table[DIAGDIR_END] = {
00073   TRACKDIR_RVREV_NE, TRACKDIR_RVREV_SE, TRACKDIR_RVREV_SW, TRACKDIR_RVREV_NW
00074 };
00075 
00077 static const Trackdir _roadveh_depot_exit_trackdir[DIAGDIR_END] = {
00078   TRACKDIR_X_NE, TRACKDIR_Y_SE, TRACKDIR_X_SW, TRACKDIR_Y_NW
00079 };
00080 
00081 
00086 bool RoadVehicle::IsBus() const
00087 {
00088   assert(this->IsFrontEngine());
00089   return IsCargoInClass(this->cargo_type, CC_PASSENGERS);
00090 }
00091 
00097 int RoadVehicle::GetDisplayImageWidth(Point *offset) const
00098 {
00099   int reference_width = ROADVEHINFO_DEFAULT_VEHICLE_WIDTH;
00100 
00101   if (offset != NULL) {
00102     offset->x = reference_width / 2;
00103     offset->y = 0;
00104   }
00105   return this->gcache.cached_veh_length * reference_width / VEHICLE_LENGTH;
00106 }
00107 
00108 static SpriteID GetRoadVehIcon(EngineID engine, EngineImageType image_type)
00109 {
00110   const Engine *e = Engine::Get(engine);
00111   uint8 spritenum = e->u.road.image_index;
00112 
00113   if (is_custom_sprite(spritenum)) {
00114     SpriteID sprite = GetCustomVehicleIcon(engine, DIR_W, image_type);
00115     if (sprite != 0) return sprite;
00116 
00117     spritenum = e->original_image_index;
00118   }
00119 
00120   return DIR_W + _roadveh_images[spritenum];
00121 }
00122 
00123 SpriteID RoadVehicle::GetImage(Direction direction, EngineImageType image_type) const
00124 {
00125   uint8 spritenum = this->spritenum;
00126   SpriteID sprite;
00127 
00128   if (is_custom_sprite(spritenum)) {
00129     sprite = GetCustomVehicleSprite(this, (Direction)(direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(spritenum)), image_type);
00130     if (sprite != 0) return sprite;
00131 
00132     spritenum = this->GetEngine()->original_image_index;
00133   }
00134 
00135   sprite = direction + _roadveh_images[spritenum];
00136 
00137   if (this->cargo.Count() >= this->cargo_cap / 2U) sprite += _roadveh_full_adder[spritenum];
00138 
00139   return sprite;
00140 }
00141 
00151 void DrawRoadVehEngine(int left, int right, int preferred_x, int y, EngineID engine, PaletteID pal, EngineImageType image_type)
00152 {
00153   SpriteID sprite = GetRoadVehIcon(engine, image_type);
00154   const Sprite *real_sprite = GetSprite(sprite, ST_NORMAL);
00155   preferred_x = Clamp(preferred_x, left - UnScaleByZoom(real_sprite->x_offs, ZOOM_LVL_GUI), right - UnScaleByZoom(real_sprite->width, ZOOM_LVL_GUI) - UnScaleByZoom(real_sprite->x_offs, ZOOM_LVL_GUI));
00156   DrawSprite(sprite, pal, preferred_x, y);
00157 }
00158 
00164 static uint GetRoadVehLength(const RoadVehicle *v)
00165 {
00166   const Engine *e = v->GetEngine();
00167   uint length = VEHICLE_LENGTH;
00168 
00169   uint16 veh_len = CALLBACK_FAILED;
00170   if (e->GetGRF() != NULL && e->GetGRF()->grf_version >= 8) {
00171     /* Use callback 36 */
00172     veh_len = GetVehicleProperty(v, PROP_ROADVEH_SHORTEN_FACTOR, CALLBACK_FAILED);
00173   } else {
00174     /* Use callback 11 */
00175     veh_len = GetVehicleCallback(CBID_VEHICLE_LENGTH, 0, 0, v->engine_type, v);
00176   }
00177   if (veh_len == CALLBACK_FAILED) veh_len = e->u.road.shorten_factor;
00178   if (veh_len != 0) {
00179     if (veh_len >= VEHICLE_LENGTH) ErrorUnknownCallbackResult(e->GetGRFID(), CBID_VEHICLE_LENGTH, veh_len);
00180     length -= Clamp(veh_len, 0, VEHICLE_LENGTH - 1);
00181   }
00182 
00183   return length;
00184 }
00185 
00192 void RoadVehUpdateCache(RoadVehicle *v, bool same_length)
00193 {
00194   assert(v->type == VEH_ROAD);
00195   assert(v->IsFrontEngine());
00196 
00197   v->InvalidateNewGRFCacheOfChain();
00198 
00199   v->gcache.cached_total_length = 0;
00200 
00201   for (RoadVehicle *u = v; u != NULL; u = u->Next()) {
00202     /* Check the v->first cache. */
00203     assert(u->First() == v);
00204 
00205     /* Update the 'first engine' */
00206     u->gcache.first_engine = (v == u) ? INVALID_ENGINE : v->engine_type;
00207 
00208     /* Update the length of the vehicle. */
00209     uint veh_len = GetRoadVehLength(u);
00210     /* Verify length hasn't changed. */
00211     if (same_length && veh_len != u->gcache.cached_veh_length) VehicleLengthChanged(u);
00212 
00213     u->gcache.cached_veh_length = veh_len;
00214     v->gcache.cached_total_length += u->gcache.cached_veh_length;
00215 
00216     /* Update visual effect */
00217     v->UpdateVisualEffect();
00218 
00219     /* Invalidate the vehicle colour map */
00220     u->colourmap = PAL_NONE;
00221 
00222     /* Update cargo aging period. */
00223     u->vcache.cached_cargo_age_period = GetVehicleProperty(u, PROP_ROADVEH_CARGO_AGE_PERIOD, EngInfo(u->engine_type)->cargo_age_period);
00224   }
00225 
00226   uint max_speed = GetVehicleProperty(v, PROP_ROADVEH_SPEED, 0);
00227   v->vcache.cached_max_speed = (max_speed != 0) ? max_speed * 4 : RoadVehInfo(v->engine_type)->max_speed;
00228 }
00229 
00239 CommandCost CmdBuildRoadVehicle(TileIndex tile, DoCommandFlag flags, const Engine *e, uint16 data, Vehicle **ret)
00240 {
00241   if (HasTileRoadType(tile, ROADTYPE_TRAM) != HasBit(e->info.misc_flags, EF_ROAD_TRAM)) return_cmd_error(STR_ERROR_DEPOT_WRONG_DEPOT_TYPE);
00242 
00243   if (flags & DC_EXEC) {
00244     const RoadVehicleInfo *rvi = &e->u.road;
00245 
00246     RoadVehicle *v = new RoadVehicle();
00247     *ret = v;
00248     v->direction = DiagDirToDir(GetRoadDepotDirection(tile));
00249     v->owner = _current_company;
00250 
00251     v->tile = tile;
00252     int x = TileX(tile) * TILE_SIZE + TILE_SIZE / 2;
00253     int y = TileY(tile) * TILE_SIZE + TILE_SIZE / 2;
00254     v->x_pos = x;
00255     v->y_pos = y;
00256     v->z_pos = GetSlopePixelZ(x, y);
00257 
00258     v->state = RVSB_IN_DEPOT;
00259     v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL;
00260 
00261     v->spritenum = rvi->image_index;
00262     v->cargo_type = e->GetDefaultCargoType();
00263     v->cargo_cap = rvi->capacity;
00264 
00265     v->last_station_visited = INVALID_STATION;
00266     v->last_loading_station = INVALID_STATION;
00267     v->engine_type = e->index;
00268     v->gcache.first_engine = INVALID_ENGINE; // needs to be set before first callback
00269 
00270     v->reliability = e->reliability;
00271     v->reliability_spd_dec = e->reliability_spd_dec;
00272     v->max_age = e->GetLifeLengthInDays();
00273     _new_vehicle_id = v->index;
00274 
00275     v->service_interval = Company::Get(v->owner)->settings.vehicle.servint_roadveh;
00276 
00277     v->date_of_last_service = _date;
00278     v->build_year = _cur_year;
00279 
00280     v->cur_image = SPR_IMG_QUERY;
00281     v->random_bits = VehicleRandomBits();
00282     v->SetFrontEngine();
00283 
00284     v->roadtype = HasBit(e->info.misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD;
00285     v->compatible_roadtypes = RoadTypeToRoadTypes(v->roadtype);
00286     v->gcache.cached_veh_length = VEHICLE_LENGTH;
00287 
00288     if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) SetBit(v->vehicle_flags, VF_BUILT_AS_PROTOTYPE);
00289 
00290     AddArticulatedParts(v);
00291     v->InvalidateNewGRFCacheOfChain();
00292 
00293     /* Call various callbacks after the whole consist has been constructed */
00294     for (RoadVehicle *u = v; u != NULL; u = u->Next()) {
00295       u->cargo_cap = u->GetEngine()->DetermineCapacity(u);
00296       v->InvalidateNewGRFCache();
00297       u->InvalidateNewGRFCache();
00298     }
00299     RoadVehUpdateCache(v);
00300     /* Initialize cached values for realistic acceleration. */
00301     if (_settings_game.vehicle.roadveh_acceleration_model != AM_ORIGINAL) v->CargoChanged();
00302 
00303     VehicleMove(v, false);
00304 
00305     CheckConsistencyOfArticulatedVehicle(v);
00306   }
00307 
00308   return CommandCost();
00309 }
00310 
00311 bool RoadVehicle::IsStoppedInDepot() const
00312 {
00313   TileIndex tile = this->tile;
00314 
00315   if (!IsRoadDepotTile(tile)) return false;
00316   if (this->IsFrontEngine() && !(this->vehstatus & VS_STOPPED)) return false;
00317 
00318   for (const RoadVehicle *v = this; v != NULL; v = v->Next()) {
00319     if (v->state != RVSB_IN_DEPOT || v->tile != tile) return false;
00320   }
00321   return true;
00322 }
00323 
00324 static FindDepotData FindClosestRoadDepot(const RoadVehicle *v, int max_distance)
00325 {
00326   if (IsRoadDepotTile(v->tile)) return FindDepotData(v->tile, 0);
00327 
00328   switch (_settings_game.pf.pathfinder_for_roadvehs) {
00329     case VPF_NPF: return NPFRoadVehicleFindNearestDepot(v, max_distance);
00330     case VPF_YAPF: return YapfRoadVehicleFindNearestDepot(v, max_distance);
00331 
00332     default: NOT_REACHED();
00333   }
00334 }
00335 
00336 bool RoadVehicle::FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse)
00337 {
00338   FindDepotData rfdd = FindClosestRoadDepot(this, 0);
00339   if (rfdd.best_length == UINT_MAX) return false;
00340 
00341   if (location    != NULL) *location    = rfdd.tile;
00342   if (destination != NULL) *destination = GetDepotIndex(rfdd.tile);
00343 
00344   return true;
00345 }
00346 
00356 CommandCost CmdTurnRoadVeh(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00357 {
00358   RoadVehicle *v = RoadVehicle::GetIfValid(p1);
00359   if (v == NULL) return CMD_ERROR;
00360 
00361   CommandCost ret = CheckOwnership(v->owner);
00362   if (ret.Failed()) return ret;
00363 
00364   if ((v->vehstatus & VS_STOPPED) ||
00365       (v->vehstatus & VS_CRASHED) ||
00366       v->breakdown_ctr != 0 ||
00367       v->overtaking != 0 ||
00368       v->state == RVSB_WORMHOLE ||
00369       v->IsInDepot() ||
00370       v->current_order.IsType(OT_LOADING)) {
00371     return CMD_ERROR;
00372   }
00373 
00374   if (IsNormalRoadTile(v->tile) && GetDisallowedRoadDirections(v->tile) != DRD_NONE) return CMD_ERROR;
00375 
00376   if (IsTileType(v->tile, MP_TUNNELBRIDGE) && DirToDiagDir(v->direction) == GetTunnelBridgeDirection(v->tile)) return CMD_ERROR;
00377 
00378   if (flags & DC_EXEC) v->reverse_ctr = 180;
00379 
00380   return CommandCost();
00381 }
00382 
00383 
00384 void RoadVehicle::MarkDirty()
00385 {
00386   for (RoadVehicle *v = this; v != NULL; v = v->Next()) {
00387     v->UpdateViewport(false, false);
00388   }
00389   this->CargoChanged();
00390 }
00391 
00392 void RoadVehicle::UpdateDeltaXY(Direction direction)
00393 {
00394 #define MKIT(a, b, c, d) ((a & 0xFF) << 24) | ((b & 0xFF) << 16) | ((c & 0xFF) << 8) | ((d & 0xFF) << 0)
00395   static const uint32 _delta_xy_table[8] = {
00396     MKIT(3, 3, -1, -1),
00397     MKIT(3, 7, -1, -3),
00398     MKIT(3, 3, -1, -1),
00399     MKIT(7, 3, -3, -1),
00400     MKIT(3, 3, -1, -1),
00401     MKIT(3, 7, -1, -3),
00402     MKIT(3, 3, -1, -1),
00403     MKIT(7, 3, -3, -1),
00404   };
00405 #undef MKIT
00406 
00407   uint32 x = _delta_xy_table[direction];
00408   this->x_offs        = GB(x,  0, 8);
00409   this->y_offs        = GB(x,  8, 8);
00410   this->x_extent      = GB(x, 16, 8);
00411   this->y_extent      = GB(x, 24, 8);
00412   this->z_extent      = 6;
00413 }
00414 
00419 FORCEINLINE int RoadVehicle::GetCurrentMaxSpeed() const
00420 {
00421   if (_settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) return this->vcache.cached_max_speed;
00422 
00423   int max_speed = this->vcache.cached_max_speed;
00424 
00425   /* Limit speed to 50% while reversing, 75% in curves. */
00426   for (const RoadVehicle *u = this; u != NULL; u = u->Next()) {
00427     if (this->state <= RVSB_TRACKDIR_MASK && IsReversingRoadTrackdir((Trackdir)this->state)) {
00428       max_speed = this->vcache.cached_max_speed / 2;
00429       break;
00430     } else if ((u->direction & 1) == 0) {
00431       max_speed = this->vcache.cached_max_speed * 3 / 4;
00432     }
00433   }
00434 
00435   return max_speed;
00436 }
00437 
00442 static void DeleteLastRoadVeh(RoadVehicle *v)
00443 {
00444   Vehicle *u = v;
00445   for (; v->Next() != NULL; v = v->Next()) u = v;
00446   u->SetNext(NULL);
00447 
00448   /* Only leave the road stop when we're really gone. */
00449   if (IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END)) RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile))->Leave(v);
00450 
00451   delete v;
00452 }
00453 
00454 static void RoadVehSetRandomDirection(RoadVehicle *v)
00455 {
00456   static const DirDiff delta[] = {
00457     DIRDIFF_45LEFT, DIRDIFF_SAME, DIRDIFF_SAME, DIRDIFF_45RIGHT
00458   };
00459 
00460   do {
00461     uint32 r = Random();
00462 
00463     v->direction = ChangeDir(v->direction, delta[r & 3]);
00464     v->UpdateViewport(true, true);
00465   } while ((v = v->Next()) != NULL);
00466 }
00467 
00473 static bool RoadVehIsCrashed(RoadVehicle *v)
00474 {
00475   v->crashed_ctr++;
00476   if (v->crashed_ctr == 2) {
00477     CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
00478   } else if (v->crashed_ctr <= 45) {
00479     if ((v->tick_counter & 7) == 0) RoadVehSetRandomDirection(v);
00480   } else if (v->crashed_ctr >= 2220 && !(v->tick_counter & 0x1F)) {
00481     bool ret = v->Next() != NULL;
00482     DeleteLastRoadVeh(v);
00483     return ret;
00484   }
00485 
00486   return true;
00487 }
00488 
00495 static Vehicle *EnumCheckRoadVehCrashTrain(Vehicle *v, void *data)
00496 {
00497   const Vehicle *u = (Vehicle*)data;
00498 
00499   return (v->type == VEH_TRAIN &&
00500       abs(v->z_pos - u->z_pos) <= 6 &&
00501       abs(v->x_pos - u->x_pos) <= 4 &&
00502       abs(v->y_pos - u->y_pos) <= 4) ? v : NULL;
00503 }
00504 
00505 uint RoadVehicle::Crash(bool flooded)
00506 {
00507   uint pass = this->GroundVehicleBase::Crash(flooded);
00508   if (this->IsFrontEngine()) {
00509     pass += 1; // driver
00510 
00511     /* If we're in a drive through road stop we ought to leave it */
00512     if (IsInsideMM(this->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END)) {
00513       RoadStop::GetByTile(this->tile, GetRoadStopType(this->tile))->Leave(this);
00514     }
00515   }
00516   this->crashed_ctr = flooded ? 2000 : 1; // max 2220, disappear pretty fast when flooded
00517   return pass;
00518 }
00519 
00520 static void RoadVehCrash(RoadVehicle *v)
00521 {
00522   uint pass = v->Crash();
00523 
00524   AI::NewEvent(v->owner, new ScriptEventVehicleCrashed(v->index, v->tile, ScriptEventVehicleCrashed::CRASH_RV_LEVEL_CROSSING));
00525 
00526   SetDParam(0, pass);
00527   AddVehicleNewsItem(
00528     (pass == 1) ?
00529       STR_NEWS_ROAD_VEHICLE_CRASH_DRIVER : STR_NEWS_ROAD_VEHICLE_CRASH,
00530     NS_ACCIDENT,
00531     v->index
00532   );
00533 
00534   ModifyStationRatingAround(v->tile, v->owner, -160, 22);
00535   SndPlayVehicleFx(SND_12_EXPLOSION, v);
00536 }
00537 
00538 static bool RoadVehCheckTrainCrash(RoadVehicle *v)
00539 {
00540   for (RoadVehicle *u = v; u != NULL; u = u->Next()) {
00541     if (u->state == RVSB_WORMHOLE) continue;
00542 
00543     TileIndex tile = u->tile;
00544 
00545     if (!IsLevelCrossingTile(tile)) continue;
00546 
00547     if (HasVehicleOnPosXY(v->x_pos, v->y_pos, u, EnumCheckRoadVehCrashTrain)) {
00548       RoadVehCrash(v);
00549       return true;
00550     }
00551   }
00552 
00553   return false;
00554 }
00555 
00556 TileIndex RoadVehicle::GetOrderStationLocation(StationID station)
00557 {
00558   if (station == this->last_station_visited) this->last_station_visited = INVALID_STATION;
00559 
00560   const Station *st = Station::Get(station);
00561   if (!CanVehicleUseStation(this, st)) {
00562     /* There is no stop left at the station, so don't even TRY to go there */
00563     this->IncrementRealOrderIndex();
00564     return 0;
00565   }
00566 
00567   return st->xy;
00568 }
00569 
00570 static void StartRoadVehSound(const RoadVehicle *v)
00571 {
00572   if (!PlayVehicleSound(v, VSE_START)) {
00573     SoundID s = RoadVehInfo(v->engine_type)->sfx;
00574     if (s == SND_19_BUS_START_PULL_AWAY && (v->tick_counter & 3) == 0) {
00575       s = SND_1A_BUS_START_PULL_AWAY_WITH_HORN;
00576     }
00577     SndPlayVehicleFx(s, v);
00578   }
00579 }
00580 
00581 struct RoadVehFindData {
00582   int x;
00583   int y;
00584   const Vehicle *veh;
00585   Vehicle *best;
00586   uint best_diff;
00587   Direction dir;
00588 };
00589 
00590 static Vehicle *EnumCheckRoadVehClose(Vehicle *v, void *data)
00591 {
00592   static const int8 dist_x[] = { -4, -8, -4, -1, 4, 8, 4, 1 };
00593   static const int8 dist_y[] = { -4, -1, 4, 8, 4, 1, -4, -8 };
00594 
00595   RoadVehFindData *rvf = (RoadVehFindData*)data;
00596 
00597   short x_diff = v->x_pos - rvf->x;
00598   short y_diff = v->y_pos - rvf->y;
00599 
00600   if (v->type == VEH_ROAD &&
00601       !v->IsInDepot() &&
00602       abs(v->z_pos - rvf->veh->z_pos) < 6 &&
00603       v->direction == rvf->dir &&
00604       rvf->veh->First() != v->First() &&
00605       (dist_x[v->direction] >= 0 || (x_diff > dist_x[v->direction] && x_diff <= 0)) &&
00606       (dist_x[v->direction] <= 0 || (x_diff < dist_x[v->direction] && x_diff >= 0)) &&
00607       (dist_y[v->direction] >= 0 || (y_diff > dist_y[v->direction] && y_diff <= 0)) &&
00608       (dist_y[v->direction] <= 0 || (y_diff < dist_y[v->direction] && y_diff >= 0))) {
00609     uint diff = abs(x_diff) + abs(y_diff);
00610 
00611     if (diff < rvf->best_diff || (diff == rvf->best_diff && v->index < rvf->best->index)) {
00612       rvf->best = v;
00613       rvf->best_diff = diff;
00614     }
00615   }
00616 
00617   return NULL;
00618 }
00619 
00620 static RoadVehicle *RoadVehFindCloseTo(RoadVehicle *v, int x, int y, Direction dir, bool update_blocked_ctr = true)
00621 {
00622   RoadVehFindData rvf;
00623   RoadVehicle *front = v->First();
00624 
00625   if (front->reverse_ctr != 0) return NULL;
00626 
00627   rvf.x = x;
00628   rvf.y = y;
00629   rvf.dir = dir;
00630   rvf.veh = v;
00631   rvf.best_diff = UINT_MAX;
00632 
00633   if (front->state == RVSB_WORMHOLE) {
00634     FindVehicleOnPos(v->tile, &rvf, EnumCheckRoadVehClose);
00635     FindVehicleOnPos(GetOtherTunnelBridgeEnd(v->tile), &rvf, EnumCheckRoadVehClose);
00636   } else {
00637     FindVehicleOnPosXY(x, y, &rvf, EnumCheckRoadVehClose);
00638   }
00639 
00640   /* This code protects a roadvehicle from being blocked for ever
00641    * If more than 1480 / 74 days a road vehicle is blocked, it will
00642    * drive just through it. The ultimate backup-code of TTD.
00643    * It can be disabled. */
00644   if (rvf.best_diff == UINT_MAX) {
00645     front->blocked_ctr = 0;
00646     return NULL;
00647   }
00648 
00649   if (update_blocked_ctr && ++front->blocked_ctr > 1480) return NULL;
00650 
00651   return RoadVehicle::From(rvf.best);
00652 }
00653 
00659 static void RoadVehArrivesAt(const RoadVehicle *v, Station *st)
00660 {
00661   if (v->IsBus()) {
00662     /* Check if station was ever visited before */
00663     if (!(st->had_vehicle_of_type & HVOT_BUS)) {
00664       st->had_vehicle_of_type |= HVOT_BUS;
00665       SetDParam(0, st->index);
00666       AddVehicleNewsItem(
00667         v->roadtype == ROADTYPE_ROAD ? STR_NEWS_FIRST_BUS_ARRIVAL : STR_NEWS_FIRST_PASSENGER_TRAM_ARRIVAL,
00668         (v->owner == _local_company) ? NS_ARRIVAL_COMPANY : NS_ARRIVAL_OTHER,
00669         v->index,
00670         st->index
00671       );
00672       AI::NewEvent(v->owner, new ScriptEventStationFirstVehicle(st->index, v->index));
00673     }
00674   } else {
00675     /* Check if station was ever visited before */
00676     if (!(st->had_vehicle_of_type & HVOT_TRUCK)) {
00677       st->had_vehicle_of_type |= HVOT_TRUCK;
00678       SetDParam(0, st->index);
00679       AddVehicleNewsItem(
00680         v->roadtype == ROADTYPE_ROAD ? STR_NEWS_FIRST_TRUCK_ARRIVAL : STR_NEWS_FIRST_CARGO_TRAM_ARRIVAL,
00681         (v->owner == _local_company) ? NS_ARRIVAL_COMPANY : NS_ARRIVAL_OTHER,
00682         v->index,
00683         st->index
00684       );
00685       AI::NewEvent(v->owner, new ScriptEventStationFirstVehicle(st->index, v->index));
00686     }
00687   }
00688 }
00689 
00697 int RoadVehicle::UpdateSpeed()
00698 {
00699   switch (_settings_game.vehicle.roadveh_acceleration_model) {
00700     default: NOT_REACHED();
00701     case AM_ORIGINAL:
00702       return this->DoUpdateSpeed(this->overtaking != 0 ? 512 : 256, 0, this->GetCurrentMaxSpeed());
00703 
00704     case AM_REALISTIC:
00705       return this->DoUpdateSpeed(this->GetAcceleration() + (this->overtaking != 0 ? 256 : 0), this->GetAccelerationStatus() == AS_BRAKE ? 0 : 4, this->GetCurrentMaxSpeed());
00706   }
00707 }
00708 
00709 static Direction RoadVehGetNewDirection(const RoadVehicle *v, int x, int y)
00710 {
00711   static const Direction _roadveh_new_dir[] = {
00712     DIR_N , DIR_NW, DIR_W , INVALID_DIR,
00713     DIR_NE, DIR_N , DIR_SW, INVALID_DIR,
00714     DIR_E , DIR_SE, DIR_S
00715   };
00716 
00717   x = x - v->x_pos + 1;
00718   y = y - v->y_pos + 1;
00719 
00720   if ((uint)x > 2 || (uint)y > 2) return v->direction;
00721   return _roadveh_new_dir[y * 4 + x];
00722 }
00723 
00724 static Direction RoadVehGetSlidingDirection(const RoadVehicle *v, int x, int y)
00725 {
00726   Direction new_dir = RoadVehGetNewDirection(v, x, y);
00727   Direction old_dir = v->direction;
00728   DirDiff delta;
00729 
00730   if (new_dir == old_dir) return old_dir;
00731   delta = (DirDifference(new_dir, old_dir) > DIRDIFF_REVERSE ? DIRDIFF_45LEFT : DIRDIFF_45RIGHT);
00732   return ChangeDir(old_dir, delta);
00733 }
00734 
00735 struct OvertakeData {
00736   const RoadVehicle *u;
00737   const RoadVehicle *v;
00738   TileIndex tile;
00739   Trackdir trackdir;
00740 };
00741 
00742 static Vehicle *EnumFindVehBlockingOvertake(Vehicle *v, void *data)
00743 {
00744   const OvertakeData *od = (OvertakeData*)data;
00745 
00746   return (v->type == VEH_ROAD && v->First() == v && v != od->u && v != od->v) ? v : NULL;
00747 }
00748 
00755 static bool CheckRoadBlockedForOvertaking(OvertakeData *od)
00756 {
00757   TrackStatus ts = GetTileTrackStatus(od->tile, TRANSPORT_ROAD, od->v->compatible_roadtypes);
00758   TrackdirBits trackdirbits = TrackStatusToTrackdirBits(ts);
00759   TrackdirBits red_signals = TrackStatusToRedSignals(ts); // barred level crossing
00760   TrackBits trackbits = TrackdirBitsToTrackBits(trackdirbits);
00761 
00762   /* Track does not continue along overtaking direction || track has junction || levelcrossing is barred */
00763   if (!HasBit(trackdirbits, od->trackdir) || (trackbits & ~TRACK_BIT_CROSS) || (red_signals != TRACKDIR_BIT_NONE)) return true;
00764 
00765   /* Are there more vehicles on the tile except the two vehicles involved in overtaking */
00766   return HasVehicleOnPos(od->tile, od, EnumFindVehBlockingOvertake);
00767 }
00768 
00769 static void RoadVehCheckOvertake(RoadVehicle *v, RoadVehicle *u)
00770 {
00771   OvertakeData od;
00772 
00773   od.v = v;
00774   od.u = u;
00775 
00776   if (u->vcache.cached_max_speed >= v->vcache.cached_max_speed &&
00777       !(u->vehstatus & VS_STOPPED) &&
00778       u->cur_speed != 0) {
00779     return;
00780   }
00781 
00782   /* Trams can't overtake other trams */
00783   if (v->roadtype == ROADTYPE_TRAM) return;
00784 
00785   /* Don't overtake in stations */
00786   if (IsTileType(v->tile, MP_STATION) || IsTileType(u->tile, MP_STATION)) return;
00787 
00788   /* For now, articulated road vehicles can't overtake anything. */
00789   if (v->HasArticulatedPart()) return;
00790 
00791   /* Vehicles are not driving in same direction || direction is not a diagonal direction */
00792   if (v->direction != u->direction || !(v->direction & 1)) return;
00793 
00794   /* Check if vehicle is in a road stop, depot, tunnel or bridge or not on a straight road */
00795   if (v->state >= RVSB_IN_ROAD_STOP || !IsStraightRoadTrackdir((Trackdir)(v->state & RVSB_TRACKDIR_MASK))) return;
00796 
00797   od.trackdir = DiagDirToDiagTrackdir(DirToDiagDir(v->direction));
00798 
00799   /* Are the current and the next tile suitable for overtaking?
00800    *  - Does the track continue along od.trackdir
00801    *  - No junctions
00802    *  - No barred levelcrossing
00803    *  - No other vehicles in the way
00804    */
00805   od.tile = v->tile;
00806   if (CheckRoadBlockedForOvertaking(&od)) return;
00807 
00808   od.tile = v->tile + TileOffsByDiagDir(DirToDiagDir(v->direction));
00809   if (CheckRoadBlockedForOvertaking(&od)) return;
00810 
00811   /* When the vehicle in front of us is stopped we may only take
00812    * half the time to pass it than when the vehicle is moving. */
00813   v->overtaking_ctr = (od.u->cur_speed == 0 || (od.u->vehstatus & VS_STOPPED)) ? RV_OVERTAKE_TIMEOUT / 2 : 0;
00814   v->overtaking = RVSB_DRIVE_SIDE;
00815 }
00816 
00817 static void RoadZPosAffectSpeed(RoadVehicle *v, byte old_z)
00818 {
00819   if (old_z == v->z_pos || _settings_game.vehicle.roadveh_acceleration_model != AM_ORIGINAL) return;
00820 
00821   if (old_z < v->z_pos) {
00822     v->cur_speed = v->cur_speed * 232 / 256; // slow down by ~10%
00823   } else {
00824     uint16 spd = v->cur_speed + 2;
00825     if (spd <= v->vcache.cached_max_speed) v->cur_speed = spd;
00826   }
00827 }
00828 
00829 static int PickRandomBit(uint bits)
00830 {
00831   uint i;
00832   uint num = RandomRange(CountBits(bits));
00833 
00834   for (i = 0; !(bits & 1) || (int)--num >= 0; bits >>= 1, i++) {}
00835   return i;
00836 }
00837 
00846 static Trackdir RoadFindPathToDest(RoadVehicle *v, TileIndex tile, DiagDirection enterdir)
00847 {
00848 #define return_track(x) { best_track = (Trackdir)x; goto found_best_track; }
00849 
00850   TileIndex desttile;
00851   Trackdir best_track;
00852   bool path_found = true;
00853 
00854   TrackStatus ts = GetTileTrackStatus(tile, TRANSPORT_ROAD, v->compatible_roadtypes);
00855   TrackdirBits red_signals = TrackStatusToRedSignals(ts); // crossing
00856   TrackdirBits trackdirs = TrackStatusToTrackdirBits(ts);
00857 
00858   if (IsTileType(tile, MP_ROAD)) {
00859     if (IsRoadDepot(tile) && (!IsTileOwner(tile, v->owner) || GetRoadDepotDirection(tile) == enterdir || (GetRoadTypes(tile) & v->compatible_roadtypes) == 0)) {
00860       /* Road depot owned by another company or with the wrong orientation */
00861       trackdirs = TRACKDIR_BIT_NONE;
00862     }
00863   } else if (IsTileType(tile, MP_STATION) && IsStandardRoadStopTile(tile)) {
00864     /* Standard road stop (drive-through stops are treated as normal road) */
00865 
00866     if (!IsTileOwner(tile, v->owner) || GetRoadStopDir(tile) == enterdir || v->HasArticulatedPart()) {
00867       /* different station owner or wrong orientation or the vehicle has articulated parts */
00868       trackdirs = TRACKDIR_BIT_NONE;
00869     } else {
00870       /* Our station */
00871       RoadStopType rstype = v->IsBus() ? ROADSTOP_BUS : ROADSTOP_TRUCK;
00872 
00873       if (GetRoadStopType(tile) != rstype) {
00874         /* Wrong station type */
00875         trackdirs = TRACKDIR_BIT_NONE;
00876       } else {
00877         /* Proper station type, check if there is free loading bay */
00878         if (!_settings_game.pf.roadveh_queue && IsStandardRoadStopTile(tile) &&
00879             !RoadStop::GetByTile(tile, rstype)->HasFreeBay()) {
00880           /* Station is full and RV queuing is off */
00881           trackdirs = TRACKDIR_BIT_NONE;
00882         }
00883       }
00884     }
00885   }
00886   /* The above lookups should be moved to GetTileTrackStatus in the
00887    * future, but that requires more changes to the pathfinder and other
00888    * stuff, probably even more arguments to GTTS.
00889    */
00890 
00891   /* Remove tracks unreachable from the enter dir */
00892   trackdirs &= _road_enter_dir_to_reachable_trackdirs[enterdir];
00893   if (trackdirs == TRACKDIR_BIT_NONE) {
00894     /* No reachable tracks, so we'll reverse */
00895     return_track(_road_reverse_table[enterdir]);
00896   }
00897 
00898   if (v->reverse_ctr != 0) {
00899     bool reverse = true;
00900     if (v->roadtype == ROADTYPE_TRAM) {
00901       /* Trams may only reverse on a tile if it contains at least the straight
00902        * trackbits or when it is a valid turning tile (i.e. one roadbit) */
00903       RoadBits rb = GetAnyRoadBits(tile, ROADTYPE_TRAM);
00904       RoadBits straight = AxisToRoadBits(DiagDirToAxis(enterdir));
00905       reverse = ((rb & straight) == straight) ||
00906                 (rb == DiagDirToRoadBits(enterdir));
00907     }
00908     if (reverse) {
00909       v->reverse_ctr = 0;
00910       if (v->tile != tile) {
00911         return_track(_road_reverse_table[enterdir]);
00912       }
00913     }
00914   }
00915 
00916   desttile = v->dest_tile;
00917   if (desttile == 0) {
00918     /* We've got no destination, pick a random track */
00919     return_track(PickRandomBit(trackdirs));
00920   }
00921 
00922   /* Only one track to choose between? */
00923   if (KillFirstBit(trackdirs) == TRACKDIR_BIT_NONE) {
00924     return_track(FindFirstBit2x64(trackdirs));
00925   }
00926 
00927   switch (_settings_game.pf.pathfinder_for_roadvehs) {
00928     case VPF_NPF:  best_track = NPFRoadVehicleChooseTrack(v, tile, enterdir, trackdirs, path_found); break;
00929     case VPF_YAPF: best_track = YapfRoadVehicleChooseTrack(v, tile, enterdir, trackdirs, path_found); break;
00930 
00931     default: NOT_REACHED();
00932   }
00933   v->HandlePathfindingResult(path_found);
00934 
00935 found_best_track:;
00936 
00937   if (HasBit(red_signals, best_track)) return INVALID_TRACKDIR;
00938 
00939   return best_track;
00940 }
00941 
00942 struct RoadDriveEntry {
00943   byte x, y;
00944 };
00945 
00946 #include "table/roadveh_movement.h"
00947 
00948 static bool RoadVehLeaveDepot(RoadVehicle *v, bool first)
00949 {
00950   /* Don't leave if not all the wagons are in the depot. */
00951   for (const RoadVehicle *u = v; u != NULL; u = u->Next()) {
00952     if (u->state != RVSB_IN_DEPOT || u->tile != v->tile) return false;
00953   }
00954 
00955   DiagDirection dir = GetRoadDepotDirection(v->tile);
00956   v->direction = DiagDirToDir(dir);
00957 
00958   Trackdir tdir = _roadveh_depot_exit_trackdir[dir];
00959   const RoadDriveEntry *rdp = _road_drive_data[v->roadtype][(_settings_game.vehicle.road_side << RVS_DRIVE_SIDE) + tdir];
00960 
00961   int x = TileX(v->tile) * TILE_SIZE + (rdp[RVC_DEPOT_START_FRAME].x & 0xF);
00962   int y = TileY(v->tile) * TILE_SIZE + (rdp[RVC_DEPOT_START_FRAME].y & 0xF);
00963 
00964   if (first) {
00965     /* We are leaving a depot, but have to go to the exact same one; re-enter */
00966     if (v->current_order.IsType(OT_GOTO_DEPOT) && v->tile == v->dest_tile) {
00967       VehicleEnterDepot(v);
00968       return true;
00969     }
00970 
00971     if (RoadVehFindCloseTo(v, x, y, v->direction, false) != NULL) return true;
00972 
00973     VehicleServiceInDepot(v);
00974 
00975     StartRoadVehSound(v);
00976 
00977     /* Vehicle is about to leave a depot */
00978     v->cur_speed = 0;
00979   }
00980 
00981   v->vehstatus &= ~VS_HIDDEN;
00982   v->state = tdir;
00983   v->frame = RVC_DEPOT_START_FRAME;
00984 
00985   v->x_pos = x;
00986   v->y_pos = y;
00987   v->UpdateInclination(true, true);
00988 
00989   InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
00990 
00991   return true;
00992 }
00993 
00994 static Trackdir FollowPreviousRoadVehicle(const RoadVehicle *v, const RoadVehicle *prev, TileIndex tile, DiagDirection entry_dir, bool already_reversed)
00995 {
00996   if (prev->tile == v->tile && !already_reversed) {
00997     /* If the previous vehicle is on the same tile as this vehicle is
00998      * then it must have reversed. */
00999     return _road_reverse_table[entry_dir];
01000   }
01001 
01002   byte prev_state = prev->state;
01003   Trackdir dir;
01004 
01005   if (prev_state == RVSB_WORMHOLE || prev_state == RVSB_IN_DEPOT) {
01006     DiagDirection diag_dir = INVALID_DIAGDIR;
01007 
01008     if (IsTileType(tile, MP_TUNNELBRIDGE)) {
01009       diag_dir = GetTunnelBridgeDirection(tile);
01010     } else if (IsRoadDepotTile(tile)) {
01011       diag_dir = ReverseDiagDir(GetRoadDepotDirection(tile));
01012     }
01013 
01014     if (diag_dir == INVALID_DIAGDIR) return INVALID_TRACKDIR;
01015     dir = DiagDirToDiagTrackdir(diag_dir);
01016   } else {
01017     if (already_reversed && prev->tile != tile) {
01018       /*
01019        * The vehicle has reversed, but did not go straight back.
01020        * It immediately turn onto another tile. This means that
01021        * the roadstate of the previous vehicle cannot be used
01022        * as the direction we have to go with this vehicle.
01023        *
01024        * Next table is build in the following way:
01025        *  - first row for when the vehicle in front went to the northern or
01026        *    western tile, second for southern and eastern.
01027        *  - columns represent the entry direction.
01028        *  - cell values are determined by the Trackdir one has to take from
01029        *    the entry dir (column) to the tile in north or south by only
01030        *    going over the trackdirs used for turning 90 degrees, i.e.
01031        *    TRACKDIR_{UPPER,RIGHT,LOWER,LEFT}_{N,E,S,W}.
01032        */
01033       static const Trackdir reversed_turn_lookup[2][DIAGDIR_END] = {
01034         { TRACKDIR_UPPER_W, TRACKDIR_RIGHT_N, TRACKDIR_LEFT_N,  TRACKDIR_UPPER_E },
01035         { TRACKDIR_RIGHT_S, TRACKDIR_LOWER_W, TRACKDIR_LOWER_E, TRACKDIR_LEFT_S  }};
01036       dir = reversed_turn_lookup[prev->tile < tile ? 0 : 1][ReverseDiagDir(entry_dir)];
01037     } else if (HasBit(prev_state, RVS_IN_DT_ROAD_STOP)) {
01038       dir = (Trackdir)(prev_state & RVSB_ROAD_STOP_TRACKDIR_MASK);
01039     } else if (prev_state < TRACKDIR_END) {
01040       dir = (Trackdir)prev_state;
01041     } else {
01042       return INVALID_TRACKDIR;
01043     }
01044   }
01045 
01046   /* Do some sanity checking. */
01047   static const RoadBits required_roadbits[] = {
01048     ROAD_X,            ROAD_Y,            ROAD_NW | ROAD_NE, ROAD_SW | ROAD_SE,
01049     ROAD_NW | ROAD_SW, ROAD_NE | ROAD_SE, ROAD_X,            ROAD_Y
01050   };
01051   RoadBits required = required_roadbits[dir & 0x07];
01052 
01053   if ((required & GetAnyRoadBits(tile, v->roadtype, true)) == ROAD_NONE) {
01054     dir = INVALID_TRACKDIR;
01055   }
01056 
01057   return dir;
01058 }
01059 
01067 static bool CanBuildTramTrackOnTile(CompanyID c, TileIndex t, RoadBits r)
01068 {
01069   /* The 'current' company is not necessarily the owner of the vehicle. */
01070   Backup<CompanyByte> cur_company(_current_company, c, FILE_LINE);
01071 
01072   CommandCost ret = DoCommand(t, ROADTYPE_TRAM << 4 | r, 0, DC_NONE, CMD_BUILD_ROAD);
01073 
01074   cur_company.Restore();
01075   return ret.Succeeded();
01076 }
01077 
01078 static bool IndividualRoadVehicleController(RoadVehicle *v, const RoadVehicle *prev)
01079 {
01080   if (v->overtaking != 0)  {
01081     if (IsTileType(v->tile, MP_STATION)) {
01082       /* Force us to be not overtaking! */
01083       v->overtaking = 0;
01084     } else if (++v->overtaking_ctr >= RV_OVERTAKE_TIMEOUT) {
01085       /* If overtaking just aborts at a random moment, we can have a out-of-bound problem,
01086        *  if the vehicle started a corner. To protect that, only allow an abort of
01087        *  overtake if we are on straight roads */
01088       if (v->state < RVSB_IN_ROAD_STOP && IsStraightRoadTrackdir((Trackdir)v->state)) {
01089         v->overtaking = 0;
01090       }
01091     }
01092   }
01093 
01094   /* If this vehicle is in a depot and we've reached this point it must be
01095    * one of the articulated parts. It will stay in the depot until activated
01096    * by the previous vehicle in the chain when it gets to the right place. */
01097   if (v->IsInDepot()) return true;
01098 
01099   if (v->state == RVSB_WORMHOLE) {
01100     /* Vehicle is entering a depot or is on a bridge or in a tunnel */
01101     GetNewVehiclePosResult gp = GetNewVehiclePos(v);
01102 
01103     /* Apply bridge speed limit */
01104     if (!(v->vehstatus & VS_HIDDEN)) {
01105       RoadVehicle *first = v->First();
01106       first->cur_speed = min(first->cur_speed, GetBridgeSpec(GetBridgeType(v->tile))->speed * 2);
01107     }
01108 
01109     if (v->IsFrontEngine()) {
01110       const Vehicle *u = RoadVehFindCloseTo(v, gp.x, gp.y, v->direction);
01111       if (u != NULL) {
01112         v->cur_speed = u->First()->cur_speed;
01113         return false;
01114       }
01115     }
01116 
01117     if (IsTileType(gp.new_tile, MP_TUNNELBRIDGE) && HasBit(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y), VETS_ENTERED_WORMHOLE)) {
01118       /* Vehicle has just entered a bridge or tunnel */
01119       v->x_pos = gp.x;
01120       v->y_pos = gp.y;
01121       v->UpdateInclination(true, true);
01122       return true;
01123     }
01124 
01125     v->x_pos = gp.x;
01126     v->y_pos = gp.y;
01127     VehicleMove(v, !(v->vehstatus & VS_HIDDEN));
01128     return true;
01129   }
01130 
01131   /* Get move position data for next frame.
01132    * For a drive-through road stop use 'straight road' move data.
01133    * In this case v->state is masked to give the road stop entry direction. */
01134   RoadDriveEntry rd = _road_drive_data[v->roadtype][(
01135     (HasBit(v->state, RVS_IN_DT_ROAD_STOP) ? v->state & RVSB_ROAD_STOP_TRACKDIR_MASK : v->state) +
01136     (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)) ^ v->overtaking][v->frame + 1];
01137 
01138   if (rd.x & RDE_NEXT_TILE) {
01139     TileIndex tile = v->tile + TileOffsByDiagDir((DiagDirection)(rd.x & 3));
01140     Trackdir dir;
01141 
01142     if (v->IsFrontEngine()) {
01143       /* If this is the front engine, look for the right path. */
01144       dir = RoadFindPathToDest(v, tile, (DiagDirection)(rd.x & 3));
01145     } else {
01146       dir = FollowPreviousRoadVehicle(v, prev, tile, (DiagDirection)(rd.x & 3), false);
01147     }
01148 
01149     if (dir == INVALID_TRACKDIR) {
01150       if (!v->IsFrontEngine()) error("Disconnecting road vehicle.");
01151       v->cur_speed = 0;
01152       return false;
01153     }
01154 
01155 again:
01156     uint start_frame = RVC_DEFAULT_START_FRAME;
01157     if (IsReversingRoadTrackdir(dir)) {
01158       /* When turning around we can't be overtaking. */
01159       v->overtaking = 0;
01160 
01161       /* Turning around */
01162       if (v->roadtype == ROADTYPE_TRAM) {
01163         /* Determine the road bits the tram needs to be able to turn around
01164          * using the 'big' corner loop. */
01165         RoadBits needed;
01166         switch (dir) {
01167           default: NOT_REACHED();
01168           case TRACKDIR_RVREV_NE: needed = ROAD_SW; break;
01169           case TRACKDIR_RVREV_SE: needed = ROAD_NW; break;
01170           case TRACKDIR_RVREV_SW: needed = ROAD_NE; break;
01171           case TRACKDIR_RVREV_NW: needed = ROAD_SE; break;
01172         }
01173         if ((v->Previous() != NULL && v->Previous()->tile == tile) ||
01174             (v->IsFrontEngine() && IsNormalRoadTile(tile) && !HasRoadWorks(tile) &&
01175               (needed & GetRoadBits(tile, ROADTYPE_TRAM)) != ROAD_NONE)) {
01176           /*
01177            * Taking the 'big' corner for trams only happens when:
01178            * - The previous vehicle in this (articulated) tram chain is
01179            *   already on the 'next' tile, we just follow them regardless of
01180            *   anything. When it is NOT on the 'next' tile, the tram started
01181            *   doing a reversing turn when the piece of tram track on the next
01182            *   tile did not exist yet. Do not use the big tram loop as that is
01183            *   going to cause the tram to split up.
01184            * - Or the front of the tram can drive over the next tile.
01185            */
01186         } else if (!v->IsFrontEngine() || !CanBuildTramTrackOnTile(v->owner, tile, needed) || ((~needed & GetAnyRoadBits(v->tile, ROADTYPE_TRAM, false)) == ROAD_NONE)) {
01187           /*
01188            * Taking the 'small' corner for trams only happens when:
01189            * - We are not the from vehicle of an articulated tram.
01190            * - Or when the company cannot build on the next tile.
01191            *
01192            * The 'small' corner means that the vehicle is on the end of a
01193            * tram track and needs to start turning there. To do this properly
01194            * the tram needs to start at an offset in the tram turning 'code'
01195            * for 'big' corners. It furthermore does not go to the next tile,
01196            * so that needs to be fixed too.
01197            */
01198           tile = v->tile;
01199           start_frame = RVC_TURN_AROUND_START_FRAME_SHORT_TRAM;
01200         } else {
01201           /* The company can build on the next tile, so wait till (s)he does. */
01202           v->cur_speed = 0;
01203           return false;
01204         }
01205       } else if (IsNormalRoadTile(v->tile) && GetDisallowedRoadDirections(v->tile) != DRD_NONE) {
01206         v->cur_speed = 0;
01207         return false;
01208       } else {
01209         tile = v->tile;
01210       }
01211     }
01212 
01213     /* Get position data for first frame on the new tile */
01214     const RoadDriveEntry *rdp = _road_drive_data[v->roadtype][(dir + (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)) ^ v->overtaking];
01215 
01216     int x = TileX(tile) * TILE_SIZE + rdp[start_frame].x;
01217     int y = TileY(tile) * TILE_SIZE + rdp[start_frame].y;
01218 
01219     Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
01220     if (v->IsFrontEngine()) {
01221       Vehicle *u = RoadVehFindCloseTo(v, x, y, new_dir);
01222       if (u != NULL) {
01223         v->cur_speed = u->First()->cur_speed;
01224         return false;
01225       }
01226     }
01227 
01228     uint32 r = VehicleEnterTile(v, tile, x, y);
01229     if (HasBit(r, VETS_CANNOT_ENTER)) {
01230       if (!IsTileType(tile, MP_TUNNELBRIDGE)) {
01231         v->cur_speed = 0;
01232         return false;
01233       }
01234       /* Try an about turn to re-enter the previous tile */
01235       dir = _road_reverse_table[rd.x & 3];
01236       goto again;
01237     }
01238 
01239     if (IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) && IsTileType(v->tile, MP_STATION)) {
01240       if (IsReversingRoadTrackdir(dir) && IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END)) {
01241         /* New direction is trying to turn vehicle around.
01242          * We can't turn at the exit of a road stop so wait.*/
01243         v->cur_speed = 0;
01244         return false;
01245       }
01246 
01247       /* If we are a drive through road stop and the next tile is of
01248        * the same road stop and the next tile isn't this one (i.e. we
01249        * are not reversing), then keep the reservation and state.
01250        * This way we will not be shortly unregister from the road
01251        * stop. It also makes it possible to load when on the edge of
01252        * two road stops; otherwise you could get vehicles that should
01253        * be loading but are not actually loading. */
01254       if (IsDriveThroughStopTile(v->tile) &&
01255           RoadStop::IsDriveThroughRoadStopContinuation(v->tile, tile) &&
01256           v->tile != tile) {
01257         /* So, keep 'our' state */
01258         dir = (Trackdir)v->state;
01259       } else if (IsRoadStop(v->tile)) {
01260         /* We're not continuing our drive through road stop, so leave. */
01261         RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile))->Leave(v);
01262       }
01263     }
01264 
01265     if (!HasBit(r, VETS_ENTERED_WORMHOLE)) {
01266       v->tile = tile;
01267       v->state = (byte)dir;
01268       v->frame = start_frame;
01269     }
01270     if (new_dir != v->direction) {
01271       v->direction = new_dir;
01272       if (_settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) v->cur_speed -= v->cur_speed >> 2;
01273     }
01274     v->x_pos = x;
01275     v->y_pos = y;
01276     RoadZPosAffectSpeed(v, v->UpdateInclination(true, true));
01277     return true;
01278   }
01279 
01280   if (rd.x & RDE_TURNED) {
01281     /* Vehicle has finished turning around, it will now head back onto the same tile */
01282     Trackdir dir;
01283     uint turn_around_start_frame = RVC_TURN_AROUND_START_FRAME;
01284 
01285     if (v->roadtype == ROADTYPE_TRAM && !IsRoadDepotTile(v->tile) && HasExactlyOneBit(GetAnyRoadBits(v->tile, ROADTYPE_TRAM, true))) {
01286       /*
01287        * The tram is turning around with one tram 'roadbit'. This means that
01288        * it is using the 'big' corner 'drive data'. However, to support the
01289        * trams to take a small corner, there is a 'turned' marker in the middle
01290        * of the turning 'drive data'. When the tram took the long corner, we
01291        * will still use the 'big' corner drive data, but we advance it one
01292        * frame. We furthermore set the driving direction so the turning is
01293        * going to be properly shown.
01294        */
01295       turn_around_start_frame = RVC_START_FRAME_AFTER_LONG_TRAM;
01296       switch (rd.x & 0x3) {
01297         default: NOT_REACHED();
01298         case DIAGDIR_NW: dir = TRACKDIR_RVREV_SE; break;
01299         case DIAGDIR_NE: dir = TRACKDIR_RVREV_SW; break;
01300         case DIAGDIR_SE: dir = TRACKDIR_RVREV_NW; break;
01301         case DIAGDIR_SW: dir = TRACKDIR_RVREV_NE; break;
01302       }
01303     } else {
01304       if (v->IsFrontEngine()) {
01305         /* If this is the front engine, look for the right path. */
01306         dir = RoadFindPathToDest(v, v->tile, (DiagDirection)(rd.x & 3));
01307       } else {
01308         dir = FollowPreviousRoadVehicle(v, prev, v->tile, (DiagDirection)(rd.x & 3), true);
01309       }
01310     }
01311 
01312     if (dir == INVALID_TRACKDIR) {
01313       v->cur_speed = 0;
01314       return false;
01315     }
01316 
01317     const RoadDriveEntry *rdp = _road_drive_data[v->roadtype][(_settings_game.vehicle.road_side << RVS_DRIVE_SIDE) + dir];
01318 
01319     int x = TileX(v->tile) * TILE_SIZE + rdp[turn_around_start_frame].x;
01320     int y = TileY(v->tile) * TILE_SIZE + rdp[turn_around_start_frame].y;
01321 
01322     Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
01323     if (v->IsFrontEngine() && RoadVehFindCloseTo(v, x, y, new_dir) != NULL) return false;
01324 
01325     uint32 r = VehicleEnterTile(v, v->tile, x, y);
01326     if (HasBit(r, VETS_CANNOT_ENTER)) {
01327       v->cur_speed = 0;
01328       return false;
01329     }
01330 
01331     v->state = dir;
01332     v->frame = turn_around_start_frame;
01333 
01334     if (new_dir != v->direction) {
01335       v->direction = new_dir;
01336       if (_settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) v->cur_speed -= v->cur_speed >> 2;
01337     }
01338 
01339     v->x_pos = x;
01340     v->y_pos = y;
01341     RoadZPosAffectSpeed(v, v->UpdateInclination(true, true));
01342     return true;
01343   }
01344 
01345   /* This vehicle is not in a wormhole and it hasn't entered a new tile. If
01346    * it's on a depot tile, check if it's time to activate the next vehicle in
01347    * the chain yet. */
01348   if (v->Next() != NULL && IsRoadDepotTile(v->tile)) {
01349     if (v->frame == v->gcache.cached_veh_length + RVC_DEPOT_START_FRAME) {
01350       RoadVehLeaveDepot(v->Next(), false);
01351     }
01352   }
01353 
01354   /* Calculate new position for the vehicle */
01355   int x = (v->x_pos & ~15) + (rd.x & 15);
01356   int y = (v->y_pos & ~15) + (rd.y & 15);
01357 
01358   Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
01359 
01360   if (v->IsFrontEngine() && !IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END)) {
01361     /* Vehicle is not in a road stop.
01362      * Check for another vehicle to overtake */
01363     RoadVehicle *u = RoadVehFindCloseTo(v, x, y, new_dir);
01364 
01365     if (u != NULL) {
01366       u = u->First();
01367       /* There is a vehicle in front overtake it if possible */
01368       if (v->overtaking == 0) RoadVehCheckOvertake(v, u);
01369       if (v->overtaking == 0) v->cur_speed = u->cur_speed;
01370 
01371       /* In case an RV is stopped in a road stop, why not try to load? */
01372       if (v->cur_speed == 0 && IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) &&
01373           v->current_order.ShouldStopAtStation(v, GetStationIndex(v->tile)) &&
01374           v->owner == GetTileOwner(v->tile) && !v->current_order.IsType(OT_LEAVESTATION) &&
01375           GetRoadStopType(v->tile) == (v->IsBus() ? ROADSTOP_BUS : ROADSTOP_TRUCK)) {
01376         Station *st = Station::GetByTile(v->tile);
01377         v->last_station_visited = st->index;
01378         RoadVehArrivesAt(v, st);
01379         v->BeginLoading();
01380       }
01381       return false;
01382     }
01383   }
01384 
01385   Direction old_dir = v->direction;
01386   if (new_dir != old_dir) {
01387     v->direction = new_dir;
01388     if (_settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) v->cur_speed -= v->cur_speed >> 2;
01389     if (old_dir != v->state) {
01390       /* The vehicle is in a road stop */
01391       v->UpdateInclination(false, true);
01392       /* Note, return here means that the frame counter is not incremented
01393        * for vehicles changing direction in a road stop. This causes frames to
01394        * be repeated. (XXX) Is this intended? */
01395       return true;
01396     }
01397   }
01398 
01399   /* If the vehicle is in a normal road stop and the frame equals the stop frame OR
01400    * if the vehicle is in a drive-through road stop and this is the destination station
01401    * and it's the correct type of stop (bus or truck) and the frame equals the stop frame...
01402    * (the station test and stop type test ensure that other vehicles, using the road stop as
01403    * a through route, do not stop) */
01404   if (v->IsFrontEngine() && ((IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END) &&
01405       _road_stop_stop_frame[v->state - RVSB_IN_ROAD_STOP + (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)] == v->frame) ||
01406       (IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) &&
01407       v->current_order.ShouldStopAtStation(v, GetStationIndex(v->tile)) &&
01408       v->owner == GetTileOwner(v->tile) &&
01409       GetRoadStopType(v->tile) == (v->IsBus() ? ROADSTOP_BUS : ROADSTOP_TRUCK) &&
01410       v->frame == RVC_DRIVE_THROUGH_STOP_FRAME))) {
01411 
01412     RoadStop *rs = RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile));
01413     Station *st = Station::GetByTile(v->tile);
01414 
01415     /* Vehicle is at the stop position (at a bay) in a road stop.
01416      * Note, if vehicle is loading/unloading it has already been handled,
01417      * so if we get here the vehicle has just arrived or is just ready to leave. */
01418     if (!HasBit(v->state, RVS_ENTERED_STOP)) {
01419       /* Vehicle has arrived at a bay in a road stop */
01420 
01421       if (IsDriveThroughStopTile(v->tile)) {
01422         TileIndex next_tile = TILE_ADD(v->tile, TileOffsByDir(v->direction));
01423 
01424         /* Check if next inline bay is free and has compatible road. */
01425         if (RoadStop::IsDriveThroughRoadStopContinuation(v->tile, next_tile) && (GetRoadTypes(next_tile) & v->compatible_roadtypes) != 0) {
01426           v->frame++;
01427           v->x_pos = x;
01428           v->y_pos = y;
01429           RoadZPosAffectSpeed(v, v->UpdateInclination(true, false));
01430           return true;
01431         }
01432       }
01433 
01434       rs->SetEntranceBusy(false);
01435       SetBit(v->state, RVS_ENTERED_STOP);
01436 
01437       v->last_station_visited = st->index;
01438 
01439       if (IsDriveThroughStopTile(v->tile) || (v->current_order.IsType(OT_GOTO_STATION) && v->current_order.GetDestination() == st->index)) {
01440         RoadVehArrivesAt(v, st);
01441         v->BeginLoading();
01442         return false;
01443       }
01444     } else {
01445       /* Vehicle is ready to leave a bay in a road stop */
01446       if (rs->IsEntranceBusy()) {
01447         /* Road stop entrance is busy, so wait as there is nowhere else to go */
01448         v->cur_speed = 0;
01449         return false;
01450       }
01451       if (v->current_order.IsType(OT_LEAVESTATION)) v->current_order.Free();
01452     }
01453 
01454     if (IsStandardRoadStopTile(v->tile)) rs->SetEntranceBusy(true);
01455 
01456     StartRoadVehSound(v);
01457     SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
01458   }
01459 
01460   /* Check tile position conditions - i.e. stop position in depot,
01461    * entry onto bridge or into tunnel */
01462   uint32 r = VehicleEnterTile(v, v->tile, x, y);
01463   if (HasBit(r, VETS_CANNOT_ENTER)) {
01464     v->cur_speed = 0;
01465     return false;
01466   }
01467 
01468   if (v->current_order.IsType(OT_LEAVESTATION) && IsDriveThroughStopTile(v->tile)) {
01469     v->current_order.Free();
01470   }
01471 
01472   /* Move to next frame unless vehicle arrived at a stop position
01473    * in a depot or entered a tunnel/bridge */
01474   if (!HasBit(r, VETS_ENTERED_WORMHOLE)) v->frame++;
01475   v->x_pos = x;
01476   v->y_pos = y;
01477   RoadZPosAffectSpeed(v, v->UpdateInclination(false, true));
01478   return true;
01479 }
01480 
01481 static bool RoadVehController(RoadVehicle *v)
01482 {
01483   /* decrease counters */
01484   v->tick_counter++;
01485   v->current_order_time++;
01486   if (v->reverse_ctr != 0) v->reverse_ctr--;
01487 
01488   /* handle crashed */
01489   if (v->vehstatus & VS_CRASHED || RoadVehCheckTrainCrash(v)) {
01490     return RoadVehIsCrashed(v);
01491   }
01492 
01493   /* road vehicle has broken down? */
01494   if (v->HandleBreakdown()) return true;
01495   if (v->vehstatus & VS_STOPPED) return true;
01496 
01497   ProcessOrders(v);
01498   v->HandleLoading();
01499 
01500   if (v->current_order.IsType(OT_LOADING)) return true;
01501 
01502   if (v->IsInDepot() && RoadVehLeaveDepot(v, true)) return true;
01503 
01504   v->ShowVisualEffect();
01505 
01506   /* Check how far the vehicle needs to proceed */
01507   int j = v->UpdateSpeed();
01508 
01509   int adv_spd = v->GetAdvanceDistance();
01510   bool blocked = false;
01511   while (j >= adv_spd) {
01512     j -= adv_spd;
01513 
01514     RoadVehicle *u = v;
01515     for (RoadVehicle *prev = NULL; u != NULL; prev = u, u = u->Next()) {
01516       if (!IndividualRoadVehicleController(u, prev)) {
01517         blocked = true;
01518         break;
01519       }
01520     }
01521     if (blocked) break;
01522 
01523     /* Determine distance to next map position */
01524     adv_spd = v->GetAdvanceDistance();
01525 
01526     /* Test for a collision, but only if another movement will occur. */
01527     if (j >= adv_spd && RoadVehCheckTrainCrash(v)) break;
01528   }
01529 
01530   v->SetLastSpeed();
01531 
01532   for (RoadVehicle *u = v; u != NULL; u = u->Next()) {
01533     if ((u->vehstatus & VS_HIDDEN) != 0) continue;
01534 
01535     u->UpdateViewport(false, false);
01536   }
01537 
01538   /* If movement is blocked, set 'progress' to its maximum, so the roadvehicle does
01539    * not accelerate again before it can actually move. I.e. make sure it tries to advance again
01540    * on next tick to discover whether it is still blocked. */
01541   if (v->progress == 0) v->progress = blocked ? adv_spd - 1 : j;
01542 
01543   return true;
01544 }
01545 
01546 Money RoadVehicle::GetRunningCost() const
01547 {
01548   const Engine *e = this->GetEngine();
01549   if (e->u.road.running_cost_class == INVALID_PRICE) return 0;
01550 
01551   uint cost_factor = GetVehicleProperty(this, PROP_ROADVEH_RUNNING_COST_FACTOR, e->u.road.running_cost);
01552   if (cost_factor == 0) return 0;
01553 
01554   return GetPrice(e->u.road.running_cost_class, cost_factor, e->GetGRF());
01555 }
01556 
01557 bool RoadVehicle::Tick()
01558 {
01559   if (this->IsFrontEngine()) {
01560     if (!(this->vehstatus & VS_STOPPED)) this->running_ticks++;
01561     return RoadVehController(this);
01562   }
01563 
01564   return true;
01565 }
01566 
01567 static void CheckIfRoadVehNeedsService(RoadVehicle *v)
01568 {
01569   /* If we already got a slot at a stop, use that FIRST, and go to a depot later */
01570   if (Company::Get(v->owner)->settings.vehicle.servint_roadveh == 0 || !v->NeedsAutomaticServicing()) return;
01571   if (v->IsInDepot()) {
01572     VehicleServiceInDepot(v);
01573     return;
01574   }
01575 
01576   uint max_penalty;
01577   switch (_settings_game.pf.pathfinder_for_roadvehs) {
01578     case VPF_NPF:  max_penalty = _settings_game.pf.npf.maximum_go_to_depot_penalty;  break;
01579     case VPF_YAPF: max_penalty = _settings_game.pf.yapf.maximum_go_to_depot_penalty; break;
01580     default: NOT_REACHED();
01581   }
01582 
01583   FindDepotData rfdd = FindClosestRoadDepot(v, max_penalty);
01584   /* Only go to the depot if it is not too far out of our way. */
01585   if (rfdd.best_length == UINT_MAX || rfdd.best_length > max_penalty) {
01586     if (v->current_order.IsType(OT_GOTO_DEPOT)) {
01587       /* If we were already heading for a depot but it has
01588        * suddenly moved farther away, we continue our normal
01589        * schedule? */
01590       v->current_order.MakeDummy();
01591       SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
01592     }
01593     return;
01594   }
01595 
01596   DepotID depot = GetDepotIndex(rfdd.tile);
01597 
01598   if (v->current_order.IsType(OT_GOTO_DEPOT) &&
01599       v->current_order.GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS &&
01600       !Chance16(1, 20)) {
01601     return;
01602   }
01603 
01604   SetBit(v->gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
01605   v->current_order.MakeGoToDepot(depot, ODTFB_SERVICE);
01606   v->dest_tile = rfdd.tile;
01607   SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
01608 }
01609 
01610 void RoadVehicle::OnNewDay()
01611 {
01612   AgeVehicle(this);
01613 
01614   if (!this->IsFrontEngine()) return;
01615 
01616   if ((++this->day_counter & 7) == 0) DecreaseVehicleValue(this);
01617   if (this->blocked_ctr == 0) CheckVehicleBreakdown(this);
01618 
01619   CheckIfRoadVehNeedsService(this);
01620 
01621   CheckOrders(this);
01622 
01623   if (this->running_ticks == 0) return;
01624 
01625   CommandCost cost(EXPENSES_ROADVEH_RUN, this->GetRunningCost() * this->running_ticks / (DAYS_IN_YEAR * DAY_TICKS));
01626 
01627   this->profit_this_year -= cost.GetCost();
01628   this->running_ticks = 0;
01629 
01630   SubtractMoneyFromCompanyFract(this->owner, cost);
01631 
01632   SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
01633   SetWindowClassesDirty(WC_ROADVEH_LIST);
01634 }
01635 
01636 Trackdir RoadVehicle::GetVehicleTrackdir() const
01637 {
01638   if (this->vehstatus & VS_CRASHED) return INVALID_TRACKDIR;
01639 
01640   if (this->IsInDepot()) {
01641     /* We'll assume the road vehicle is facing outwards */
01642     return DiagDirToDiagTrackdir(GetRoadDepotDirection(this->tile));
01643   }
01644 
01645   if (IsStandardRoadStopTile(this->tile)) {
01646     /* We'll assume the road vehicle is facing outwards */
01647     return DiagDirToDiagTrackdir(GetRoadStopDir(this->tile)); // Road vehicle in a station
01648   }
01649 
01650   /* Drive through road stops / wormholes (tunnels) */
01651   if (this->state > RVSB_TRACKDIR_MASK) return DiagDirToDiagTrackdir(DirToDiagDir(this->direction));
01652 
01653   /* If vehicle's state is a valid track direction (vehicle is not turning around) return it,
01654    * otherwise transform it into a valid track direction */
01655   return (Trackdir)((IsReversingRoadTrackdir((Trackdir)this->state)) ? (this->state - 6) : this->state);
01656 }