vehicle.cpp

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