# vehicle.cpp

Go to the documentation of this file.

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