# vehicle.cpp

Go to the documentation of this file.

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