vehicle.cpp

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