roadveh_cmd.cpp

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