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 "window_func.h"
00026 #include "date_func.h"
00027 #include "vehicle_func.h"
00028 #include "sound_func.h"
00029 #include "ai/ai.hpp"
00030 #include "depot_map.h"
00031 #include "effectvehicle_func.h"
00032 #include "roadstop_base.h"
00033 #include "spritecache.h"
00034 #include "core/random_func.hpp"
00035 #include "company_base.h"
00036 #include "core/backup_type.hpp"
00037 
00038 #include "table/strings.h"
00039 
00040 static const uint16 _roadveh_images[63] = {
00041   0xCD4, 0xCDC, 0xCE4, 0xCEC, 0xCF4, 0xCFC, 0xD0C, 0xD14,
00042   0xD24, 0xD1C, 0xD2C, 0xD04, 0xD1C, 0xD24, 0xD6C, 0xD74,
00043   0xD7C, 0xC14, 0xC1C, 0xC24, 0xC2C, 0xC34, 0xC3C, 0xC4C,
00044   0xC54, 0xC64, 0xC5C, 0xC6C, 0xC44, 0xC5C, 0xC64, 0xCAC,
00045   0xCB4, 0xCBC, 0xD94, 0xD9C, 0xDA4, 0xDAC, 0xDB4, 0xDBC,
00046   0xDCC, 0xDD4, 0xDE4, 0xDDC, 0xDEC, 0xDC4, 0xDDC, 0xDE4,
00047   0xE2C, 0xE34, 0xE3C, 0xC14, 0xC1C, 0xC2C, 0xC3C, 0xC4C,
00048   0xC5C, 0xC64, 0xC6C, 0xC74, 0xC84, 0xC94, 0xCA4
00049 };
00050 
00051 static const uint16 _roadveh_full_adder[63] = {
00052    0,  88,   0,   0,   0,   0,  48,  48,
00053   48,  48,   0,   0,  64,  64,   0,  16,
00054   16,   0,  88,   0,   0,   0,   0,  48,
00055   48,  48,  48,   0,   0,  64,  64,   0,
00056   16,  16,   0,  88,   0,   0,   0,   0,
00057   48,  48,  48,  48,   0,   0,  64,  64,
00058    0,  16,  16,   0,   8,   8,   8,   8,
00059    0,   0,   0,   8,   8,   8,   8
00060 };
00061 
00063 static const TrackdirBits _road_enter_dir_to_reachable_trackdirs[DIAGDIR_END] = {
00064   TRACKDIR_BIT_LEFT_N  | TRACKDIR_BIT_LOWER_E | TRACKDIR_BIT_X_NE,    // Enter from north east
00065   TRACKDIR_BIT_LEFT_S  | TRACKDIR_BIT_UPPER_E | TRACKDIR_BIT_Y_SE,    // Enter from south east
00066   TRACKDIR_BIT_UPPER_W | TRACKDIR_BIT_X_SW    | TRACKDIR_BIT_RIGHT_S, // Enter from south west
00067   TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_LOWER_W | TRACKDIR_BIT_Y_NW     // Enter from north west
00068 };
00069 
00070 static const Trackdir _road_reverse_table[DIAGDIR_END] = {
00071   TRACKDIR_RVREV_NE, TRACKDIR_RVREV_SE, TRACKDIR_RVREV_SW, TRACKDIR_RVREV_NW
00072 };
00073 
00075 static const Trackdir _roadveh_depot_exit_trackdir[DIAGDIR_END] = {
00076   TRACKDIR_X_NE, TRACKDIR_Y_SE, TRACKDIR_X_SW, TRACKDIR_Y_NW
00077 };
00078 
00079 
00084 bool RoadVehicle::IsBus() const
00085 {
00086   assert(this->IsFrontEngine());
00087   return IsCargoInClass(this->cargo_type, CC_PASSENGERS);
00088 }
00089 
00095 int RoadVehicle::GetDisplayImageWidth(Point *offset) const
00096 {
00097   int reference_width = ROADVEHINFO_DEFAULT_VEHICLE_WIDTH;
00098 
00099   if (offset != NULL) {
00100     offset->x = reference_width / 2;
00101     offset->y = 0;
00102   }
00103   return this->gcache.cached_veh_length * reference_width / VEHICLE_LENGTH;
00104 }
00105 
00106 static SpriteID GetRoadVehIcon(EngineID engine)
00107 {
00108   const Engine *e = Engine::Get(engine);
00109   uint8 spritenum = e->u.road.image_index;
00110 
00111   if (is_custom_sprite(spritenum)) {
00112     SpriteID sprite = GetCustomVehicleIcon(engine, DIR_W);
00113     if (sprite != 0) return sprite;
00114 
00115     spritenum = e->original_image_index;
00116   }
00117 
00118   return DIR_W + _roadveh_images[spritenum];
00119 }
00120 
00121 SpriteID RoadVehicle::GetImage(Direction direction) const
00122 {
00123   uint8 spritenum = this->spritenum;
00124   SpriteID sprite;
00125 
00126   if (is_custom_sprite(spritenum)) {
00127     sprite = GetCustomVehicleSprite(this, (Direction)(direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(spritenum)));
00128     if (sprite != 0) return sprite;
00129 
00130     spritenum = Engine::Get(this->engine_type)->original_image_index;
00131   }
00132 
00133   sprite = direction + _roadveh_images[spritenum];
00134 
00135   if (this->cargo.Count() >= this->cargo_cap / 2U) sprite += _roadveh_full_adder[spritenum];
00136 
00137   return sprite;
00138 }
00139 
00149 void DrawRoadVehEngine(int left, int right, int preferred_x, int y, EngineID engine, PaletteID pal)
00150 {
00151   SpriteID sprite = GetRoadVehIcon(engine);
00152   const Sprite *real_sprite = GetSprite(sprite, ST_NORMAL);
00153   preferred_x = Clamp(preferred_x, left - real_sprite->x_offs, right - real_sprite->width - real_sprite->x_offs);
00154   DrawSprite(sprite, pal, preferred_x, y);
00155 }
00156 
00162 static uint GetRoadVehLength(const RoadVehicle *v)
00163 {
00164   uint length = VEHICLE_LENGTH;
00165 
00166   uint16 veh_len = GetVehicleCallback(CBID_VEHICLE_LENGTH, 0, 0, v->engine_type, v);
00167   if (veh_len != CALLBACK_FAILED) {
00168     length -= Clamp(veh_len, 0, VEHICLE_LENGTH - 1);
00169   }
00170 
00171   return length;
00172 }
00173 
00179 void RoadVehUpdateCache(RoadVehicle *v)
00180 {
00181   assert(v->type == VEH_ROAD);
00182   assert(v->IsFrontEngine());
00183 
00184   v->InvalidateNewGRFCacheOfChain();
00185 
00186   v->gcache.cached_total_length = 0;
00187 
00188   uint32 cargo_mask = 0;
00189 
00190   for (RoadVehicle *u = v; u != NULL; u = u->Next()) {
00191     /* Check the v->first cache. */
00192     assert(u->First() == v);
00193 
00194     /* Update the 'first engine' */
00195     u->gcache.first_engine = (v == u) ? INVALID_ENGINE : v->engine_type;
00196 
00197     /* Update the length of the vehicle. */
00198     u->gcache.cached_veh_length = GetRoadVehLength(u);
00199     v->gcache.cached_total_length += u->gcache.cached_veh_length;
00200 
00201     /* Update visual effect */
00202     v->UpdateVisualEffect();
00203 
00204     /* Invalidate the vehicle colour map */
00205     u->colourmap = PAL_NONE;
00206 
00207     /* Update carried cargo. */
00208     if (u->cargo_type != INVALID_CARGO && u->cargo_cap > 0) SetBit(cargo_mask, u->cargo_type);
00209   }
00210 
00211   uint max_speed = GetVehicleProperty(v, PROP_ROADVEH_SPEED, 0);
00212   v->vcache.cached_max_speed = (max_speed != 0) ? max_speed * 4 : RoadVehInfo(v->engine_type)->max_speed;
00213   v->vcache.cached_cargo_mask = cargo_mask;
00214 }
00215 
00225 CommandCost CmdBuildRoadVehicle(TileIndex tile, DoCommandFlag flags, const Engine *e, uint16 data, Vehicle **ret)
00226 {
00227   if (HasTileRoadType(tile, ROADTYPE_TRAM) != HasBit(e->info.misc_flags, EF_ROAD_TRAM)) return_cmd_error(STR_ERROR_DEPOT_WRONG_DEPOT_TYPE);
00228 
00229   if (flags & DC_EXEC) {
00230     const RoadVehicleInfo *rvi = &e->u.road;
00231 
00232     RoadVehicle *v = new RoadVehicle();
00233     *ret = v;
00234     v->direction = DiagDirToDir(GetRoadDepotDirection(tile));
00235     v->owner = _current_company;
00236 
00237     v->tile = tile;
00238     int x = TileX(tile) * TILE_SIZE + TILE_SIZE / 2;
00239     int y = TileY(tile) * TILE_SIZE + TILE_SIZE / 2;
00240     v->x_pos = x;
00241     v->y_pos = y;
00242     v->z_pos = GetSlopeZ(x, y);
00243 
00244     v->state = RVSB_IN_DEPOT;
00245     v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL;
00246 
00247     v->spritenum = rvi->image_index;
00248     v->cargo_type = e->GetDefaultCargoType();
00249     v->cargo_cap = rvi->capacity;
00250 
00251     v->last_station_visited = INVALID_STATION;
00252     v->engine_type = e->index;
00253     v->gcache.first_engine = INVALID_ENGINE; // needs to be set before first callback
00254 
00255     v->reliability = e->reliability;
00256     v->reliability_spd_dec = e->reliability_spd_dec;
00257     v->max_age = e->GetLifeLengthInDays();
00258     _new_vehicle_id = v->index;
00259 
00260     v->service_interval = Company::Get(v->owner)->settings.vehicle.servint_roadveh;
00261 
00262     v->date_of_last_service = _date;
00263     v->build_year = _cur_year;
00264 
00265     v->cur_image = SPR_IMG_QUERY;
00266     v->random_bits = VehicleRandomBits();
00267     v->SetFrontEngine();
00268 
00269     v->roadtype = HasBit(e->info.misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD;
00270     v->compatible_roadtypes = RoadTypeToRoadTypes(v->roadtype);
00271     v->gcache.cached_veh_length = VEHICLE_LENGTH;
00272 
00273     if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) SetBit(v->vehicle_flags, VF_BUILT_AS_PROTOTYPE);
00274 
00275     AddArticulatedParts(v);
00276     v->InvalidateNewGRFCacheOfChain();
00277 
00278     /* Call various callbacks after the whole consist has been constructed */
00279     for (RoadVehicle *u = v; u != NULL; u = u->Next()) {
00280       u->cargo_cap = GetVehicleCapacity(u);
00281       v->InvalidateNewGRFCache();
00282       u->InvalidateNewGRFCache();
00283     }
00284     RoadVehUpdateCache(v);
00285     /* Initialize cached values for realistic acceleration. */
00286     if (_settings_game.vehicle.roadveh_acceleration_model != AM_ORIGINAL) v->CargoChanged();
00287 
00288     VehicleMove(v, false);
00289 
00290     CheckConsistencyOfArticulatedVehicle(v);
00291   }
00292 
00293   return CommandCost();
00294 }
00295 
00296 bool RoadVehicle::IsStoppedInDepot() const
00297 {
00298   TileIndex tile = this->tile;
00299 
00300   if (!IsRoadDepotTile(tile)) return false;
00301   if (this->IsFrontEngine() && !(this->vehstatus & VS_STOPPED)) return false;
00302 
00303   for (const RoadVehicle *v = this; v != NULL; v = v->Next()) {
00304     if (v->state != RVSB_IN_DEPOT || v->tile != tile) return false;
00305   }
00306   return true;
00307 }
00308 
00309 static FindDepotData FindClosestRoadDepot(const RoadVehicle *v, int max_distance)
00310 {
00311   if (IsRoadDepotTile(v->tile)) return FindDepotData(v->tile, 0);
00312 
00313   switch (_settings_game.pf.pathfinder_for_roadvehs) {
00314     case VPF_NPF: return NPFRoadVehicleFindNearestDepot(v, max_distance);
00315     case VPF_YAPF: return YapfRoadVehicleFindNearestDepot(v, max_distance);
00316 
00317     default: NOT_REACHED();
00318   }
00319 }
00320 
00321 bool RoadVehicle::FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse)
00322 {
00323   FindDepotData rfdd = FindClosestRoadDepot(this, 0);
00324   if (rfdd.best_length == UINT_MAX) return false;
00325 
00326   if (location    != NULL) *location    = rfdd.tile;
00327   if (destination != NULL) *destination = GetDepotIndex(rfdd.tile);
00328 
00329   return true;
00330 }
00331 
00341 CommandCost CmdTurnRoadVeh(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00342 {
00343   RoadVehicle *v = RoadVehicle::GetIfValid(p1);
00344   if (v == NULL) return CMD_ERROR;
00345 
00346   CommandCost ret = CheckOwnership(v->owner);
00347   if (ret.Failed()) return ret;
00348 
00349   if ((v->vehstatus & VS_STOPPED) ||
00350       (v->vehstatus & VS_CRASHED) ||
00351       v->breakdown_ctr != 0 ||
00352       v->overtaking != 0 ||
00353       v->state == RVSB_WORMHOLE ||
00354       v->IsInDepot() ||
00355       v->current_order.IsType(OT_LOADING)) {
00356     return CMD_ERROR;
00357   }
00358 
00359   if (IsNormalRoadTile(v->tile) && GetDisallowedRoadDirections(v->tile) != DRD_NONE) return CMD_ERROR;
00360 
00361   if (IsTileType(v->tile, MP_TUNNELBRIDGE) && DirToDiagDir(v->direction) == GetTunnelBridgeDirection(v->tile)) return CMD_ERROR;
00362 
00363   if (flags & DC_EXEC) v->reverse_ctr = 180;
00364 
00365   return CommandCost();
00366 }
00367 
00368 
00369 void RoadVehicle::MarkDirty()
00370 {
00371   for (RoadVehicle *v = this; v != NULL; v = v->Next()) {
00372     v->UpdateViewport(false, false);
00373   }
00374   this->CargoChanged();
00375 }
00376 
00377 void RoadVehicle::UpdateDeltaXY(Direction direction)
00378 {
00379 #define MKIT(a, b, c, d) ((a & 0xFF) << 24) | ((b & 0xFF) << 16) | ((c & 0xFF) << 8) | ((d & 0xFF) << 0)
00380   static const uint32 _delta_xy_table[8] = {
00381     MKIT(3, 3, -1, -1),
00382     MKIT(3, 7, -1, -3),
00383     MKIT(3, 3, -1, -1),
00384     MKIT(7, 3, -3, -1),
00385     MKIT(3, 3, -1, -1),
00386     MKIT(3, 7, -1, -3),
00387     MKIT(3, 3, -1, -1),
00388     MKIT(7, 3, -3, -1),
00389   };
00390 #undef MKIT
00391 
00392   uint32 x = _delta_xy_table[direction];
00393   this->x_offs        = GB(x,  0, 8);
00394   this->y_offs        = GB(x,  8, 8);
00395   this->x_extent      = GB(x, 16, 8);
00396   this->y_extent      = GB(x, 24, 8);
00397   this->z_extent      = 6;
00398 }
00399 
00404 FORCEINLINE int RoadVehicle::GetCurrentMaxSpeed() const
00405 {
00406   if (_settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) return this->vcache.cached_max_speed;
00407 
00408   int max_speed = this->vcache.cached_max_speed;
00409 
00410   /* Limit speed to 50% while reversing, 75% in curves. */
00411   for (const RoadVehicle *u = this; u != NULL; u = u->Next()) {
00412     if (this->state <= RVSB_TRACKDIR_MASK && IsReversingRoadTrackdir((Trackdir)this->state)) {
00413       max_speed = this->vcache.cached_max_speed / 2;
00414       break;
00415     } else if ((u->direction & 1) == 0) {
00416       max_speed = this->vcache.cached_max_speed * 3 / 4;
00417     }
00418   }
00419 
00420   return max_speed;
00421 }
00422 
00427 static void DeleteLastRoadVeh(RoadVehicle *v)
00428 {
00429   Vehicle *u = v;
00430   for (; v->Next() != NULL; v = v->Next()) u = v;
00431   u->SetNext(NULL);
00432 
00433   /* Only leave the road stop when we're really gone. */
00434   if (IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END)) RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile))->Leave(v);
00435 
00436   delete v;
00437 }
00438 
00439 static void RoadVehSetRandomDirection(RoadVehicle *v)
00440 {
00441   static const DirDiff delta[] = {
00442     DIRDIFF_45LEFT, DIRDIFF_SAME, DIRDIFF_SAME, DIRDIFF_45RIGHT
00443   };
00444 
00445   do {
00446     uint32 r = Random();
00447 
00448     v->direction = ChangeDir(v->direction, delta[r & 3]);
00449     v->UpdateViewport(true, true);
00450   } while ((v = v->Next()) != NULL);
00451 }
00452 
00458 static bool RoadVehIsCrashed(RoadVehicle *v)
00459 {
00460   v->crashed_ctr++;
00461   if (v->crashed_ctr == 2) {
00462     CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
00463   } else if (v->crashed_ctr <= 45) {
00464     if ((v->tick_counter & 7) == 0) RoadVehSetRandomDirection(v);
00465   } else if (v->crashed_ctr >= 2220 && !(v->tick_counter & 0x1F)) {
00466     bool ret = v->Next() != NULL;
00467     DeleteLastRoadVeh(v);
00468     return ret;
00469   }
00470 
00471   return true;
00472 }
00473 
00480 static Vehicle *EnumCheckRoadVehCrashTrain(Vehicle *v, void *data)
00481 {
00482   const Vehicle *u = (Vehicle*)data;
00483 
00484   return (v->type == VEH_TRAIN &&
00485       abs(v->z_pos - u->z_pos) <= 6 &&
00486       abs(v->x_pos - u->x_pos) <= 4 &&
00487       abs(v->y_pos - u->y_pos) <= 4) ? v : NULL;
00488 }
00489 
00490 uint RoadVehicle::Crash(bool flooded)
00491 {
00492   uint pass = this->GroundVehicleBase::Crash(flooded);
00493   if (this->IsFrontEngine()) {
00494     pass += 1; // driver
00495 
00496     /* If we're in a drive through road stop we ought to leave it */
00497     if (IsInsideMM(this->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END)) {
00498       RoadStop::GetByTile(this->tile, GetRoadStopType(this->tile))->Leave(this);
00499     }
00500   }
00501   this->crashed_ctr = flooded ? 2000 : 1; // max 2220, disappear pretty fast when flooded
00502   return pass;
00503 }
00504 
00505 static void RoadVehCrash(RoadVehicle *v)
00506 {
00507   uint pass = v->Crash();
00508 
00509   AI::NewEvent(v->owner, new AIEventVehicleCrashed(v->index, v->tile, AIEventVehicleCrashed::CRASH_RV_LEVEL_CROSSING));
00510 
00511   SetDParam(0, pass);
00512   AddVehicleNewsItem(
00513     (pass == 1) ?
00514       STR_NEWS_ROAD_VEHICLE_CRASH_DRIVER : STR_NEWS_ROAD_VEHICLE_CRASH,
00515     NS_ACCIDENT,
00516     v->index
00517   );
00518 
00519   ModifyStationRatingAround(v->tile, v->owner, -160, 22);
00520   SndPlayVehicleFx(SND_12_EXPLOSION, v);
00521 }
00522 
00523 static bool RoadVehCheckTrainCrash(RoadVehicle *v)
00524 {
00525   for (RoadVehicle *u = v; u != NULL; u = u->Next()) {
00526     if (u->state == RVSB_WORMHOLE) continue;
00527 
00528     TileIndex tile = u->tile;
00529 
00530     if (!IsLevelCrossingTile(tile)) continue;
00531 
00532     if (HasVehicleOnPosXY(v->x_pos, v->y_pos, u, EnumCheckRoadVehCrashTrain)) {
00533       RoadVehCrash(v);
00534       return true;
00535     }
00536   }
00537 
00538   return false;
00539 }
00540 
00541 TileIndex RoadVehicle::GetOrderStationLocation(StationID station)
00542 {
00543   if (station == this->last_station_visited) this->last_station_visited = INVALID_STATION;
00544 
00545   const Station *st = Station::Get(station);
00546   if (!CanVehicleUseStation(this, st)) {
00547     /* There is no stop left at the station, so don't even TRY to go there */
00548     this->IncrementRealOrderIndex();
00549     return 0;
00550   }
00551 
00552   return st->xy;
00553 }
00554 
00555 static void StartRoadVehSound(const RoadVehicle *v)
00556 {
00557   if (!PlayVehicleSound(v, VSE_START)) {
00558     SoundID s = RoadVehInfo(v->engine_type)->sfx;
00559     if (s == SND_19_BUS_START_PULL_AWAY && (v->tick_counter & 3) == 0) {
00560       s = SND_1A_BUS_START_PULL_AWAY_WITH_HORN;
00561     }
00562     SndPlayVehicleFx(s, v);
00563   }
00564 }
00565 
00566 struct RoadVehFindData {
00567   int x;
00568   int y;
00569   const Vehicle *veh;
00570   Vehicle *best;
00571   uint best_diff;
00572   Direction dir;
00573 };
00574 
00575 static Vehicle *EnumCheckRoadVehClose(Vehicle *v, void *data)
00576 {
00577   static const int8 dist_x[] = { -4, -8, -4, -1, 4, 8, 4, 1 };
00578   static const int8 dist_y[] = { -4, -1, 4, 8, 4, 1, -4, -8 };
00579 
00580   RoadVehFindData *rvf = (RoadVehFindData*)data;
00581 
00582   short x_diff = v->x_pos - rvf->x;
00583   short y_diff = v->y_pos - rvf->y;
00584 
00585   if (v->type == VEH_ROAD &&
00586       !v->IsInDepot() &&
00587       abs(v->z_pos - rvf->veh->z_pos) < 6 &&
00588       v->direction == rvf->dir &&
00589       rvf->veh->First() != v->First() &&
00590       (dist_x[v->direction] >= 0 || (x_diff > dist_x[v->direction] && x_diff <= 0)) &&
00591       (dist_x[v->direction] <= 0 || (x_diff < dist_x[v->direction] && x_diff >= 0)) &&
00592       (dist_y[v->direction] >= 0 || (y_diff > dist_y[v->direction] && y_diff <= 0)) &&
00593       (dist_y[v->direction] <= 0 || (y_diff < dist_y[v->direction] && y_diff >= 0))) {
00594     uint diff = abs(x_diff) + abs(y_diff);
00595 
00596     if (diff < rvf->best_diff || (diff == rvf->best_diff && v->index < rvf->best->index)) {
00597       rvf->best = v;
00598       rvf->best_diff = diff;
00599     }
00600   }
00601 
00602   return NULL;
00603 }
00604 
00605 static RoadVehicle *RoadVehFindCloseTo(RoadVehicle *v, int x, int y, Direction dir, bool update_blocked_ctr = true)
00606 {
00607   RoadVehFindData rvf;
00608   RoadVehicle *front = v->First();
00609 
00610   if (front->reverse_ctr != 0) return NULL;
00611 
00612   rvf.x = x;
00613   rvf.y = y;
00614   rvf.dir = dir;
00615   rvf.veh = v;
00616   rvf.best_diff = UINT_MAX;
00617 
00618   if (front->state == RVSB_WORMHOLE) {
00619     FindVehicleOnPos(v->tile, &rvf, EnumCheckRoadVehClose);
00620     FindVehicleOnPos(GetOtherTunnelBridgeEnd(v->tile), &rvf, EnumCheckRoadVehClose);
00621   } else {
00622     FindVehicleOnPosXY(x, y, &rvf, EnumCheckRoadVehClose);
00623   }
00624 
00625   /* This code protects a roadvehicle from being blocked for ever
00626    * If more than 1480 / 74 days a road vehicle is blocked, it will
00627    * drive just through it. The ultimate backup-code of TTD.
00628    * It can be disabled. */
00629   if (rvf.best_diff == UINT_MAX) {
00630     front->blocked_ctr = 0;
00631     return NULL;
00632   }
00633 
00634   if (update_blocked_ctr && ++front->blocked_ctr > 1480) return NULL;
00635 
00636   return RoadVehicle::From(rvf.best);
00637 }
00638 
00644 static void RoadVehArrivesAt(const RoadVehicle *v, Station *st)
00645 {
00646   if (v->IsBus()) {
00647     /* Check if station was ever visited before */
00648     if (!(st->had_vehicle_of_type & HVOT_BUS)) {
00649       st->had_vehicle_of_type |= HVOT_BUS;
00650       SetDParam(0, st->index);
00651       AddVehicleNewsItem(
00652         v->roadtype == ROADTYPE_ROAD ? STR_NEWS_FIRST_BUS_ARRIVAL : STR_NEWS_FIRST_PASSENGER_TRAM_ARRIVAL,
00653         (v->owner == _local_company) ? NS_ARRIVAL_COMPANY : NS_ARRIVAL_OTHER,
00654         v->index,
00655         st->index
00656       );
00657       AI::NewEvent(v->owner, new AIEventStationFirstVehicle(st->index, v->index));
00658     }
00659   } else {
00660     /* Check if station was ever visited before */
00661     if (!(st->had_vehicle_of_type & HVOT_TRUCK)) {
00662       st->had_vehicle_of_type |= HVOT_TRUCK;
00663       SetDParam(0, st->index);
00664       AddVehicleNewsItem(
00665         v->roadtype == ROADTYPE_ROAD ? STR_NEWS_FIRST_TRUCK_ARRIVAL : STR_NEWS_FIRST_CARGO_TRAM_ARRIVAL,
00666         (v->owner == _local_company) ? NS_ARRIVAL_COMPANY : NS_ARRIVAL_OTHER,
00667         v->index,
00668         st->index
00669       );
00670       AI::NewEvent(v->owner, new AIEventStationFirstVehicle(st->index, v->index));
00671     }
00672   }
00673 }
00674 
00682 int RoadVehicle::UpdateSpeed()
00683 {
00684   switch (_settings_game.vehicle.roadveh_acceleration_model) {
00685     default: NOT_REACHED();
00686     case AM_ORIGINAL:
00687       return this->DoUpdateSpeed(this->overtaking != 0 ? 512 : 256, 0, this->GetCurrentMaxSpeed());
00688 
00689     case AM_REALISTIC:
00690       return this->DoUpdateSpeed(this->GetAcceleration() + (this->overtaking != 0 ? 256 : 0), this->GetAccelerationStatus() == AS_BRAKE ? 0 : 4, this->GetCurrentMaxSpeed());
00691   }
00692 }
00693 
00694 static Direction RoadVehGetNewDirection(const RoadVehicle *v, int x, int y)
00695 {
00696   static const Direction _roadveh_new_dir[] = {
00697     DIR_N , DIR_NW, DIR_W , INVALID_DIR,
00698     DIR_NE, DIR_N , DIR_SW, INVALID_DIR,
00699     DIR_E , DIR_SE, DIR_S
00700   };
00701 
00702   x = x - v->x_pos + 1;
00703   y = y - v->y_pos + 1;
00704 
00705   if ((uint)x > 2 || (uint)y > 2) return v->direction;
00706   return _roadveh_new_dir[y * 4 + x];
00707 }
00708 
00709 static Direction RoadVehGetSlidingDirection(const RoadVehicle *v, int x, int y)
00710 {
00711   Direction new_dir = RoadVehGetNewDirection(v, x, y);
00712   Direction old_dir = v->direction;
00713   DirDiff delta;
00714 
00715   if (new_dir == old_dir) return old_dir;
00716   delta = (DirDifference(new_dir, old_dir) > DIRDIFF_REVERSE ? DIRDIFF_45LEFT : DIRDIFF_45RIGHT);
00717   return ChangeDir(old_dir, delta);
00718 }
00719 
00720 struct OvertakeData {
00721   const RoadVehicle *u;
00722   const RoadVehicle *v;
00723   TileIndex tile;
00724   Trackdir trackdir;
00725 };
00726 
00727 static Vehicle *EnumFindVehBlockingOvertake(Vehicle *v, void *data)
00728 {
00729   const OvertakeData *od = (OvertakeData*)data;
00730 
00731   return (v->type == VEH_ROAD && v->First() == v && v != od->u && v != od->v) ? v : NULL;
00732 }
00733 
00740 static bool CheckRoadBlockedForOvertaking(OvertakeData *od)
00741 {
00742   TrackStatus ts = GetTileTrackStatus(od->tile, TRANSPORT_ROAD, od->v->compatible_roadtypes);
00743   TrackdirBits trackdirbits = TrackStatusToTrackdirBits(ts);
00744   TrackdirBits red_signals = TrackStatusToRedSignals(ts); // barred level crossing
00745   TrackBits trackbits = TrackdirBitsToTrackBits(trackdirbits);
00746 
00747   /* Track does not continue along overtaking direction || track has junction || levelcrossing is barred */
00748   if (!HasBit(trackdirbits, od->trackdir) || (trackbits & ~TRACK_BIT_CROSS) || (red_signals != TRACKDIR_BIT_NONE)) return true;
00749 
00750   /* Are there more vehicles on the tile except the two vehicles involved in overtaking */
00751   return HasVehicleOnPos(od->tile, od, EnumFindVehBlockingOvertake);
00752 }
00753 
00754 static void RoadVehCheckOvertake(RoadVehicle *v, RoadVehicle *u)
00755 {
00756   OvertakeData od;
00757 
00758   od.v = v;
00759   od.u = u;
00760 
00761   if (u->vcache.cached_max_speed >= v->vcache.cached_max_speed &&
00762       !(u->vehstatus & VS_STOPPED) &&
00763       u->cur_speed != 0) {
00764     return;
00765   }
00766 
00767   /* Trams can't overtake other trams */
00768   if (v->roadtype == ROADTYPE_TRAM) return;
00769 
00770   /* Don't overtake in stations */
00771   if (IsTileType(v->tile, MP_STATION) || IsTileType(u->tile, MP_STATION)) return;
00772 
00773   /* For now, articulated road vehicles can't overtake anything. */
00774   if (v->HasArticulatedPart()) return;
00775 
00776   /* Vehicles are not driving in same direction || direction is not a diagonal direction */
00777   if (v->direction != u->direction || !(v->direction & 1)) return;
00778 
00779   /* Check if vehicle is in a road stop, depot, tunnel or bridge or not on a straight road */
00780   if (v->state >= RVSB_IN_ROAD_STOP || !IsStraightRoadTrackdir((Trackdir)(v->state & RVSB_TRACKDIR_MASK))) return;
00781 
00782   od.trackdir = DiagDirToDiagTrackdir(DirToDiagDir(v->direction));
00783 
00784   /* Are the current and the next tile suitable for overtaking?
00785    *  - Does the track continue along od.trackdir
00786    *  - No junctions
00787    *  - No barred levelcrossing
00788    *  - No other vehicles in the way
00789    */
00790   od.tile = v->tile;
00791   if (CheckRoadBlockedForOvertaking(&od)) return;
00792 
00793   od.tile = v->tile + TileOffsByDiagDir(DirToDiagDir(v->direction));
00794   if (CheckRoadBlockedForOvertaking(&od)) return;
00795 
00796   /* When the vehicle in front of us is stopped we may only take
00797    * half the time to pass it than when the vehicle is moving. */
00798   v->overtaking_ctr = (od.u->cur_speed == 0 || (od.u->vehstatus & VS_STOPPED)) ? RV_OVERTAKE_TIMEOUT / 2 : 0;
00799   v->overtaking = RVSB_DRIVE_SIDE;
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     /* We are leaving a depot, but have to go to the exact same one; re-enter */
00951     if (v->current_order.IsType(OT_GOTO_DEPOT) && v->tile == v->dest_tile) {
00952       VehicleEnterDepot(v);
00953       return true;
00954     }
00955 
00956     if (RoadVehFindCloseTo(v, x, y, v->direction, false) != NULL) return true;
00957 
00958     VehicleServiceInDepot(v);
00959 
00960     StartRoadVehSound(v);
00961 
00962     /* Vehicle is about to leave a depot */
00963     v->cur_speed = 0;
00964   }
00965 
00966   v->vehstatus &= ~VS_HIDDEN;
00967   v->state = tdir;
00968   v->frame = RVC_DEPOT_START_FRAME;
00969 
00970   v->x_pos = x;
00971   v->y_pos = y;
00972   v->UpdateInclination(true, true);
00973 
00974   InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
00975 
00976   return true;
00977 }
00978 
00979 static Trackdir FollowPreviousRoadVehicle(const RoadVehicle *v, const RoadVehicle *prev, TileIndex tile, DiagDirection entry_dir, bool already_reversed)
00980 {
00981   if (prev->tile == v->tile && !already_reversed) {
00982     /* If the previous vehicle is on the same tile as this vehicle is
00983      * then it must have reversed. */
00984     return _road_reverse_table[entry_dir];
00985   }
00986 
00987   byte prev_state = prev->state;
00988   Trackdir dir;
00989 
00990   if (prev_state == RVSB_WORMHOLE || prev_state == RVSB_IN_DEPOT) {
00991     DiagDirection diag_dir = INVALID_DIAGDIR;
00992 
00993     if (IsTileType(tile, MP_TUNNELBRIDGE)) {
00994       diag_dir = GetTunnelBridgeDirection(tile);
00995     } else if (IsRoadDepotTile(tile)) {
00996       diag_dir = ReverseDiagDir(GetRoadDepotDirection(tile));
00997     }
00998 
00999     if (diag_dir == INVALID_DIAGDIR) return INVALID_TRACKDIR;
01000     dir = DiagDirToDiagTrackdir(diag_dir);
01001   } else {
01002     if (already_reversed && prev->tile != tile) {
01003       /*
01004        * The vehicle has reversed, but did not go straight back.
01005        * It immediately turn onto another tile. This means that
01006        * the roadstate of the previous vehicle cannot be used
01007        * as the direction we have to go with this vehicle.
01008        *
01009        * Next table is build in the following way:
01010        *  - first row for when the vehicle in front went to the northern or
01011        *    western tile, second for southern and eastern.
01012        *  - columns represent the entry direction.
01013        *  - cell values are determined by the Trackdir one has to take from
01014        *    the entry dir (column) to the tile in north or south by only
01015        *    going over the trackdirs used for turning 90 degrees, i.e.
01016        *    TRACKDIR_{UPPER,RIGHT,LOWER,LEFT}_{N,E,S,W}.
01017        */
01018       static const Trackdir reversed_turn_lookup[2][DIAGDIR_END] = {
01019         { TRACKDIR_UPPER_W, TRACKDIR_RIGHT_N, TRACKDIR_LEFT_N,  TRACKDIR_UPPER_E },
01020         { TRACKDIR_RIGHT_S, TRACKDIR_LOWER_W, TRACKDIR_LOWER_E, TRACKDIR_LEFT_S  }};
01021       dir = reversed_turn_lookup[prev->tile < tile ? 0 : 1][ReverseDiagDir(entry_dir)];
01022     } else if (HasBit(prev_state, RVS_IN_DT_ROAD_STOP)) {
01023       dir = (Trackdir)(prev_state & RVSB_ROAD_STOP_TRACKDIR_MASK);
01024     } else if (prev_state < TRACKDIR_END) {
01025       dir = (Trackdir)prev_state;
01026     } else {
01027       return INVALID_TRACKDIR;
01028     }
01029   }
01030 
01031   /* Do some sanity checking. */
01032   static const RoadBits required_roadbits[] = {
01033     ROAD_X,            ROAD_Y,            ROAD_NW | ROAD_NE, ROAD_SW | ROAD_SE,
01034     ROAD_NW | ROAD_SW, ROAD_NE | ROAD_SE, ROAD_X,            ROAD_Y
01035   };
01036   RoadBits required = required_roadbits[dir & 0x07];
01037 
01038   if ((required & GetAnyRoadBits(tile, v->roadtype, true)) == ROAD_NONE) {
01039     dir = INVALID_TRACKDIR;
01040   }
01041 
01042   return dir;
01043 }
01044 
01052 static bool CanBuildTramTrackOnTile(CompanyID c, TileIndex t, RoadBits r)
01053 {
01054   /* The 'current' company is not necessarily the owner of the vehicle. */
01055   Backup<CompanyByte> cur_company(_current_company, c, FILE_LINE);
01056 
01057   CommandCost ret = DoCommand(t, ROADTYPE_TRAM << 4 | r, 0, DC_NONE, CMD_BUILD_ROAD);
01058 
01059   cur_company.Restore();
01060   return ret.Succeeded();
01061 }
01062 
01063 static bool IndividualRoadVehicleController(RoadVehicle *v, const RoadVehicle *prev)
01064 {
01065   if (v->overtaking != 0)  {
01066     if (IsTileType(v->tile, MP_STATION)) {
01067       /* Force us to be not overtaking! */
01068       v->overtaking = 0;
01069     } else if (++v->overtaking_ctr >= RV_OVERTAKE_TIMEOUT) {
01070       /* If overtaking just aborts at a random moment, we can have a out-of-bound problem,
01071        *  if the vehicle started a corner. To protect that, only allow an abort of
01072        *  overtake if we are on straight roads */
01073       if (v->state < RVSB_IN_ROAD_STOP && IsStraightRoadTrackdir((Trackdir)v->state)) {
01074         v->overtaking = 0;
01075       }
01076     }
01077   }
01078 
01079   /* If this vehicle is in a depot and we've reached this point it must be
01080    * one of the articulated parts. It will stay in the depot until activated
01081    * by the previous vehicle in the chain when it gets to the right place. */
01082   if (v->IsInDepot()) return true;
01083 
01084   if (v->state == RVSB_WORMHOLE) {
01085     /* Vehicle is entering a depot or is on a bridge or in a tunnel */
01086     GetNewVehiclePosResult gp = GetNewVehiclePos(v);
01087 
01088     /* Apply bridge speed limit */
01089     if (!(v->vehstatus & VS_HIDDEN)) {
01090       RoadVehicle *first = v->First();
01091       first->cur_speed = min(first->cur_speed, GetBridgeSpec(GetBridgeType(v->tile))->speed * 2);
01092     }
01093 
01094     if (v->IsFrontEngine()) {
01095       const Vehicle *u = RoadVehFindCloseTo(v, gp.x, gp.y, v->direction);
01096       if (u != NULL) {
01097         v->cur_speed = u->First()->cur_speed;
01098         return false;
01099       }
01100     }
01101 
01102     if (IsTileType(gp.new_tile, MP_TUNNELBRIDGE) && HasBit(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y), VETS_ENTERED_WORMHOLE)) {
01103       /* Vehicle has just entered a bridge or tunnel */
01104       v->x_pos = gp.x;
01105       v->y_pos = gp.y;
01106       v->UpdateInclination(true, true);
01107       return true;
01108     }
01109 
01110     v->x_pos = gp.x;
01111     v->y_pos = gp.y;
01112     VehicleMove(v, !(v->vehstatus & VS_HIDDEN));
01113     return true;
01114   }
01115 
01116   /* Get move position data for next frame.
01117    * For a drive-through road stop use 'straight road' move data.
01118    * In this case v->state is masked to give the road stop entry direction. */
01119   RoadDriveEntry rd = _road_drive_data[v->roadtype][(
01120     (HasBit(v->state, RVS_IN_DT_ROAD_STOP) ? v->state & RVSB_ROAD_STOP_TRACKDIR_MASK : v->state) +
01121     (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)) ^ v->overtaking][v->frame + 1];
01122 
01123   if (rd.x & RDE_NEXT_TILE) {
01124     TileIndex tile = v->tile + TileOffsByDiagDir((DiagDirection)(rd.x & 3));
01125     Trackdir dir;
01126 
01127     if (v->IsFrontEngine()) {
01128       /* If this is the front engine, look for the right path. */
01129       dir = RoadFindPathToDest(v, tile, (DiagDirection)(rd.x & 3));
01130     } else {
01131       dir = FollowPreviousRoadVehicle(v, prev, tile, (DiagDirection)(rd.x & 3), false);
01132     }
01133 
01134     if (dir == INVALID_TRACKDIR) {
01135       if (!v->IsFrontEngine()) error("Disconnecting road vehicle.");
01136       v->cur_speed = 0;
01137       return false;
01138     }
01139 
01140 again:
01141     uint start_frame = RVC_DEFAULT_START_FRAME;
01142     if (IsReversingRoadTrackdir(dir)) {
01143       /* When turning around we can't be overtaking. */
01144       v->overtaking = 0;
01145 
01146       /* Turning around */
01147       if (v->roadtype == ROADTYPE_TRAM) {
01148         /* Determine the road bits the tram needs to be able to turn around
01149          * using the 'big' corner loop. */
01150         RoadBits needed;
01151         switch (dir) {
01152           default: NOT_REACHED();
01153           case TRACKDIR_RVREV_NE: needed = ROAD_SW; break;
01154           case TRACKDIR_RVREV_SE: needed = ROAD_NW; break;
01155           case TRACKDIR_RVREV_SW: needed = ROAD_NE; break;
01156           case TRACKDIR_RVREV_NW: needed = ROAD_SE; break;
01157         }
01158         if ((v->Previous() != NULL && v->Previous()->tile == tile) ||
01159             (v->IsFrontEngine() && IsNormalRoadTile(tile) && !HasRoadWorks(tile) &&
01160               (needed & GetRoadBits(tile, ROADTYPE_TRAM)) != ROAD_NONE)) {
01161           /*
01162            * Taking the 'big' corner for trams only happens when:
01163            * - The previous vehicle in this (articulated) tram chain is
01164            *   already on the 'next' tile, we just follow them regardless of
01165            *   anything. When it is NOT on the 'next' tile, the tram started
01166            *   doing a reversing turn when the piece of tram track on the next
01167            *   tile did not exist yet. Do not use the big tram loop as that is
01168            *   going to cause the tram to split up.
01169            * - Or the front of the tram can drive over the next tile.
01170            */
01171         } else if (!v->IsFrontEngine() || !CanBuildTramTrackOnTile(v->owner, tile, needed) || ((~needed & GetAnyRoadBits(v->tile, ROADTYPE_TRAM, false)) == ROAD_NONE)) {
01172           /*
01173            * Taking the 'small' corner for trams only happens when:
01174            * - We are not the from vehicle of an articulated tram.
01175            * - Or when the company cannot build on the next tile.
01176            *
01177            * The 'small' corner means that the vehicle is on the end of a
01178            * tram track and needs to start turning there. To do this properly
01179            * the tram needs to start at an offset in the tram turning 'code'
01180            * for 'big' corners. It furthermore does not go to the next tile,
01181            * so that needs to be fixed too.
01182            */
01183           tile = v->tile;
01184           start_frame = RVC_TURN_AROUND_START_FRAME_SHORT_TRAM;
01185         } else {
01186           /* The company can build on the next tile, so wait till (s)he does. */
01187           v->cur_speed = 0;
01188           return false;
01189         }
01190       } else if (IsNormalRoadTile(v->tile) && GetDisallowedRoadDirections(v->tile) != DRD_NONE) {
01191         v->cur_speed = 0;
01192         return false;
01193       } else {
01194         tile = v->tile;
01195       }
01196     }
01197 
01198     /* Get position data for first frame on the new tile */
01199     const RoadDriveEntry *rdp = _road_drive_data[v->roadtype][(dir + (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)) ^ v->overtaking];
01200 
01201     int x = TileX(tile) * TILE_SIZE + rdp[start_frame].x;
01202     int y = TileY(tile) * TILE_SIZE + rdp[start_frame].y;
01203 
01204     Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
01205     if (v->IsFrontEngine()) {
01206       Vehicle *u = RoadVehFindCloseTo(v, x, y, new_dir);
01207       if (u != NULL) {
01208         v->cur_speed = u->First()->cur_speed;
01209         return false;
01210       }
01211     }
01212 
01213     uint32 r = VehicleEnterTile(v, tile, x, y);
01214     if (HasBit(r, VETS_CANNOT_ENTER)) {
01215       if (!IsTileType(tile, MP_TUNNELBRIDGE)) {
01216         v->cur_speed = 0;
01217         return false;
01218       }
01219       /* Try an about turn to re-enter the previous tile */
01220       dir = _road_reverse_table[rd.x & 3];
01221       goto again;
01222     }
01223 
01224     if (IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) && IsTileType(v->tile, MP_STATION)) {
01225       if (IsReversingRoadTrackdir(dir) && IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END)) {
01226         /* New direction is trying to turn vehicle around.
01227          * We can't turn at the exit of a road stop so wait.*/
01228         v->cur_speed = 0;
01229         return false;
01230       }
01231 
01232       /* If we are a drive through road stop and the next tile is of
01233        * the same road stop and the next tile isn't this one (i.e. we
01234        * are not reversing), then keep the reservation and state.
01235        * This way we will not be shortly unregister from the road
01236        * stop. It also makes it possible to load when on the edge of
01237        * two road stops; otherwise you could get vehicles that should
01238        * be loading but are not actually loading. */
01239       if (IsDriveThroughStopTile(v->tile) &&
01240           RoadStop::IsDriveThroughRoadStopContinuation(v->tile, tile) &&
01241           v->tile != tile) {
01242         /* So, keep 'our' state */
01243         dir = (Trackdir)v->state;
01244       } else if (IsRoadStop(v->tile)) {
01245         /* We're not continuing our drive through road stop, so leave. */
01246         RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile))->Leave(v);
01247       }
01248     }
01249 
01250     if (!HasBit(r, VETS_ENTERED_WORMHOLE)) {
01251       v->tile = tile;
01252       v->state = (byte)dir;
01253       v->frame = start_frame;
01254     }
01255     if (new_dir != v->direction) {
01256       v->direction = new_dir;
01257       if (_settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) v->cur_speed -= v->cur_speed >> 2;
01258     }
01259     v->x_pos = x;
01260     v->y_pos = y;
01261     RoadZPosAffectSpeed(v, v->UpdateInclination(true, true));
01262     return true;
01263   }
01264 
01265   if (rd.x & RDE_TURNED) {
01266     /* Vehicle has finished turning around, it will now head back onto the same tile */
01267     Trackdir dir;
01268     uint turn_around_start_frame = RVC_TURN_AROUND_START_FRAME;
01269 
01270     if (v->roadtype == ROADTYPE_TRAM && !IsRoadDepotTile(v->tile) && HasExactlyOneBit(GetAnyRoadBits(v->tile, ROADTYPE_TRAM, true))) {
01271       /*
01272        * The tram is turning around with one tram 'roadbit'. This means that
01273        * it is using the 'big' corner 'drive data'. However, to support the
01274        * trams to take a small corner, there is a 'turned' marker in the middle
01275        * of the turning 'drive data'. When the tram took the long corner, we
01276        * will still use the 'big' corner drive data, but we advance it one
01277        * frame. We furthermore set the driving direction so the turning is
01278        * going to be properly shown.
01279        */
01280       turn_around_start_frame = RVC_START_FRAME_AFTER_LONG_TRAM;
01281       switch (rd.x & 0x3) {
01282         default: NOT_REACHED();
01283         case DIAGDIR_NW: dir = TRACKDIR_RVREV_SE; break;
01284         case DIAGDIR_NE: dir = TRACKDIR_RVREV_SW; break;
01285         case DIAGDIR_SE: dir = TRACKDIR_RVREV_NW; break;
01286         case DIAGDIR_SW: dir = TRACKDIR_RVREV_NE; break;
01287       }
01288     } else {
01289       if (v->IsFrontEngine()) {
01290         /* If this is the front engine, look for the right path. */
01291         dir = RoadFindPathToDest(v, v->tile, (DiagDirection)(rd.x & 3));
01292       } else {
01293         dir = FollowPreviousRoadVehicle(v, prev, v->tile, (DiagDirection)(rd.x & 3), true);
01294       }
01295     }
01296 
01297     if (dir == INVALID_TRACKDIR) {
01298       v->cur_speed = 0;
01299       return false;
01300     }
01301 
01302     const RoadDriveEntry *rdp = _road_drive_data[v->roadtype][(_settings_game.vehicle.road_side << RVS_DRIVE_SIDE) + dir];
01303 
01304     int x = TileX(v->tile) * TILE_SIZE + rdp[turn_around_start_frame].x;
01305     int y = TileY(v->tile) * TILE_SIZE + rdp[turn_around_start_frame].y;
01306 
01307     Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
01308     if (v->IsFrontEngine() && RoadVehFindCloseTo(v, x, y, new_dir) != NULL) return false;
01309 
01310     uint32 r = VehicleEnterTile(v, v->tile, x, y);
01311     if (HasBit(r, VETS_CANNOT_ENTER)) {
01312       v->cur_speed = 0;
01313       return false;
01314     }
01315 
01316     v->state = dir;
01317     v->frame = turn_around_start_frame;
01318 
01319     if (new_dir != v->direction) {
01320       v->direction = new_dir;
01321       if (_settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) v->cur_speed -= v->cur_speed >> 2;
01322     }
01323 
01324     v->x_pos = x;
01325     v->y_pos = y;
01326     RoadZPosAffectSpeed(v, v->UpdateInclination(true, true));
01327     return true;
01328   }
01329 
01330   /* This vehicle is not in a wormhole and it hasn't entered a new tile. If
01331    * it's on a depot tile, check if it's time to activate the next vehicle in
01332    * the chain yet. */
01333   if (v->Next() != NULL && IsRoadDepotTile(v->tile)) {
01334     if (v->frame == v->gcache.cached_veh_length + RVC_DEPOT_START_FRAME) {
01335       RoadVehLeaveDepot(v->Next(), false);
01336     }
01337   }
01338 
01339   /* Calculate new position for the vehicle */
01340   int x = (v->x_pos & ~15) + (rd.x & 15);
01341   int y = (v->y_pos & ~15) + (rd.y & 15);
01342 
01343   Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
01344 
01345   if (v->IsFrontEngine() && !IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END)) {
01346     /* Vehicle is not in a road stop.
01347      * Check for another vehicle to overtake */
01348     RoadVehicle *u = RoadVehFindCloseTo(v, x, y, new_dir);
01349 
01350     if (u != NULL) {
01351       u = u->First();
01352       /* There is a vehicle in front overtake it if possible */
01353       if (v->overtaking == 0) RoadVehCheckOvertake(v, u);
01354       if (v->overtaking == 0) v->cur_speed = u->cur_speed;
01355 
01356       /* In case an RV is stopped in a road stop, why not try to load? */
01357       if (v->cur_speed == 0 && IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) &&
01358           v->current_order.ShouldStopAtStation(v, GetStationIndex(v->tile)) &&
01359           v->owner == GetTileOwner(v->tile) && !v->current_order.IsType(OT_LEAVESTATION) &&
01360           GetRoadStopType(v->tile) == (v->IsBus() ? ROADSTOP_BUS : ROADSTOP_TRUCK)) {
01361         Station *st = Station::GetByTile(v->tile);
01362         RoadVehArrivesAt(v, st);
01363         v->BeginLoading(st->index);
01364       }
01365       return false;
01366     }
01367   }
01368 
01369   Direction old_dir = v->direction;
01370   if (new_dir != old_dir) {
01371     v->direction = new_dir;
01372     if (_settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) v->cur_speed -= v->cur_speed >> 2;
01373     if (old_dir != v->state) {
01374       /* The vehicle is in a road stop */
01375       v->UpdateInclination(false, true);
01376       /* Note, return here means that the frame counter is not incremented
01377        * for vehicles changing direction in a road stop. This causes frames to
01378        * be repeated. (XXX) Is this intended? */
01379       return true;
01380     }
01381   }
01382 
01383   /* If the vehicle is in a normal road stop and the frame equals the stop frame OR
01384    * if the vehicle is in a drive-through road stop and this is the destination station
01385    * and it's the correct type of stop (bus or truck) and the frame equals the stop frame...
01386    * (the station test and stop type test ensure that other vehicles, using the road stop as
01387    * a through route, do not stop) */
01388   if (v->IsFrontEngine() && ((IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END) &&
01389       _road_stop_stop_frame[v->state - RVSB_IN_ROAD_STOP + (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)] == v->frame) ||
01390       (IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) &&
01391       v->current_order.ShouldStopAtStation(v, GetStationIndex(v->tile)) &&
01392       v->owner == GetTileOwner(v->tile) &&
01393       GetRoadStopType(v->tile) == (v->IsBus() ? ROADSTOP_BUS : ROADSTOP_TRUCK) &&
01394       v->frame == RVC_DRIVE_THROUGH_STOP_FRAME))) {
01395 
01396     RoadStop *rs = RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile));
01397     Station *st = Station::GetByTile(v->tile);
01398 
01399     /* Vehicle is at the stop position (at a bay) in a road stop.
01400      * Note, if vehicle is loading/unloading it has already been handled,
01401      * so if we get here the vehicle has just arrived or is just ready to leave. */
01402     if (!HasBit(v->state, RVS_ENTERED_STOP)) {
01403       /* Vehicle has arrived at a bay in a road stop */
01404 
01405       if (IsDriveThroughStopTile(v->tile)) {
01406         TileIndex next_tile = TILE_ADD(v->tile, TileOffsByDir(v->direction));
01407 
01408         /* Check if next inline bay is free and has compatible road. */
01409         if (RoadStop::IsDriveThroughRoadStopContinuation(v->tile, next_tile) && (GetRoadTypes(next_tile) & v->compatible_roadtypes) != 0) {
01410           v->frame++;
01411           v->x_pos = x;
01412           v->y_pos = y;
01413           RoadZPosAffectSpeed(v, v->UpdateInclination(true, false));
01414           return true;
01415         }
01416       }
01417 
01418       rs->SetEntranceBusy(false);
01419       SetBit(v->state, RVS_ENTERED_STOP);
01420 
01421       if (IsDriveThroughStopTile(v->tile) || (v->current_order.IsType(OT_GOTO_STATION) && v->current_order.GetDestination() == st->index)) {
01422         RoadVehArrivesAt(v, st);
01423         v->BeginLoading(st->index);
01424         return false;
01425       }
01426 
01427       v->last_station_visited = st->index;
01428     } else {
01429       /* Vehicle is ready to leave a bay in a road stop */
01430       if (rs->IsEntranceBusy()) {
01431         /* Road stop entrance is busy, so wait as there is nowhere else to go */
01432         v->cur_speed = 0;
01433         return false;
01434       }
01435       if (v->current_order.IsType(OT_LEAVESTATION)) v->current_order.Free();
01436     }
01437 
01438     if (IsStandardRoadStopTile(v->tile)) rs->SetEntranceBusy(true);
01439 
01440     StartRoadVehSound(v);
01441     SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
01442   }
01443 
01444   /* Check tile position conditions - i.e. stop position in depot,
01445    * entry onto bridge or into tunnel */
01446   uint32 r = VehicleEnterTile(v, v->tile, x, y);
01447   if (HasBit(r, VETS_CANNOT_ENTER)) {
01448     v->cur_speed = 0;
01449     return false;
01450   }
01451 
01452   if (v->current_order.IsType(OT_LEAVESTATION) && IsDriveThroughStopTile(v->tile)) {
01453     v->current_order.Free();
01454   }
01455 
01456   /* Move to next frame unless vehicle arrived at a stop position
01457    * in a depot or entered a tunnel/bridge */
01458   if (!HasBit(r, VETS_ENTERED_WORMHOLE)) v->frame++;
01459   v->x_pos = x;
01460   v->y_pos = y;
01461   RoadZPosAffectSpeed(v, v->UpdateInclination(false, true));
01462   return true;
01463 }
01464 
01465 static bool RoadVehController(RoadVehicle *v)
01466 {
01467   /* decrease counters */
01468   v->tick_counter++;
01469   v->current_order_time++;
01470   if (v->reverse_ctr != 0) v->reverse_ctr--;
01471 
01472   /* handle crashed */
01473   if (v->vehstatus & VS_CRASHED || RoadVehCheckTrainCrash(v)) {
01474     return RoadVehIsCrashed(v);
01475   }
01476 
01477   /* road vehicle has broken down? */
01478   if (v->HandleBreakdown()) return true;
01479   if (v->vehstatus & VS_STOPPED) return true;
01480 
01481   ProcessOrders(v);
01482   v->HandleLoading();
01483 
01484   if (v->current_order.IsType(OT_LOADING)) return true;
01485 
01486   if (v->IsInDepot() && RoadVehLeaveDepot(v, true)) return true;
01487 
01488   v->ShowVisualEffect();
01489 
01490   /* Check how far the vehicle needs to proceed */
01491   int j = v->UpdateSpeed();
01492 
01493   int adv_spd = v->GetAdvanceDistance();
01494   bool blocked = false;
01495   while (j >= adv_spd) {
01496     j -= adv_spd;
01497 
01498     RoadVehicle *u = v;
01499     for (RoadVehicle *prev = NULL; u != NULL; prev = u, u = u->Next()) {
01500       if (!IndividualRoadVehicleController(u, prev)) {
01501         blocked = true;
01502         break;
01503       }
01504     }
01505     if (blocked) break;
01506 
01507     /* Determine distance to next map position */
01508     adv_spd = v->GetAdvanceDistance();
01509 
01510     /* Test for a collision, but only if another movement will occur. */
01511     if (j >= adv_spd && RoadVehCheckTrainCrash(v)) break;
01512   }
01513 
01514   v->SetLastSpeed();
01515 
01516   for (RoadVehicle *u = v; u != NULL; u = u->Next()) {
01517     if ((u->vehstatus & VS_HIDDEN) != 0) continue;
01518 
01519     u->UpdateViewport(false, false);
01520   }
01521 
01522   /* If movement is blocked, set 'progress' to its maximum, so the roadvehicle does
01523    * not accelerate again before it can actually move. I.e. make sure it tries to advance again
01524    * on next tick to discover whether it is still blocked. */
01525   if (v->progress == 0) v->progress = blocked ? adv_spd - 1 : j;
01526 
01527   return true;
01528 }
01529 
01530 Money RoadVehicle::GetRunningCost() const
01531 {
01532   const Engine *e = Engine::Get(this->engine_type);
01533   if (e->u.road.running_cost_class == INVALID_PRICE) return 0;
01534 
01535   uint cost_factor = GetVehicleProperty(this, PROP_ROADVEH_RUNNING_COST_FACTOR, e->u.road.running_cost);
01536   if (cost_factor == 0) return 0;
01537 
01538   return GetPrice(e->u.road.running_cost_class, cost_factor, e->grf_prop.grffile);
01539 }
01540 
01541 bool RoadVehicle::Tick()
01542 {
01543   if (this->IsFrontEngine()) {
01544     if (!(this->vehstatus & VS_STOPPED)) this->running_ticks++;
01545     return RoadVehController(this);
01546   }
01547 
01548   return true;
01549 }
01550 
01551 static void CheckIfRoadVehNeedsService(RoadVehicle *v)
01552 {
01553   /* If we already got a slot at a stop, use that FIRST, and go to a depot later */
01554   if (Company::Get(v->owner)->settings.vehicle.servint_roadveh == 0 || !v->NeedsAutomaticServicing()) return;
01555   if (v->IsInDepot()) {
01556     VehicleServiceInDepot(v);
01557     return;
01558   }
01559 
01560   uint max_penalty;
01561   switch (_settings_game.pf.pathfinder_for_roadvehs) {
01562     case VPF_NPF:  max_penalty = _settings_game.pf.npf.maximum_go_to_depot_penalty;  break;
01563     case VPF_YAPF: max_penalty = _settings_game.pf.yapf.maximum_go_to_depot_penalty; break;
01564     default: NOT_REACHED();
01565   }
01566 
01567   FindDepotData rfdd = FindClosestRoadDepot(v, max_penalty);
01568   /* Only go to the depot if it is not too far out of our way. */
01569   if (rfdd.best_length == UINT_MAX || rfdd.best_length > max_penalty) {
01570     if (v->current_order.IsType(OT_GOTO_DEPOT)) {
01571       /* If we were already heading for a depot but it has
01572        * suddenly moved farther away, we continue our normal
01573        * schedule? */
01574       v->current_order.MakeDummy();
01575       SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
01576     }
01577     return;
01578   }
01579 
01580   DepotID depot = GetDepotIndex(rfdd.tile);
01581 
01582   if (v->current_order.IsType(OT_GOTO_DEPOT) &&
01583       v->current_order.GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS &&
01584       !Chance16(1, 20)) {
01585     return;
01586   }
01587 
01588   SetBit(v->gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
01589   v->current_order.MakeGoToDepot(depot, ODTFB_SERVICE);
01590   v->dest_tile = rfdd.tile;
01591   SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
01592 }
01593 
01594 void RoadVehicle::OnNewDay()
01595 {
01596   if (!this->IsFrontEngine()) return;
01597 
01598   if ((++this->day_counter & 7) == 0) DecreaseVehicleValue(this);
01599   if (this->blocked_ctr == 0) CheckVehicleBreakdown(this);
01600 
01601   AgeVehicle(this);
01602   CheckIfRoadVehNeedsService(this);
01603 
01604   CheckOrders(this);
01605 
01606   if (this->running_ticks == 0) return;
01607 
01608   CommandCost cost(EXPENSES_ROADVEH_RUN, this->GetRunningCost() * this->running_ticks / (DAYS_IN_YEAR * DAY_TICKS));
01609 
01610   this->profit_this_year -= cost.GetCost();
01611   this->running_ticks = 0;
01612 
01613   SubtractMoneyFromCompanyFract(this->owner, cost);
01614 
01615   SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
01616   SetWindowClassesDirty(WC_ROADVEH_LIST);
01617 }
01618 
01619 Trackdir RoadVehicle::GetVehicleTrackdir() const
01620 {
01621   if (this->vehstatus & VS_CRASHED) return INVALID_TRACKDIR;
01622 
01623   if (this->IsInDepot()) {
01624     /* We'll assume the road vehicle is facing outwards */
01625     return DiagDirToDiagTrackdir(GetRoadDepotDirection(this->tile));
01626   }
01627 
01628   if (IsStandardRoadStopTile(this->tile)) {
01629     /* We'll assume the road vehicle is facing outwards */
01630     return DiagDirToDiagTrackdir(GetRoadStopDir(this->tile)); // Road vehicle in a station
01631   }
01632 
01633   /* Drive through road stops / wormholes (tunnels) */
01634   if (this->state > RVSB_TRACKDIR_MASK) return DiagDirToDiagTrackdir(DirToDiagDir(this->direction));
01635 
01636   /* If vehicle's state is a valid track direction (vehicle is not turning around) return it,
01637    * otherwise transform it into a valid track direction */
01638   return (Trackdir)((IsReversingRoadTrackdir((Trackdir)this->state)) ? (this->state - 6) : this->state);
01639 }

Generated on Fri Jun 3 05:18:57 2011 for OpenTTD by  doxygen 1.6.1