roadveh_cmd.cpp

Go to the documentation of this file.
00001 /* $Id: roadveh_cmd.cpp 22392 2011-04-30 20:46:58Z rubidium $ */
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),
00376     MKIT(3, 7, -1, -3),
00377     MKIT(3, 3, -1, -1),
00378     MKIT(7, 3, -3, -1),
00379     MKIT(3, 3, -1, -1),
00380     MKIT(3, 7, -1, -3),
00381     MKIT(3, 3, -1, -1),
00382     MKIT(7, 3, -3, -1),
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     /* We are leaving a depot, but have to go to the exact same one; re-enter */
00945     if (v->current_order.IsType(OT_GOTO_DEPOT) && v->tile == v->dest_tile) {
00946       VehicleEnterDepot(v);
00947       return true;
00948     }
00949 
00950     if (RoadVehFindCloseTo(v, x, y, v->direction, false) != NULL) return true;
00951 
00952     VehicleServiceInDepot(v);
00953 
00954     StartRoadVehSound(v);
00955 
00956     /* Vehicle is about to leave a depot */
00957     v->cur_speed = 0;
00958   }
00959 
00960   v->vehstatus &= ~VS_HIDDEN;
00961   v->state = tdir;
00962   v->frame = RVC_DEPOT_START_FRAME;
00963 
00964   v->x_pos = x;
00965   v->y_pos = y;
00966   v->UpdateInclination(true, true);
00967 
00968   InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
00969 
00970   return true;
00971 }
00972 
00973 static Trackdir FollowPreviousRoadVehicle(const RoadVehicle *v, const RoadVehicle *prev, TileIndex tile, DiagDirection entry_dir, bool already_reversed)
00974 {
00975   if (prev->tile == v->tile && !already_reversed) {
00976     /* If the previous vehicle is on the same tile as this vehicle is
00977      * then it must have reversed. */
00978     return _road_reverse_table[entry_dir];
00979   }
00980 
00981   byte prev_state = prev->state;
00982   Trackdir dir;
00983 
00984   if (prev_state == RVSB_WORMHOLE || prev_state == RVSB_IN_DEPOT) {
00985     DiagDirection diag_dir = INVALID_DIAGDIR;
00986 
00987     if (IsTileType(tile, MP_TUNNELBRIDGE)) {
00988       diag_dir = GetTunnelBridgeDirection(tile);
00989     } else if (IsRoadDepotTile(tile)) {
00990       diag_dir = ReverseDiagDir(GetRoadDepotDirection(tile));
00991     }
00992 
00993     if (diag_dir == INVALID_DIAGDIR) return INVALID_TRACKDIR;
00994     dir = DiagDirToDiagTrackdir(diag_dir);
00995   } else {
00996     if (already_reversed && prev->tile != tile) {
00997       /*
00998        * The vehicle has reversed, but did not go straight back.
00999        * It immediately turn onto another tile. This means that
01000        * the roadstate of the previous vehicle cannot be used
01001        * as the direction we have to go with this vehicle.
01002        *
01003        * Next table is build in the following way:
01004        *  - first row for when the vehicle in front went to the northern or
01005        *    western tile, second for southern and eastern.
01006        *  - columns represent the entry direction.
01007        *  - cell values are determined by the Trackdir one has to take from
01008        *    the entry dir (column) to the tile in north or south by only
01009        *    going over the trackdirs used for turning 90 degrees, i.e.
01010        *    TRACKDIR_{UPPER,RIGHT,LOWER,LEFT}_{N,E,S,W}.
01011        */
01012       static const Trackdir reversed_turn_lookup[2][DIAGDIR_END] = {
01013         { TRACKDIR_UPPER_W, TRACKDIR_RIGHT_N, TRACKDIR_LEFT_N,  TRACKDIR_UPPER_E },
01014         { TRACKDIR_RIGHT_S, TRACKDIR_LOWER_W, TRACKDIR_LOWER_E, TRACKDIR_LEFT_S  }};
01015       dir = reversed_turn_lookup[prev->tile < tile ? 0 : 1][ReverseDiagDir(entry_dir)];
01016     } else if (HasBit(prev_state, RVS_IN_DT_ROAD_STOP)) {
01017       dir = (Trackdir)(prev_state & RVSB_ROAD_STOP_TRACKDIR_MASK);
01018     } else if (prev_state < TRACKDIR_END) {
01019       dir = (Trackdir)prev_state;
01020     } else {
01021       return INVALID_TRACKDIR;
01022     }
01023   }
01024 
01025   /* Do some sanity checking. */
01026   static const RoadBits required_roadbits[] = {
01027     ROAD_X,            ROAD_Y,            ROAD_NW | ROAD_NE, ROAD_SW | ROAD_SE,
01028     ROAD_NW | ROAD_SW, ROAD_NE | ROAD_SE, ROAD_X,            ROAD_Y
01029   };
01030   RoadBits required = required_roadbits[dir & 0x07];
01031 
01032   if ((required & GetAnyRoadBits(tile, v->roadtype, true)) == ROAD_NONE) {
01033     dir = INVALID_TRACKDIR;
01034   }
01035 
01036   return dir;
01037 }
01038 
01046 static bool CanBuildTramTrackOnTile(CompanyID c, TileIndex t, RoadBits r)
01047 {
01048   /* The 'current' company is not necessarily the owner of the vehicle. */
01049   Backup<CompanyByte> cur_company(_current_company, c, FILE_LINE);
01050 
01051   CommandCost ret = DoCommand(t, ROADTYPE_TRAM << 4 | r, 0, DC_NONE, CMD_BUILD_ROAD);
01052 
01053   cur_company.Restore();
01054   return ret.Succeeded();
01055 }
01056 
01057 static bool IndividualRoadVehicleController(RoadVehicle *v, const RoadVehicle *prev)
01058 {
01059   if (v->overtaking != 0)  {
01060     if (IsTileType(v->tile, MP_STATION)) {
01061       /* Force us to be not overtaking! */
01062       v->overtaking = 0;
01063     } else if (++v->overtaking_ctr >= RV_OVERTAKE_TIMEOUT) {
01064       /* If overtaking just aborts at a random moment, we can have a out-of-bound problem,
01065        *  if the vehicle started a corner. To protect that, only allow an abort of
01066        *  overtake if we are on straight roads */
01067       if (v->state < RVSB_IN_ROAD_STOP && IsStraightRoadTrackdir((Trackdir)v->state)) {
01068         v->overtaking = 0;
01069       }
01070     }
01071   }
01072 
01073   /* If this vehicle is in a depot and we've reached this point it must be
01074    * one of the articulated parts. It will stay in the depot until activated
01075    * by the previous vehicle in the chain when it gets to the right place. */
01076   if (v->IsInDepot()) return true;
01077 
01078   if (v->state == RVSB_WORMHOLE) {
01079     /* Vehicle is entering a depot or is on a bridge or in a tunnel */
01080     GetNewVehiclePosResult gp = GetNewVehiclePos(v);
01081 
01082     /* Apply bridge speed limit */
01083     if (!(v->vehstatus & VS_HIDDEN)) {
01084       RoadVehicle *first = v->First();
01085       first->cur_speed = min(first->cur_speed, GetBridgeSpec(GetBridgeType(v->tile))->speed * 2);
01086     }
01087 
01088     if (v->IsFrontEngine()) {
01089       const Vehicle *u = RoadVehFindCloseTo(v, gp.x, gp.y, v->direction);
01090       if (u != NULL) {
01091         v->cur_speed = u->First()->cur_speed;
01092         return false;
01093       }
01094     }
01095 
01096     if (IsTileType(gp.new_tile, MP_TUNNELBRIDGE) && HasBit(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y), VETS_ENTERED_WORMHOLE)) {
01097       /* Vehicle has just entered a bridge or tunnel */
01098       v->x_pos = gp.x;
01099       v->y_pos = gp.y;
01100       v->UpdateInclination(true, true);
01101       return true;
01102     }
01103 
01104     v->x_pos = gp.x;
01105     v->y_pos = gp.y;
01106     VehicleMove(v, !(v->vehstatus & VS_HIDDEN));
01107     return true;
01108   }
01109 
01110   /* Get move position data for next frame.
01111    * For a drive-through road stop use 'straight road' move data.
01112    * In this case v->state is masked to give the road stop entry direction. */
01113   RoadDriveEntry rd = _road_drive_data[v->roadtype][(
01114     (HasBit(v->state, RVS_IN_DT_ROAD_STOP) ? v->state & RVSB_ROAD_STOP_TRACKDIR_MASK : v->state) +
01115     (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)) ^ v->overtaking][v->frame + 1];
01116 
01117   if (rd.x & RDE_NEXT_TILE) {
01118     TileIndex tile = v->tile + TileOffsByDiagDir((DiagDirection)(rd.x & 3));
01119     Trackdir dir;
01120 
01121     if (v->IsFrontEngine()) {
01122       /* If this is the front engine, look for the right path. */
01123       dir = RoadFindPathToDest(v, tile, (DiagDirection)(rd.x & 3));
01124     } else {
01125       dir = FollowPreviousRoadVehicle(v, prev, tile, (DiagDirection)(rd.x & 3), false);
01126     }
01127 
01128     if (dir == INVALID_TRACKDIR) {
01129       if (!v->IsFrontEngine()) error("Disconnecting road vehicle.");
01130       v->cur_speed = 0;
01131       return false;
01132     }
01133 
01134 again:
01135     uint start_frame = RVC_DEFAULT_START_FRAME;
01136     if (IsReversingRoadTrackdir(dir)) {
01137       /* When turning around we can't be overtaking. */
01138       v->overtaking = 0;
01139 
01140       /* Turning around */
01141       if (v->roadtype == ROADTYPE_TRAM) {
01142         /* Determine the road bits the tram needs to be able to turn around
01143          * using the 'big' corner loop. */
01144         RoadBits needed;
01145         switch (dir) {
01146           default: NOT_REACHED();
01147           case TRACKDIR_RVREV_NE: needed = ROAD_SW; break;
01148           case TRACKDIR_RVREV_SE: needed = ROAD_NW; break;
01149           case TRACKDIR_RVREV_SW: needed = ROAD_NE; break;
01150           case TRACKDIR_RVREV_NW: needed = ROAD_SE; break;
01151         }
01152         if ((v->Previous() != NULL && v->Previous()->tile == tile) ||
01153             (v->IsFrontEngine() && IsNormalRoadTile(tile) && !HasRoadWorks(tile) &&
01154               (needed & GetRoadBits(tile, ROADTYPE_TRAM)) != ROAD_NONE)) {
01155           /*
01156            * Taking the 'big' corner for trams only happens when:
01157            * - The previous vehicle in this (articulated) tram chain is
01158            *   already on the 'next' tile, we just follow them regardless of
01159            *   anything. When it is NOT on the 'next' tile, the tram started
01160            *   doing a reversing turn when the piece of tram track on the next
01161            *   tile did not exist yet. Do not use the big tram loop as that is
01162            *   going to cause the tram to split up.
01163            * - Or the front of the tram can drive over the next tile.
01164            */
01165         } else if (!v->IsFrontEngine() || !CanBuildTramTrackOnTile(v->owner, tile, needed) || ((~needed & GetAnyRoadBits(v->tile, ROADTYPE_TRAM, false)) == ROAD_NONE)) {
01166           /*
01167            * Taking the 'small' corner for trams only happens when:
01168            * - We are not the from vehicle of an articulated tram.
01169            * - Or when the company cannot build on the next tile.
01170            *
01171            * The 'small' corner means that the vehicle is on the end of a
01172            * tram track and needs to start turning there. To do this properly
01173            * the tram needs to start at an offset in the tram turning 'code'
01174            * for 'big' corners. It furthermore does not go to the next tile,
01175            * so that needs to be fixed too.
01176            */
01177           tile = v->tile;
01178           start_frame = RVC_TURN_AROUND_START_FRAME_SHORT_TRAM;
01179         } else {
01180           /* The company can build on the next tile, so wait till (s)he does. */
01181           v->cur_speed = 0;
01182           return false;
01183         }
01184       } else if (IsNormalRoadTile(v->tile) && GetDisallowedRoadDirections(v->tile) != DRD_NONE) {
01185         v->cur_speed = 0;
01186         return false;
01187       } else {
01188         tile = v->tile;
01189       }
01190     }
01191 
01192     /* Get position data for first frame on the new tile */
01193     const RoadDriveEntry *rdp = _road_drive_data[v->roadtype][(dir + (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)) ^ v->overtaking];
01194 
01195     int x = TileX(tile) * TILE_SIZE + rdp[start_frame].x;
01196     int y = TileY(tile) * TILE_SIZE + rdp[start_frame].y;
01197 
01198     Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
01199     if (v->IsFrontEngine()) {
01200       Vehicle *u = RoadVehFindCloseTo(v, x, y, new_dir);
01201       if (u != NULL) {
01202         v->cur_speed = u->First()->cur_speed;
01203         return false;
01204       }
01205     }
01206 
01207     uint32 r = VehicleEnterTile(v, tile, x, y);
01208     if (HasBit(r, VETS_CANNOT_ENTER)) {
01209       if (!IsTileType(tile, MP_TUNNELBRIDGE)) {
01210         v->cur_speed = 0;
01211         return false;
01212       }
01213       /* Try an about turn to re-enter the previous tile */
01214       dir = _road_reverse_table[rd.x & 3];
01215       goto again;
01216     }
01217 
01218     if (IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) && IsTileType(v->tile, MP_STATION)) {
01219       if (IsReversingRoadTrackdir(dir) && IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END)) {
01220         /* New direction is trying to turn vehicle around.
01221          * We can't turn at the exit of a road stop so wait.*/
01222         v->cur_speed = 0;
01223         return false;
01224       }
01225 
01226       /* If we are a drive through road stop and the next tile is of
01227        * the same road stop and the next tile isn't this one (i.e. we
01228        * are not reversing), then keep the reservation and state.
01229        * This way we will not be shortly unregister from the road
01230        * stop. It also makes it possible to load when on the edge of
01231        * two road stops; otherwise you could get vehicles that should
01232        * be loading but are not actually loading. */
01233       if (IsDriveThroughStopTile(v->tile) &&
01234           RoadStop::IsDriveThroughRoadStopContinuation(v->tile, tile) &&
01235           v->tile != tile) {
01236         /* So, keep 'our' state */
01237         dir = (Trackdir)v->state;
01238       } else if (IsRoadStop(v->tile)) {
01239         /* We're not continuing our drive through road stop, so leave. */
01240         RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile))->Leave(v);
01241       }
01242     }
01243 
01244     if (!HasBit(r, VETS_ENTERED_WORMHOLE)) {
01245       v->tile = tile;
01246       v->state = (byte)dir;
01247       v->frame = start_frame;
01248     }
01249     if (new_dir != v->direction) {
01250       v->direction = new_dir;
01251       if (_settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) v->cur_speed -= v->cur_speed >> 2;
01252     }
01253     v->x_pos = x;
01254     v->y_pos = y;
01255     RoadZPosAffectSpeed(v, v->UpdateInclination(true, true));
01256     return true;
01257   }
01258 
01259   if (rd.x & RDE_TURNED) {
01260     /* Vehicle has finished turning around, it will now head back onto the same tile */
01261     Trackdir dir;
01262     uint turn_around_start_frame = RVC_TURN_AROUND_START_FRAME;
01263 
01264     if (v->roadtype == ROADTYPE_TRAM && !IsRoadDepotTile(v->tile) && HasExactlyOneBit(GetAnyRoadBits(v->tile, ROADTYPE_TRAM, true))) {
01265       /*
01266        * The tram is turning around with one tram 'roadbit'. This means that
01267        * it is using the 'big' corner 'drive data'. However, to support the
01268        * trams to take a small corner, there is a 'turned' marker in the middle
01269        * of the turning 'drive data'. When the tram took the long corner, we
01270        * will still use the 'big' corner drive data, but we advance it one
01271        * frame. We furthermore set the driving direction so the turning is
01272        * going to be properly shown.
01273        */
01274       turn_around_start_frame = RVC_START_FRAME_AFTER_LONG_TRAM;
01275       switch (rd.x & 0x3) {
01276         default: NOT_REACHED();
01277         case DIAGDIR_NW: dir = TRACKDIR_RVREV_SE; break;
01278         case DIAGDIR_NE: dir = TRACKDIR_RVREV_SW; break;
01279         case DIAGDIR_SE: dir = TRACKDIR_RVREV_NW; break;
01280         case DIAGDIR_SW: dir = TRACKDIR_RVREV_NE; break;
01281       }
01282     } else {
01283       if (v->IsFrontEngine()) {
01284         /* If this is the front engine, look for the right path. */
01285         dir = RoadFindPathToDest(v, v->tile, (DiagDirection)(rd.x & 3));
01286       } else {
01287         dir = FollowPreviousRoadVehicle(v, prev, v->tile, (DiagDirection)(rd.x & 3), true);
01288       }
01289     }
01290 
01291     if (dir == INVALID_TRACKDIR) {
01292       v->cur_speed = 0;
01293       return false;
01294     }
01295 
01296     const RoadDriveEntry *rdp = _road_drive_data[v->roadtype][(_settings_game.vehicle.road_side << RVS_DRIVE_SIDE) + dir];
01297 
01298     int x = TileX(v->tile) * TILE_SIZE + rdp[turn_around_start_frame].x;
01299     int y = TileY(v->tile) * TILE_SIZE + rdp[turn_around_start_frame].y;
01300 
01301     Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
01302     if (v->IsFrontEngine() && RoadVehFindCloseTo(v, x, y, new_dir) != NULL) return false;
01303 
01304     uint32 r = VehicleEnterTile(v, v->tile, x, y);
01305     if (HasBit(r, VETS_CANNOT_ENTER)) {
01306       v->cur_speed = 0;
01307       return false;
01308     }
01309 
01310     v->state = dir;
01311     v->frame = turn_around_start_frame;
01312 
01313     if (new_dir != v->direction) {
01314       v->direction = new_dir;
01315       if (_settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) v->cur_speed -= v->cur_speed >> 2;
01316     }
01317 
01318     v->x_pos = x;
01319     v->y_pos = y;
01320     RoadZPosAffectSpeed(v, v->UpdateInclination(true, true));
01321     return true;
01322   }
01323 
01324   /* This vehicle is not in a wormhole and it hasn't entered a new tile. If
01325    * it's on a depot tile, check if it's time to activate the next vehicle in
01326    * the chain yet. */
01327   if (v->Next() != NULL && IsRoadDepotTile(v->tile)) {
01328     if (v->frame == v->gcache.cached_veh_length + RVC_DEPOT_START_FRAME) {
01329       RoadVehLeaveDepot(v->Next(), false);
01330     }
01331   }
01332 
01333   /* Calculate new position for the vehicle */
01334   int x = (v->x_pos & ~15) + (rd.x & 15);
01335   int y = (v->y_pos & ~15) + (rd.y & 15);
01336 
01337   Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
01338 
01339   if (v->IsFrontEngine() && !IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END)) {
01340     /* Vehicle is not in a road stop.
01341      * Check for another vehicle to overtake */
01342     RoadVehicle *u = RoadVehFindCloseTo(v, x, y, new_dir);
01343 
01344     if (u != NULL) {
01345       u = u->First();
01346       /* There is a vehicle in front overtake it if possible */
01347       if (v->overtaking == 0) RoadVehCheckOvertake(v, u);
01348       if (v->overtaking == 0) v->cur_speed = u->cur_speed;
01349 
01350       /* In case an RV is stopped in a road stop, why not try to load? */
01351       if (v->cur_speed == 0 && IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) &&
01352           v->current_order.ShouldStopAtStation(v, GetStationIndex(v->tile)) &&
01353           v->owner == GetTileOwner(v->tile) && !v->current_order.IsType(OT_LEAVESTATION) &&
01354           GetRoadStopType(v->tile) == (v->IsBus() ? ROADSTOP_BUS : ROADSTOP_TRUCK)) {
01355         Station *st = Station::GetByTile(v->tile);
01356         v->last_station_visited = st->index;
01357         RoadVehArrivesAt(v, st);
01358         v->BeginLoading();
01359       }
01360       return false;
01361     }
01362   }
01363 
01364   Direction old_dir = v->direction;
01365   if (new_dir != old_dir) {
01366     v->direction = new_dir;
01367     if (_settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) v->cur_speed -= v->cur_speed >> 2;
01368     if (old_dir != v->state) {
01369       /* The vehicle is in a road stop */
01370       v->UpdateInclination(false, true);
01371       /* Note, return here means that the frame counter is not incremented
01372        * for vehicles changing direction in a road stop. This causes frames to
01373        * be repeated. (XXX) Is this intended? */
01374       return true;
01375     }
01376   }
01377 
01378   /* If the vehicle is in a normal road stop and the frame equals the stop frame OR
01379    * if the vehicle is in a drive-through road stop and this is the destination station
01380    * and it's the correct type of stop (bus or truck) and the frame equals the stop frame...
01381    * (the station test and stop type test ensure that other vehicles, using the road stop as
01382    * a through route, do not stop) */
01383   if (v->IsFrontEngine() && ((IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END) &&
01384       _road_stop_stop_frame[v->state - RVSB_IN_ROAD_STOP + (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)] == v->frame) ||
01385       (IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) &&
01386       v->current_order.ShouldStopAtStation(v, GetStationIndex(v->tile)) &&
01387       v->owner == GetTileOwner(v->tile) &&
01388       GetRoadStopType(v->tile) == (v->IsBus() ? ROADSTOP_BUS : ROADSTOP_TRUCK) &&
01389       v->frame == RVC_DRIVE_THROUGH_STOP_FRAME))) {
01390 
01391     RoadStop *rs = RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile));
01392     Station *st = Station::GetByTile(v->tile);
01393 
01394     /* Vehicle is at the stop position (at a bay) in a road stop.
01395      * Note, if vehicle is loading/unloading it has already been handled,
01396      * so if we get here the vehicle has just arrived or is just ready to leave. */
01397     if (!HasBit(v->state, RVS_ENTERED_STOP)) {
01398       /* Vehicle has arrived at a bay in a road stop */
01399 
01400       if (IsDriveThroughStopTile(v->tile)) {
01401         TileIndex next_tile = TILE_ADD(v->tile, TileOffsByDir(v->direction));
01402 
01403         /* Check if next inline bay is free and has compatible road. */
01404         if (RoadStop::IsDriveThroughRoadStopContinuation(v->tile, next_tile) && (GetRoadTypes(next_tile) & v->compatible_roadtypes) != 0) {
01405           v->frame++;
01406           v->x_pos = x;
01407           v->y_pos = y;
01408           RoadZPosAffectSpeed(v, v->UpdateInclination(true, false));
01409           return true;
01410         }
01411       }
01412 
01413       rs->SetEntranceBusy(false);
01414       SetBit(v->state, RVS_ENTERED_STOP);
01415 
01416       v->last_station_visited = st->index;
01417 
01418       if (IsDriveThroughStopTile(v->tile) || (v->current_order.IsType(OT_GOTO_STATION) && v->current_order.GetDestination() == st->index)) {
01419         RoadVehArrivesAt(v, st);
01420         v->BeginLoading();
01421         return false;
01422       }
01423     } else {
01424       /* Vehicle is ready to leave a bay in a road stop */
01425       if (rs->IsEntranceBusy()) {
01426         /* Road stop entrance is busy, so wait as there is nowhere else to go */
01427         v->cur_speed = 0;
01428         return false;
01429       }
01430       if (v->current_order.IsType(OT_LEAVESTATION)) v->current_order.Free();
01431     }
01432 
01433     if (IsStandardRoadStopTile(v->tile)) rs->SetEntranceBusy(true);
01434 
01435     StartRoadVehSound(v);
01436     SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
01437   }
01438 
01439   /* Check tile position conditions - i.e. stop position in depot,
01440    * entry onto bridge or into tunnel */
01441   uint32 r = VehicleEnterTile(v, v->tile, x, y);
01442   if (HasBit(r, VETS_CANNOT_ENTER)) {
01443     v->cur_speed = 0;
01444     return false;
01445   }
01446 
01447   if (v->current_order.IsType(OT_LEAVESTATION) && IsDriveThroughStopTile(v->tile)) {
01448     v->current_order.Free();
01449   }
01450 
01451   /* Move to next frame unless vehicle arrived at a stop position
01452    * in a depot or entered a tunnel/bridge */
01453   if (!HasBit(r, VETS_ENTERED_WORMHOLE)) v->frame++;
01454   v->x_pos = x;
01455   v->y_pos = y;
01456   RoadZPosAffectSpeed(v, v->UpdateInclination(false, true));
01457   return true;
01458 }
01459 
01460 static bool RoadVehController(RoadVehicle *v)
01461 {
01462   /* decrease counters */
01463   v->tick_counter++;
01464   v->current_order_time++;
01465   if (v->reverse_ctr != 0) v->reverse_ctr--;
01466 
01467   /* handle crashed */
01468   if (v->vehstatus & VS_CRASHED || RoadVehCheckTrainCrash(v)) {
01469     return RoadVehIsCrashed(v);
01470   }
01471 
01472   /* road vehicle has broken down? */
01473   if (v->HandleBreakdown()) return true;
01474   if (v->vehstatus & VS_STOPPED) return true;
01475 
01476   ProcessOrders(v);
01477   v->HandleLoading();
01478 
01479   if (v->current_order.IsType(OT_LOADING)) return true;
01480 
01481   if (v->IsInDepot() && RoadVehLeaveDepot(v, true)) return true;
01482 
01483   v->ShowVisualEffect();
01484 
01485   /* Check how far the vehicle needs to proceed */
01486   int j = v->UpdateSpeed();
01487 
01488   int adv_spd = v->GetAdvanceDistance();
01489   bool blocked = false;
01490   while (j >= adv_spd) {
01491     j -= adv_spd;
01492 
01493     RoadVehicle *u = v;
01494     for (RoadVehicle *prev = NULL; u != NULL; prev = u, u = u->Next()) {
01495       if (!IndividualRoadVehicleController(u, prev)) {
01496         blocked = true;
01497         break;
01498       }
01499     }
01500     if (blocked) break;
01501 
01502     /* Determine distance to next map position */
01503     adv_spd = v->GetAdvanceDistance();
01504 
01505     /* Test for a collision, but only if another movement will occur. */
01506     if (j >= adv_spd && RoadVehCheckTrainCrash(v)) break;
01507   }
01508 
01509   v->SetLastSpeed();
01510 
01511   for (RoadVehicle *u = v; u != NULL; u = u->Next()) {
01512     if ((u->vehstatus & VS_HIDDEN) != 0) continue;
01513 
01514     u->UpdateViewport(false, false);
01515   }
01516 
01517   /* If movement is blocked, set 'progress' to its maximum, so the roadvehicle does
01518    * not accelerate again before it can actually move. I.e. make sure it tries to advance again
01519    * on next tick to discover whether it is still blocked. */
01520   if (v->progress == 0) v->progress = blocked ? adv_spd - 1 : j;
01521 
01522   return true;
01523 }
01524 
01525 Money RoadVehicle::GetRunningCost() const
01526 {
01527   const Engine *e = Engine::Get(this->engine_type);
01528   if (e->u.road.running_cost_class == INVALID_PRICE) return 0;
01529 
01530   uint cost_factor = GetVehicleProperty(this, PROP_ROADVEH_RUNNING_COST_FACTOR, e->u.road.running_cost);
01531   if (cost_factor == 0) return 0;
01532 
01533   return GetPrice(e->u.road.running_cost_class, cost_factor, e->grf_prop.grffile);
01534 }
01535 
01536 bool RoadVehicle::Tick()
01537 {
01538   if (this->IsFrontEngine()) {
01539     if (!(this->vehstatus & VS_STOPPED)) this->running_ticks++;
01540     return RoadVehController(this);
01541   }
01542 
01543   return true;
01544 }
01545 
01546 static void CheckIfRoadVehNeedsService(RoadVehicle *v)
01547 {
01548   /* If we already got a slot at a stop, use that FIRST, and go to a depot later */
01549   if (Company::Get(v->owner)->settings.vehicle.servint_roadveh == 0 || !v->NeedsAutomaticServicing()) return;
01550   if (v->IsInDepot()) {
01551     VehicleServiceInDepot(v);
01552     return;
01553   }
01554 
01555   uint max_penalty;
01556   switch (_settings_game.pf.pathfinder_for_roadvehs) {
01557     case VPF_NPF:  max_penalty = _settings_game.pf.npf.maximum_go_to_depot_penalty;  break;
01558     case VPF_YAPF: max_penalty = _settings_game.pf.yapf.maximum_go_to_depot_penalty; break;
01559     default: NOT_REACHED();
01560   }
01561 
01562   FindDepotData rfdd = FindClosestRoadDepot(v, max_penalty);
01563   /* Only go to the depot if it is not too far out of our way. */
01564   if (rfdd.best_length == UINT_MAX || rfdd.best_length > max_penalty) {
01565     if (v->current_order.IsType(OT_GOTO_DEPOT)) {
01566       /* If we were already heading for a depot but it has
01567        * suddenly moved farther away, we continue our normal
01568        * schedule? */
01569       v->current_order.MakeDummy();
01570       SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
01571     }
01572     return;
01573   }
01574 
01575   DepotID depot = GetDepotIndex(rfdd.tile);
01576 
01577   if (v->current_order.IsType(OT_GOTO_DEPOT) &&
01578       v->current_order.GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS &&
01579       !Chance16(1, 20)) {
01580     return;
01581   }
01582 
01583   SetBit(v->gv_flags, GVF_SUPPRESS_AUTOMATIC_ORDERS);
01584   v->current_order.MakeGoToDepot(depot, ODTFB_SERVICE);
01585   v->dest_tile = rfdd.tile;
01586   SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
01587 }
01588 
01589 void RoadVehicle::OnNewDay()
01590 {
01591   if (!this->IsFrontEngine()) return;
01592 
01593   if ((++this->day_counter & 7) == 0) DecreaseVehicleValue(this);
01594   if (this->blocked_ctr == 0) CheckVehicleBreakdown(this);
01595 
01596   AgeVehicle(this);
01597   CheckIfRoadVehNeedsService(this);
01598 
01599   CheckOrders(this);
01600 
01601   if (this->running_ticks == 0) return;
01602 
01603   CommandCost cost(EXPENSES_ROADVEH_RUN, this->GetRunningCost() * this->running_ticks / (DAYS_IN_YEAR * DAY_TICKS));
01604 
01605   this->profit_this_year -= cost.GetCost();
01606   this->running_ticks = 0;
01607 
01608   SubtractMoneyFromCompanyFract(this->owner, cost);
01609 
01610   SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
01611   SetWindowClassesDirty(WC_ROADVEH_LIST);
01612 }
01613 
01614 Trackdir RoadVehicle::GetVehicleTrackdir() const
01615 {
01616   if (this->vehstatus & VS_CRASHED) return INVALID_TRACKDIR;
01617 
01618   if (this->IsInDepot()) {
01619     /* We'll assume the road vehicle is facing outwards */
01620     return DiagDirToDiagTrackdir(GetRoadDepotDirection(this->tile));
01621   }
01622 
01623   if (IsStandardRoadStopTile(this->tile)) {
01624     /* We'll assume the road vehicle is facing outwards */
01625     return DiagDirToDiagTrackdir(GetRoadStopDir(this->tile)); // Road vehicle in a station
01626   }
01627 
01628   /* Drive through road stops / wormholes (tunnels) */
01629   if (this->state > RVSB_TRACKDIR_MASK) return DiagDirToDiagTrackdir(DirToDiagDir(this->direction));
01630 
01631   /* If vehicle's state is a valid track direction (vehicle is not turning around) return it,
01632    * otherwise transform it into a valid track direction */
01633   return (Trackdir)((IsReversingRoadTrackdir((Trackdir)this->state)) ? (this->state - 6) : this->state);
01634 }

Generated on Sun May 15 19:20:13 2011 for OpenTTD by  doxygen 1.6.1