# roadveh_cmd.cpp

Go to the documentation of this file.

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