# vehicle.cpp

Go to the documentation of this file.

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