# roadveh_cmd.cpp

Go to the documentation of this file.

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