# vehicle.cpp

Go to the documentation of this file.

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