vehicle.cpp

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