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