roadveh_cmd.cpp

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