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