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