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

Generated on Thu Apr 14 00:48:18 2011 for OpenTTD by  doxygen 1.6.1