vehicle.cpp

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