roadveh_cmd.cpp

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

Generated on Thu Jan 20 22:57:39 2011 for OpenTTD by  doxygen 1.6.1