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