roadveh_cmd.cpp

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