roadveh_cmd.cpp

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

Generated on Fri Feb 4 20:53:46 2011 for OpenTTD by  doxygen 1.6.1