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

Generated on Sun Jan 23 01:49:08 2011 for OpenTTD by  doxygen 1.6.1