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

Generated on Fri May 27 04:19:47 2011 for OpenTTD by  doxygen 1.6.1