# roadveh_cmd.cpp

Go to the documentation of this file.

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