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