vehicle.cpp

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