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