# vehicle.cpp

Go to the documentation of this file.

    00001 /* $Id: vehicle.cpp 24231 2012-05-12 07:46:05Z rubidium $ */
    00002
    00003 /*
    00004  * This file is part of OpenTTD.
    00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
    00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
    00008  */
    00009
    00012 #include "stdafx.h"
    00013 #include "error.h"
    00014 #include "roadveh.h"
    00015 #include "ship.h"
    00016 #include "spritecache.h"
    00017 #include "timetable.h"
    00018 #include "viewport_func.h"
    00019 #include "news_func.h"
    00020 #include "command_func.h"
    00021 #include "company_func.h"
    00022 #include "train.h"
    00023 #include "aircraft.h"
    00024 #include "newgrf_debug.h"
    00025 #include "newgrf_sound.h"
    00026 #include "newgrf_station.h"
    00027 #include "group_gui.h"
    00028 #include "strings_func.h"
    00029 #include "zoom_func.h"
    00030 #include "date_func.h"
    00031 #include "vehicle_func.h"
    00032 #include "autoreplace_func.h"
    00033 #include "autoreplace_gui.h"
    00034 #include "station_base.h"
    00035 #include "ai/ai.hpp"
    00036 #include "depot_func.h"
    00037 #include "network/network.h"
    00038 #include "core/pool_func.hpp"
    00039 #include "economy_base.h"
    00040 #include "articulated_vehicles.h"
    00041 #include "roadstop_base.h"
    00042 #include "core/random_func.hpp"
    00043 #include "core/backup_type.hpp"
    00044 #include "order_backup.h"
    00045 #include "sound_func.h"
    00046 #include "effectvehicle_func.h"
    00047 #include "effectvehicle_base.h"
    00048 #include "vehiclelist.h"
    00049 #include "bridge_map.h"
    00050 #include "tunnel_map.h"
    00051 #include "depot_map.h"
    00052 #include "gamelog.h"
    00053
    00054 #include "table/strings.h"
    00055
    00056 #define GEN_HASH(x, y) ((GB((y), 6 + ZOOM_LVL_SHIFT, 6) << 6) + GB((x), 7 + ZOOM_LVL_SHIFT, 6))
    00057
    00058 VehicleID _new_vehicle_id;
    00059 uint16 _returned_refit_capacity;
    00060 uint16 _returned_mail_refit_capacity;
    00061
    00062
    00064 VehiclePool _vehicle_pool("Vehicle");
    00065 INSTANTIATE_POOL_METHODS(Vehicle)
    00066
    00067
    00072 bool Vehicle::NeedsAutorenewing(const Company *c) const
    00073 {
    00074   /* We can always generate the Company pointer when we have the vehicle.
    00075    * However this takes time and since the Company pointer is often present
    00076    * when this function is called then it's faster to pass the pointer as an
    00077    * argument rather than finding it again. */
    00078   assert(c == Company::Get(this->owner));
    00079
    00080   if (!c->settings.engine_renew) return false;
    00081   if (this->age - this->max_age < (c->settings.engine_renew_months * 30)) return false;
    00082
    00083   /* Only engines need renewing */
    00084   if (this->type == VEH_TRAIN && !Train::From(this)->IsEngine()) return false;
    00085
    00086   return true;
    00087 }
    00088
    00089 void VehicleServiceInDepot(Vehicle *v)
    00090 {
    00091   v->date_of_last_service = _date;
    00092   v->breakdowns_since_last_service = 0;
    00093   v->reliability = v->GetEngine()->reliability;
    00094   SetWindowDirty(WC_VEHICLE_DETAILS, v->index); // ensure that last service date and reliability are updated
    00095 }
    00096
    00103 bool Vehicle::NeedsServicing() const
    00104 {
    00105   /* Stopped or crashed vehicles will not move, as such making unmovable
    00106    * vehicles to go for service is lame. */
    00107   if (this->vehstatus & (VS_STOPPED | VS_CRASHED)) return false;
    00108
    00109   /* Are we ready for the next service cycle? */
    00110   const Company *c = Company::Get(this->owner);
    00111   if (c->settings.vehicle.servint_ispercent ?
    00112       (this->reliability >= this->GetEngine()->reliability * (100 - this->service_interval) / 100) :
    00113       (this->date_of_last_service + this->service_interval >= _date)) {
    00114     return false;
    00115   }
    00116
    00117   /* If we're servicing anyway, because we have not disabled servicing when
    00118    * there are no breakdowns or we are playing with breakdowns, bail out. */
    00119   if (!_settings_game.order.no_servicing_if_no_breakdowns ||
    00120       _settings_game.difficulty.vehicle_breakdowns != 0) {
    00121     return true;
    00122   }
    00123
    00124   /* Test whether there is some pending autoreplace.
    00125    * Note: We do this after the service-interval test.
    00126    * There are a lot more reasons for autoreplace to fail than we can test here reasonably. */
    00127   bool pending_replace = false;
    00128   Money needed_money = c->settings.engine_renew_money;
    00129   if (needed_money > c->money) return false;
    00130
    00131   for (const Vehicle *v = this; v != NULL; v = (v->type == VEH_TRAIN) ? Train::From(v)->GetNextUnit() : NULL) {
    00132     EngineID new_engine = EngineReplacementForCompany(c, v->engine_type, v->group_id);
    00133
    00134     /* Check engine availability */
    00135     if (new_engine == INVALID_ENGINE || !HasBit(Engine::Get(new_engine)->company_avail, v->owner)) continue;
    00136
    00137     /* Check refittability */
    00138     uint32 available_cargo_types, union_mask;
    00139     GetArticulatedRefitMasks(new_engine, true, &union_mask, &available_cargo_types);
    00140     /* Is there anything to refit? */
    00141     if (union_mask != 0) {
    00142       CargoID cargo_type;
    00143       /* We cannot refit to mixed cargoes in an automated way */
    00144       if (IsArticulatedVehicleCarryingDifferentCargoes(v, &cargo_type)) continue;
    00145
    00146       /* Did the old vehicle carry anything? */
    00147       if (cargo_type != CT_INVALID) {
    00148         /* We can't refit the vehicle to carry the cargo we want */
    00149         if (!HasBit(available_cargo_types, cargo_type)) continue;
    00150       }
    00151     }
    00152
    00153     /* Check money.
    00154      * We want 2*(the price of the new vehicle) without looking at the value of the vehicle we are going to sell. */
    00155     pending_replace = true;
    00156     needed_money += 2 * Engine::Get(new_engine)->GetCost();
    00157     if (needed_money > c->money) return false;
    00158   }
    00159
    00160   return pending_replace;
    00161 }
    00162
    00168 bool Vehicle::NeedsAutomaticServicing() const
    00169 {
    00170   if (this->HasDepotOrder()) return false;
    00171   if (this->current_order.IsType(OT_LOADING)) return false;
    00172   if (this->current_order.IsType(OT_GOTO_DEPOT) && this->current_order.GetDepotOrderType() != ODTFB_SERVICE) return false;
    00173   return NeedsServicing();
    00174 }
    00175
    00176 uint Vehicle::Crash(bool flooded)
    00177 {
    00178   assert((this->vehstatus & VS_CRASHED) == 0);
    00179   assert(this->Previous() == NULL); // IsPrimaryVehicle fails for free-wagon-chains
    00180
    00181   uint pass = 0;
    00182   /* Stop the vehicle. */
    00183   if (this->IsPrimaryVehicle()) this->vehstatus |= VS_STOPPED;
    00184   /* crash all wagons, and count passengers */
    00185   for (Vehicle *v = this; v != NULL; v = v->Next()) {
    00186     if (IsCargoInClass(v->cargo_type, CC_PASSENGERS)) pass += v->cargo.Count();
    00187     v->vehstatus |= VS_CRASHED;
    00188     MarkSingleVehicleDirty(v);
    00189   }
    00190
    00191   /* Dirty some windows */
    00192   InvalidateWindowClassesData(GetWindowClassForVehicleType(this->type), 0);
    00193   SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
    00194   SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
    00195   SetWindowDirty(WC_VEHICLE_DEPOT, this->tile);
    00196
    00197   delete this->cargo_payment;
    00198   this->cargo_payment = NULL;
    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::Get(this->last_station_visited)->loading_vehicles.remove(this);
    00718
    00719     HideFillingPercent(&this->fill_percent_te_id);
    00720
    00721     delete this->cargo_payment;
    00722   }
    00723
    00724   if (this->IsEngineCountable()) {
    00725     GroupStatistics::CountEngine(this, -1);
    00726     if (this->IsPrimaryVehicle()) GroupStatistics::CountVehicle(this, -1);
    00727     GroupStatistics::UpdateAutoreplace(this->owner);
    00728
    00729     if (this->owner == _local_company) InvalidateAutoreplaceWindow(this->engine_type, this->group_id);
    00730     DeleteGroupHighlightOfVehicle(this);
    00731   }
    00732
    00733   if (this->type == VEH_AIRCRAFT && this->IsPrimaryVehicle()) {
    00734     Aircraft *a = Aircraft::From(this);
    00735     Station *st = GetTargetAirportIfValid(a);
    00736     if (st != NULL) {
    00737       const AirportFTA *layout = st->airport.GetFTA()->layout;
    00738       CLRBITS(st->airport.flags, layout[a->previous_pos].block | layout[a->pos].block);
    00739     }
    00740   }
    00741
    00742
    00743   if (this->type == VEH_ROAD && this->IsPrimaryVehicle()) {
    00744     RoadVehicle *v = RoadVehicle::From(this);
    00745     if (!(v->vehstatus & VS_CRASHED) && IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END)) {
    00746       /* Leave the drive through roadstop, when you have not already left it. */
    00747       RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile))->Leave(v);
    00748     }
    00749   }
    00750
    00751   if (this->Previous() == NULL) {
    00752     InvalidateWindowData(WC_VEHICLE_DEPOT, this->tile);
    00753   }
    00754
    00755   if (this->IsPrimaryVehicle()) {
    00756     DeleteWindowById(WC_VEHICLE_VIEW, this->index);
    00757     DeleteWindowById(WC_VEHICLE_ORDERS, this->index);
    00758     DeleteWindowById(WC_VEHICLE_REFIT, this->index);
    00759     DeleteWindowById(WC_VEHICLE_DETAILS, this->index);
    00760     DeleteWindowById(WC_VEHICLE_TIMETABLE, this->index);
    00761     SetWindowDirty(WC_COMPANY, this->owner);
    00762     OrderBackup::ClearVehicle(this);
    00763   }
    00764   InvalidateWindowClassesData(GetWindowClassForVehicleType(this->type), 0);
    00765
    00766   this->cargo.Truncate(0);
    00767   DeleteVehicleOrders(this);
    00768   DeleteDepotHighlightOfVehicle(this);
    00769
    00770   extern void StopGlobalFollowVehicle(const Vehicle *v);
    00771   StopGlobalFollowVehicle(this);
    00772
    00773   ReleaseDisastersTargetingVehicle(this->index);
    00774 }
    00775
    00776 Vehicle::~Vehicle()
    00777 {
    00778   free(this->name);
    00779
    00780   if (CleaningPool()) {
    00781     this->cargo.OnCleanPool();
    00782     return;
    00783   }
    00784
    00785   /* sometimes, eg. for disaster vehicles, when company bankrupts, when removing crashed/flooded vehicles,
    00786    * it may happen that vehicle chain is deleted when visible */
    00787   if (!(this->vehstatus & VS_HIDDEN)) MarkSingleVehicleDirty(this);
    00788
    00789   Vehicle *v = this->Next();
    00790   this->SetNext(NULL);
    00791
    00792   delete v;
    00793
    00794   UpdateVehicleTileHash(this, true);
    00795   UpdateVehicleViewportHash(this, INVALID_COORD, 0);
    00796   DeleteVehicleNews(this->index, INVALID_STRING_ID);
    00797   DeleteNewGRFInspectWindow(GetGrfSpecFeature(this->type), this->index);
    00798 }
    00799
    00804 void VehicleEnteredDepotThisTick(Vehicle *v)
    00805 {
    00806   /* Vehicle should stop in the depot if it was in 'stopping' state */
    00807   _vehicles_to_autoreplace[v] = !(v->vehstatus & VS_STOPPED);
    00808
    00809   /* We ALWAYS set the stopped state. Even when the vehicle does not plan on
    00810    * stopping in the depot, so we stop it to ensure that it will not reserve
    00811    * the path out of the depot before we might autoreplace it to a different
    00812    * engine. The new engine would not own the reserved path we store that we
    00813    * stopped the vehicle, so autoreplace can start it again */
    00814   v->vehstatus |= VS_STOPPED;
    00815 }
    00816
    00822 static void RunVehicleDayProc()
    00823 {
    00824   if (_game_mode != GM_NORMAL) return;
    00825
    00826   /* Run the day_proc for every DAY_TICKS vehicle starting at _date_fract. */
    00827   for (size_t i = _date_fract; i < Vehicle::GetPoolSize(); i += DAY_TICKS) {
    00828     Vehicle *v = Vehicle::Get(i);
    00829     if (v == NULL) continue;
    00830
    00831     /* Call the 32-day callback if needed */
    00832     if ((v->day_counter & 0x1F) == 0 && v->HasEngineType()) {
    00833       uint16 callback = GetVehicleCallback(CBID_VEHICLE_32DAY_CALLBACK, 0, 0, v->engine_type, v);
    00834       if (callback != CALLBACK_FAILED) {
    00835         if (HasBit(callback, 0)) TriggerVehicle(v, VEHICLE_TRIGGER_CALLBACK_32); // Trigger vehicle trigger 10
    00836         if (HasBit(callback, 1)) v->colourmap = PAL_NONE;
    00837
    00838         if (callback & ~3) ErrorUnknownCallbackResult(v->GetGRFID(), CBID_VEHICLE_32DAY_CALLBACK, callback);
    00839       }
    00840     }
    00841
    00842     /* This is called once per day for each vehicle, but not in the first tick of the day */
    00843     v->OnNewDay();
    00844   }
    00845 }
    00846
    00847 void CallVehicleTicks()
    00848 {
    00849   _vehicles_to_autoreplace.Clear();
    00850
    00851   RunVehicleDayProc();
    00852
    00853   Station *st;
    00854   FOR_ALL_STATIONS(st) LoadUnloadStation(st);
    00855
    00856   Vehicle *v;
    00857   FOR_ALL_VEHICLES(v) {
    00858     /* Vehicle could be deleted in this tick */
    00859     if (!v->Tick()) {
    00860       assert(Vehicle::Get(vehicle_index) == NULL);
    00861       continue;
    00862     }
    00863
    00864     assert(Vehicle::Get(vehicle_index) == v);
    00865
    00866     switch (v->type) {
    00867       default: break;
    00868
    00869       case VEH_TRAIN:
    00870       case VEH_ROAD:
    00871       case VEH_AIRCRAFT:
    00872       case VEH_SHIP:
    00873         if (v->vcache.cached_cargo_age_period != 0) {
    00874           v->cargo_age_counter = min(v->cargo_age_counter, v->vcache.cached_cargo_age_period);
    00875           if (--v->cargo_age_counter == 0) {
    00876             v->cargo.AgeCargo();
    00877             v->cargo_age_counter = v->vcache.cached_cargo_age_period;
    00878           }
    00879         }
    00880
    00881         if (v->type == VEH_TRAIN && Train::From(v)->IsWagon()) continue;
    00882         if (v->type == VEH_AIRCRAFT && v->subtype != AIR_HELICOPTER) continue;
    00883         if (v->type == VEH_ROAD && !RoadVehicle::From(v)->IsFrontEngine()) continue;
    00884
    00885         v->motion_counter += v->cur_speed;
    00886         /* Play a running sound if the motion counter passes 256 (Do we not skip sounds?) */
    00887         if (GB(v->motion_counter, 0, 8) < v->cur_speed) PlayVehicleSound(v, VSE_RUNNING);
    00888
    00889         /* Play an alterate running sound every 16 ticks */
    00890         if (GB(v->tick_counter, 0, 4) == 0) PlayVehicleSound(v, v->cur_speed > 0 ? VSE_RUNNING_16 : VSE_STOPPED_16);
    00891     }
    00892   }
    00893
    00894   Backup<CompanyByte> cur_company(_current_company, FILE_LINE);
    00895   for (AutoreplaceMap::iterator it = _vehicles_to_autoreplace.Begin(); it != _vehicles_to_autoreplace.End(); it++) {
    00896     v = it->first;
    00897     /* Autoreplace needs the current company set as the vehicle owner */
    00898     cur_company.Change(v->owner);
    00899
    00900     /* Start vehicle if we stopped them in VehicleEnteredDepotThisTick()
    00901      * We need to stop them between VehicleEnteredDepotThisTick() and here or we risk that
    00902      * they are already leaving the depot again before being replaced. */
    00903     if (it->second) v->vehstatus &= ~VS_STOPPED;
    00904
    00905     /* Store the position of the effect as the vehicle pointer will become invalid later */
    00906     int x = v->x_pos;
    00907     int y = v->y_pos;
    00908     int z = v->z_pos;
    00909
    00910     const Company *c = Company::Get(_current_company);
    00911     SubtractMoneyFromCompany(CommandCost(EXPENSES_NEW_VEHICLES, (Money)c->settings.engine_renew_money));
    00912     CommandCost res = DoCommand(0, v->index, 0, DC_EXEC, CMD_AUTOREPLACE_VEHICLE);
    00913     SubtractMoneyFromCompany(CommandCost(EXPENSES_NEW_VEHICLES, -(Money)c->settings.engine_renew_money));
    00914
    00915     if (!IsLocalCompany()) continue;
    00916
    00917     if (res.Succeeded()) {
    00918       ShowCostOrIncomeAnimation(x, y, z, res.GetCost());
    00919       continue;
    00920     }
    00921
    00922     StringID error_message = res.GetErrorMessage();
    00923     if (error_message == STR_ERROR_AUTOREPLACE_NOTHING_TO_DO || error_message == INVALID_STRING_ID) continue;
    00924
    00925     if (error_message == STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY) error_message = STR_ERROR_AUTOREPLACE_MONEY_LIMIT;
    00926
    00927     StringID message;
    00928     if (error_message == STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT) {
    00929       message = error_message;
    00930     } else {
    00931       message = STR_NEWS_VEHICLE_AUTORENEW_FAILED;
    00932     }
    00933
    00934     SetDParam(0, v->index);
    00935     SetDParam(1, error_message);
    00936     AddVehicleNewsItem(message, NS_ADVICE, v->index);
    00937   }
    00938
    00939   cur_company.Restore();
    00940 }
    00941
    00946 static void DoDrawVehicle(const Vehicle *v)
    00947 {
    00948   SpriteID image = v->cur_image;
    00949   PaletteID pal = PAL_NONE;
    00950
    00951   if (v->vehstatus & VS_DEFPAL) pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
    00952
    00953   /* Check whether the vehicle shall be transparent due to the game state */
    00954   bool shadowed = (v->vehstatus & VS_SHADOW) != 0;
    00955
    00956   if (v->type == VEH_EFFECT) {
    00957     /* Check whether the vehicle shall be transparent/invisible due to GUI settings.
    00958      * However, transparent smoke and bubbles look weird, so always hide them. */
    00959     TransparencyOption to = EffectVehicle::From(v)->GetTransparencyOption();
    00960     if (to != TO_INVALID && (IsTransparencySet(to) || IsInvisibilitySet(to))) return;
    00961   }
    00962
    00963   AddSortableSpriteToDraw(image, pal, v->x_pos + v->x_offs, v->y_pos + v->y_offs,
    00964     v->x_extent, v->y_extent, v->z_extent, v->z_pos, shadowed, v->x_bb_offs, v->y_bb_offs);
    00965 }
    00966
    00971 void ViewportAddVehicles(DrawPixelInfo *dpi)
    00972 {
    00973   /* The bounding rectangle */
    00974   const int l = dpi->left;
    00975   const int r = dpi->left + dpi->width;
    00976   const int t = dpi->top;
    00977   const int b = dpi->top + dpi->height;
    00978
    00979   /* The hash area to scan */
    00980   int xl, xu, yl, yu;
    00981
    00982   if (dpi->width + (70 * ZOOM_LVL_BASE) < (1 << (7 + 6 + ZOOM_LVL_SHIFT))) {
    00983     xl = GB(l - (70 * ZOOM_LVL_BASE), 7 + ZOOM_LVL_SHIFT, 6);
    00984     xu = GB(r,                        7 + ZOOM_LVL_SHIFT, 6);
    00985   } else {
    00986     /* scan whole hash row */
    00987     xl = 0;
    00988     xu = 0x3F;
    00989   }
    00990
    00991   if (dpi->height + (70 * ZOOM_LVL_BASE) < (1 << (6 + 6 + ZOOM_LVL_SHIFT))) {
    00992     yl = GB(t - (70 * ZOOM_LVL_BASE), 6 + ZOOM_LVL_SHIFT, 6) << 6;
    00993     yu = GB(b,                        6 + ZOOM_LVL_SHIFT, 6) << 6;
    00994   } else {
    00995     /* scan whole column */
    00996     yl = 0;
    00997     yu = 0x3F << 6;
    00998   }
    00999
    01000   for (int y = yl;; y = (y + (1 << 6)) & (0x3F << 6)) {
    01001     for (int x = xl;; x = (x + 1) & 0x3F) {
    01002       const Vehicle *v = _vehicle_viewport_hash[x + y]; // already masked & 0xFFF
    01003
    01004       while (v != NULL) {
    01005         if (!(v->vehstatus & VS_HIDDEN) &&
    01006             l <= v->coord.right &&
    01007             t <= v->coord.bottom &&
    01008             r >= v->coord.left &&
    01009             b >= v->coord.top) {
    01010           DoDrawVehicle(v);
    01011         }
    01012         v = v->hash_viewport_next;
    01013       }
    01014
    01015       if (x == xu) break;
    01016     }
    01017
    01018     if (y == yu) break;
    01019   }
    01020 }
    01021
    01029 Vehicle *CheckClickOnVehicle(const ViewPort *vp, int x, int y)
    01030 {
    01031   Vehicle *found = NULL, *v;
    01032   uint dist, best_dist = UINT_MAX;
    01033
    01034   if ((uint)(x -= vp->left) >= (uint)vp->width || (uint)(y -= vp->top) >= (uint)vp->height) return NULL;
    01035
    01036   x = ScaleByZoom(x, vp->zoom) + vp->virtual_left;
    01037   y = ScaleByZoom(y, vp->zoom) + vp->virtual_top;
    01038
    01039   FOR_ALL_VEHICLES(v) {
    01040     if ((v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) == 0 &&
    01041         x >= v->coord.left && x <= v->coord.right &&
    01042         y >= v->coord.top && y <= v->coord.bottom) {
    01043
    01044       dist = max(
    01045         abs(((v->coord.left + v->coord.right) >> 1) - x),
    01046         abs(((v->coord.top + v->coord.bottom) >> 1) - y)
    01047       );
    01048
    01049       if (dist < best_dist) {
    01050         found = v;
    01051         best_dist = dist;
    01052       }
    01053     }
    01054   }
    01055
    01056   return found;
    01057 }
    01058
    01063 void DecreaseVehicleValue(Vehicle *v)
    01064 {
    01065   v->value -= v->value >> 8;
    01066   SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
    01067 }
    01068
    01069 static const byte _breakdown_chance[64] = {
    01070     3,   3,   3,   3,   3,   3,   3,   3,
    01071     4,   4,   5,   5,   6,   6,   7,   7,
    01072     8,   8,   9,   9,  10,  10,  11,  11,
    01073    12,  13,  13,  13,  13,  14,  15,  16,
    01074    17,  19,  21,  25,  28,  31,  34,  37,
    01075    40,  44,  48,  52,  56,  60,  64,  68,
    01076    72,  80,  90, 100, 110, 120, 130, 140,
    01077   150, 170, 190, 210, 230, 250, 250, 250,
    01078 };
    01079
    01080 void CheckVehicleBreakdown(Vehicle *v)
    01081 {
    01082   int rel, rel_old;
    01083
    01084   /* decrease reliability */
    01085   v->reliability = rel = max((rel_old = v->reliability) - v->reliability_spd_dec, 0);
    01086   if ((rel_old >> 8) != (rel >> 8)) SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
    01087
    01088   if (v->breakdown_ctr != 0 || (v->vehstatus & VS_STOPPED) ||
    01089       _settings_game.difficulty.vehicle_breakdowns < 1 ||
    01090       v->cur_speed < 5 || _game_mode == GM_MENU) {
    01091     return;
    01092   }
    01093
    01094   uint32 r = Random();
    01095
    01096   /* increase chance of failure */
    01097   int chance = v->breakdown_chance + 1;
    01098   if (Chance16I(1, 25, r)) chance += 25;
    01099   v->breakdown_chance = min(255, chance);
    01100
    01101   /* calculate reliability value to use in comparison */
    01102   rel = v->reliability;
    01103   if (v->type == VEH_SHIP) rel += 0x6666;
    01104
    01105   /* reduced breakdowns? */
    01106   if (_settings_game.difficulty.vehicle_breakdowns == 1) rel += 0x6666;
    01107
    01108   /* check if to break down */
    01109   if (_breakdown_chance[(uint)min(rel, 0xffff) >> 10] <= v->breakdown_chance) {
    01110     v->breakdown_ctr    = GB(r, 16, 6) + 0x3F;
    01111     v->breakdown_delay  = GB(r, 24, 7) + 0x80;
    01112     v->breakdown_chance = 0;
    01113   }
    01114 }
    01115
    01122 bool Vehicle::HandleBreakdown()
    01123 {
    01124   /* Possible states for Vehicle::breakdown_ctr
    01125    * 0  - vehicle is running normally
    01126    * 1  - vehicle is currently broken down
    01127    * 2  - vehicle is going to break down now
    01128    * >2 - vehicle is counting down to the actual breakdown event */
    01129   switch (this->breakdown_ctr) {
    01130     case 0:
    01131       return false;
    01132
    01133     case 2:
    01134       this->breakdown_ctr = 1;
    01135
    01136       if (this->breakdowns_since_last_service != 255) {
    01137         this->breakdowns_since_last_service++;
    01138       }
    01139
    01140       if (this->type == VEH_AIRCRAFT) {
    01141         /* Aircraft just need this flag, the rest is handled elsewhere */
    01142         this->vehstatus |= VS_AIRCRAFT_BROKEN;
    01143       } else {
    01144         this->cur_speed = 0;
    01145
    01146         if (!PlayVehicleSound(this, VSE_BREAKDOWN)) {
    01147           SndPlayVehicleFx((_settings_game.game_creation.landscape != LT_TOYLAND) ?
    01148             (this->type == VEH_TRAIN ? SND_10_TRAIN_BREAKDOWN : SND_0F_VEHICLE_BREAKDOWN) :
    01149             (this->type == VEH_TRAIN ? SND_3A_COMEDY_BREAKDOWN_2 : SND_35_COMEDY_BREAKDOWN), this);
    01150         }
    01151
    01152         if (!(this->vehstatus & VS_HIDDEN)) {
    01153           EffectVehicle *u = CreateEffectVehicleRel(this, 4, 4, 5, EV_BREAKDOWN_SMOKE);
    01154           if (u != NULL) u->animation_state = this->breakdown_delay * 2;
    01155         }
    01156       }
    01157
    01158       this->MarkDirty(); // Update graphics after speed is zeroed
    01159       SetWindowDirty(WC_VEHICLE_VIEW, this->index);
    01160       SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
    01161
    01162       /* FALL THROUGH */
    01163     case 1:
    01164       /* Aircraft breakdowns end only when arriving at the airport */
    01165       if (this->type == VEH_AIRCRAFT) return false;
    01166
    01167       /* For trains this function is called twice per tick, so decrease v->breakdown_delay at half the rate */
    01168       if ((this->tick_counter & (this->type == VEH_TRAIN ? 3 : 1)) == 0) {
    01169         if (--this->breakdown_delay == 0) {
    01170           this->breakdown_ctr = 0;
    01171           this->MarkDirty();
    01172           SetWindowDirty(WC_VEHICLE_VIEW, this->index);
    01173         }
    01174       }
    01175       return true;
    01176
    01177     default:
    01178       if (!this->current_order.IsType(OT_LOADING)) this->breakdown_ctr--;
    01179       return false;
    01180   }
    01181 }
    01182
    01187 void AgeVehicle(Vehicle *v)
    01188 {
    01189   if (v->age < MAX_DAY) {
    01190     v->age++;
    01191     if (v->IsPrimaryVehicle() && v->age == VEHICLE_PROFIT_MIN_AGE + 1) GroupStatistics::VehicleReachedProfitAge(v);
    01192   }
    01193
    01194   if (!v->IsPrimaryVehicle() && (v->type != VEH_TRAIN || !Train::From(v)->IsEngine())) return;
    01195
    01196   int age = v->age - v->max_age;
    01197   if (age == DAYS_IN_LEAP_YEAR * 0 || age == DAYS_IN_LEAP_YEAR * 1 ||
    01198       age == DAYS_IN_LEAP_YEAR * 2 || age == DAYS_IN_LEAP_YEAR * 3 || age == DAYS_IN_LEAP_YEAR * 4) {
    01199     v->reliability_spd_dec <<= 1;
    01200   }
    01201
    01202   SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
    01203
    01204   /* Don't warn about non-primary or not ours vehicles or vehicles that are crashed */
    01205   if (v->Previous() != NULL || v->owner != _local_company || (v->vehstatus & VS_CRASHED) != 0) return;
    01206
    01207   /* Don't warn if a renew is active */
    01208   if (Company::Get(v->owner)->settings.engine_renew && v->GetEngine()->company_avail != 0) return;
    01209
    01210   StringID str;
    01211   if (age == -DAYS_IN_LEAP_YEAR) {
    01212     str = STR_NEWS_VEHICLE_IS_GETTING_OLD;
    01213   } else if (age == 0) {
    01214     str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD;
    01215   } else if (age > 0 && (age % DAYS_IN_LEAP_YEAR) == 0) {
    01216     str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD_AND;
    01217   } else {
    01218     return;
    01219   }
    01220
    01221   SetDParam(0, v->index);
    01222   AddVehicleNewsItem(str, NS_ADVICE, v->index);
    01223 }
    01224
    01231 uint8 CalcPercentVehicleFilled(const Vehicle *v, StringID *colour)
    01232 {
    01233   int count = 0;
    01234   int max = 0;
    01235   int cars = 0;
    01236   int unloading = 0;
    01237   bool loading = false;
    01238
    01239   const Vehicle *u = v;
    01240   /* The station may be NULL when the (colour) string does not need to be set. */
    01241   const Station *st = Station::GetIfValid(v->last_station_visited);
    01242   assert(colour == NULL || st != NULL);
    01243
    01244   /* Count up max and used */
    01245   for (; v != NULL; v = v->Next()) {
    01246     count += v->cargo.Count();
    01247     max += v->cargo_cap;
    01248     if (v->cargo_cap != 0 && colour != NULL) {
    01249       unloading += HasBit(v->vehicle_flags, VF_CARGO_UNLOADING) ? 1 : 0;
    01250       loading |= !(u->current_order.GetLoadType() & OLFB_NO_LOAD) && st->goods[v->cargo_type].days_since_pickup != 255;
    01251       cars++;
    01252     }
    01253   }
    01254
    01255   if (colour != NULL) {
    01256     if (unloading == 0 && loading) {
    01257       *colour = STR_PERCENT_UP;
    01258     } else if (cars == unloading || !loading) {
    01259       *colour = STR_PERCENT_DOWN;
    01260     } else {
    01261       *colour = STR_PERCENT_UP_DOWN;
    01262     }
    01263   }
    01264
    01265   /* Train without capacity */
    01266   if (max == 0) return 100;
    01267
    01268   /* Return the percentage */
    01269   return (count * 100) / max;
    01270 }
    01271
    01276 void VehicleEnterDepot(Vehicle *v)
    01277 {
    01278   /* Always work with the front of the vehicle */
    01279   assert(v == v->First());
    01280
    01281   switch (v->type) {
    01282     case VEH_TRAIN: {
    01283       Train *t = Train::From(v);
    01284       SetWindowClassesDirty(WC_TRAINS_LIST);
    01285       /* Clear path reservation */
    01286       SetDepotReservation(t->tile, false);
    01287       if (_settings_client.gui.show_track_reservation) MarkTileDirtyByTile(t->tile);
    01288
    01289       UpdateSignalsOnSegment(t->tile, INVALID_DIAGDIR, t->owner);
    01290       t->wait_counter = 0;
    01291       t->force_proceed = TFP_NONE;
    01292       ClrBit(t->flags, VRF_TOGGLE_REVERSE);
    01293       t->ConsistChanged(true);
    01294       break;
    01295     }
    01296
    01297     case VEH_ROAD:
    01298       SetWindowClassesDirty(WC_ROADVEH_LIST);
    01299       break;
    01300
    01301     case VEH_SHIP: {
    01302       SetWindowClassesDirty(WC_SHIPS_LIST);
    01303       Ship *ship = Ship::From(v);
    01304       ship->state = TRACK_BIT_DEPOT;
    01305       ship->UpdateCache();
    01306       ship->UpdateViewport(true, true);
    01307       SetWindowDirty(WC_VEHICLE_DEPOT, v->tile);
    01308       break;
    01309     }
    01310
    01311     case VEH_AIRCRAFT:
    01312       SetWindowClassesDirty(WC_AIRCRAFT_LIST);
    01313       HandleAircraftEnterHangar(Aircraft::From(v));
    01314       break;
    01315     default: NOT_REACHED();
    01316   }
    01317   SetWindowDirty(WC_VEHICLE_VIEW, v->index);
    01318
    01319   if (v->type != VEH_TRAIN) {
    01320     /* Trains update the vehicle list when the first unit enters the depot and calls VehicleEnterDepot() when the last unit enters.
    01321      * 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 */
    01322     InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
    01323   }
    01324   SetWindowDirty(WC_VEHICLE_DEPOT, v->tile);
    01325
    01326   v->vehstatus |= VS_HIDDEN;
    01327   v->cur_speed = 0;
    01328
    01329   VehicleServiceInDepot(v);
    01330
    01331   TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);
    01332
    01333   if (v->current_order.IsType(OT_GOTO_DEPOT)) {
    01334     SetWindowDirty(WC_VEHICLE_VIEW, v->index);
    01335
    01336     const Order *real_order = v->GetOrder(v->cur_real_order_index);
    01337     Order t = v->current_order;
    01338     v->current_order.MakeDummy();
    01339
    01340     /* Test whether we are heading for this depot. If not, do nothing.
    01341      * Note: The target depot for nearest-/manual-depot-orders is only updated on junctions, but we want to accept every depot. */
    01342     if ((t.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) &&
    01343         real_order != NULL && !(real_order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) &&
    01344         (v->type == VEH_AIRCRAFT ? t.GetDestination() != GetStationIndex(v->tile) : v->dest_tile != v->tile)) {
    01345       /* We are heading for another depot, keep driving. */
    01346       return;
    01347     }
    01348
    01349     if (t.IsRefit()) {
    01350       Backup<CompanyByte> cur_company(_current_company, v->owner, FILE_LINE);
    01351       CommandCost cost = DoCommand(v->tile, v->index, t.GetRefitCargo() | t.GetRefitSubtype() << 8, DC_EXEC, GetCmdRefitVeh(v));
    01352       cur_company.Restore();
    01353
    01354       if (cost.Failed()) {
    01355         _vehicles_to_autoreplace[v] = false;
    01356         if (v->owner == _local_company) {
    01357           /* Notify the user that we stopped the vehicle */
    01358           SetDParam(0, v->index);
    01359           AddVehicleNewsItem(STR_NEWS_ORDER_REFIT_FAILED, NS_ADVICE, v->index);
    01360         }
    01361       } else if (cost.GetCost() != 0) {
    01362         v->profit_this_year -= cost.GetCost() << 8;
    01363         if (v->owner == _local_company) {
    01364           ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost.GetCost());
    01365         }
    01366       }
    01367     }
    01368
    01369     if (t.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) {
    01370       /* Part of orders */
    01371       v->DeleteUnreachedImplicitOrders();
    01372       UpdateVehicleTimetable(v, true);
    01373       v->IncrementImplicitOrderIndex();
    01374     }
    01375     if (t.GetDepotActionType() & ODATFB_HALT) {
    01376       /* Vehicles are always stopped on entering depots. Do not restart this one. */
    01377       _vehicles_to_autoreplace[v] = false;
    01378       if (v->owner == _local_company) {
    01379         SetDParam(0, v->index);
    01380         AddVehicleNewsItem(STR_NEWS_TRAIN_IS_WAITING + v->type, NS_ADVICE, v->index);
    01381       }
    01382       AI::NewEvent(v->owner, new ScriptEventVehicleWaitingInDepot(v->index));
    01383     }
    01384   }
    01385 }
    01386
    01387
    01393 void VehicleUpdatePosition(Vehicle *v)
    01394 {
    01395   UpdateVehicleTileHash(v, false);
    01396 }
    01397
    01404 void VehicleUpdateViewport(Vehicle *v, bool dirty)
    01405 {
    01406   int img = v->cur_image;
    01407   Point pt = RemapCoords(v->x_pos + v->x_offs, v->y_pos + v->y_offs, v->z_pos);
    01408   const Sprite *spr = GetSprite(img, ST_NORMAL);
    01409
    01410   pt.x += spr->x_offs;
    01411   pt.y += spr->y_offs;
    01412
    01413   UpdateVehicleViewportHash(v, pt.x, pt.y);
    01414
    01415   Rect old_coord = v->coord;
    01416   v->coord.left   = pt.x;
    01417   v->coord.top    = pt.y;
    01418   v->coord.right  = pt.x + spr->width + 2 * ZOOM_LVL_BASE;
    01419   v->coord.bottom = pt.y + spr->height + 2 * ZOOM_LVL_BASE;
    01420
    01421   if (dirty) {
    01422     if (old_coord.left == INVALID_COORD) {
    01423       MarkSingleVehicleDirty(v);
    01424     } else {
    01425       MarkAllViewportsDirty(
    01426         min(old_coord.left,   v->coord.left),
    01427         min(old_coord.top,    v->coord.top),
    01428         max(old_coord.right,  v->coord.right) + 1 * ZOOM_LVL_BASE,
    01429         max(old_coord.bottom, v->coord.bottom) + 1 * ZOOM_LVL_BASE
    01430       );
    01431     }
    01432   }
    01433 }
    01434
    01439 void VehicleUpdatePositionAndViewport(Vehicle *v)
    01440 {
    01441   VehicleUpdatePosition(v);
    01442   VehicleUpdateViewport(v, true);
    01443 }
    01444
    01449 void MarkSingleVehicleDirty(const Vehicle *v)
    01450 {
    01451   MarkAllViewportsDirty(v->coord.left, v->coord.top, v->coord.right + 1 * ZOOM_LVL_BASE, v->coord.bottom + 1 * ZOOM_LVL_BASE);
    01452 }
    01453
    01459 GetNewVehiclePosResult GetNewVehiclePos(const Vehicle *v)
    01460 {
    01461   static const int8 _delta_coord[16] = {
    01462     -1,-1,-1, 0, 1, 1, 1, 0, /* x */
    01463     -1, 0, 1, 1, 1, 0,-1,-1, /* y */
    01464   };
    01465
    01466   int x = v->x_pos + _delta_coord[v->direction];
    01467   int y = v->y_pos + _delta_coord[v->direction + 8];
    01468
    01469   GetNewVehiclePosResult gp;
    01470   gp.x = x;
    01471   gp.y = y;
    01472   gp.old_tile = v->tile;
    01473   gp.new_tile = TileVirtXY(x, y);
    01474   return gp;
    01475 }
    01476
    01477 static const Direction _new_direction_table[] = {
    01478   DIR_N,  DIR_NW, DIR_W,
    01479   DIR_NE, DIR_SE, DIR_SW,
    01480   DIR_E,  DIR_SE, DIR_S
    01481 };
    01482
    01483 Direction GetDirectionTowards(const Vehicle *v, int x, int y)
    01484 {
    01485   int i = 0;
    01486
    01487   if (y >= v->y_pos) {
    01488     if (y != v->y_pos) i += 3;
    01489     i += 3;
    01490   }
    01491
    01492   if (x >= v->x_pos) {
    01493     if (x != v->x_pos) i++;
    01494     i++;
    01495   }
    01496
    01497   Direction dir = v->direction;
    01498
    01499   DirDiff dirdiff = DirDifference(_new_direction_table[i], dir);
    01500   if (dirdiff == DIRDIFF_SAME) return dir;
    01501   return ChangeDir(dir, dirdiff > DIRDIFF_REVERSE ? DIRDIFF_45LEFT : DIRDIFF_45RIGHT);
    01502 }
    01503
    01513 VehicleEnterTileStatus VehicleEnterTile(Vehicle *v, TileIndex tile, int x, int y)
    01514 {
    01515   return _tile_type_procs[GetTileType(tile)]->vehicle_enter_tile_proc(v, tile, x, y);
    01516 }
    01517
    01525 FreeUnitIDGenerator::FreeUnitIDGenerator(VehicleType type, CompanyID owner) : cache(NULL), maxid(0), curid(0)
    01526 {
    01527   /* Find maximum */
    01528   const Vehicle *v;
    01529   FOR_ALL_VEHICLES(v) {
    01530     if (v->type == type && v->owner == owner) {
    01531       this->maxid = max<UnitID>(this->maxid, v->unitnumber);
    01532     }
    01533   }
    01534
    01535   if (this->maxid == 0) return;
    01536
    01537   /* Reserving 'maxid + 2' because we need:
    01538    * - space for the last item (with v->unitnumber == maxid)
    01539    * - one free slot working as loop terminator in FreeUnitIDGenerator::NextID() */
    01540   this->cache = CallocT<bool>(this->maxid + 2);
    01541
    01542   /* Fill the cache */
    01543   FOR_ALL_VEHICLES(v) {
    01544     if (v->type == type && v->owner == owner) {
    01545       this->cache[v->unitnumber] = true;
    01546     }
    01547   }
    01548 }
    01549
    01551 UnitID FreeUnitIDGenerator::NextID()
    01552 {
    01553   if (this->maxid <= this->curid) return ++this->curid;
    01554
    01555   while (this->cache[++this->curid]) { } // it will stop, we reserved more space than needed
    01556
    01557   return this->curid;
    01558 }
    01559
    01565 UnitID GetFreeUnitNumber(VehicleType type)
    01566 {
    01567   /* Check whether it is allowed to build another vehicle. */
    01568   uint max_veh;
    01569   switch (type) {
    01570     case VEH_TRAIN:    max_veh = _settings_game.vehicle.max_trains;   break;
    01571     case VEH_ROAD:     max_veh = _settings_game.vehicle.max_roadveh;  break;
    01572     case VEH_SHIP:     max_veh = _settings_game.vehicle.max_ships;    break;
    01573     case VEH_AIRCRAFT: max_veh = _settings_game.vehicle.max_aircraft; break;
    01574     default: NOT_REACHED();
    01575   }
    01576
    01577   const Company *c = Company::Get(_current_company);
    01578   if (c->group_all[type].num_vehicle >= max_veh) return UINT16_MAX; // Currently already at the limit, no room to make a new one.
    01579
    01580   FreeUnitIDGenerator gen(type, _current_company);
    01581
    01582   return gen.NextID();
    01583 }
    01584
    01585
    01594 bool CanBuildVehicleInfrastructure(VehicleType type)
    01595 {
    01596   assert(IsCompanyBuildableVehicleType(type));
    01597
    01598   if (!Company::IsValidID(_local_company)) return false;
    01599   if (!_settings_client.gui.disable_unsuitable_building) return true;
    01600
    01601   UnitID max;
    01602   switch (type) {
    01603     case VEH_TRAIN:    max = _settings_game.vehicle.max_trains; break;
    01604     case VEH_ROAD:     max = _settings_game.vehicle.max_roadveh; break;
    01605     case VEH_SHIP:     max = _settings_game.vehicle.max_ships; break;
    01606     case VEH_AIRCRAFT: max = _settings_game.vehicle.max_aircraft; break;
    01607     default: NOT_REACHED();
    01608   }
    01609
    01610   /* We can build vehicle infrastructure when we may build the vehicle type */
    01611   if (max > 0) {
    01612     /* Can we actually build the vehicle type? */
    01613     const Engine *e;
    01614     FOR_ALL_ENGINES_OF_TYPE(e, type) {
    01615       if (HasBit(e->company_avail, _local_company)) return true;
    01616     }
    01617     return false;
    01618   }
    01619
    01620   /* We should be able to build infrastructure when we have the actual vehicle type */
    01621   const Vehicle *v;
    01622   FOR_ALL_VEHICLES(v) {
    01623     if (v->owner == _local_company && v->type == type) return true;
    01624   }
    01625
    01626   return false;
    01627 }
    01628
    01629
    01637 LiveryScheme GetEngineLiveryScheme(EngineID engine_type, EngineID parent_engine_type, const Vehicle *v)
    01638 {
    01639   CargoID cargo_type = v == NULL ? (CargoID)CT_INVALID : v->cargo_type;
    01640   const Engine *e = Engine::Get(engine_type);
    01641   switch (e->type) {
    01642     default: NOT_REACHED();
    01643     case VEH_TRAIN:
    01644       if (v != NULL && parent_engine_type != INVALID_ENGINE && (UsesWagonOverride(v) || (v->IsArticulatedPart() && e->u.rail.railveh_type != RAILVEH_WAGON))) {
    01645         /* Wagonoverrides use the colour scheme of the front engine.
    01646          * Articulated parts use the colour scheme of the first part. (Not supported for articulated wagons) */
    01647         engine_type = parent_engine_type;
    01648         e = Engine::Get(engine_type);
    01649         /* Note: Luckily cargo_type is not needed for engines */
    01650       }
    01651
    01652       if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
    01653       if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
    01654       if (e->u.rail.railveh_type == RAILVEH_WAGON) {
    01655         if (!CargoSpec::Get(cargo_type)->is_freight) {
    01656           if (parent_engine_type == INVALID_ENGINE) {
    01657             return LS_PASSENGER_WAGON_STEAM;
    01658           } else {
    01659             switch (RailVehInfo(parent_engine_type)->engclass) {
    01660               default: NOT_REACHED();
    01661               case EC_STEAM:    return LS_PASSENGER_WAGON_STEAM;
    01662               case EC_DIESEL:   return LS_PASSENGER_WAGON_DIESEL;
    01663               case EC_ELECTRIC: return LS_PASSENGER_WAGON_ELECTRIC;
    01664               case EC_MONORAIL: return LS_PASSENGER_WAGON_MONORAIL;
    01665               case EC_MAGLEV:   return LS_PASSENGER_WAGON_MAGLEV;
    01666             }
    01667           }
    01668         } else {
    01669           return LS_FREIGHT_WAGON;
    01670         }
    01671       } else {
    01672         bool is_mu = HasBit(e->info.misc_flags, EF_RAIL_IS_MU);
    01673
    01674         switch (e->u.rail.engclass) {
    01675           default: NOT_REACHED();
    01676           case EC_STEAM:    return LS_STEAM;
    01677           case EC_DIESEL:   return is_mu ? LS_DMU : LS_DIESEL;
    01678           case EC_ELECTRIC: return is_mu ? LS_EMU : LS_ELECTRIC;
    01679           case EC_MONORAIL: return LS_MONORAIL;
    01680           case EC_MAGLEV:   return LS_MAGLEV;
    01681         }
    01682       }
    01683
    01684     case VEH_ROAD:
    01685       /* Always use the livery of the front */
    01686       if (v != NULL && parent_engine_type != INVALID_ENGINE) {
    01687         engine_type = parent_engine_type;
    01688         e = Engine::Get(engine_type);
    01689         cargo_type = v->First()->cargo_type;
    01690       }
    01691       if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
    01692       if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
    01693
    01694       /* Important: Use Tram Flag of front part. Luckily engine_type refers to the front part here. */
    01695       if (HasBit(e->info.misc_flags, EF_ROAD_TRAM)) {
    01696         /* Tram */
    01697         return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_TRAM : LS_FREIGHT_TRAM;
    01698       } else {
    01699         /* Bus or truck */
    01700         return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_BUS : LS_TRUCK;
    01701       }
    01702
    01703     case VEH_SHIP:
    01704       if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
    01705       if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
    01706       return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_SHIP : LS_FREIGHT_SHIP;
    01707
    01708     case VEH_AIRCRAFT:
    01709       switch (e->u.air.subtype) {
    01710         case AIR_HELI: return LS_HELICOPTER;
    01711         case AIR_CTOL: return LS_SMALL_PLANE;
    01712         case AIR_CTOL | AIR_FAST: return LS_LARGE_PLANE;
    01713         default: NOT_REACHED();
    01714       }
    01715   }
    01716 }
    01717
    01727 const Livery *GetEngineLivery(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v, byte livery_setting)
    01728 {
    01729   const Company *c = Company::Get(company);
    01730   LiveryScheme scheme = LS_DEFAULT;
    01731
    01732   /* The default livery is always available for use, but its in_use flag determines
    01733    * whether any _other_ liveries are in use. */
    01734   if (c->livery[LS_DEFAULT].in_use && (livery_setting == LIT_ALL || (livery_setting == LIT_COMPANY && company == _local_company))) {
    01735     /* Determine the livery scheme to use */
    01736     scheme = GetEngineLiveryScheme(engine_type, parent_engine_type, v);
    01737
    01738     /* Switch back to the default scheme if the resolved scheme is not in use */
    01739     if (!c->livery[scheme].in_use) scheme = LS_DEFAULT;
    01740   }
    01741
    01742   return &c->livery[scheme];
    01743 }
    01744
    01745
    01746 static PaletteID GetEngineColourMap(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v)
    01747 {
    01748   PaletteID map = (v != NULL) ? v->colourmap : PAL_NONE;
    01749
    01750   /* Return cached value if any */
    01751   if (map != PAL_NONE) return map;
    01752
    01753   const Engine *e = Engine::Get(engine_type);
    01754
    01755   /* Check if we should use the colour map callback */
    01756   if (HasBit(e->info.callback_mask, CBM_VEHICLE_COLOUR_REMAP)) {
    01757     uint16 callback = GetVehicleCallback(CBID_VEHICLE_COLOUR_MAPPING, 0, 0, engine_type, v);
    01758     /* Failure means "use the default two-colour" */
    01759     if (callback != CALLBACK_FAILED) {
    01760       assert_compile(PAL_NONE == 0); // Returning 0x4000 (resp. 0xC000) conincidences with default value (PAL_NONE)
    01761       map = GB(callback, 0, 14);
    01762       /* If bit 14 is set, then the company colours are applied to the
    01763        * map else it's returned as-is. */
    01764       if (!HasBit(callback, 14)) {
    01765         /* Update cache */
    01766         if (v != NULL) const_cast<Vehicle *>(v)->colourmap = map;
    01767         return map;
    01768       }
    01769     }
    01770   }
    01771
    01772   bool twocc = HasBit(e->info.misc_flags, EF_USES_2CC);
    01773
    01774   if (map == PAL_NONE) map = twocc ? (PaletteID)SPR_2CCMAP_BASE : (PaletteID)PALETTE_RECOLOUR_START;
    01775
    01776   /* Spectator has news shown too, but has invalid company ID - as well as dedicated server */
    01777   if (!Company::IsValidID(company)) return map;
    01778
    01779   const Livery *livery = GetEngineLivery(engine_type, company, parent_engine_type, v, _settings_client.gui.liveries);
    01780
    01781   map += livery->colour1;
    01782   if (twocc) map += livery->colour2 * 16;
    01783
    01784   /* Update cache */
    01785   if (v != NULL) const_cast<Vehicle *>(v)->colourmap = map;
    01786   return map;
    01787 }
    01788
    01795 PaletteID GetEnginePalette(EngineID engine_type, CompanyID company)
    01796 {
    01797   return GetEngineColourMap(engine_type, company, INVALID_ENGINE, NULL);
    01798 }
    01799
    01805 PaletteID GetVehiclePalette(const Vehicle *v)
    01806 {
    01807   if (v->IsGroundVehicle()) {
    01808     return GetEngineColourMap(v->engine_type, v->owner, v->GetGroundVehicleCache()->first_engine, v);
    01809   }
    01810
    01811   return GetEngineColourMap(v->engine_type, v->owner, INVALID_ENGINE, v);
    01812 }
    01813
    01817 void Vehicle::DeleteUnreachedImplicitOrders()
    01818 {
    01819   if (this->IsGroundVehicle()) {
    01820     uint16 &gv_flags = this->GetGroundVehicleFlags();
    01821     if (HasBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS)) {
    01822       /* Do not delete orders, only skip them */
    01823       ClrBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
    01824       this->cur_implicit_order_index = this->cur_real_order_index;
    01825       InvalidateVehicleOrder(this, 0);
    01826       return;
    01827     }
    01828   }
    01829
    01830   const Order *order = this->GetOrder(this->cur_implicit_order_index);
    01831   while (order != NULL) {
    01832     if (this->cur_implicit_order_index == this->cur_real_order_index) break;
    01833
    01834     if (order->IsType(OT_IMPLICIT)) {
    01835       /* Delete order effectively deletes order, so get the next before deleting it. */
    01836       order = order->next;
    01837       DeleteOrder(this, this->cur_implicit_order_index);
    01838     } else {
    01839       /* Skip non-implicit orders, e.g. service-orders */
    01840       order = order->next;
    01841       this->cur_implicit_order_index++;
    01842     }
    01843
    01844     /* Wrap around */
    01845     if (order == NULL) {
    01846       order = this->GetOrder(0);
    01847       this->cur_implicit_order_index = 0;
    01848     }
    01849   }
    01850 }
    01851
    01856 void Vehicle::BeginLoading()
    01857 {
    01858   assert(IsTileType(this->tile, MP_STATION) || this->type == VEH_SHIP);
    01859
    01860   if (this->current_order.IsType(OT_GOTO_STATION) &&
    01861       this->current_order.GetDestination() == this->last_station_visited) {
    01862     this->DeleteUnreachedImplicitOrders();
    01863
    01864     /* Now both order indices point to the destination station, and we can start loading */
    01865     this->current_order.MakeLoading(true);
    01866     UpdateVehicleTimetable(this, true);
    01867
    01868     /* Furthermore add the Non Stop flag to mark that this station
    01869      * is the actual destination of the vehicle, which is (for example)
    01870      * necessary to be known for HandleTrainLoading to determine
    01871      * whether the train is lost or not; not marking a train lost
    01872      * that arrives at random stations is bad. */
    01873     this->current_order.SetNonStopType(ONSF_NO_STOP_AT_ANY_STATION);
    01874
    01875   } else {
    01876     /* We weren't scheduled to stop here. Insert an implicit order
    01877      * to show that we are stopping here, but only do that if the order
    01878      * list isn't empty.
    01879      * While only groundvehicles have implicit orders, e.g. aircraft might still enter
    01880      * the 'wrong' terminal when skipping orders etc. */
    01881     Order *in_list = this->GetOrder(this->cur_implicit_order_index);
    01882     if (this->IsGroundVehicle() && in_list != NULL &&
    01883         (!in_list->IsType(OT_IMPLICIT) ||
    01884         in_list->GetDestination() != this->last_station_visited)) {
    01885       bool suppress_implicit_orders = HasBit(this->GetGroundVehicleFlags(), GVF_SUPPRESS_IMPLICIT_ORDERS);
    01886       /* Do not create consecutive duplicates of implicit orders */
    01887       Order *prev_order = this->cur_implicit_order_index > 0 ? this->GetOrder(this->cur_implicit_order_index - 1) : (this->GetNumOrders() > 1 ? this->GetLastOrder() : NULL);
    01888       if (prev_order == NULL ||
    01889           (!prev_order->IsType(OT_IMPLICIT) && !prev_order->IsType(OT_GOTO_STATION)) ||
    01890           prev_order->GetDestination() != this->last_station_visited) {
    01891
    01892         /* Prefer deleting implicit orders instead of inserting new ones,
    01893          * so test whether the right order follows later */
    01894         int target_index = this->cur_implicit_order_index;
    01895         bool found = false;
    01896         while (target_index != this->cur_real_order_index) {
    01897           const Order *order = this->GetOrder(target_index);
    01898           if (order->IsType(OT_IMPLICIT) && order->GetDestination() == this->last_station_visited) {
    01899             found = true;
    01900             break;
    01901           }
    01902           target_index++;
    01903           if (target_index >= this->orders.list->GetNumOrders()) target_index = 0;
    01904           assert(target_index != this->cur_implicit_order_index); // infinite loop?
    01905         }
    01906
    01907         if (found) {
    01908           if (suppress_implicit_orders) {
    01909             /* Skip to the found order */
    01910             this->cur_implicit_order_index = target_index;
    01911             InvalidateVehicleOrder(this, 0);
    01912           } else {
    01913             /* Delete all implicit orders up to the station we just reached */
    01914             const Order *order = this->GetOrder(this->cur_implicit_order_index);
    01915             while (!order->IsType(OT_IMPLICIT) || order->GetDestination() != this->last_station_visited) {
    01916               if (order->IsType(OT_IMPLICIT)) {
    01917                 /* Delete order effectively deletes order, so get the next before deleting it. */
    01918                 order = order->next;
    01919                 DeleteOrder(this, this->cur_implicit_order_index);
    01920               } else {
    01921                 /* Skip non-implicit orders, e.g. service-orders */
    01922                 order = order->next;
    01923                 this->cur_implicit_order_index++;
    01924               }
    01925
    01926               /* Wrap around */
    01927               if (order == NULL) {
    01928                 order = this->GetOrder(0);
    01929                 this->cur_implicit_order_index = 0;
    01930               }
    01931               assert(order != NULL);
    01932             }
    01933           }
    01934         } else if (!suppress_implicit_orders && this->orders.list->GetNumOrders() < MAX_VEH_ORDER_ID && Order::CanAllocateItem()) {
    01935           /* Insert new implicit order */
    01936           Order *implicit_order = new Order();
    01937           implicit_order->MakeImplicit(this->last_station_visited);
    01938           InsertOrder(this, implicit_order, this->cur_implicit_order_index);
    01939           if (this->cur_implicit_order_index > 0) --this->cur_implicit_order_index;
    01940
    01941           /* InsertOrder disabled creation of implicit orders for all vehicles with the same implicit order.
    01942            * Reenable it for this vehicle */
    01943           uint16 &gv_flags = this->GetGroundVehicleFlags();
    01944           ClrBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
    01945         }
    01946       }
    01947     }
    01948     this->current_order.MakeLoading(false);
    01949   }
    01950
    01951   Station::Get(this->last_station_visited)->loading_vehicles.push_back(this);
    01952
    01953   PrepareUnload(this);
    01954
    01955   SetWindowDirty(GetWindowClassForVehicleType(this->type), this->owner);
    01956   SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
    01957   SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
    01958   SetWindowDirty(WC_STATION_VIEW, this->last_station_visited);
    01959
    01960   Station::Get(this->last_station_visited)->MarkTilesDirty(true);
    01961   this->cur_speed = 0;
    01962   this->MarkDirty();
    01963 }
    01964
    01969 void Vehicle::LeaveStation()
    01970 {
    01971   assert(this->current_order.IsType(OT_LOADING));
    01972
    01973   delete this->cargo_payment;
    01974
    01975   /* Only update the timetable if the vehicle was supposed to stop here. */
    01976   if (this->current_order.GetNonStopType() != ONSF_STOP_EVERYWHERE) UpdateVehicleTimetable(this, false);
    01977
    01978   this->current_order.MakeLeaveStation();
    01979   Station *st = Station::Get(this->last_station_visited);
    01980   st->loading_vehicles.remove(this);
    01981
    01982   HideFillingPercent(&this->fill_percent_te_id);
    01983
    01984   if (this->type == VEH_TRAIN && !(this->vehstatus & VS_CRASHED)) {
    01985     /* Trigger station animation (trains only) */
    01986     if (IsTileType(this->tile, MP_STATION)) TriggerStationAnimation(st, this->tile, SAT_TRAIN_DEPARTS);
    01987
    01988     SetBit(Train::From(this)->flags, VRF_LEAVING_STATION);
    01989   }
    01990 }
    01991
    01992
    01998 void Vehicle::HandleLoading(bool mode)
    01999 {
    02000   switch (this->current_order.GetType()) {
    02001     case OT_LOADING: {
    02002       uint wait_time = max(this->current_order.wait_time - this->lateness_counter, 0);
    02003
    02004       /* Not the first call for this tick, or still loading */
    02005       if (mode || !HasBit(this->vehicle_flags, VF_LOADING_FINISHED) || this->current_order_time < wait_time) return;
    02006
    02007       this->PlayLeaveStationSound();
    02008
    02009       this->LeaveStation();
    02010
    02011       /* Only advance to next order if we just loaded at the current one */
    02012       const Order *order = this->GetOrder(this->cur_implicit_order_index);
    02013       if (order == NULL ||
    02014           (!order->IsType(OT_IMPLICIT) && !order->IsType(OT_GOTO_STATION)) ||
    02015           order->GetDestination() != this->last_station_visited) {
    02016         return;
    02017       }
    02018       break;
    02019     }
    02020
    02021     case OT_DUMMY: break;
    02022
    02023     default: return;
    02024   }
    02025
    02026   this->IncrementImplicitOrderIndex();
    02027 }
    02028
    02035 CommandCost Vehicle::SendToDepot(DoCommandFlag flags, DepotCommand command)
    02036 {
    02037   CommandCost ret = CheckOwnership(this->owner);
    02038   if (ret.Failed()) return ret;
    02039
    02040   if (this->vehstatus & VS_CRASHED) return CMD_ERROR;
    02041   if (this->IsStoppedInDepot()) return CMD_ERROR;
    02042
    02043   if (this->current_order.IsType(OT_GOTO_DEPOT)) {
    02044     bool halt_in_depot = (this->current_order.GetDepotActionType() & ODATFB_HALT) != 0;
    02045     if (!!(command & DEPOT_SERVICE) == halt_in_depot) {
    02046       /* We called with a different DEPOT_SERVICE setting.
    02047        * Now we change the setting to apply the new one and let the vehicle head for the same depot.
    02048        * Note: the if is (true for requesting service == true for ordered to stop in depot)          */
    02049       if (flags & DC_EXEC) {
    02050         this->current_order.SetDepotOrderType(ODTF_MANUAL);
    02051         this->current_order.SetDepotActionType(halt_in_depot ? ODATF_SERVICE_ONLY : ODATFB_HALT);
    02052         SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
    02053       }
    02054       return CommandCost();
    02055     }
    02056
    02057     if (command & DEPOT_DONT_CANCEL) return CMD_ERROR; // Requested no cancelation of depot orders
    02058     if (flags & DC_EXEC) {
    02059       /* If the orders to 'goto depot' are in the orders list (forced servicing),
    02060        * then skip to the next order; effectively cancelling this forced service */
    02061       if (this->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) this->IncrementRealOrderIndex();
    02062
    02063       if (this->IsGroundVehicle()) {
    02064         uint16 &gv_flags = this->GetGroundVehicleFlags();
    02065         SetBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
    02066       }
    02067
    02068       this->current_order.MakeDummy();
    02069       SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
    02070     }
    02071     return CommandCost();
    02072   }
    02073
    02074   TileIndex location;
    02075   DestinationID destination;
    02076   bool reverse;
    02077   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};
    02078   if (!this->FindClosestDepot(&location, &destination, &reverse)) return_cmd_error(no_depot[this->type]);
    02079
    02080   if (flags & DC_EXEC) {
    02081     if (this->current_order.IsType(OT_LOADING)) this->LeaveStation();
    02082
    02083     if (this->IsGroundVehicle()) {
    02084       uint16 &gv_flags = this->GetGroundVehicleFlags();
    02085       SetBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
    02086     }
    02087
    02088     this->dest_tile = location;
    02089     this->current_order.MakeGoToDepot(destination, ODTF_MANUAL);
    02090     if (!(command & DEPOT_SERVICE)) this->current_order.SetDepotActionType(ODATFB_HALT);
    02091     SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
    02092
    02093     /* If there is no depot in front, reverse automatically (trains only) */
    02094     if (this->type == VEH_TRAIN && reverse) DoCommand(this->tile, this->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
    02095
    02096     if (this->type == VEH_AIRCRAFT) {
    02097       Aircraft *a = Aircraft::From(this);
    02098       if (a->state == FLYING && a->targetairport != destination) {
    02099         /* The aircraft is now heading for a different hangar than the next in the orders */
    02100         extern void AircraftNextAirportPos_and_Order(Aircraft *a);
    02101         AircraftNextAirportPos_and_Order(a);
    02102       }
    02103     }
    02104   }
    02105
    02106   return CommandCost();
    02107
    02108 }
    02109
    02114 void Vehicle::UpdateVisualEffect(bool allow_power_change)
    02115 {
    02116   bool powered_before = HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER);
    02117   const Engine *e = this->GetEngine();
    02118
    02119   /* Evaluate properties */
    02120   byte visual_effect;
    02121   switch (e->type) {
    02122     case VEH_TRAIN: visual_effect = e->u.rail.visual_effect; break;
    02123     case VEH_ROAD:  visual_effect = e->u.road.visual_effect; break;
    02124     case VEH_SHIP:  visual_effect = e->u.ship.visual_effect; break;
    02125     default:        visual_effect = 1 << VE_DISABLE_EFFECT;  break;
    02126   }
    02127
    02128   /* Check powered wagon / visual effect callback */
    02129   if (HasBit(e->info.callback_mask, CBM_VEHICLE_VISUAL_EFFECT)) {
    02130     uint16 callback = GetVehicleCallback(CBID_VEHICLE_VISUAL_EFFECT, 0, 0, this->engine_type, this);
    02131
    02132     if (callback != CALLBACK_FAILED) {
    02133       if (callback >= 0x100 && e->GetGRF()->grf_version >= 8) ErrorUnknownCallbackResult(e->GetGRFID(), CBID_VEHICLE_VISUAL_EFFECT, callback);
    02134
    02135       callback = GB(callback, 0, 8);
    02136       /* Avoid accidentally setting 'visual_effect' to the default value
    02137        * Since bit 6 (disable effects) is set anyways, we can safely erase some bits. */
    02138       if (callback == VE_DEFAULT) {
    02139         assert(HasBit(callback, VE_DISABLE_EFFECT));
    02140         SB(callback, VE_TYPE_START, VE_TYPE_COUNT, 0);
    02141       }
    02142       visual_effect = callback;
    02143     }
    02144   }
    02145
    02146   /* Apply default values */
    02147   if (visual_effect == VE_DEFAULT ||
    02148       (!HasBit(visual_effect, VE_DISABLE_EFFECT) && GB(visual_effect, VE_TYPE_START, VE_TYPE_COUNT) == VE_TYPE_DEFAULT)) {
    02149     /* Only train engines have default effects.
    02150      * Note: This is independent of whether the engine is a front engine or articulated part or whatever. */
    02151     if (e->type != VEH_TRAIN || e->u.rail.railveh_type == RAILVEH_WAGON || !IsInsideMM(e->u.rail.engclass, EC_STEAM, EC_MONORAIL)) {
    02152       if (visual_effect == VE_DEFAULT) {
    02153         visual_effect = 1 << VE_DISABLE_EFFECT;
    02154       } else {
    02155         SetBit(visual_effect, VE_DISABLE_EFFECT);
    02156       }
    02157     } else {
    02158       if (visual_effect == VE_DEFAULT) {
    02159         /* Also set the offset */
    02160         visual_effect = (VE_OFFSET_CENTRE - (e->u.rail.engclass == EC_STEAM ? 4 : 0)) << VE_OFFSET_START;
    02161       }
    02162       SB(visual_effect, VE_TYPE_START, VE_TYPE_COUNT, e->u.rail.engclass - EC_STEAM + VE_TYPE_STEAM);
    02163     }
    02164   }
    02165
    02166   this->vcache.cached_vis_effect = visual_effect;
    02167
    02168   if (!allow_power_change && powered_before != HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER)) {
    02169     ToggleBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER);
    02170     ShowNewGrfVehicleError(this->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_POWERED_WAGON, GBUG_VEH_POWERED_WAGON, false);
    02171   }
    02172 }
    02173
    02174 static const int8 _vehicle_smoke_pos[8] = {
    02175   1, 1, 1, 0, -1, -1, -1, 0
    02176 };
    02177
    02182 void Vehicle::ShowVisualEffect() const
    02183 {
    02184   assert(this->IsPrimaryVehicle());
    02185   bool sound = false;
    02186
    02187   /* Do not show any smoke when:
    02188    * - vehicle smoke is disabled by the player
    02189    * - the vehicle is slowing down or stopped (by the player)
    02190    * - the vehicle is moving very slowly
    02191    */
    02192   if (_settings_game.vehicle.smoke_amount == 0 ||
    02193       this->vehstatus & (VS_TRAIN_SLOWING | VS_STOPPED) ||
    02194       this->cur_speed < 2) {
    02195     return;
    02196   }
    02197
    02198   uint max_speed = this->vcache.cached_max_speed;
    02199   if (this->type == VEH_TRAIN) {
    02200     const Train *t = Train::From(this);
    02201     /* For trains, do not show any smoke when:
    02202      * - the train is reversing
    02203      * - is entering a station with an order to stop there and its speed is equal to maximum station entering speed
    02204      */
    02205     if (HasBit(t->flags, VRF_REVERSING) ||
    02206         (IsRailStationTile(t->tile) && t->IsFrontEngine() && t->current_order.ShouldStopAtStation(t, GetStationIndex(t->tile)) &&
    02207         t->cur_speed >= t->Train::GetCurrentMaxSpeed())) {
    02208       return;
    02209     }
    02210
    02211     max_speed = min(max_speed, t->gcache.cached_max_track_speed);
    02212     max_speed = min(max_speed, this->current_order.max_speed);
    02213   }
    02214   if (this->type == VEH_ROAD || this->type == VEH_SHIP) max_speed = min(max_speed, this->current_order.max_speed * 2);
    02215
    02216   const Vehicle *v = this;
    02217
    02218   do {
    02219     int effect_offset = GB(v->vcache.cached_vis_effect, VE_OFFSET_START, VE_OFFSET_COUNT) - VE_OFFSET_CENTRE;
    02220     byte effect_type = GB(v->vcache.cached_vis_effect, VE_TYPE_START, VE_TYPE_COUNT);
    02221     bool disable_effect = HasBit(v->vcache.cached_vis_effect, VE_DISABLE_EFFECT);
    02222
    02223     /* Show no smoke when:
    02224      * - Smoke has been disabled for this vehicle
    02225      * - The vehicle is not visible
    02226      * - The vehicle is under a bridge
    02227      * - The vehicle is on a depot tile
    02228      * - The vehicle is on a tunnel tile
    02229      * - The vehicle is a train engine that is currently unpowered */
    02230     if (disable_effect ||
    02231         v->vehstatus & VS_HIDDEN ||
    02232         (MayHaveBridgeAbove(v->tile) && IsBridgeAbove(v->tile)) ||
    02233         IsDepotTile(v->tile) ||
    02234         IsTunnelTile(v->tile) ||
    02235         (v->type == VEH_TRAIN &&
    02236         !HasPowerOnRail(Train::From(v)->railtype, GetTileRailType(v->tile)))) {
    02237       continue;
    02238     }
    02239
    02240     /* The effect offset is relative to a point 4 units behind the vehicle's
    02241      * front (which is the center of an 8/8 vehicle). Shorter vehicles need a
    02242      * correction factor. */
    02243     if (v->type == VEH_TRAIN) effect_offset += (VEHICLE_LENGTH - Train::From(v)->gcache.cached_veh_length) / 2;
    02244
    02245     int x = _vehicle_smoke_pos[v->direction] * effect_offset;
    02246     int y = _vehicle_smoke_pos[(v->direction + 2) % 8] * effect_offset;
    02247
    02248     if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION)) {
    02249       x = -x;
    02250       y = -y;
    02251     }
    02252
    02253     switch (effect_type) {
    02254       case VE_TYPE_STEAM:
    02255         /* Steam smoke - amount is gradually falling until vehicle reaches its maximum speed, after that it's normal.
    02256          * Details: while vehicle's current speed is gradually increasing, steam plumes' density decreases by one third each
    02257          * third of its maximum speed spectrum. Steam emission finally normalises at very close to vehicle's maximum speed.
    02258          * REGULATION:
    02259          * - instead of 1, 4 / 2^smoke_amount (max. 2) is used to provide sufficient regulation to steam puffs' amount. */
    02260         if (GB(v->tick_counter, 0, ((4 >> _settings_game.vehicle.smoke_amount) + ((this->cur_speed * 3) / max_speed))) == 0) {
    02261           CreateEffectVehicleRel(v, x, y, 10, EV_STEAM_SMOKE);
    02262           sound = true;
    02263         }
    02264         break;
    02265
    02266       case VE_TYPE_DIESEL: {
    02267         /* Diesel smoke - thicker when vehicle is starting, gradually subsiding till it reaches its maximum speed
    02268          * when smoke emission stops.
    02269          * Details: Vehicle's (max.) speed spectrum is divided into 32 parts. When max. speed is reached, chance for smoke
    02270          * emission erodes by 32 (1/4). For trains, power and weight come in handy too to either increase smoke emission in
    02271          * 6 steps (1000HP each) if the power is low or decrease smoke emission in 6 steps (512 tonnes each) if the train
    02272          * isn't overweight. Power and weight contributions are expressed in a way that neither extreme power, nor
    02273          * extreme weight can ruin the balance (e.g. FreightWagonMultiplier) in the formula. When the vehicle reaches
    02274          * maximum speed no diesel_smoke is emitted.
    02275          * REGULATION:
    02276          * - up to which speed a diesel vehicle is emitting smoke (with reduced/small setting only until 1/2 of max_speed),
    02277          * - in Chance16 - the last value is 512 / 2^smoke_amount (max. smoke when 128 = smoke_amount of 2). */
    02278         int power_weight_effect = 0;
    02279         if (v->type == VEH_TRAIN) {
    02280           power_weight_effect = (32 >> (Train::From(this)->gcache.cached_power >> 10)) - (32 >> (Train::From(this)->gcache.cached_weight >> 9));
    02281         }
    02282         if (this->cur_speed < (max_speed >> (2 >> _settings_game.vehicle.smoke_amount)) &&
    02283             Chance16((64 - ((this->cur_speed << 5) / max_speed) + power_weight_effect), (512 >> _settings_game.vehicle.smoke_amount))) {
    02284           CreateEffectVehicleRel(v, x, y, 10, EV_DIESEL_SMOKE);
    02285           sound = true;
    02286         }
    02287         break;
    02288       }
    02289
    02290       case VE_TYPE_ELECTRIC:
    02291         /* Electric train's spark - more often occurs when train is departing (more load)
    02292          * Details: Electric locomotives are usually at least twice as powerful as their diesel counterparts, so spark
    02293          * emissions are kept simple. Only when starting, creating huge force are sparks more likely to happen, but when
    02294          * reaching its max. speed, quarter by quarter of it, chance decreases untill the usuall 2,22% at train's top speed.
    02295          * REGULATION:
    02296          * - in Chance16 the last value is 360 / 2^smoke_amount (max. sparks when 90 = smoke_amount of 2). */
    02297         if (GB(v->tick_counter, 0, 2) == 0 &&
    02298             Chance16((6 - ((this->cur_speed << 2) / max_speed)), (360 >> _settings_game.vehicle.smoke_amount))) {
    02299           CreateEffectVehicleRel(v, x, y, 10, EV_ELECTRIC_SPARK);
    02300           sound = true;
    02301         }
    02302         break;
    02303
    02304       default:
    02305         break;
    02306     }
    02307   } while ((v = v->Next()) != NULL);
    02308
    02309   if (sound) PlayVehicleSound(this, VSE_VISUAL_EFFECT);
    02310 }
    02311
    02316 void Vehicle::SetNext(Vehicle *next)
    02317 {
    02318   assert(this != next);
    02319
    02320   if (this->next != NULL) {
    02321     /* We had an old next vehicle. Update the first and previous pointers */
    02322     for (Vehicle *v = this->next; v != NULL; v = v->Next()) {
    02323       v->first = this->next;
    02324     }
    02325     this->next->previous = NULL;
    02326   }
    02327
    02328   this->next = next;
    02329
    02330   if (this->next != NULL) {
    02331     /* A new next vehicle. Update the first and previous pointers */
    02332     if (this->next->previous != NULL) this->next->previous->next = NULL;
    02333     this->next->previous = this;
    02334     for (Vehicle *v = this->next; v != NULL; v = v->Next()) {
    02335       v->first = this->first;
    02336     }
    02337   }
    02338 }
    02339
    02345 void Vehicle::AddToShared(Vehicle *shared_chain)
    02346 {
    02347   assert(this->previous_shared == NULL && this->next_shared == NULL);
    02348
    02349   if (shared_chain->orders.list == NULL) {
    02350     assert(shared_chain->previous_shared == NULL);
    02351     assert(shared_chain->next_shared == NULL);
    02352     this->orders.list = shared_chain->orders.list = new OrderList(NULL, shared_chain);
    02353   }
    02354
    02355   this->next_shared     = shared_chain->next_shared;
    02356   this->previous_shared = shared_chain;
    02357
    02358   shared_chain->next_shared = this;
    02359
    02360   if (this->next_shared != NULL) this->next_shared->previous_shared = this;
    02361
    02362   shared_chain->orders.list->AddVehicle(this);
    02363 }
    02364
    02368 void Vehicle::RemoveFromShared()
    02369 {
    02370   /* Remember if we were first and the old window number before RemoveVehicle()
    02371    * as this changes first if needed. */
    02372   bool were_first = (this->FirstShared() == this);
    02373   VehicleListIdentifier vli(VL_SHARED_ORDERS, this->type, this->owner, this->FirstShared()->index);
    02374
    02375   this->orders.list->RemoveVehicle(this);
    02376
    02377   if (!were_first) {
    02378     /* We are not the first shared one, so only relink our previous one. */
    02379     this->previous_shared->next_shared = this->NextShared();
    02380   }
    02381
    02382   if (this->next_shared != NULL) this->next_shared->previous_shared = this->previous_shared;
    02383
    02384
    02385   if (this->orders.list->GetNumVehicles() == 1) {
    02386     /* When there is only one vehicle, remove the shared order list window. */
    02387     DeleteWindowById(GetWindowClassForVehicleType(this->type), vli.Pack());
    02388     InvalidateVehicleOrder(this->FirstShared(), 0);
    02389   } else if (were_first) {
    02390     /* If we were the first one, update to the new first one.
    02391      * Note: FirstShared() is already the new first */
    02392     InvalidateWindowData(GetWindowClassForVehicleType(this->type), vli.Pack(), this->FirstShared()->index | (1U << 31));
    02393   }
    02394
    02395   this->next_shared     = NULL;
    02396   this->previous_shared = NULL;
    02397 }
    02398
    02399 void VehiclesYearlyLoop()
    02400 {
    02401   Vehicle *v;
    02402   FOR_ALL_VEHICLES(v) {
    02403     if (v->IsPrimaryVehicle()) {
    02404       /* show warning if vehicle is not generating enough income last 2 years (corresponds to a red icon in the vehicle list) */
    02405       Money profit = v->GetDisplayProfitThisYear();
    02406       if (v->age >= 730 && profit < 0) {
    02407         if (_settings_client.gui.vehicle_income_warn && v->owner == _local_company) {
    02408           SetDParam(0, v->index);
    02409           SetDParam(1, profit);
    02410           AddVehicleNewsItem(
    02411             STR_NEWS_VEHICLE_IS_UNPROFITABLE,
    02412             NS_ADVICE,
    02413             v->index
    02414           );
    02415         }
    02416         AI::NewEvent(v->owner, new ScriptEventVehicleUnprofitable(v->index));
    02417       }
    02418
    02419       v->profit_last_year = v->profit_this_year;
    02420       v->profit_this_year = 0;
    02421       SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
    02422     }
    02423   }
    02424   GroupStatistics::UpdateProfits();
    02425   SetWindowClassesDirty(WC_TRAINS_LIST);
    02426   SetWindowClassesDirty(WC_SHIPS_LIST);
    02427   SetWindowClassesDirty(WC_ROADVEH_LIST);
    02428   SetWindowClassesDirty(WC_AIRCRAFT_LIST);
    02429 }
    02430
    02431
    02441 bool CanVehicleUseStation(EngineID engine_type, const Station *st)
    02442 {
    02443   const Engine *e = Engine::GetIfValid(engine_type);
    02444   assert(e != NULL);
    02445
    02446   switch (e->type) {
    02447     case VEH_TRAIN:
    02448       return (st->facilities & FACIL_TRAIN) != 0;
    02449
    02450     case VEH_ROAD:
    02451       /* For road vehicles we need the vehicle to know whether it can actually
    02452        * use the station, but if it doesn't have facilities for RVs it is
    02453        * certainly not possible that the station can be used. */
    02454       return (st->facilities & (FACIL_BUS_STOP | FACIL_TRUCK_STOP)) != 0;
    02455
    02456     case VEH_SHIP:
    02457       return (st->facilities & FACIL_DOCK) != 0;
    02458
    02459     case VEH_AIRCRAFT:
    02460       return (st->facilities & FACIL_AIRPORT) != 0 &&
    02461           (st->airport.GetFTA()->flags & (e->u.air.subtype & AIR_CTOL ? AirportFTAClass::AIRPLANES : AirportFTAClass::HELICOPTERS)) != 0;
    02462
    02463     default:
    02464       return false;
    02465   }
    02466 }
    02467
    02474 bool CanVehicleUseStation(const Vehicle *v, const Station *st)
    02475 {
    02476   if (v->type == VEH_ROAD) return st->GetPrimaryRoadStop(RoadVehicle::From(v)) != NULL;
    02477
    02478   return CanVehicleUseStation(v->engine_type, st);
    02479 }
    02480
    02486 GroundVehicleCache *Vehicle::GetGroundVehicleCache()
    02487 {
    02488   assert(this->IsGroundVehicle());
    02489   if (this->type == VEH_TRAIN) {
    02490     return &Train::From(this)->gcache;
    02491   } else {
    02492     return &RoadVehicle::From(this)->gcache;
    02493   }
    02494 }
    02495
    02501 const GroundVehicleCache *Vehicle::GetGroundVehicleCache() const
    02502 {
    02503   assert(this->IsGroundVehicle());
    02504   if (this->type == VEH_TRAIN) {
    02505     return &Train::From(this)->gcache;
    02506   } else {
    02507     return &RoadVehicle::From(this)->gcache;
    02508   }
    02509 }
    02510
    02516 uint16 &Vehicle::GetGroundVehicleFlags()
    02517 {
    02518   assert(this->IsGroundVehicle());
    02519   if (this->type == VEH_TRAIN) {
    02520     return Train::From(this)->gv_flags;
    02521   } else {
    02522     return RoadVehicle::From(this)->gv_flags;
    02523   }
    02524 }
    02525
    02531 const uint16 &Vehicle::GetGroundVehicleFlags() const
    02532 {
    02533   assert(this->IsGroundVehicle());
    02534   if (this->type == VEH_TRAIN) {
    02535     return Train::From(this)->gv_flags;
    02536   } else {
    02537     return RoadVehicle::From(this)->gv_flags;
    02538   }
    02539 }
    02540
    02549 void GetVehicleSet(VehicleSet &set, Vehicle *v, uint8 num_vehicles)
    02550 {
    02551   if (v->type == VEH_TRAIN) {
    02552     Train *u = Train::From(v);
    02553     /* Only include whole vehicles, so start with the first articulated part */
    02554     u = u->GetFirstEnginePart();
    02555
    02556     /* Include num_vehicles vehicles, not counting articulated parts */
    02557     for (; u != NULL && num_vehicles > 0; num_vehicles--) {
    02558       do {
    02559         /* Include current vehicle in the selection. */
    02560         set.Include(u->index);
    02561
    02562         /* If the vehicle is multiheaded, add the other part too. */
    02563         if (u->IsMultiheaded()) set.Include(u->other_multiheaded_part->index);
    02564
    02565         u = u->Next();
    02566       } while (u != NULL && u->IsArticulatedPart());
    02567     }
    02568   }
    02569 }