vehicle.cpp

Go to the documentation of this file.
00001 /* $Id: vehicle.cpp 23740 2012-01-03 21:32:51Z 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 "error.h"
00014 #include "roadveh.h"
00015 #include "ship.h"
00016 #include "spritecache.h"
00017 #include "timetable.h"
00018 #include "viewport_func.h"
00019 #include "news_func.h"
00020 #include "command_func.h"
00021 #include "company_func.h"
00022 #include "train.h"
00023 #include "aircraft.h"
00024 #include "newgrf_debug.h"
00025 #include "newgrf_sound.h"
00026 #include "newgrf_station.h"
00027 #include "group_gui.h"
00028 #include "strings_func.h"
00029 #include "zoom_func.h"
00030 #include "date_func.h"
00031 #include "vehicle_func.h"
00032 #include "autoreplace_func.h"
00033 #include "autoreplace_gui.h"
00034 #include "station_base.h"
00035 #include "ai/ai.hpp"
00036 #include "depot_func.h"
00037 #include "network/network.h"
00038 #include "core/pool_func.hpp"
00039 #include "economy_base.h"
00040 #include "articulated_vehicles.h"
00041 #include "roadstop_base.h"
00042 #include "core/random_func.hpp"
00043 #include "core/backup_type.hpp"
00044 #include "order_backup.h"
00045 #include "sound_func.h"
00046 #include "effectvehicle_func.h"
00047 #include "effectvehicle_base.h"
00048 #include "vehiclelist.h"
00049 #include "bridge_map.h"
00050 #include "tunnel_map.h"
00051 #include "depot_map.h"
00052 #include "gamelog.h"
00053 
00054 #include "table/strings.h"
00055 
00056 #define GEN_HASH(x, y) ((GB((y), 6 + ZOOM_LVL_SHIFT, 6) << 6) + GB((x), 7 + ZOOM_LVL_SHIFT, 6))
00057 
00058 VehicleID _new_vehicle_id;
00059 uint16 _returned_refit_capacity;      
00060 uint16 _returned_mail_refit_capacity; 
00061 
00062 
00064 VehiclePool _vehicle_pool("Vehicle");
00065 INSTANTIATE_POOL_METHODS(Vehicle)
00066 
00067 
00072 bool Vehicle::NeedsAutorenewing(const Company *c) const
00073 {
00074   /* We can always generate the Company pointer when we have the vehicle.
00075    * However this takes time and since the Company pointer is often present
00076    * when this function is called then it's faster to pass the pointer as an
00077    * argument rather than finding it again. */
00078   assert(c == Company::Get(this->owner));
00079 
00080   if (!c->settings.engine_renew) return false;
00081   if (this->age - this->max_age < (c->settings.engine_renew_months * 30)) return false;
00082 
00083   /* Only engines need renewing */
00084   if (this->type == VEH_TRAIN && !Train::From(this)->IsEngine()) return false;
00085 
00086   return true;
00087 }
00088 
00089 void VehicleServiceInDepot(Vehicle *v)
00090 {
00091   v->date_of_last_service = _date;
00092   v->breakdowns_since_last_service = 0;
00093   v->reliability = v->GetEngine()->reliability;
00094   SetWindowDirty(WC_VEHICLE_DETAILS, v->index); // ensure that last service date and reliability are updated
00095 }
00096 
00103 bool Vehicle::NeedsServicing() const
00104 {
00105   /* Stopped or crashed vehicles will not move, as such making unmovable
00106    * vehicles to go for service is lame. */
00107   if (this->vehstatus & (VS_STOPPED | VS_CRASHED)) return false;
00108 
00109   /* Are we ready for the next service cycle? */
00110   const Company *c = Company::Get(this->owner);
00111   if (c->settings.vehicle.servint_ispercent ?
00112       (this->reliability >= this->GetEngine()->reliability * (100 - this->service_interval) / 100) :
00113       (this->date_of_last_service + this->service_interval >= _date)) {
00114     return false;
00115   }
00116 
00117   /* If we're servicing anyway, because we have not disabled servicing when
00118    * there are no breakdowns or we are playing with breakdowns, bail out. */
00119   if (!_settings_game.order.no_servicing_if_no_breakdowns ||
00120       _settings_game.difficulty.vehicle_breakdowns != 0) {
00121     return true;
00122   }
00123 
00124   /* Test whether there is some pending autoreplace.
00125    * Note: We do this after the service-interval test.
00126    * There are a lot more reasons for autoreplace to fail than we can test here reasonably. */
00127   bool pending_replace = false;
00128   Money needed_money = c->settings.engine_renew_money;
00129   if (needed_money > c->money) return false;
00130 
00131   for (const Vehicle *v = this; v != NULL; v = (v->type == VEH_TRAIN) ? Train::From(v)->GetNextUnit() : NULL) {
00132     EngineID new_engine = EngineReplacementForCompany(c, v->engine_type, v->group_id);
00133 
00134     /* Check engine availability */
00135     if (new_engine == INVALID_ENGINE || !HasBit(Engine::Get(new_engine)->company_avail, v->owner)) continue;
00136 
00137     /* Check refittability */
00138     uint32 available_cargo_types, union_mask;
00139     GetArticulatedRefitMasks(new_engine, true, &union_mask, &available_cargo_types);
00140     /* Is there anything to refit? */
00141     if (union_mask != 0) {
00142       CargoID cargo_type;
00143       /* We cannot refit to mixed cargoes in an automated way */
00144       if (IsArticulatedVehicleCarryingDifferentCargoes(v, &cargo_type)) continue;
00145 
00146       /* Did the old vehicle carry anything? */
00147       if (cargo_type != CT_INVALID) {
00148         /* We can't refit the vehicle to carry the cargo we want */
00149         if (!HasBit(available_cargo_types, cargo_type)) continue;
00150       }
00151     }
00152 
00153     /* Check money.
00154      * We want 2*(the price of the new vehicle) without looking at the value of the vehicle we are going to sell. */
00155     pending_replace = true;
00156     needed_money += 2 * Engine::Get(new_engine)->GetCost();
00157     if (needed_money > c->money) return false;
00158   }
00159 
00160   return pending_replace;
00161 }
00162 
00168 bool Vehicle::NeedsAutomaticServicing() const
00169 {
00170   if (this->HasDepotOrder()) return false;
00171   if (this->current_order.IsType(OT_LOADING)) return false;
00172   if (this->current_order.IsType(OT_GOTO_DEPOT) && this->current_order.GetDepotOrderType() != ODTFB_SERVICE) return false;
00173   return NeedsServicing();
00174 }
00175 
00176 uint Vehicle::Crash(bool flooded)
00177 {
00178   assert((this->vehstatus & VS_CRASHED) == 0);
00179   assert(this->Previous() == NULL); // IsPrimaryVehicle fails for free-wagon-chains
00180 
00181   uint pass = 0;
00182   /* Stop the vehicle. */
00183   if (this->IsPrimaryVehicle()) this->vehstatus |= VS_STOPPED;
00184   /* crash all wagons, and count passengers */
00185   for (Vehicle *v = this; v != NULL; v = v->Next()) {
00186     if (IsCargoInClass(v->cargo_type, CC_PASSENGERS)) pass += v->cargo.Count();
00187     v->vehstatus |= VS_CRASHED;
00188     MarkSingleVehicleDirty(v);
00189   }
00190 
00191   /* Dirty some windows */
00192   InvalidateWindowClassesData(GetWindowClassForVehicleType(this->type), 0);
00193   SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
00194   SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
00195   SetWindowDirty(WC_VEHICLE_DEPOT, this->tile);
00196 
00197   return pass;
00198 }
00199 
00200 
00209 void ShowNewGrfVehicleError(EngineID engine, StringID part1, StringID part2, GRFBugs bug_type, bool critical)
00210 {
00211   const Engine *e = Engine::Get(engine);
00212   GRFConfig *grfconfig = GetGRFConfig(e->GetGRFID());
00213 
00214   if (!HasBit(grfconfig->grf_bugs, bug_type)) {
00215     SetBit(grfconfig->grf_bugs, bug_type);
00216     SetDParamStr(0, grfconfig->GetName());
00217     SetDParam(1, engine);
00218     ShowErrorMessage(part1, part2, WL_CRITICAL);
00219     if (!_networking) DoCommand(0, critical ? PM_PAUSED_ERROR : PM_PAUSED_NORMAL, 1, DC_EXEC, CMD_PAUSE);
00220   }
00221 
00222   /* debug output */
00223   char buffer[512];
00224 
00225   SetDParamStr(0, grfconfig->GetName());
00226   GetString(buffer, part1, lastof(buffer));
00227   DEBUG(grf, 0, "%s", buffer + 3);
00228 
00229   SetDParam(1, engine);
00230   GetString(buffer, part2, lastof(buffer));
00231   DEBUG(grf, 0, "%s", buffer + 3);
00232 }
00233 
00239 void VehicleLengthChanged(const Vehicle *u)
00240 {
00241   /* show a warning once for each engine in whole game and once for each GRF after each game load */
00242   const Engine *engine = u->GetEngine();
00243   uint32 grfid = engine->grf_prop.grffile->grfid;
00244   GRFConfig *grfconfig = GetGRFConfig(grfid);
00245   if (GamelogGRFBugReverse(grfid, engine->grf_prop.local_id) || !HasBit(grfconfig->grf_bugs, GBUG_VEH_LENGTH)) {
00246     ShowNewGrfVehicleError(u->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_VEHICLE_LENGTH, GBUG_VEH_LENGTH, true);
00247   }
00248 }
00249 
00254 Vehicle::Vehicle(VehicleType type)
00255 {
00256   this->type               = type;
00257   this->coord.left         = INVALID_COORD;
00258   this->group_id           = DEFAULT_GROUP;
00259   this->fill_percent_te_id = INVALID_TE_ID;
00260   this->first              = this;
00261   this->colourmap          = PAL_NONE;
00262   this->cargo_age_counter  = 1;
00263 }
00264 
00269 byte VehicleRandomBits()
00270 {
00271   return GB(Random(), 0, 8);
00272 }
00273 
00274 /* Size of the hash, 6 = 64 x 64, 7 = 128 x 128. Larger sizes will (in theory) reduce hash
00275  * lookup times at the expense of memory usage. */
00276 const int HASH_BITS = 7;
00277 const int HASH_SIZE = 1 << HASH_BITS;
00278 const int HASH_MASK = HASH_SIZE - 1;
00279 const int TOTAL_HASH_SIZE = 1 << (HASH_BITS * 2);
00280 const int TOTAL_HASH_MASK = TOTAL_HASH_SIZE - 1;
00281 
00282 /* Resolution of the hash, 0 = 1*1 tile, 1 = 2*2 tiles, 2 = 4*4 tiles, etc.
00283  * Profiling results show that 0 is fastest. */
00284 const int HASH_RES = 0;
00285 
00286 static Vehicle *_vehicle_tile_hash[TOTAL_HASH_SIZE];
00287 
00288 static Vehicle *VehicleFromTileHash(int xl, int yl, int xu, int yu, void *data, VehicleFromPosProc *proc, bool find_first)
00289 {
00290   for (int y = yl; ; y = (y + (1 << HASH_BITS)) & (HASH_MASK << HASH_BITS)) {
00291     for (int x = xl; ; x = (x + 1) & HASH_MASK) {
00292       Vehicle *v = _vehicle_tile_hash[(x + y) & TOTAL_HASH_MASK];
00293       for (; v != NULL; v = v->hash_tile_next) {
00294         Vehicle *a = proc(v, data);
00295         if (find_first && a != NULL) return a;
00296       }
00297       if (x == xu) break;
00298     }
00299     if (y == yu) break;
00300   }
00301 
00302   return NULL;
00303 }
00304 
00305 
00317 static Vehicle *VehicleFromPosXY(int x, int y, void *data, VehicleFromPosProc *proc, bool find_first)
00318 {
00319   const int COLL_DIST = 6;
00320 
00321   /* Hash area to scan is from xl,yl to xu,yu */
00322   int xl = GB((x - COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS);
00323   int xu = GB((x + COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS);
00324   int yl = GB((y - COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS) << HASH_BITS;
00325   int yu = GB((y + COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS) << HASH_BITS;
00326 
00327   return VehicleFromTileHash(xl, yl, xu, yu, data, proc, find_first);
00328 }
00329 
00344 void FindVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc)
00345 {
00346   VehicleFromPosXY(x, y, data, proc, false);
00347 }
00348 
00360 bool HasVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc)
00361 {
00362   return VehicleFromPosXY(x, y, data, proc, true) != NULL;
00363 }
00364 
00375 static Vehicle *VehicleFromPos(TileIndex tile, void *data, VehicleFromPosProc *proc, bool find_first)
00376 {
00377   int x = GB(TileX(tile), HASH_RES, HASH_BITS);
00378   int y = GB(TileY(tile), HASH_RES, HASH_BITS) << HASH_BITS;
00379 
00380   Vehicle *v = _vehicle_tile_hash[(x + y) & TOTAL_HASH_MASK];
00381   for (; v != NULL; v = v->hash_tile_next) {
00382     if (v->tile != tile) continue;
00383 
00384     Vehicle *a = proc(v, data);
00385     if (find_first && a != NULL) return a;
00386   }
00387 
00388   return NULL;
00389 }
00390 
00404 void FindVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
00405 {
00406   VehicleFromPos(tile, data, proc, false);
00407 }
00408 
00419 bool HasVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
00420 {
00421   return VehicleFromPos(tile, data, proc, true) != NULL;
00422 }
00423 
00430 static Vehicle *EnsureNoVehicleProcZ(Vehicle *v, void *data)
00431 {
00432   int z = *(int*)data;
00433 
00434   if (v->type == VEH_DISASTER || (v->type == VEH_AIRCRAFT && v->subtype == AIR_SHADOW)) return NULL;
00435   if (v->z_pos > z) return NULL;
00436 
00437   return v;
00438 }
00439 
00445 CommandCost EnsureNoVehicleOnGround(TileIndex tile)
00446 {
00447   int z = GetTileMaxPixelZ(tile);
00448 
00449   /* Value v is not safe in MP games, however, it is used to generate a local
00450    * error message only (which may be different for different machines).
00451    * Such a message does not affect MP synchronisation.
00452    */
00453   Vehicle *v = VehicleFromPos(tile, &z, &EnsureNoVehicleProcZ, true);
00454   if (v != NULL) return_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
00455   return CommandCost();
00456 }
00457 
00459 static Vehicle *GetVehicleTunnelBridgeProc(Vehicle *v, void *data)
00460 {
00461   if (v->type != VEH_TRAIN && v->type != VEH_ROAD && v->type != VEH_SHIP) return NULL;
00462   if (v == (const Vehicle *)data) return NULL;
00463 
00464   return v;
00465 }
00466 
00474 CommandCost TunnelBridgeIsFree(TileIndex tile, TileIndex endtile, const Vehicle *ignore)
00475 {
00476   /* Value v is not safe in MP games, however, it is used to generate a local
00477    * error message only (which may be different for different machines).
00478    * Such a message does not affect MP synchronisation.
00479    */
00480   Vehicle *v = VehicleFromPos(tile, const_cast<Vehicle *>(ignore), &GetVehicleTunnelBridgeProc, true);
00481   if (v == NULL) v = VehicleFromPos(endtile, const_cast<Vehicle *>(ignore), &GetVehicleTunnelBridgeProc, true);
00482 
00483   if (v != NULL) return_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
00484   return CommandCost();
00485 }
00486 
00487 static Vehicle *EnsureNoTrainOnTrackProc(Vehicle *v, void *data)
00488 {
00489   TrackBits rail_bits = *(TrackBits *)data;
00490 
00491   if (v->type != VEH_TRAIN) return NULL;
00492 
00493   Train *t = Train::From(v);
00494   if ((t->track != rail_bits) && !TracksOverlap(t->track | rail_bits)) return NULL;
00495 
00496   return v;
00497 }
00498 
00507 CommandCost EnsureNoTrainOnTrackBits(TileIndex tile, TrackBits track_bits)
00508 {
00509   /* Value v is not safe in MP games, however, it is used to generate a local
00510    * error message only (which may be different for different machines).
00511    * Such a message does not affect MP synchronisation.
00512    */
00513   Vehicle *v = VehicleFromPos(tile, &track_bits, &EnsureNoTrainOnTrackProc, true);
00514   if (v != NULL) return_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
00515   return CommandCost();
00516 }
00517 
00518 static void UpdateVehicleTileHash(Vehicle *v, bool remove)
00519 {
00520   Vehicle **old_hash = v->hash_tile_current;
00521   Vehicle **new_hash;
00522 
00523   if (remove) {
00524     new_hash = NULL;
00525   } else {
00526     int x = GB(TileX(v->tile), HASH_RES, HASH_BITS);
00527     int y = GB(TileY(v->tile), HASH_RES, HASH_BITS) << HASH_BITS;
00528     new_hash = &_vehicle_tile_hash[(x + y) & TOTAL_HASH_MASK];
00529   }
00530 
00531   if (old_hash == new_hash) return;
00532 
00533   /* Remove from the old position in the hash table */
00534   if (old_hash != NULL) {
00535     if (v->hash_tile_next != NULL) v->hash_tile_next->hash_tile_prev = v->hash_tile_prev;
00536     *v->hash_tile_prev = v->hash_tile_next;
00537   }
00538 
00539   /* Insert vehicle at beginning of the new position in the hash table */
00540   if (new_hash != NULL) {
00541     v->hash_tile_next = *new_hash;
00542     if (v->hash_tile_next != NULL) v->hash_tile_next->hash_tile_prev = &v->hash_tile_next;
00543     v->hash_tile_prev = new_hash;
00544     *new_hash = v;
00545   }
00546 
00547   /* Remember current hash position */
00548   v->hash_tile_current = new_hash;
00549 }
00550 
00551 static Vehicle *_vehicle_viewport_hash[0x1000];
00552 
00553 static void UpdateVehicleViewportHash(Vehicle *v, int x, int y)
00554 {
00555   Vehicle **old_hash, **new_hash;
00556   int old_x = v->coord.left;
00557   int old_y = v->coord.top;
00558 
00559   new_hash = (x == INVALID_COORD) ? NULL : &_vehicle_viewport_hash[GEN_HASH(x, y)];
00560   old_hash = (old_x == INVALID_COORD) ? NULL : &_vehicle_viewport_hash[GEN_HASH(old_x, old_y)];
00561 
00562   if (old_hash == new_hash) return;
00563 
00564   /* remove from hash table? */
00565   if (old_hash != NULL) {
00566     if (v->hash_viewport_next != NULL) v->hash_viewport_next->hash_viewport_prev = v->hash_viewport_prev;
00567     *v->hash_viewport_prev = v->hash_viewport_next;
00568   }
00569 
00570   /* insert into hash table? */
00571   if (new_hash != NULL) {
00572     v->hash_viewport_next = *new_hash;
00573     if (v->hash_viewport_next != NULL) v->hash_viewport_next->hash_viewport_prev = &v->hash_viewport_next;
00574     v->hash_viewport_prev = new_hash;
00575     *new_hash = v;
00576   }
00577 }
00578 
00579 void ResetVehicleHash()
00580 {
00581   Vehicle *v;
00582   FOR_ALL_VEHICLES(v) { v->hash_tile_current = NULL; }
00583   memset(_vehicle_viewport_hash, 0, sizeof(_vehicle_viewport_hash));
00584   memset(_vehicle_tile_hash, 0, sizeof(_vehicle_tile_hash));
00585 }
00586 
00587 void ResetVehicleColourMap()
00588 {
00589   Vehicle *v;
00590   FOR_ALL_VEHICLES(v) { v->colourmap = PAL_NONE; }
00591 }
00592 
00597 typedef SmallMap<Vehicle *, bool, 4> AutoreplaceMap;
00598 static AutoreplaceMap _vehicles_to_autoreplace;
00599 
00600 void InitializeVehicles()
00601 {
00602   _vehicles_to_autoreplace.Reset();
00603   ResetVehicleHash();
00604 }
00605 
00606 uint CountVehiclesInChain(const Vehicle *v)
00607 {
00608   uint count = 0;
00609   do count++; while ((v = v->Next()) != NULL);
00610   return count;
00611 }
00612 
00617 bool Vehicle::IsEngineCountable() const
00618 {
00619   switch (this->type) {
00620     case VEH_AIRCRAFT: return Aircraft::From(this)->IsNormalAircraft(); // don't count plane shadows and helicopter rotors
00621     case VEH_TRAIN:
00622       return !this->IsArticulatedPart() && // tenders and other articulated parts
00623           !Train::From(this)->IsRearDualheaded(); // rear parts of multiheaded engines
00624     case VEH_ROAD: return RoadVehicle::From(this)->IsFrontEngine();
00625     case VEH_SHIP: return true;
00626     default: return false; // Only count company buildable vehicles
00627   }
00628 }
00629 
00634 bool Vehicle::HasEngineType() const
00635 {
00636   switch (this->type) {
00637     case VEH_AIRCRAFT: return Aircraft::From(this)->IsNormalAircraft();
00638     case VEH_TRAIN:
00639     case VEH_ROAD:
00640     case VEH_SHIP: return true;
00641     default: return false;
00642   }
00643 }
00644 
00650 const Engine *Vehicle::GetEngine() const
00651 {
00652   return Engine::Get(this->engine_type);
00653 }
00654 
00660 const GRFFile *Vehicle::GetGRF() const
00661 {
00662   return this->GetEngine()->GetGRF();
00663 }
00664 
00670 uint32 Vehicle::GetGRFID() const
00671 {
00672   return this->GetEngine()->GetGRFID();
00673 }
00674 
00682 void Vehicle::HandlePathfindingResult(bool path_found)
00683 {
00684   if (path_found) {
00685     /* Route found, is the vehicle marked with "lost" flag? */
00686     if (!HasBit(this->vehicle_flags, VF_PATHFINDER_LOST)) return;
00687 
00688     /* Clear the flag as the PF's problem was solved. */
00689     ClrBit(this->vehicle_flags, VF_PATHFINDER_LOST);
00690     /* Delete the news item. */
00691     DeleteVehicleNews(this->index, STR_NEWS_VEHICLE_IS_LOST);
00692     return;
00693   }
00694 
00695   /* Were we already lost? */
00696   if (HasBit(this->vehicle_flags, VF_PATHFINDER_LOST)) return;
00697 
00698   /* It is first time the problem occurred, set the "lost" flag. */
00699   SetBit(this->vehicle_flags, VF_PATHFINDER_LOST);
00700   /* Notify user about the event. */
00701   AI::NewEvent(this->owner, new ScriptEventVehicleLost(this->index));
00702   if (_settings_client.gui.lost_vehicle_warn && this->owner == _local_company) {
00703     SetDParam(0, this->index);
00704     AddVehicleNewsItem(STR_NEWS_VEHICLE_IS_LOST, NS_ADVICE, this->index);
00705   }
00706 }
00707 
00709 void Vehicle::PreDestructor()
00710 {
00711   if (CleaningPool()) return;
00712 
00713   if (Station::IsValidID(this->last_station_visited)) {
00714     Station::Get(this->last_station_visited)->loading_vehicles.remove(this);
00715 
00716     HideFillingPercent(&this->fill_percent_te_id);
00717 
00718     delete this->cargo_payment;
00719   }
00720 
00721   if (this->IsEngineCountable()) {
00722     GroupStatistics::CountEngine(this, -1);
00723     if (this->IsPrimaryVehicle()) GroupStatistics::CountVehicle(this, -1);
00724     GroupStatistics::UpdateAutoreplace(this->owner);
00725 
00726     if (this->owner == _local_company) InvalidateAutoreplaceWindow(this->engine_type, this->group_id);
00727     DeleteGroupHighlightOfVehicle(this);
00728   }
00729 
00730   if (this->type == VEH_AIRCRAFT && this->IsPrimaryVehicle()) {
00731     Aircraft *a = Aircraft::From(this);
00732     Station *st = GetTargetAirportIfValid(a);
00733     if (st != NULL) {
00734       const AirportFTA *layout = st->airport.GetFTA()->layout;
00735       CLRBITS(st->airport.flags, layout[a->previous_pos].block | layout[a->pos].block);
00736     }
00737   }
00738 
00739 
00740   if (this->type == VEH_ROAD && this->IsPrimaryVehicle()) {
00741     RoadVehicle *v = RoadVehicle::From(this);
00742     if (!(v->vehstatus & VS_CRASHED) && IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END)) {
00743       /* Leave the drive through roadstop, when you have not already left it. */
00744       RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile))->Leave(v);
00745     }
00746   }
00747 
00748   if (this->Previous() == NULL) {
00749     InvalidateWindowData(WC_VEHICLE_DEPOT, this->tile);
00750   }
00751 
00752   if (this->IsPrimaryVehicle()) {
00753     DeleteWindowById(WC_VEHICLE_VIEW, this->index);
00754     DeleteWindowById(WC_VEHICLE_ORDERS, this->index);
00755     DeleteWindowById(WC_VEHICLE_REFIT, this->index);
00756     DeleteWindowById(WC_VEHICLE_DETAILS, this->index);
00757     DeleteWindowById(WC_VEHICLE_TIMETABLE, this->index);
00758     SetWindowDirty(WC_COMPANY, this->owner);
00759     OrderBackup::ClearVehicle(this);
00760   }
00761   InvalidateWindowClassesData(GetWindowClassForVehicleType(this->type), 0);
00762 
00763   this->cargo.Truncate(0);
00764   DeleteVehicleOrders(this);
00765   DeleteDepotHighlightOfVehicle(this);
00766 
00767   extern void StopGlobalFollowVehicle(const Vehicle *v);
00768   StopGlobalFollowVehicle(this);
00769 
00770   ReleaseDisastersTargetingVehicle(this->index);
00771 }
00772 
00773 Vehicle::~Vehicle()
00774 {
00775   free(this->name);
00776 
00777   if (CleaningPool()) {
00778     this->cargo.OnCleanPool();
00779     return;
00780   }
00781 
00782   /* sometimes, eg. for disaster vehicles, when company bankrupts, when removing crashed/flooded vehicles,
00783    * it may happen that vehicle chain is deleted when visible */
00784   if (!(this->vehstatus & VS_HIDDEN)) MarkSingleVehicleDirty(this);
00785 
00786   Vehicle *v = this->Next();
00787   this->SetNext(NULL);
00788 
00789   delete v;
00790 
00791   UpdateVehicleTileHash(this, true);
00792   UpdateVehicleViewportHash(this, INVALID_COORD, 0);
00793   DeleteVehicleNews(this->index, INVALID_STRING_ID);
00794   DeleteNewGRFInspectWindow(GetGrfSpecFeature(this->type), this->index);
00795 }
00796 
00801 void VehicleEnteredDepotThisTick(Vehicle *v)
00802 {
00803   /* Vehicle should stop in the depot if it was in 'stopping' state */
00804   _vehicles_to_autoreplace[v] = !(v->vehstatus & VS_STOPPED);
00805 
00806   /* We ALWAYS set the stopped state. Even when the vehicle does not plan on
00807    * stopping in the depot, so we stop it to ensure that it will not reserve
00808    * the path out of the depot before we might autoreplace it to a different
00809    * engine. The new engine would not own the reserved path we store that we
00810    * stopped the vehicle, so autoreplace can start it again */
00811   v->vehstatus |= VS_STOPPED;
00812 }
00813 
00819 static void RunVehicleDayProc()
00820 {
00821   if (_game_mode != GM_NORMAL) return;
00822 
00823   /* Run the day_proc for every DAY_TICKS vehicle starting at _date_fract. */
00824   for (size_t i = _date_fract; i < Vehicle::GetPoolSize(); i += DAY_TICKS) {
00825     Vehicle *v = Vehicle::Get(i);
00826     if (v == NULL) continue;
00827 
00828     /* Call the 32-day callback if needed */
00829     if ((v->day_counter & 0x1F) == 0 && v->HasEngineType()) {
00830       uint16 callback = GetVehicleCallback(CBID_VEHICLE_32DAY_CALLBACK, 0, 0, v->engine_type, v);
00831       if (callback != CALLBACK_FAILED) {
00832         if (HasBit(callback, 0)) TriggerVehicle(v, VEHICLE_TRIGGER_CALLBACK_32); // Trigger vehicle trigger 10
00833         if (HasBit(callback, 1)) v->colourmap = PAL_NONE;
00834 
00835         if (callback & ~3) ErrorUnknownCallbackResult(v->GetGRFID(), CBID_VEHICLE_32DAY_CALLBACK, callback);
00836       }
00837     }
00838 
00839     /* This is called once per day for each vehicle, but not in the first tick of the day */
00840     v->OnNewDay();
00841   }
00842 }
00843 
00844 void CallVehicleTicks()
00845 {
00846   _vehicles_to_autoreplace.Clear();
00847 
00848   RunVehicleDayProc();
00849 
00850   Station *st;
00851   FOR_ALL_STATIONS(st) LoadUnloadStation(st);
00852 
00853   Vehicle *v;
00854   FOR_ALL_VEHICLES(v) {
00855     /* Vehicle could be deleted in this tick */
00856     if (!v->Tick()) {
00857       assert(Vehicle::Get(vehicle_index) == NULL);
00858       continue;
00859     }
00860 
00861     assert(Vehicle::Get(vehicle_index) == v);
00862 
00863     switch (v->type) {
00864       default: break;
00865 
00866       case VEH_TRAIN:
00867       case VEH_ROAD:
00868       case VEH_AIRCRAFT:
00869       case VEH_SHIP:
00870         if (v->vcache.cached_cargo_age_period != 0) {
00871           v->cargo_age_counter = min(v->cargo_age_counter, v->vcache.cached_cargo_age_period);
00872           if (--v->cargo_age_counter == 0) {
00873             v->cargo.AgeCargo();
00874             v->cargo_age_counter = v->vcache.cached_cargo_age_period;
00875           }
00876         }
00877 
00878         if (v->type == VEH_TRAIN && Train::From(v)->IsWagon()) continue;
00879         if (v->type == VEH_AIRCRAFT && v->subtype != AIR_HELICOPTER) continue;
00880         if (v->type == VEH_ROAD && !RoadVehicle::From(v)->IsFrontEngine()) continue;
00881 
00882         v->motion_counter += v->cur_speed;
00883         /* Play a running sound if the motion counter passes 256 (Do we not skip sounds?) */
00884         if (GB(v->motion_counter, 0, 8) < v->cur_speed) PlayVehicleSound(v, VSE_RUNNING);
00885 
00886         /* Play an alterate running sound every 16 ticks */
00887         if (GB(v->tick_counter, 0, 4) == 0) PlayVehicleSound(v, v->cur_speed > 0 ? VSE_RUNNING_16 : VSE_STOPPED_16);
00888     }
00889   }
00890 
00891   Backup<CompanyByte> cur_company(_current_company, FILE_LINE);
00892   for (AutoreplaceMap::iterator it = _vehicles_to_autoreplace.Begin(); it != _vehicles_to_autoreplace.End(); it++) {
00893     v = it->first;
00894     /* Autoreplace needs the current company set as the vehicle owner */
00895     cur_company.Change(v->owner);
00896 
00897     /* Start vehicle if we stopped them in VehicleEnteredDepotThisTick()
00898      * We need to stop them between VehicleEnteredDepotThisTick() and here or we risk that
00899      * they are already leaving the depot again before being replaced. */
00900     if (it->second) v->vehstatus &= ~VS_STOPPED;
00901 
00902     /* Store the position of the effect as the vehicle pointer will become invalid later */
00903     int x = v->x_pos;
00904     int y = v->y_pos;
00905     int z = v->z_pos;
00906 
00907     const Company *c = Company::Get(_current_company);
00908     SubtractMoneyFromCompany(CommandCost(EXPENSES_NEW_VEHICLES, (Money)c->settings.engine_renew_money));
00909     CommandCost res = DoCommand(0, v->index, 0, DC_EXEC, CMD_AUTOREPLACE_VEHICLE);
00910     SubtractMoneyFromCompany(CommandCost(EXPENSES_NEW_VEHICLES, -(Money)c->settings.engine_renew_money));
00911 
00912     if (!IsLocalCompany()) continue;
00913 
00914     if (res.Succeeded()) {
00915       ShowCostOrIncomeAnimation(x, y, z, res.GetCost());
00916       continue;
00917     }
00918 
00919     StringID error_message = res.GetErrorMessage();
00920     if (error_message == STR_ERROR_AUTOREPLACE_NOTHING_TO_DO || error_message == INVALID_STRING_ID) continue;
00921 
00922     if (error_message == STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY) error_message = STR_ERROR_AUTOREPLACE_MONEY_LIMIT;
00923 
00924     StringID message;
00925     if (error_message == STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT) {
00926       message = error_message;
00927     } else {
00928       message = STR_NEWS_VEHICLE_AUTORENEW_FAILED;
00929     }
00930 
00931     SetDParam(0, v->index);
00932     SetDParam(1, error_message);
00933     AddVehicleNewsItem(message, NS_ADVICE, v->index);
00934   }
00935 
00936   cur_company.Restore();
00937 }
00938 
00943 static void DoDrawVehicle(const Vehicle *v)
00944 {
00945   SpriteID image = v->cur_image;
00946   PaletteID pal = PAL_NONE;
00947 
00948   if (v->vehstatus & VS_DEFPAL) pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
00949 
00950   /* Check whether the vehicle shall be transparent due to the game state */
00951   bool shadowed = (v->vehstatus & VS_SHADOW) != 0;
00952 
00953   if (v->type == VEH_EFFECT) {
00954     /* Check whether the vehicle shall be transparent/invisible due to GUI settings.
00955      * However, transparent smoke and bubbles look weird, so always hide them. */
00956     TransparencyOption to = EffectVehicle::From(v)->GetTransparencyOption();
00957     if (to != TO_INVALID && (IsTransparencySet(to) || IsInvisibilitySet(to))) return;
00958   }
00959 
00960   AddSortableSpriteToDraw(image, pal, v->x_pos + v->x_offs, v->y_pos + v->y_offs,
00961     v->x_extent, v->y_extent, v->z_extent, v->z_pos, shadowed, v->x_bb_offs, v->y_bb_offs);
00962 }
00963 
00968 void ViewportAddVehicles(DrawPixelInfo *dpi)
00969 {
00970   /* The bounding rectangle */
00971   const int l = dpi->left;
00972   const int r = dpi->left + dpi->width;
00973   const int t = dpi->top;
00974   const int b = dpi->top + dpi->height;
00975 
00976   /* The hash area to scan */
00977   int xl, xu, yl, yu;
00978 
00979   if (dpi->width + (70 * ZOOM_LVL_BASE) < (1 << (7 + 6 + ZOOM_LVL_SHIFT))) {
00980     xl = GB(l - (70 * ZOOM_LVL_BASE), 7 + ZOOM_LVL_SHIFT, 6);
00981     xu = GB(r,                        7 + ZOOM_LVL_SHIFT, 6);
00982   } else {
00983     /* scan whole hash row */
00984     xl = 0;
00985     xu = 0x3F;
00986   }
00987 
00988   if (dpi->height + (70 * ZOOM_LVL_BASE) < (1 << (6 + 6 + ZOOM_LVL_SHIFT))) {
00989     yl = GB(t - (70 * ZOOM_LVL_BASE), 6 + ZOOM_LVL_SHIFT, 6) << 6;
00990     yu = GB(b,                        6 + ZOOM_LVL_SHIFT, 6) << 6;
00991   } else {
00992     /* scan whole column */
00993     yl = 0;
00994     yu = 0x3F << 6;
00995   }
00996 
00997   for (int y = yl;; y = (y + (1 << 6)) & (0x3F << 6)) {
00998     for (int x = xl;; x = (x + 1) & 0x3F) {
00999       const Vehicle *v = _vehicle_viewport_hash[x + y]; // already masked & 0xFFF
01000 
01001       while (v != NULL) {
01002         if (!(v->vehstatus & VS_HIDDEN) &&
01003             l <= v->coord.right &&
01004             t <= v->coord.bottom &&
01005             r >= v->coord.left &&
01006             b >= v->coord.top) {
01007           DoDrawVehicle(v);
01008         }
01009         v = v->hash_viewport_next;
01010       }
01011 
01012       if (x == xu) break;
01013     }
01014 
01015     if (y == yu) break;
01016   }
01017 }
01018 
01026 Vehicle *CheckClickOnVehicle(const ViewPort *vp, int x, int y)
01027 {
01028   Vehicle *found = NULL, *v;
01029   uint dist, best_dist = UINT_MAX;
01030 
01031   if ((uint)(x -= vp->left) >= (uint)vp->width || (uint)(y -= vp->top) >= (uint)vp->height) return NULL;
01032 
01033   x = ScaleByZoom(x, vp->zoom) + vp->virtual_left;
01034   y = ScaleByZoom(y, vp->zoom) + vp->virtual_top;
01035 
01036   FOR_ALL_VEHICLES(v) {
01037     if ((v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) == 0 &&
01038         x >= v->coord.left && x <= v->coord.right &&
01039         y >= v->coord.top && y <= v->coord.bottom) {
01040 
01041       dist = max(
01042         abs(((v->coord.left + v->coord.right) >> 1) - x),
01043         abs(((v->coord.top + v->coord.bottom) >> 1) - y)
01044       );
01045 
01046       if (dist < best_dist) {
01047         found = v;
01048         best_dist = dist;
01049       }
01050     }
01051   }
01052 
01053   return found;
01054 }
01055 
01060 void DecreaseVehicleValue(Vehicle *v)
01061 {
01062   v->value -= v->value >> 8;
01063   SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
01064 }
01065 
01066 static const byte _breakdown_chance[64] = {
01067     3,   3,   3,   3,   3,   3,   3,   3,
01068     4,   4,   5,   5,   6,   6,   7,   7,
01069     8,   8,   9,   9,  10,  10,  11,  11,
01070    12,  13,  13,  13,  13,  14,  15,  16,
01071    17,  19,  21,  25,  28,  31,  34,  37,
01072    40,  44,  48,  52,  56,  60,  64,  68,
01073    72,  80,  90, 100, 110, 120, 130, 140,
01074   150, 170, 190, 210, 230, 250, 250, 250,
01075 };
01076 
01077 void CheckVehicleBreakdown(Vehicle *v)
01078 {
01079   int rel, rel_old;
01080 
01081   /* decrease reliability */
01082   v->reliability = rel = max((rel_old = v->reliability) - v->reliability_spd_dec, 0);
01083   if ((rel_old >> 8) != (rel >> 8)) SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
01084 
01085   if (v->breakdown_ctr != 0 || (v->vehstatus & VS_STOPPED) ||
01086       _settings_game.difficulty.vehicle_breakdowns < 1 ||
01087       v->cur_speed < 5 || _game_mode == GM_MENU) {
01088     return;
01089   }
01090 
01091   uint32 r = Random();
01092 
01093   /* increase chance of failure */
01094   int chance = v->breakdown_chance + 1;
01095   if (Chance16I(1, 25, r)) chance += 25;
01096   v->breakdown_chance = min(255, chance);
01097 
01098   /* calculate reliability value to use in comparison */
01099   rel = v->reliability;
01100   if (v->type == VEH_SHIP) rel += 0x6666;
01101 
01102   /* reduced breakdowns? */
01103   if (_settings_game.difficulty.vehicle_breakdowns == 1) rel += 0x6666;
01104 
01105   /* check if to break down */
01106   if (_breakdown_chance[(uint)min(rel, 0xffff) >> 10] <= v->breakdown_chance) {
01107     v->breakdown_ctr    = GB(r, 16, 6) + 0x3F;
01108     v->breakdown_delay  = GB(r, 24, 7) + 0x80;
01109     v->breakdown_chance = 0;
01110   }
01111 }
01112 
01119 bool Vehicle::HandleBreakdown()
01120 {
01121   /* Possible states for Vehicle::breakdown_ctr
01122    * 0  - vehicle is running normally
01123    * 1  - vehicle is currently broken down
01124    * 2  - vehicle is going to break down now
01125    * >2 - vehicle is counting down to the actual breakdown event */
01126   switch (this->breakdown_ctr) {
01127     case 0:
01128       return false;
01129 
01130     case 2:
01131       this->breakdown_ctr = 1;
01132 
01133       if (this->breakdowns_since_last_service != 255) {
01134         this->breakdowns_since_last_service++;
01135       }
01136 
01137       if (this->type == VEH_AIRCRAFT) {
01138         /* Aircraft just need this flag, the rest is handled elsewhere */
01139         this->vehstatus |= VS_AIRCRAFT_BROKEN;
01140       } else {
01141         this->cur_speed = 0;
01142 
01143         if (!PlayVehicleSound(this, VSE_BREAKDOWN)) {
01144           SndPlayVehicleFx((_settings_game.game_creation.landscape != LT_TOYLAND) ?
01145             (this->type == VEH_TRAIN ? SND_10_TRAIN_BREAKDOWN : SND_0F_VEHICLE_BREAKDOWN) :
01146             (this->type == VEH_TRAIN ? SND_3A_COMEDY_BREAKDOWN_2 : SND_35_COMEDY_BREAKDOWN), this);
01147         }
01148 
01149         if (!(this->vehstatus & VS_HIDDEN)) {
01150           EffectVehicle *u = CreateEffectVehicleRel(this, 4, 4, 5, EV_BREAKDOWN_SMOKE);
01151           if (u != NULL) u->animation_state = this->breakdown_delay * 2;
01152         }
01153       }
01154 
01155       this->MarkDirty(); // Update graphics after speed is zeroed
01156       SetWindowDirty(WC_VEHICLE_VIEW, this->index);
01157       SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
01158 
01159       /* FALL THROUGH */
01160     case 1:
01161       /* Aircraft breakdowns end only when arriving at the airport */
01162       if (this->type == VEH_AIRCRAFT) return false;
01163 
01164       /* For trains this function is called twice per tick, so decrease v->breakdown_delay at half the rate */
01165       if ((this->tick_counter & (this->type == VEH_TRAIN ? 3 : 1)) == 0) {
01166         if (--this->breakdown_delay == 0) {
01167           this->breakdown_ctr = 0;
01168           this->MarkDirty();
01169           SetWindowDirty(WC_VEHICLE_VIEW, this->index);
01170         }
01171       }
01172       return true;
01173 
01174     default:
01175       if (!this->current_order.IsType(OT_LOADING)) this->breakdown_ctr--;
01176       return false;
01177   }
01178 }
01179 
01184 void AgeVehicle(Vehicle *v)
01185 {
01186   if (v->age < MAX_DAY) {
01187     v->age++;
01188     if (v->IsPrimaryVehicle() && v->age == VEHICLE_PROFIT_MIN_AGE + 1) GroupStatistics::VehicleReachedProfitAge(v);
01189   }
01190 
01191   if (!v->IsPrimaryVehicle() && (v->type != VEH_TRAIN || !Train::From(v)->IsEngine())) return;
01192 
01193   int age = v->age - v->max_age;
01194   if (age == DAYS_IN_LEAP_YEAR * 0 || age == DAYS_IN_LEAP_YEAR * 1 ||
01195       age == DAYS_IN_LEAP_YEAR * 2 || age == DAYS_IN_LEAP_YEAR * 3 || age == DAYS_IN_LEAP_YEAR * 4) {
01196     v->reliability_spd_dec <<= 1;
01197   }
01198 
01199   SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
01200 
01201   /* Don't warn about non-primary or not ours vehicles or vehicles that are crashed */
01202   if (v->Previous() != NULL || v->owner != _local_company || (v->vehstatus & VS_CRASHED) != 0) return;
01203 
01204   /* Don't warn if a renew is active */
01205   if (Company::Get(v->owner)->settings.engine_renew && v->GetEngine()->company_avail != 0) return;
01206 
01207   StringID str;
01208   if (age == -DAYS_IN_LEAP_YEAR) {
01209     str = STR_NEWS_VEHICLE_IS_GETTING_OLD;
01210   } else if (age == 0) {
01211     str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD;
01212   } else if (age > 0 && (age % DAYS_IN_LEAP_YEAR) == 0) {
01213     str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD_AND;
01214   } else {
01215     return;
01216   }
01217 
01218   SetDParam(0, v->index);
01219   AddVehicleNewsItem(str, NS_ADVICE, v->index);
01220 }
01221 
01228 uint8 CalcPercentVehicleFilled(const Vehicle *v, StringID *colour)
01229 {
01230   int count = 0;
01231   int max = 0;
01232   int cars = 0;
01233   int unloading = 0;
01234   bool loading = false;
01235 
01236   const Vehicle *u = v;
01237   /* The station may be NULL when the (colour) string does not need to be set. */
01238   const Station *st = Station::GetIfValid(v->last_station_visited);
01239   assert(colour == NULL || st != NULL);
01240 
01241   /* Count up max and used */
01242   for (; v != NULL; v = v->Next()) {
01243     count += v->cargo.Count();
01244     max += v->cargo_cap;
01245     if (v->cargo_cap != 0 && colour != NULL) {
01246       unloading += HasBit(v->vehicle_flags, VF_CARGO_UNLOADING) ? 1 : 0;
01247       loading |= !(u->current_order.GetLoadType() & OLFB_NO_LOAD) && st->goods[v->cargo_type].days_since_pickup != 255;
01248       cars++;
01249     }
01250   }
01251 
01252   if (colour != NULL) {
01253     if (unloading == 0 && loading) {
01254       *colour = STR_PERCENT_UP;
01255     } else if (cars == unloading || !loading) {
01256       *colour = STR_PERCENT_DOWN;
01257     } else {
01258       *colour = STR_PERCENT_UP_DOWN;
01259     }
01260   }
01261 
01262   /* Train without capacity */
01263   if (max == 0) return 100;
01264 
01265   /* Return the percentage */
01266   return (count * 100) / max;
01267 }
01268 
01273 void VehicleEnterDepot(Vehicle *v)
01274 {
01275   /* Always work with the front of the vehicle */
01276   assert(v == v->First());
01277 
01278   switch (v->type) {
01279     case VEH_TRAIN: {
01280       Train *t = Train::From(v);
01281       SetWindowClassesDirty(WC_TRAINS_LIST);
01282       /* Clear path reservation */
01283       SetDepotReservation(t->tile, false);
01284       if (_settings_client.gui.show_track_reservation) MarkTileDirtyByTile(t->tile);
01285 
01286       UpdateSignalsOnSegment(t->tile, INVALID_DIAGDIR, t->owner);
01287       t->wait_counter = 0;
01288       t->force_proceed = TFP_NONE;
01289       ClrBit(t->flags, VRF_TOGGLE_REVERSE);
01290       t->ConsistChanged(true);
01291       break;
01292     }
01293 
01294     case VEH_ROAD:
01295       SetWindowClassesDirty(WC_ROADVEH_LIST);
01296       break;
01297 
01298     case VEH_SHIP: {
01299       SetWindowClassesDirty(WC_SHIPS_LIST);
01300       Ship *ship = Ship::From(v);
01301       ship->state = TRACK_BIT_DEPOT;
01302       ship->UpdateCache();
01303       ship->UpdateViewport(true, true);
01304       SetWindowDirty(WC_VEHICLE_DEPOT, v->tile);
01305       break;
01306     }
01307 
01308     case VEH_AIRCRAFT:
01309       SetWindowClassesDirty(WC_AIRCRAFT_LIST);
01310       HandleAircraftEnterHangar(Aircraft::From(v));
01311       break;
01312     default: NOT_REACHED();
01313   }
01314   SetWindowDirty(WC_VEHICLE_VIEW, v->index);
01315 
01316   if (v->type != VEH_TRAIN) {
01317     /* Trains update the vehicle list when the first unit enters the depot and calls VehicleEnterDepot() when the last unit enters.
01318      * We only increase the number of vehicles when the first one enters, so we will not need to search for more vehicles in the depot */
01319     InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
01320   }
01321   SetWindowDirty(WC_VEHICLE_DEPOT, v->tile);
01322 
01323   v->vehstatus |= VS_HIDDEN;
01324   v->cur_speed = 0;
01325 
01326   VehicleServiceInDepot(v);
01327 
01328   TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);
01329 
01330   if (v->current_order.IsType(OT_GOTO_DEPOT)) {
01331     SetWindowDirty(WC_VEHICLE_VIEW, v->index);
01332 
01333     const Order *real_order = v->GetOrder(v->cur_real_order_index);
01334     Order t = v->current_order;
01335     v->current_order.MakeDummy();
01336 
01337     /* Test whether we are heading for this depot. If not, do nothing.
01338      * Note: The target depot for nearest-/manual-depot-orders is only updated on junctions, but we want to accept every depot. */
01339     if ((t.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) &&
01340         real_order != NULL && !(real_order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) &&
01341         (v->type == VEH_AIRCRAFT ? t.GetDestination() != GetStationIndex(v->tile) : v->dest_tile != v->tile)) {
01342       /* We are heading for another depot, keep driving. */
01343       return;
01344     }
01345 
01346     if (t.IsRefit()) {
01347       Backup<CompanyByte> cur_company(_current_company, v->owner, FILE_LINE);
01348       CommandCost cost = DoCommand(v->tile, v->index, t.GetRefitCargo() | t.GetRefitSubtype() << 8, DC_EXEC, GetCmdRefitVeh(v));
01349       cur_company.Restore();
01350 
01351       if (cost.Failed()) {
01352         _vehicles_to_autoreplace[v] = false;
01353         if (v->owner == _local_company) {
01354           /* Notify the user that we stopped the vehicle */
01355           SetDParam(0, v->index);
01356           AddVehicleNewsItem(STR_NEWS_ORDER_REFIT_FAILED, NS_ADVICE, v->index);
01357         }
01358       } else if (cost.GetCost() != 0) {
01359         v->profit_this_year -= cost.GetCost() << 8;
01360         if (v->owner == _local_company) {
01361           ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost.GetCost());
01362         }
01363       }
01364     }
01365 
01366     if (t.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) {
01367       /* Part of orders */
01368       v->DeleteUnreachedImplicitOrders();
01369       UpdateVehicleTimetable(v, true);
01370       v->IncrementImplicitOrderIndex();
01371     }
01372     if (t.GetDepotActionType() & ODATFB_HALT) {
01373       /* Vehicles are always stopped on entering depots. Do not restart this one. */
01374       _vehicles_to_autoreplace[v] = false;
01375       if (v->owner == _local_company) {
01376         SetDParam(0, v->index);
01377         AddVehicleNewsItem(STR_NEWS_TRAIN_IS_WAITING + v->type, NS_ADVICE, v->index);
01378       }
01379       AI::NewEvent(v->owner, new ScriptEventVehicleWaitingInDepot(v->index));
01380     }
01381   }
01382 }
01383 
01384 
01390 void VehicleUpdatePosition(Vehicle *v)
01391 {
01392   UpdateVehicleTileHash(v, false);
01393 }
01394 
01401 void VehicleUpdateViewport(Vehicle *v, bool dirty)
01402 {
01403   int img = v->cur_image;
01404   Point pt = RemapCoords(v->x_pos + v->x_offs, v->y_pos + v->y_offs, v->z_pos);
01405   const Sprite *spr = GetSprite(img, ST_NORMAL);
01406 
01407   pt.x += spr->x_offs;
01408   pt.y += spr->y_offs;
01409 
01410   UpdateVehicleViewportHash(v, pt.x, pt.y);
01411 
01412   Rect old_coord = v->coord;
01413   v->coord.left   = pt.x;
01414   v->coord.top    = pt.y;
01415   v->coord.right  = pt.x + spr->width + 2 * ZOOM_LVL_BASE;
01416   v->coord.bottom = pt.y + spr->height + 2 * ZOOM_LVL_BASE;
01417 
01418   if (dirty) {
01419     MarkAllViewportsDirty(
01420       min(old_coord.left,   v->coord.left),
01421       min(old_coord.top,    v->coord.top),
01422       max(old_coord.right,  v->coord.right) + 1 * ZOOM_LVL_BASE,
01423       max(old_coord.bottom, v->coord.bottom) + 1 * ZOOM_LVL_BASE
01424     );
01425   }
01426 }
01427 
01432 void VehicleUpdatePositionAndViewport(Vehicle *v)
01433 {
01434   VehicleUpdatePosition(v);
01435   VehicleUpdateViewport(v, true);
01436 }
01437 
01442 void MarkSingleVehicleDirty(const Vehicle *v)
01443 {
01444   MarkAllViewportsDirty(v->coord.left, v->coord.top, v->coord.right + 1 * ZOOM_LVL_BASE, v->coord.bottom + 1 * ZOOM_LVL_BASE);
01445 }
01446 
01452 GetNewVehiclePosResult GetNewVehiclePos(const Vehicle *v)
01453 {
01454   static const int8 _delta_coord[16] = {
01455     -1,-1,-1, 0, 1, 1, 1, 0, /* x */
01456     -1, 0, 1, 1, 1, 0,-1,-1, /* y */
01457   };
01458 
01459   int x = v->x_pos + _delta_coord[v->direction];
01460   int y = v->y_pos + _delta_coord[v->direction + 8];
01461 
01462   GetNewVehiclePosResult gp;
01463   gp.x = x;
01464   gp.y = y;
01465   gp.old_tile = v->tile;
01466   gp.new_tile = TileVirtXY(x, y);
01467   return gp;
01468 }
01469 
01470 static const Direction _new_direction_table[] = {
01471   DIR_N,  DIR_NW, DIR_W,
01472   DIR_NE, DIR_SE, DIR_SW,
01473   DIR_E,  DIR_SE, DIR_S
01474 };
01475 
01476 Direction GetDirectionTowards(const Vehicle *v, int x, int y)
01477 {
01478   int i = 0;
01479 
01480   if (y >= v->y_pos) {
01481     if (y != v->y_pos) i += 3;
01482     i += 3;
01483   }
01484 
01485   if (x >= v->x_pos) {
01486     if (x != v->x_pos) i++;
01487     i++;
01488   }
01489 
01490   Direction dir = v->direction;
01491 
01492   DirDiff dirdiff = DirDifference(_new_direction_table[i], dir);
01493   if (dirdiff == DIRDIFF_SAME) return dir;
01494   return ChangeDir(dir, dirdiff > DIRDIFF_REVERSE ? DIRDIFF_45LEFT : DIRDIFF_45RIGHT);
01495 }
01496 
01506 VehicleEnterTileStatus VehicleEnterTile(Vehicle *v, TileIndex tile, int x, int y)
01507 {
01508   return _tile_type_procs[GetTileType(tile)]->vehicle_enter_tile_proc(v, tile, x, y);
01509 }
01510 
01518 FreeUnitIDGenerator::FreeUnitIDGenerator(VehicleType type, CompanyID owner) : cache(NULL), maxid(0), curid(0)
01519 {
01520   /* Find maximum */
01521   const Vehicle *v;
01522   FOR_ALL_VEHICLES(v) {
01523     if (v->type == type && v->owner == owner) {
01524       this->maxid = max<UnitID>(this->maxid, v->unitnumber);
01525     }
01526   }
01527 
01528   if (this->maxid == 0) return;
01529 
01530   /* Reserving 'maxid + 2' because we need:
01531    * - space for the last item (with v->unitnumber == maxid)
01532    * - one free slot working as loop terminator in FreeUnitIDGenerator::NextID() */
01533   this->cache = CallocT<bool>(this->maxid + 2);
01534 
01535   /* Fill the cache */
01536   FOR_ALL_VEHICLES(v) {
01537     if (v->type == type && v->owner == owner) {
01538       this->cache[v->unitnumber] = true;
01539     }
01540   }
01541 }
01542 
01544 UnitID FreeUnitIDGenerator::NextID()
01545 {
01546   if (this->maxid <= this->curid) return ++this->curid;
01547 
01548   while (this->cache[++this->curid]) { } // it will stop, we reserved more space than needed
01549 
01550   return this->curid;
01551 }
01552 
01558 UnitID GetFreeUnitNumber(VehicleType type)
01559 {
01560   /* Check whether it is allowed to build another vehicle. */
01561   uint max_veh;
01562   switch (type) {
01563     case VEH_TRAIN:    max_veh = _settings_game.vehicle.max_trains;   break;
01564     case VEH_ROAD:     max_veh = _settings_game.vehicle.max_roadveh;  break;
01565     case VEH_SHIP:     max_veh = _settings_game.vehicle.max_ships;    break;
01566     case VEH_AIRCRAFT: max_veh = _settings_game.vehicle.max_aircraft; break;
01567     default: NOT_REACHED();
01568   }
01569 
01570   const Company *c = Company::Get(_current_company);
01571   if (c->group_all[type].num_vehicle >= max_veh) return UINT16_MAX; // Currently already at the limit, no room to make a new one.
01572 
01573   FreeUnitIDGenerator gen(type, _current_company);
01574 
01575   return gen.NextID();
01576 }
01577 
01578 
01587 bool CanBuildVehicleInfrastructure(VehicleType type)
01588 {
01589   assert(IsCompanyBuildableVehicleType(type));
01590 
01591   if (!Company::IsValidID(_local_company)) return false;
01592   if (!_settings_client.gui.disable_unsuitable_building) return true;
01593 
01594   UnitID max;
01595   switch (type) {
01596     case VEH_TRAIN:    max = _settings_game.vehicle.max_trains; break;
01597     case VEH_ROAD:     max = _settings_game.vehicle.max_roadveh; break;
01598     case VEH_SHIP:     max = _settings_game.vehicle.max_ships; break;
01599     case VEH_AIRCRAFT: max = _settings_game.vehicle.max_aircraft; break;
01600     default: NOT_REACHED();
01601   }
01602 
01603   /* We can build vehicle infrastructure when we may build the vehicle type */
01604   if (max > 0) {
01605     /* Can we actually build the vehicle type? */
01606     const Engine *e;
01607     FOR_ALL_ENGINES_OF_TYPE(e, type) {
01608       if (HasBit(e->company_avail, _local_company)) return true;
01609     }
01610     return false;
01611   }
01612 
01613   /* We should be able to build infrastructure when we have the actual vehicle type */
01614   const Vehicle *v;
01615   FOR_ALL_VEHICLES(v) {
01616     if (v->owner == _local_company && v->type == type) return true;
01617   }
01618 
01619   return false;
01620 }
01621 
01622 
01630 LiveryScheme GetEngineLiveryScheme(EngineID engine_type, EngineID parent_engine_type, const Vehicle *v)
01631 {
01632   CargoID cargo_type = v == NULL ? (CargoID)CT_INVALID : v->cargo_type;
01633   const Engine *e = Engine::Get(engine_type);
01634   switch (e->type) {
01635     default: NOT_REACHED();
01636     case VEH_TRAIN:
01637       if (v != NULL && parent_engine_type != INVALID_ENGINE && (UsesWagonOverride(v) || (v->IsArticulatedPart() && e->u.rail.railveh_type != RAILVEH_WAGON))) {
01638         /* Wagonoverrides use the colour scheme of the front engine.
01639          * Articulated parts use the colour scheme of the first part. (Not supported for articulated wagons) */
01640         engine_type = parent_engine_type;
01641         e = Engine::Get(engine_type);
01642         /* Note: Luckily cargo_type is not needed for engines */
01643       }
01644 
01645       if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
01646       if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
01647       if (e->u.rail.railveh_type == RAILVEH_WAGON) {
01648         if (!CargoSpec::Get(cargo_type)->is_freight) {
01649           if (parent_engine_type == INVALID_ENGINE) {
01650             return LS_PASSENGER_WAGON_STEAM;
01651           } else {
01652             switch (RailVehInfo(parent_engine_type)->engclass) {
01653               default: NOT_REACHED();
01654               case EC_STEAM:    return LS_PASSENGER_WAGON_STEAM;
01655               case EC_DIESEL:   return LS_PASSENGER_WAGON_DIESEL;
01656               case EC_ELECTRIC: return LS_PASSENGER_WAGON_ELECTRIC;
01657               case EC_MONORAIL: return LS_PASSENGER_WAGON_MONORAIL;
01658               case EC_MAGLEV:   return LS_PASSENGER_WAGON_MAGLEV;
01659             }
01660           }
01661         } else {
01662           return LS_FREIGHT_WAGON;
01663         }
01664       } else {
01665         bool is_mu = HasBit(e->info.misc_flags, EF_RAIL_IS_MU);
01666 
01667         switch (e->u.rail.engclass) {
01668           default: NOT_REACHED();
01669           case EC_STEAM:    return LS_STEAM;
01670           case EC_DIESEL:   return is_mu ? LS_DMU : LS_DIESEL;
01671           case EC_ELECTRIC: return is_mu ? LS_EMU : LS_ELECTRIC;
01672           case EC_MONORAIL: return LS_MONORAIL;
01673           case EC_MAGLEV:   return LS_MAGLEV;
01674         }
01675       }
01676 
01677     case VEH_ROAD:
01678       /* Always use the livery of the front */
01679       if (v != NULL && parent_engine_type != INVALID_ENGINE) {
01680         engine_type = parent_engine_type;
01681         e = Engine::Get(engine_type);
01682         cargo_type = v->First()->cargo_type;
01683       }
01684       if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
01685       if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
01686 
01687       /* Important: Use Tram Flag of front part. Luckily engine_type refers to the front part here. */
01688       if (HasBit(e->info.misc_flags, EF_ROAD_TRAM)) {
01689         /* Tram */
01690         return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_TRAM : LS_FREIGHT_TRAM;
01691       } else {
01692         /* Bus or truck */
01693         return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_BUS : LS_TRUCK;
01694       }
01695 
01696     case VEH_SHIP:
01697       if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
01698       if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
01699       return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_SHIP : LS_FREIGHT_SHIP;
01700 
01701     case VEH_AIRCRAFT:
01702       switch (e->u.air.subtype) {
01703         case AIR_HELI: return LS_HELICOPTER;
01704         case AIR_CTOL: return LS_SMALL_PLANE;
01705         case AIR_CTOL | AIR_FAST: return LS_LARGE_PLANE;
01706         default: NOT_REACHED();
01707       }
01708   }
01709 }
01710 
01720 const Livery *GetEngineLivery(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v, byte livery_setting)
01721 {
01722   const Company *c = Company::Get(company);
01723   LiveryScheme scheme = LS_DEFAULT;
01724 
01725   /* The default livery is always available for use, but its in_use flag determines
01726    * whether any _other_ liveries are in use. */
01727   if (c->livery[LS_DEFAULT].in_use && (livery_setting == LIT_ALL || (livery_setting == LIT_COMPANY && company == _local_company))) {
01728     /* Determine the livery scheme to use */
01729     scheme = GetEngineLiveryScheme(engine_type, parent_engine_type, v);
01730 
01731     /* Switch back to the default scheme if the resolved scheme is not in use */
01732     if (!c->livery[scheme].in_use) scheme = LS_DEFAULT;
01733   }
01734 
01735   return &c->livery[scheme];
01736 }
01737 
01738 
01739 static PaletteID GetEngineColourMap(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v)
01740 {
01741   PaletteID map = (v != NULL) ? v->colourmap : PAL_NONE;
01742 
01743   /* Return cached value if any */
01744   if (map != PAL_NONE) return map;
01745 
01746   const Engine *e = Engine::Get(engine_type);
01747 
01748   /* Check if we should use the colour map callback */
01749   if (HasBit(e->info.callback_mask, CBM_VEHICLE_COLOUR_REMAP)) {
01750     uint16 callback = GetVehicleCallback(CBID_VEHICLE_COLOUR_MAPPING, 0, 0, engine_type, v);
01751     /* Failure means "use the default two-colour" */
01752     if (callback != CALLBACK_FAILED) {
01753       assert_compile(PAL_NONE == 0); // Returning 0x4000 (resp. 0xC000) conincidences with default value (PAL_NONE)
01754       map = GB(callback, 0, 14);
01755       /* If bit 14 is set, then the company colours are applied to the
01756        * map else it's returned as-is. */
01757       if (!HasBit(callback, 14)) {
01758         /* Update cache */
01759         if (v != NULL) const_cast<Vehicle *>(v)->colourmap = map;
01760         return map;
01761       }
01762     }
01763   }
01764 
01765   bool twocc = HasBit(e->info.misc_flags, EF_USES_2CC);
01766 
01767   if (map == PAL_NONE) map = twocc ? (PaletteID)SPR_2CCMAP_BASE : (PaletteID)PALETTE_RECOLOUR_START;
01768 
01769   /* Spectator has news shown too, but has invalid company ID - as well as dedicated server */
01770   if (!Company::IsValidID(company)) return map;
01771 
01772   const Livery *livery = GetEngineLivery(engine_type, company, parent_engine_type, v, _settings_client.gui.liveries);
01773 
01774   map += livery->colour1;
01775   if (twocc) map += livery->colour2 * 16;
01776 
01777   /* Update cache */
01778   if (v != NULL) const_cast<Vehicle *>(v)->colourmap = map;
01779   return map;
01780 }
01781 
01788 PaletteID GetEnginePalette(EngineID engine_type, CompanyID company)
01789 {
01790   return GetEngineColourMap(engine_type, company, INVALID_ENGINE, NULL);
01791 }
01792 
01798 PaletteID GetVehiclePalette(const Vehicle *v)
01799 {
01800   if (v->IsGroundVehicle()) {
01801     return GetEngineColourMap(v->engine_type, v->owner, v->GetGroundVehicleCache()->first_engine, v);
01802   }
01803 
01804   return GetEngineColourMap(v->engine_type, v->owner, INVALID_ENGINE, v);
01805 }
01806 
01810 void Vehicle::DeleteUnreachedImplicitOrders()
01811 {
01812   if (this->IsGroundVehicle()) {
01813     uint16 &gv_flags = this->GetGroundVehicleFlags();
01814     if (HasBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS)) {
01815       /* Do not delete orders, only skip them */
01816       ClrBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
01817       this->cur_implicit_order_index = this->cur_real_order_index;
01818       InvalidateVehicleOrder(this, 0);
01819       return;
01820     }
01821   }
01822 
01823   const Order *order = this->GetOrder(this->cur_implicit_order_index);
01824   while (order != NULL) {
01825     if (this->cur_implicit_order_index == this->cur_real_order_index) break;
01826 
01827     if (order->IsType(OT_IMPLICIT)) {
01828       /* Delete order effectively deletes order, so get the next before deleting it. */
01829       order = order->next;
01830       DeleteOrder(this, this->cur_implicit_order_index);
01831     } else {
01832       /* Skip non-implicit orders, e.g. service-orders */
01833       order = order->next;
01834       this->cur_implicit_order_index++;
01835     }
01836 
01837     /* Wrap around */
01838     if (order == NULL) {
01839       order = this->GetOrder(0);
01840       this->cur_implicit_order_index = 0;
01841     }
01842   }
01843 }
01844 
01849 void Vehicle::BeginLoading()
01850 {
01851   assert(IsTileType(this->tile, MP_STATION) || this->type == VEH_SHIP);
01852 
01853   if (this->current_order.IsType(OT_GOTO_STATION) &&
01854       this->current_order.GetDestination() == this->last_station_visited) {
01855     this->DeleteUnreachedImplicitOrders();
01856 
01857     /* Now both order indices point to the destination station, and we can start loading */
01858     this->current_order.MakeLoading(true);
01859     UpdateVehicleTimetable(this, true);
01860 
01861     /* Furthermore add the Non Stop flag to mark that this station
01862      * is the actual destination of the vehicle, which is (for example)
01863      * necessary to be known for HandleTrainLoading to determine
01864      * whether the train is lost or not; not marking a train lost
01865      * that arrives at random stations is bad. */
01866     this->current_order.SetNonStopType(ONSF_NO_STOP_AT_ANY_STATION);
01867 
01868   } else {
01869     /* We weren't scheduled to stop here. Insert an implicit order
01870      * to show that we are stopping here, but only do that if the order
01871      * list isn't empty.
01872      * While only groundvehicles have implicit orders, e.g. aircraft might still enter
01873      * the 'wrong' terminal when skipping orders etc. */
01874     Order *in_list = this->GetOrder(this->cur_implicit_order_index);
01875     if (this->IsGroundVehicle() && in_list != NULL &&
01876         (!in_list->IsType(OT_IMPLICIT) ||
01877         in_list->GetDestination() != this->last_station_visited)) {
01878       bool suppress_implicit_orders = HasBit(this->GetGroundVehicleFlags(), GVF_SUPPRESS_IMPLICIT_ORDERS);
01879       /* Do not create consecutive duplicates of implicit orders */
01880       Order *prev_order = this->cur_implicit_order_index > 0 ? this->GetOrder(this->cur_implicit_order_index - 1) : (this->GetNumOrders() > 1 ? this->GetLastOrder() : NULL);
01881       if (prev_order == NULL ||
01882           (!prev_order->IsType(OT_IMPLICIT) && !prev_order->IsType(OT_GOTO_STATION)) ||
01883           prev_order->GetDestination() != this->last_station_visited) {
01884 
01885         /* Prefer deleting implicit orders instead of inserting new ones,
01886          * so test whether the right order follows later */
01887         int target_index = this->cur_implicit_order_index;
01888         bool found = false;
01889         while (target_index != this->cur_real_order_index) {
01890           const Order *order = this->GetOrder(target_index);
01891           if (order->IsType(OT_IMPLICIT) && order->GetDestination() == this->last_station_visited) {
01892             found = true;
01893             break;
01894           }
01895           target_index++;
01896           if (target_index >= this->orders.list->GetNumOrders()) target_index = 0;
01897           assert(target_index != this->cur_implicit_order_index); // infinite loop?
01898         }
01899 
01900         if (found) {
01901           if (suppress_implicit_orders) {
01902             /* Skip to the found order */
01903             this->cur_implicit_order_index = target_index;
01904             InvalidateVehicleOrder(this, 0);
01905           } else {
01906             /* Delete all implicit orders up to the station we just reached */
01907             const Order *order = this->GetOrder(this->cur_implicit_order_index);
01908             while (!order->IsType(OT_IMPLICIT) || order->GetDestination() != this->last_station_visited) {
01909               if (order->IsType(OT_IMPLICIT)) {
01910                 /* Delete order effectively deletes order, so get the next before deleting it. */
01911                 order = order->next;
01912                 DeleteOrder(this, this->cur_implicit_order_index);
01913               } else {
01914                 /* Skip non-implicit orders, e.g. service-orders */
01915                 order = order->next;
01916                 this->cur_implicit_order_index++;
01917               }
01918 
01919               /* Wrap around */
01920               if (order == NULL) {
01921                 order = this->GetOrder(0);
01922                 this->cur_implicit_order_index = 0;
01923               }
01924               assert(order != NULL);
01925             }
01926           }
01927         } else if (!suppress_implicit_orders && this->orders.list->GetNumOrders() < MAX_VEH_ORDER_ID && Order::CanAllocateItem()) {
01928           /* Insert new implicit order */
01929           Order *implicit_order = new Order();
01930           implicit_order->MakeImplicit(this->last_station_visited);
01931           InsertOrder(this, implicit_order, this->cur_implicit_order_index);
01932           if (this->cur_implicit_order_index > 0) --this->cur_implicit_order_index;
01933 
01934           /* InsertOrder disabled creation of implicit orders for all vehicles with the same implicit order.
01935            * Reenable it for this vehicle */
01936           uint16 &gv_flags = this->GetGroundVehicleFlags();
01937           ClrBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
01938         }
01939       }
01940     }
01941     this->current_order.MakeLoading(false);
01942   }
01943 
01944   Station::Get(this->last_station_visited)->loading_vehicles.push_back(this);
01945 
01946   PrepareUnload(this);
01947 
01948   SetWindowDirty(GetWindowClassForVehicleType(this->type), this->owner);
01949   SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
01950   SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
01951   SetWindowDirty(WC_STATION_VIEW, this->last_station_visited);
01952 
01953   Station::Get(this->last_station_visited)->MarkTilesDirty(true);
01954   this->cur_speed = 0;
01955   this->MarkDirty();
01956 }
01957 
01962 void Vehicle::LeaveStation()
01963 {
01964   assert(this->current_order.IsType(OT_LOADING));
01965 
01966   delete this->cargo_payment;
01967 
01968   /* Only update the timetable if the vehicle was supposed to stop here. */
01969   if (this->current_order.GetNonStopType() != ONSF_STOP_EVERYWHERE) UpdateVehicleTimetable(this, false);
01970 
01971   this->current_order.MakeLeaveStation();
01972   Station *st = Station::Get(this->last_station_visited);
01973   st->loading_vehicles.remove(this);
01974 
01975   HideFillingPercent(&this->fill_percent_te_id);
01976 
01977   if (this->type == VEH_TRAIN && !(this->vehstatus & VS_CRASHED)) {
01978     /* Trigger station animation (trains only) */
01979     if (IsTileType(this->tile, MP_STATION)) TriggerStationAnimation(st, this->tile, SAT_TRAIN_DEPARTS);
01980 
01981     SetBit(Train::From(this)->flags, VRF_LEAVING_STATION);
01982   }
01983 }
01984 
01985 
01991 void Vehicle::HandleLoading(bool mode)
01992 {
01993   switch (this->current_order.GetType()) {
01994     case OT_LOADING: {
01995       uint wait_time = max(this->current_order.wait_time - this->lateness_counter, 0);
01996 
01997       /* Not the first call for this tick, or still loading */
01998       if (mode || !HasBit(this->vehicle_flags, VF_LOADING_FINISHED) || this->current_order_time < wait_time) return;
01999 
02000       this->PlayLeaveStationSound();
02001 
02002       this->LeaveStation();
02003 
02004       /* Only advance to next order if we just loaded at the current one */
02005       const Order *order = this->GetOrder(this->cur_implicit_order_index);
02006       if (order == NULL ||
02007           (!order->IsType(OT_IMPLICIT) && !order->IsType(OT_GOTO_STATION)) ||
02008           order->GetDestination() != this->last_station_visited) {
02009         return;
02010       }
02011       break;
02012     }
02013 
02014     case OT_DUMMY: break;
02015 
02016     default: return;
02017   }
02018 
02019   this->IncrementImplicitOrderIndex();
02020 }
02021 
02028 CommandCost Vehicle::SendToDepot(DoCommandFlag flags, DepotCommand command)
02029 {
02030   CommandCost ret = CheckOwnership(this->owner);
02031   if (ret.Failed()) return ret;
02032 
02033   if (this->vehstatus & VS_CRASHED) return CMD_ERROR;
02034   if (this->IsStoppedInDepot()) return CMD_ERROR;
02035 
02036   if (this->current_order.IsType(OT_GOTO_DEPOT)) {
02037     bool halt_in_depot = (this->current_order.GetDepotActionType() & ODATFB_HALT) != 0;
02038     if (!!(command & DEPOT_SERVICE) == halt_in_depot) {
02039       /* We called with a different DEPOT_SERVICE setting.
02040        * Now we change the setting to apply the new one and let the vehicle head for the same depot.
02041        * Note: the if is (true for requesting service == true for ordered to stop in depot)          */
02042       if (flags & DC_EXEC) {
02043         this->current_order.SetDepotOrderType(ODTF_MANUAL);
02044         this->current_order.SetDepotActionType(halt_in_depot ? ODATF_SERVICE_ONLY : ODATFB_HALT);
02045         SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
02046       }
02047       return CommandCost();
02048     }
02049 
02050     if (command & DEPOT_DONT_CANCEL) return CMD_ERROR; // Requested no cancelation of depot orders
02051     if (flags & DC_EXEC) {
02052       /* If the orders to 'goto depot' are in the orders list (forced servicing),
02053        * then skip to the next order; effectively cancelling this forced service */
02054       if (this->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) this->IncrementRealOrderIndex();
02055 
02056       if (this->IsGroundVehicle()) {
02057         uint16 &gv_flags = this->GetGroundVehicleFlags();
02058         SetBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
02059       }
02060 
02061       this->current_order.MakeDummy();
02062       SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
02063     }
02064     return CommandCost();
02065   }
02066 
02067   TileIndex location;
02068   DestinationID destination;
02069   bool reverse;
02070   static const StringID no_depot[] = {STR_ERROR_UNABLE_TO_FIND_ROUTE_TO, STR_ERROR_UNABLE_TO_FIND_LOCAL_DEPOT, STR_ERROR_UNABLE_TO_FIND_LOCAL_DEPOT, STR_ERROR_CAN_T_SEND_AIRCRAFT_TO_HANGAR};
02071   if (!this->FindClosestDepot(&location, &destination, &reverse)) return_cmd_error(no_depot[this->type]);
02072 
02073   if (flags & DC_EXEC) {
02074     if (this->current_order.IsType(OT_LOADING)) this->LeaveStation();
02075 
02076     if (this->IsGroundVehicle()) {
02077       uint16 &gv_flags = this->GetGroundVehicleFlags();
02078       SetBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
02079     }
02080 
02081     this->dest_tile = location;
02082     this->current_order.MakeGoToDepot(destination, ODTF_MANUAL);
02083     if (!(command & DEPOT_SERVICE)) this->current_order.SetDepotActionType(ODATFB_HALT);
02084     SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
02085 
02086     /* If there is no depot in front, reverse automatically (trains only) */
02087     if (this->type == VEH_TRAIN && reverse) DoCommand(this->tile, this->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
02088 
02089     if (this->type == VEH_AIRCRAFT) {
02090       Aircraft *a = Aircraft::From(this);
02091       if (a->state == FLYING && a->targetairport != destination) {
02092         /* The aircraft is now heading for a different hangar than the next in the orders */
02093         extern void AircraftNextAirportPos_and_Order(Aircraft *a);
02094         AircraftNextAirportPos_and_Order(a);
02095       }
02096     }
02097   }
02098 
02099   return CommandCost();
02100 
02101 }
02102 
02107 void Vehicle::UpdateVisualEffect(bool allow_power_change)
02108 {
02109   bool powered_before = HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER);
02110   const Engine *e = this->GetEngine();
02111 
02112   /* Evaluate properties */
02113   byte visual_effect;
02114   switch (e->type) {
02115     case VEH_TRAIN: visual_effect = e->u.rail.visual_effect; break;
02116     case VEH_ROAD:  visual_effect = e->u.road.visual_effect; break;
02117     case VEH_SHIP:  visual_effect = e->u.ship.visual_effect; break;
02118     default:        visual_effect = 1 << VE_DISABLE_EFFECT;  break;
02119   }
02120 
02121   /* Check powered wagon / visual effect callback */
02122   if (HasBit(e->info.callback_mask, CBM_VEHICLE_VISUAL_EFFECT)) {
02123     uint16 callback = GetVehicleCallback(CBID_VEHICLE_VISUAL_EFFECT, 0, 0, this->engine_type, this);
02124 
02125     if (callback != CALLBACK_FAILED) {
02126       if (callback >= 0x100 && e->GetGRF()->grf_version >= 8) ErrorUnknownCallbackResult(e->GetGRFID(), CBID_VEHICLE_VISUAL_EFFECT, callback);
02127 
02128       callback = GB(callback, 0, 8);
02129       /* Avoid accidentally setting 'visual_effect' to the default value
02130        * Since bit 6 (disable effects) is set anyways, we can safely erase some bits. */
02131       if (callback == VE_DEFAULT) {
02132         assert(HasBit(callback, VE_DISABLE_EFFECT));
02133         SB(callback, VE_TYPE_START, VE_TYPE_COUNT, 0);
02134       }
02135       visual_effect = callback;
02136     }
02137   }
02138 
02139   /* Apply default values */
02140   if (visual_effect == VE_DEFAULT ||
02141       (!HasBit(visual_effect, VE_DISABLE_EFFECT) && GB(visual_effect, VE_TYPE_START, VE_TYPE_COUNT) == VE_TYPE_DEFAULT)) {
02142     /* Only train engines have default effects.
02143      * Note: This is independent of whether the engine is a front engine or articulated part or whatever. */
02144     if (e->type != VEH_TRAIN || e->u.rail.railveh_type == RAILVEH_WAGON || !IsInsideMM(e->u.rail.engclass, EC_STEAM, EC_MONORAIL)) {
02145       if (visual_effect == VE_DEFAULT) {
02146         visual_effect = 1 << VE_DISABLE_EFFECT;
02147       } else {
02148         SetBit(visual_effect, VE_DISABLE_EFFECT);
02149       }
02150     } else {
02151       if (visual_effect == VE_DEFAULT) {
02152         /* Also set the offset */
02153         visual_effect = (VE_OFFSET_CENTRE - (e->u.rail.engclass == EC_STEAM ? 4 : 0)) << VE_OFFSET_START;
02154       }
02155       SB(visual_effect, VE_TYPE_START, VE_TYPE_COUNT, e->u.rail.engclass - EC_STEAM + VE_TYPE_STEAM);
02156     }
02157   }
02158 
02159   this->vcache.cached_vis_effect = visual_effect;
02160 
02161   if (!allow_power_change && powered_before != HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER)) {
02162     ToggleBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER);
02163     ShowNewGrfVehicleError(this->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_POWERED_WAGON, GBUG_VEH_POWERED_WAGON, false);
02164   }
02165 }
02166 
02167 static const int8 _vehicle_smoke_pos[8] = {
02168   1, 1, 1, 0, -1, -1, -1, 0
02169 };
02170 
02175 void Vehicle::ShowVisualEffect() const
02176 {
02177   assert(this->IsPrimaryVehicle());
02178   bool sound = false;
02179 
02180   /* Do not show any smoke when:
02181    * - vehicle smoke is disabled by the player
02182    * - the vehicle is slowing down or stopped (by the player)
02183    * - the vehicle is moving very slowly
02184    */
02185   if (_settings_game.vehicle.smoke_amount == 0 ||
02186       this->vehstatus & (VS_TRAIN_SLOWING | VS_STOPPED) ||
02187       this->cur_speed < 2) {
02188     return;
02189   }
02190   if (this->type == VEH_TRAIN) {
02191     const Train *t = Train::From(this);
02192     /* For trains, do not show any smoke when:
02193      * - the train is reversing
02194      * - is entering a station with an order to stop there and its speed is equal to maximum station entering speed
02195      */
02196     if (HasBit(t->flags, VRF_REVERSING) ||
02197         (IsRailStationTile(t->tile) && t->IsFrontEngine() && t->current_order.ShouldStopAtStation(t, GetStationIndex(t->tile)) &&
02198         t->cur_speed >= t->Train::GetCurrentMaxSpeed())) {
02199       return;
02200     }
02201   }
02202 
02203   const Vehicle *v = this;
02204 
02205   do {
02206     int effect_offset = GB(v->vcache.cached_vis_effect, VE_OFFSET_START, VE_OFFSET_COUNT) - VE_OFFSET_CENTRE;
02207     byte effect_type = GB(v->vcache.cached_vis_effect, VE_TYPE_START, VE_TYPE_COUNT);
02208     bool disable_effect = HasBit(v->vcache.cached_vis_effect, VE_DISABLE_EFFECT);
02209 
02210     /* Show no smoke when:
02211      * - Smoke has been disabled for this vehicle
02212      * - The vehicle is not visible
02213      * - The vehicle is under a bridge
02214      * - The vehicle is on a depot tile
02215      * - The vehicle is on a tunnel tile
02216      * - The vehicle is a train engine that is currently unpowered */
02217     if (disable_effect ||
02218         v->vehstatus & VS_HIDDEN ||
02219         (MayHaveBridgeAbove(v->tile) && IsBridgeAbove(v->tile)) ||
02220         IsDepotTile(v->tile) ||
02221         IsTunnelTile(v->tile) ||
02222         (v->type == VEH_TRAIN &&
02223         !HasPowerOnRail(Train::From(v)->railtype, GetTileRailType(v->tile)))) {
02224       continue;
02225     }
02226 
02227     /* The effect offset is relative to a point 4 units behind the vehicle's
02228      * front (which is the center of an 8/8 vehicle). Shorter vehicles need a
02229      * correction factor. */
02230     if (v->type == VEH_TRAIN) effect_offset += (VEHICLE_LENGTH - Train::From(v)->gcache.cached_veh_length) / 2;
02231 
02232     int x = _vehicle_smoke_pos[v->direction] * effect_offset;
02233     int y = _vehicle_smoke_pos[(v->direction + 2) % 8] * effect_offset;
02234 
02235     if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION)) {
02236       x = -x;
02237       y = -y;
02238     }
02239 
02240     switch (effect_type) {
02241       case VE_TYPE_STEAM:
02242         /* Steam smoke - amount is gradually falling until vehicle reaches its maximum speed, after that it's normal.
02243          * Details: while vehicle's current speed is gradually increasing, steam plumes' density decreases by one third each
02244          * third of its maximum speed spectrum. Steam emission finally normalises at very close to vehicle's maximum speed.
02245          * REGULATION:
02246          * - instead of 1, 4 / 2^smoke_amount (max. 2) is used to provide sufficient regulation to steam puffs' amount. */
02247         if (GB(v->tick_counter, 0, ((4 >> _settings_game.vehicle.smoke_amount) + ((this->cur_speed * 3) / this->vcache.cached_max_speed))) == 0) {
02248           CreateEffectVehicleRel(v, x, y, 10, EV_STEAM_SMOKE);
02249           sound = true;
02250         }
02251         break;
02252 
02253       case VE_TYPE_DIESEL: {
02254         /* Diesel smoke - thicker when vehicle is starting, gradually subsiding till it reaches its maximum speed
02255          * when smoke emission stops.
02256          * Details: Vehicle's (max.) speed spectrum is divided into 32 parts. When max. speed is reached, chance for smoke
02257          * emission erodes by 32 (1/4). For trains, power and weight come in handy too to either increase smoke emission in
02258          * 6 steps (1000HP each) if the power is low or decrease smoke emission in 6 steps (512 tonnes each) if the train
02259          * isn't overweight. Power and weight contributions are expressed in a way that neither extreme power, nor
02260          * extreme weight can ruin the balance (e.g. FreightWagonMultiplier) in the formula. When the vehicle reaches
02261          * maximum speed no diesel_smoke is emitted.
02262          * REGULATION:
02263          * - up to which speed a diesel vehicle is emitting smoke (with reduced/small setting only until 1/2 of max_speed),
02264          * - in Chance16 - the last value is 512 / 2^smoke_amount (max. smoke when 128 = smoke_amount of 2). */
02265         int power_weight_effect = 0;
02266         if (v->type == VEH_TRAIN) {
02267           power_weight_effect = (32 >> (Train::From(this)->gcache.cached_power >> 10)) - (32 >> (Train::From(this)->gcache.cached_weight >> 9));
02268         }
02269         if (this->cur_speed < (this->vcache.cached_max_speed >> (2 >> _settings_game.vehicle.smoke_amount)) &&
02270             Chance16((64 - ((this->cur_speed << 5) / this->vcache.cached_max_speed) + power_weight_effect), (512 >> _settings_game.vehicle.smoke_amount))) {
02271           CreateEffectVehicleRel(v, x, y, 10, EV_DIESEL_SMOKE);
02272           sound = true;
02273         }
02274         break;
02275       }
02276 
02277       case VE_TYPE_ELECTRIC:
02278         /* Electric train's spark - more often occurs when train is departing (more load)
02279          * Details: Electric locomotives are usually at least twice as powerful as their diesel counterparts, so spark
02280          * emissions are kept simple. Only when starting, creating huge force are sparks more likely to happen, but when
02281          * reaching its max. speed, quarter by quarter of it, chance decreases untill the usuall 2,22% at train's top speed.
02282          * REGULATION:
02283          * - in Chance16 the last value is 360 / 2^smoke_amount (max. sparks when 90 = smoke_amount of 2). */
02284         if (GB(v->tick_counter, 0, 2) == 0 &&
02285             Chance16((6 - ((this->cur_speed << 2) / this->vcache.cached_max_speed)), (360 >> _settings_game.vehicle.smoke_amount))) {
02286           CreateEffectVehicleRel(v, x, y, 10, EV_ELECTRIC_SPARK);
02287           sound = true;
02288         }
02289         break;
02290 
02291       default:
02292         break;
02293     }
02294   } while ((v = v->Next()) != NULL);
02295 
02296   if (sound) PlayVehicleSound(this, VSE_VISUAL_EFFECT);
02297 }
02298 
02303 void Vehicle::SetNext(Vehicle *next)
02304 {
02305   assert(this != next);
02306 
02307   if (this->next != NULL) {
02308     /* We had an old next vehicle. Update the first and previous pointers */
02309     for (Vehicle *v = this->next; v != NULL; v = v->Next()) {
02310       v->first = this->next;
02311     }
02312     this->next->previous = NULL;
02313   }
02314 
02315   this->next = next;
02316 
02317   if (this->next != NULL) {
02318     /* A new next vehicle. Update the first and previous pointers */
02319     if (this->next->previous != NULL) this->next->previous->next = NULL;
02320     this->next->previous = this;
02321     for (Vehicle *v = this->next; v != NULL; v = v->Next()) {
02322       v->first = this->first;
02323     }
02324   }
02325 }
02326 
02332 void Vehicle::AddToShared(Vehicle *shared_chain)
02333 {
02334   assert(this->previous_shared == NULL && this->next_shared == NULL);
02335 
02336   if (shared_chain->orders.list == NULL) {
02337     assert(shared_chain->previous_shared == NULL);
02338     assert(shared_chain->next_shared == NULL);
02339     this->orders.list = shared_chain->orders.list = new OrderList(NULL, shared_chain);
02340   }
02341 
02342   this->next_shared     = shared_chain->next_shared;
02343   this->previous_shared = shared_chain;
02344 
02345   shared_chain->next_shared = this;
02346 
02347   if (this->next_shared != NULL) this->next_shared->previous_shared = this;
02348 
02349   shared_chain->orders.list->AddVehicle(this);
02350 }
02351 
02355 void Vehicle::RemoveFromShared()
02356 {
02357   /* Remember if we were first and the old window number before RemoveVehicle()
02358    * as this changes first if needed. */
02359   bool were_first = (this->FirstShared() == this);
02360   VehicleListIdentifier vli(VL_SHARED_ORDERS, this->type, this->owner, this->FirstShared()->index);
02361 
02362   this->orders.list->RemoveVehicle(this);
02363 
02364   if (!were_first) {
02365     /* We are not the first shared one, so only relink our previous one. */
02366     this->previous_shared->next_shared = this->NextShared();
02367   }
02368 
02369   if (this->next_shared != NULL) this->next_shared->previous_shared = this->previous_shared;
02370 
02371 
02372   if (this->orders.list->GetNumVehicles() == 1) {
02373     /* When there is only one vehicle, remove the shared order list window. */
02374     DeleteWindowById(GetWindowClassForVehicleType(this->type), vli.Pack());
02375     InvalidateVehicleOrder(this->FirstShared(), 0);
02376   } else if (were_first) {
02377     /* If we were the first one, update to the new first one.
02378      * Note: FirstShared() is already the new first */
02379     InvalidateWindowData(GetWindowClassForVehicleType(this->type), vli.Pack(), this->FirstShared()->index | (1U << 31));
02380   }
02381 
02382   this->next_shared     = NULL;
02383   this->previous_shared = NULL;
02384 }
02385 
02386 void VehiclesYearlyLoop()
02387 {
02388   Vehicle *v;
02389   FOR_ALL_VEHICLES(v) {
02390     if (v->IsPrimaryVehicle()) {
02391       /* show warning if vehicle is not generating enough income last 2 years (corresponds to a red icon in the vehicle list) */
02392       Money profit = v->GetDisplayProfitThisYear();
02393       if (v->age >= 730 && profit < 0) {
02394         if (_settings_client.gui.vehicle_income_warn && v->owner == _local_company) {
02395           SetDParam(0, v->index);
02396           SetDParam(1, profit);
02397           AddVehicleNewsItem(
02398             STR_NEWS_VEHICLE_IS_UNPROFITABLE,
02399             NS_ADVICE,
02400             v->index
02401           );
02402         }
02403         AI::NewEvent(v->owner, new ScriptEventVehicleUnprofitable(v->index));
02404       }
02405 
02406       v->profit_last_year = v->profit_this_year;
02407       v->profit_this_year = 0;
02408       SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
02409     }
02410   }
02411   GroupStatistics::UpdateProfits();
02412   SetWindowClassesDirty(WC_TRAINS_LIST);
02413   SetWindowClassesDirty(WC_SHIPS_LIST);
02414   SetWindowClassesDirty(WC_ROADVEH_LIST);
02415   SetWindowClassesDirty(WC_AIRCRAFT_LIST);
02416 }
02417 
02418 
02428 bool CanVehicleUseStation(EngineID engine_type, const Station *st)
02429 {
02430   const Engine *e = Engine::GetIfValid(engine_type);
02431   assert(e != NULL);
02432 
02433   switch (e->type) {
02434     case VEH_TRAIN:
02435       return (st->facilities & FACIL_TRAIN) != 0;
02436 
02437     case VEH_ROAD:
02438       /* For road vehicles we need the vehicle to know whether it can actually
02439        * use the station, but if it doesn't have facilities for RVs it is
02440        * certainly not possible that the station can be used. */
02441       return (st->facilities & (FACIL_BUS_STOP | FACIL_TRUCK_STOP)) != 0;
02442 
02443     case VEH_SHIP:
02444       return (st->facilities & FACIL_DOCK) != 0;
02445 
02446     case VEH_AIRCRAFT:
02447       return (st->facilities & FACIL_AIRPORT) != 0 &&
02448           (st->airport.GetFTA()->flags & (e->u.air.subtype & AIR_CTOL ? AirportFTAClass::AIRPLANES : AirportFTAClass::HELICOPTERS)) != 0;
02449 
02450     default:
02451       return false;
02452   }
02453 }
02454 
02461 bool CanVehicleUseStation(const Vehicle *v, const Station *st)
02462 {
02463   if (v->type == VEH_ROAD) return st->GetPrimaryRoadStop(RoadVehicle::From(v)) != NULL;
02464 
02465   return CanVehicleUseStation(v->engine_type, st);
02466 }
02467 
02473 GroundVehicleCache *Vehicle::GetGroundVehicleCache()
02474 {
02475   assert(this->IsGroundVehicle());
02476   if (this->type == VEH_TRAIN) {
02477     return &Train::From(this)->gcache;
02478   } else {
02479     return &RoadVehicle::From(this)->gcache;
02480   }
02481 }
02482 
02488 const GroundVehicleCache *Vehicle::GetGroundVehicleCache() const
02489 {
02490   assert(this->IsGroundVehicle());
02491   if (this->type == VEH_TRAIN) {
02492     return &Train::From(this)->gcache;
02493   } else {
02494     return &RoadVehicle::From(this)->gcache;
02495   }
02496 }
02497 
02503 uint16 &Vehicle::GetGroundVehicleFlags()
02504 {
02505   assert(this->IsGroundVehicle());
02506   if (this->type == VEH_TRAIN) {
02507     return Train::From(this)->gv_flags;
02508   } else {
02509     return RoadVehicle::From(this)->gv_flags;
02510   }
02511 }
02512 
02518 const uint16 &Vehicle::GetGroundVehicleFlags() const
02519 {
02520   assert(this->IsGroundVehicle());
02521   if (this->type == VEH_TRAIN) {
02522     return Train::From(this)->gv_flags;
02523   } else {
02524     return RoadVehicle::From(this)->gv_flags;
02525   }
02526 }
02527 
02536 void GetVehicleSet(VehicleSet &set, Vehicle *v, uint8 num_vehicles)
02537 {
02538   if (v->type == VEH_TRAIN) {
02539     Train *u = Train::From(v);
02540     /* Only include whole vehicles, so start with the first articulated part */
02541     u = u->GetFirstEnginePart();
02542 
02543     /* Include num_vehicles vehicles, not counting articulated parts */
02544     for (; u != NULL && num_vehicles > 0; num_vehicles--) {
02545       do {
02546         /* Include current vehicle in the selection. */
02547         set.Include(u->index);
02548 
02549         /* If the vehicle is multiheaded, add the other part too. */
02550         if (u->IsMultiheaded()) set.Include(u->other_multiheaded_part->index);
02551 
02552         u = u->Next();
02553       } while (u != NULL && u->IsArticulatedPart());
02554     }
02555   }
02556 }