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