# vehicle.cpp

Go to the documentation of this file.

    00001 /* $Id: vehicle.cpp 15652 2009-03-09 18:41:54Z michi_cc $ */
    00002
    00005 #include "stdafx.h"
    00006 #include "openttd.h"
    00007 #include "roadveh.h"
    00008 #include "ship.h"
    00009 #include "spritecache.h"
    00010 #include "landscape.h"
    00011 #include "timetable.h"
    00012 #include "viewport_func.h"
    00013 #include "gfx_func.h"
    00014 #include "news_func.h"
    00015 #include "command_func.h"
    00016 #include "company_func.h"
    00017 #include "vehicle_gui.h"
    00018 #include "train.h"
    00019 #include "aircraft.h"
    00020 #include "newgrf_engine.h"
    00021 #include "newgrf_sound.h"
    00022 #include "newgrf_station.h"
    00023 #include "newgrf_text.h"
    00024 #include "group.h"
    00025 #include "group_gui.h"
    00026 #include "strings_func.h"
    00027 #include "zoom_func.h"
    00028 #include "functions.h"
    00029 #include "date_func.h"
    00030 #include "window_func.h"
    00031 #include "vehicle_func.h"
    00032 #include "autoreplace_func.h"
    00033 #include "autoreplace_gui.h"
    00034 #include "string_func.h"
    00035 #include "oldpool_func.h"
    00036 #include "depot_map.h"
    00037 #include "ai/ai.hpp"
    00038 #include "core/smallmap_type.hpp"
    00039 #include "vehiclelist.h"
    00040 #include "depot_func.h"
    00041 #include "settings_type.h"
    00042
    00043 #include "table/sprites.h"
    00044 #include "table/strings.h"
    00045
    00046 #define GEN_HASH(x, y) ((GB((y), 6, 6) << 6) + GB((x), 7, 6))
    00047
    00048 VehicleID _vehicle_id_ctr_day;
    00049 const Vehicle *_place_clicked_vehicle;
    00050 VehicleID _new_vehicle_id;
    00051 uint16 _returned_refit_capacity;
    00052
    00053
    00054 /* Tables used in vehicle.h to find the right command for a certain vehicle type */
    00055 const uint32 _veh_build_proc_table[] = {
    00056   CMD_BUILD_RAIL_VEHICLE,
    00057   CMD_BUILD_ROAD_VEH,
    00058   CMD_BUILD_SHIP,
    00059   CMD_BUILD_AIRCRAFT,
    00060 };
    00061 const uint32 _veh_sell_proc_table[] = {
    00062   CMD_SELL_RAIL_WAGON,
    00063   CMD_SELL_ROAD_VEH,
    00064   CMD_SELL_SHIP,
    00065   CMD_SELL_AIRCRAFT,
    00066 };
    00067
    00068 const uint32 _veh_refit_proc_table[] = {
    00069   CMD_REFIT_RAIL_VEHICLE,
    00070   CMD_REFIT_ROAD_VEH,
    00071   CMD_REFIT_SHIP,
    00072   CMD_REFIT_AIRCRAFT,
    00073 };
    00074
    00075 const uint32 _send_to_depot_proc_table[] = {
    00076   CMD_SEND_TRAIN_TO_DEPOT,
    00077   CMD_SEND_ROADVEH_TO_DEPOT,
    00078   CMD_SEND_SHIP_TO_DEPOT,
    00079   CMD_SEND_AIRCRAFT_TO_HANGAR,
    00080 };
    00081
    00082
    00083 /* Initialize the vehicle-pool */
    00084 DEFINE_OLD_POOL_GENERIC(Vehicle, Vehicle)
    00085
    00086
    00090 bool Vehicle::NeedsAutorenewing(const Company *c) const
    00091 {
    00092   /* We can always generate the Company pointer when we have the vehicle.
    00093    * However this takes time and since the Company pointer is often present
    00094    * when this function is called then it's faster to pass the pointer as an
    00095    * argument rather than finding it again. */
    00096   assert(c == GetCompany(this->owner));
    00097
    00098   if (!c->engine_renew) return false;
    00099   if (this->age - this->max_age < (c->engine_renew_months * 30)) return false;
    00100   if (this->age == 0) return false; // rail cars don't age and lacks a max age
    00101
    00102   return true;
    00103 }
    00104
    00105 void VehicleServiceInDepot(Vehicle *v)
    00106 {
    00107   v->date_of_last_service = _date;
    00108   v->breakdowns_since_last_service = 0;
    00109   v->reliability = GetEngine(v->engine_type)->reliability;
    00110   InvalidateWindow(WC_VEHICLE_DETAILS, v->index); // ensure that last service date and reliability are updated
    00111 }
    00112
    00113 bool Vehicle::NeedsServicing() const
    00114 {
    00115   if (this->vehstatus & (VS_STOPPED | VS_CRASHED)) return false;
    00116
    00117   if (_settings_game.order.no_servicing_if_no_breakdowns && _settings_game.difficulty.vehicle_breakdowns == 0) {
    00118     /* Vehicles set for autoreplacing needs to go to a depot even if breakdowns are turned off.
    00119      * Note: If servicing is enabled, we postpone replacement till next service. */
    00120     return EngineHasReplacementForCompany(GetCompany(this->owner), this->engine_type, this->group_id);
    00121   }
    00122
    00123   return _settings_game.vehicle.servint_ispercent ?
    00124     (this->reliability < GetEngine(this->engine_type)->reliability * (100 - this->service_interval) / 100) :
    00125     (this->date_of_last_service + this->service_interval < _date);
    00126 }
    00127
    00128 bool Vehicle::NeedsAutomaticServicing() const
    00129 {
    00130   if (_settings_game.order.gotodepot && VehicleHasDepotOrders(this)) return false;
    00131   if (this->current_order.IsType(OT_LOADING))            return false;
    00132   if (this->current_order.IsType(OT_GOTO_DEPOT) && this->current_order.GetDepotOrderType() != ODTFB_SERVICE) return false;
    00133   return NeedsServicing();
    00134 }
    00135
    00136 StringID VehicleInTheWayErrMsg(const Vehicle *v)
    00137 {
    00138   switch (v->type) {
    00139     case VEH_TRAIN:    return STR_8803_TRAIN_IN_THE_WAY;
    00140     case VEH_ROAD:     return STR_9000_ROAD_VEHICLE_IN_THE_WAY;
    00141     case VEH_AIRCRAFT: return STR_A015_AIRCRAFT_IN_THE_WAY;
    00142     default:           return STR_980E_SHIP_IN_THE_WAY;
    00143   }
    00144 }
    00145
    00146 static Vehicle *EnsureNoVehicleProcZ(Vehicle *v, void *data)
    00147 {
    00148   byte z = *(byte*)data;
    00149
    00150   if (v->type == VEH_DISASTER || (v->type == VEH_AIRCRAFT && v->subtype == AIR_SHADOW)) return NULL;
    00151   if (v->z_pos > z) return NULL;
    00152
    00153   _error_message = VehicleInTheWayErrMsg(v);
    00154   return v;
    00155 }
    00156
    00157 bool EnsureNoVehicleOnGround(TileIndex tile)
    00158 {
    00159   byte z = GetTileMaxZ(tile);
    00160   return !HasVehicleOnPos(tile, &z, &EnsureNoVehicleProcZ);
    00161 }
    00162
    00164 static Vehicle *GetVehicleTunnelBridgeProc(Vehicle *v, void *data)
    00165 {
    00166   if (v->type != VEH_TRAIN && v->type != VEH_ROAD && v->type != VEH_SHIP) return NULL;
    00167   if (v == (const Vehicle *)data) return NULL;
    00168
    00169   _error_message = VehicleInTheWayErrMsg(v);
    00170   return v;
    00171 }
    00172
    00180 bool HasVehicleOnTunnelBridge(TileIndex tile, TileIndex endtile, const Vehicle *ignore)
    00181 {
    00182   return HasVehicleOnPos(tile, (void *)ignore, &GetVehicleTunnelBridgeProc) ||
    00183       HasVehicleOnPos(endtile, (void *)ignore, &GetVehicleTunnelBridgeProc);
    00184 }
    00185
    00186
    00187 static void UpdateVehiclePosHash(Vehicle *v, int x, int y);
    00188
    00189 void VehiclePositionChanged(Vehicle *v)
    00190 {
    00191   int img = v->cur_image;
    00192   Point pt = RemapCoords(v->x_pos + v->x_offs, v->y_pos + v->y_offs, v->z_pos);
    00193   const Sprite *spr = GetSprite(img, ST_NORMAL);
    00194
    00195   pt.x += spr->x_offs;
    00196   pt.y += spr->y_offs;
    00197
    00198   UpdateVehiclePosHash(v, pt.x, pt.y);
    00199
    00200   v->left_coord = pt.x;
    00201   v->top_coord = pt.y;
    00202   v->right_coord = pt.x + spr->width + 2;
    00203   v->bottom_coord = pt.y + spr->height + 2;
    00204 }
    00205
    00206 Vehicle::Vehicle()
    00207 {
    00208   this->type               = VEH_INVALID;
    00209   this->left_coord         = INVALID_COORD;
    00210   this->group_id           = DEFAULT_GROUP;
    00211   this->fill_percent_te_id = INVALID_TE_ID;
    00212   this->first              = this;
    00213   this->colourmap           = PAL_NONE;
    00214 }
    00215
    00220 byte VehicleRandomBits()
    00221 {
    00222   return GB(Random(), 0, 8);
    00223 }
    00224
    00225
    00226 /* static */ bool Vehicle::AllocateList(Vehicle **vl, int num)
    00227 {
    00228   if (!Vehicle::CanAllocateItem(num)) return false;
    00229   if (vl == NULL) return true;
    00230
    00231   uint counter = _Vehicle_pool.first_free_index;
    00232
    00233   for (int i = 0; i != num; i++) {
    00234     vl[i] = new (AllocateRaw(counter)) InvalidVehicle();
    00235     counter++;
    00236   }
    00237
    00238   return true;
    00239 }
    00240
    00241 /* Size of the hash, 6 = 64 x 64, 7 = 128 x 128. Larger sizes will (in theory) reduce hash
    00242  * lookup times at the expense of memory usage. */
    00243 const int HASH_BITS = 7;
    00244 const int HASH_SIZE = 1 << HASH_BITS;
    00245 const int HASH_MASK = HASH_SIZE - 1;
    00246 const int TOTAL_HASH_SIZE = 1 << (HASH_BITS * 2);
    00247 const int TOTAL_HASH_MASK = TOTAL_HASH_SIZE - 1;
    00248
    00249 /* Resolution of the hash, 0 = 1*1 tile, 1 = 2*2 tiles, 2 = 4*4 tiles, etc.
    00250  * Profiling results show that 0 is fastest. */
    00251 const int HASH_RES = 0;
    00252
    00253 static Vehicle *_new_vehicle_position_hash[TOTAL_HASH_SIZE];
    00254
    00255 static Vehicle *VehicleFromHash(int xl, int yl, int xu, int yu, void *data, VehicleFromPosProc *proc, bool find_first)
    00256 {
    00257   for (int y = yl; ; y = (y + (1 << HASH_BITS)) & (HASH_MASK << HASH_BITS)) {
    00258     for (int x = xl; ; x = (x + 1) & HASH_MASK) {
    00259       Vehicle *v = _new_vehicle_position_hash[(x + y) & TOTAL_HASH_MASK];
    00260       for (; v != NULL; v = v->next_new_hash) {
    00261         Vehicle *a = proc(v, data);
    00262         if (find_first && a != NULL) return a;
    00263       }
    00264       if (x == xu) break;
    00265     }
    00266     if (y == yu) break;
    00267   }
    00268
    00269   return NULL;
    00270 }
    00271
    00272
    00284 static Vehicle *VehicleFromPosXY(int x, int y, void *data, VehicleFromPosProc *proc, bool find_first)
    00285 {
    00286   const int COLL_DIST = 6;
    00287
    00288   /* Hash area to scan is from xl,yl to xu,yu */
    00289   int xl = GB((x - COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS);
    00290   int xu = GB((x + COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS);
    00291   int yl = GB((y - COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS) << HASH_BITS;
    00292   int yu = GB((y + COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS) << HASH_BITS;
    00293
    00294   return VehicleFromHash(xl, yl, xu, yu, data, proc, find_first);
    00295 }
    00296
    00311 void FindVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc)
    00312 {
    00313   VehicleFromPosXY(x, y, data, proc, false);
    00314 }
    00315
    00327 bool HasVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc)
    00328 {
    00329   return VehicleFromPosXY(x, y, data, proc, true) != NULL;
    00330 }
    00331
    00342 static Vehicle *VehicleFromPos(TileIndex tile, void *data, VehicleFromPosProc *proc, bool find_first)
    00343 {
    00344   int x = GB(TileX(tile), HASH_RES, HASH_BITS);
    00345   int y = GB(TileY(tile), HASH_RES, HASH_BITS) << HASH_BITS;
    00346
    00347   Vehicle *v = _new_vehicle_position_hash[(x + y) & TOTAL_HASH_MASK];
    00348   for (; v != NULL; v = v->next_new_hash) {
    00349     if (v->tile != tile) continue;
    00350
    00351     Vehicle *a = proc(v, data);
    00352     if (find_first && a != NULL) return a;
    00353   }
    00354
    00355   return NULL;
    00356 }
    00357
    00371 void FindVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
    00372 {
    00373   VehicleFromPos(tile, data, proc, false);
    00374 }
    00375
    00386 bool HasVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
    00387 {
    00388   return VehicleFromPos(tile, data, proc, true) != NULL;
    00389 }
    00390
    00391
    00392 static void UpdateNewVehiclePosHash(Vehicle *v, bool remove)
    00393 {
    00394   Vehicle **old_hash = v->old_new_hash;
    00395   Vehicle **new_hash;
    00396
    00397   if (remove) {
    00398     new_hash = NULL;
    00399   } else {
    00400     int x = GB(TileX(v->tile), HASH_RES, HASH_BITS);
    00401     int y = GB(TileY(v->tile), HASH_RES, HASH_BITS) << HASH_BITS;
    00402     new_hash = &_new_vehicle_position_hash[(x + y) & TOTAL_HASH_MASK];
    00403   }
    00404
    00405   if (old_hash == new_hash) return;
    00406
    00407   /* Remove from the old position in the hash table */
    00408   if (old_hash != NULL) {
    00409     Vehicle *last = NULL;
    00410     Vehicle *u = *old_hash;
    00411     while (u != v) {
    00412       last = u;
    00413       u = u->next_new_hash;
    00414       assert(u != NULL);
    00415     }
    00416
    00417     if (last == NULL) {
    00418       *old_hash = v->next_new_hash;
    00419     } else {
    00420       last->next_new_hash = v->next_new_hash;
    00421     }
    00422   }
    00423
    00424   /* Insert vehicle at beginning of the new position in the hash table */
    00425   if (new_hash != NULL) {
    00426     v->next_new_hash = *new_hash;
    00427     *new_hash = v;
    00428     assert(v != v->next_new_hash);
    00429   }
    00430
    00431   /* Remember current hash position */
    00432   v->old_new_hash = new_hash;
    00433 }
    00434
    00435 static Vehicle *_vehicle_position_hash[0x1000];
    00436
    00437 static void UpdateVehiclePosHash(Vehicle *v, int x, int y)
    00438 {
    00439   UpdateNewVehiclePosHash(v, x == INVALID_COORD);
    00440
    00441   Vehicle **old_hash, **new_hash;
    00442   int old_x = v->left_coord;
    00443   int old_y = v->top_coord;
    00444
    00445   new_hash = (x == INVALID_COORD) ? NULL : &_vehicle_position_hash[GEN_HASH(x, y)];
    00446   old_hash = (old_x == INVALID_COORD) ? NULL : &_vehicle_position_hash[GEN_HASH(old_x, old_y)];
    00447
    00448   if (old_hash == new_hash) return;
    00449
    00450   /* remove from hash table? */
    00451   if (old_hash != NULL) {
    00452     Vehicle *last = NULL;
    00453     Vehicle *u = *old_hash;
    00454     while (u != v) {
    00455       last = u;
    00456       u = u->next_hash;
    00457       assert(u != NULL);
    00458     }
    00459
    00460     if (last == NULL) {
    00461       *old_hash = v->next_hash;
    00462     } else {
    00463       last->next_hash = v->next_hash;
    00464     }
    00465   }
    00466
    00467   /* insert into hash table? */
    00468   if (new_hash != NULL) {
    00469     v->next_hash = *new_hash;
    00470     *new_hash = v;
    00471   }
    00472 }
    00473
    00474 void ResetVehiclePosHash()
    00475 {
    00476   Vehicle *v;
    00477   FOR_ALL_VEHICLES(v) { v->old_new_hash = NULL; }
    00478   memset(_vehicle_position_hash, 0, sizeof(_vehicle_position_hash));
    00479   memset(_new_vehicle_position_hash, 0, sizeof(_new_vehicle_position_hash));
    00480 }
    00481
    00482 void ResetVehicleColourMap()
    00483 {
    00484   Vehicle *v;
    00485   FOR_ALL_VEHICLES(v) { v->colourmap = PAL_NONE; }
    00486 }
    00487
    00492 typedef SmallMap<Vehicle *, bool, 4> AutoreplaceMap;
    00493 static AutoreplaceMap _vehicles_to_autoreplace;
    00494
    00495 void InitializeVehicles()
    00496 {
    00497   _Vehicle_pool.CleanPool();
    00498   _Vehicle_pool.AddBlockToPool();
    00499
    00500   _vehicles_to_autoreplace.Reset();
    00501   ResetVehiclePosHash();
    00502 }
    00503
    00504 Vehicle *GetLastVehicleInChain(Vehicle *v)
    00505 {
    00506   while (v->Next() != NULL) v = v->Next();
    00507   return v;
    00508 }
    00509
    00510 const Vehicle *GetLastVehicleInChain(const Vehicle *v)
    00511 {
    00512   while (v->Next() != NULL) v = v->Next();
    00513   return v;
    00514 }
    00515
    00516 uint CountVehiclesInChain(const Vehicle *v)
    00517 {
    00518   uint count = 0;
    00519   do count++; while ((v = v->Next()) != NULL);
    00520   return count;
    00521 }
    00522
    00527 bool IsEngineCountable(const Vehicle *v)
    00528 {
    00529   switch (v->type) {
    00530     case VEH_AIRCRAFT: return IsNormalAircraft(v); // don't count plane shadows and helicopter rotors
    00531     case VEH_TRAIN:
    00532       return !IsArticulatedPart(v) && // tenders and other articulated parts
    00533       !IsRearDualheaded(v); // rear parts of multiheaded engines
    00534     case VEH_ROAD: return IsRoadVehFront(v);
    00535     case VEH_SHIP: return true;
    00536     default: return false; // Only count company buildable vehicles
    00537   }
    00538 }
    00539
    00540 void Vehicle::PreDestructor()
    00541 {
    00542   if (CleaningPool()) return;
    00543
    00544   if (IsValidStationID(this->last_station_visited)) {
    00545     GetStation(this->last_station_visited)->loading_vehicles.remove(this);
    00546
    00547     HideFillingPercent(&this->fill_percent_te_id);
    00548   }
    00549
    00550   if (IsEngineCountable(this)) {
    00551     GetCompany(this->owner)->num_engines[this->engine_type]--;
    00552     if (this->owner == _local_company) InvalidateAutoreplaceWindow(this->engine_type, this->group_id);
    00553
    00554     DeleteGroupHighlightOfVehicle(this);
    00555     if (IsValidGroupID(this->group_id)) GetGroup(this->group_id)->num_engines[this->engine_type]--;
    00556     if (this->IsPrimaryVehicle()) DecreaseGroupNumVehicle(this->group_id);
    00557   }
    00558
    00559   if (this->type == VEH_ROAD) ClearSlot(this);
    00560   if (this->type == VEH_AIRCRAFT && this->IsPrimaryVehicle()) {
    00561     Station *st = GetTargetAirportIfValid(this);
    00562     if (st != NULL) {
    00563       const AirportFTA *layout = st->Airport()->layout;
    00564       CLRBITS(st->airport_flags, layout[this->u.air.previous_pos].block | layout[this->u.air.pos].block);
    00565     }
    00566   }
    00567
    00568   if (this->type != VEH_TRAIN || (this->type == VEH_TRAIN && (IsFrontEngine(this) || IsFreeWagon(this)))) {
    00569     InvalidateWindowData(WC_VEHICLE_DEPOT, this->tile);
    00570   }
    00571
    00572   if (this->IsPrimaryVehicle()) {
    00573     DeleteWindowById(WC_VEHICLE_VIEW, this->index);
    00574     DeleteWindowById(WC_VEHICLE_ORDERS, this->index);
    00575     DeleteWindowById(WC_VEHICLE_REFIT, this->index);
    00576     DeleteWindowById(WC_VEHICLE_DETAILS, this->index);
    00577     DeleteWindowById(WC_VEHICLE_TIMETABLE, this->index);
    00578     InvalidateWindow(WC_COMPANY, this->owner);
    00579   }
    00580   InvalidateWindowClassesData(GetWindowClassForVehicleType(this->type), 0);
    00581
    00582   this->cargo.Truncate(0);
    00583   DeleteVehicleOrders(this);
    00584   DeleteDepotHighlightOfVehicle(this);
    00585
    00586   extern void StopGlobalFollowVehicle(const Vehicle *v);
    00587   StopGlobalFollowVehicle(this);
    00588 }
    00589
    00590 Vehicle::~Vehicle()
    00591 {
    00592   free(this->name);
    00593
    00594   if (CleaningPool()) return;
    00595
    00596   /* sometimes, eg. for disaster vehicles, when company bankrupts, when removing crashed/flooded vehicles,
    00597    * it may happen that vehicle chain is deleted when visible */
    00598   if (!(this->vehstatus & VS_HIDDEN)) MarkSingleVehicleDirty(this);
    00599
    00600   Vehicle *v = this->Next();
    00601   this->SetNext(NULL);
    00602
    00603   delete v;
    00604
    00605   UpdateVehiclePosHash(this, INVALID_COORD, 0);
    00606   this->next_hash = NULL;
    00607   this->next_new_hash = NULL;
    00608
    00609   DeleteVehicleNews(this->index, INVALID_STRING_ID);
    00610
    00611   this->type = VEH_INVALID;
    00612 }
    00613
    00617 void VehicleEnteredDepotThisTick(Vehicle *v)
    00618 {
    00619   /* Vehicle should stop in the depot if it was in 'stopping' state or
    00620    * when the vehicle is ordered to halt in the depot. */
    00621   _vehicles_to_autoreplace[v] = !(v->vehstatus & VS_STOPPED) &&
    00622       (!v->current_order.IsType(OT_GOTO_DEPOT) ||
    00623        !(v->current_order.GetDepotActionType() & ODATFB_HALT));
    00624
    00625   /* We ALWAYS set the stopped state. Even when the vehicle does not plan on
    00626    * stopping in the depot, so we stop it to ensure that it will not reserve
    00627    * the path out of the depot before we might autoreplace it to a different
    00628    * engine. The new engine would not own the reserved path we store that we
    00629    * stopped the vehicle, so autoreplace can start it again */
    00630   v->vehstatus |= VS_STOPPED;
    00631 }
    00632
    00633 void CallVehicleTicks()
    00634 {
    00635   _vehicles_to_autoreplace.Clear();
    00636
    00637   Station *st;
    00638   FOR_ALL_STATIONS(st) LoadUnloadStation(st);
    00639
    00640   Vehicle *v;
    00641   FOR_ALL_VEHICLES(v) {
    00642     v->Tick();
    00643
    00644     switch (v->type) {
    00645       default: break;
    00646
    00647       case VEH_TRAIN:
    00648       case VEH_ROAD:
    00649       case VEH_AIRCRAFT:
    00650       case VEH_SHIP:
    00651         if (v->type == VEH_TRAIN && IsTrainWagon(v)) continue;
    00652         if (v->type == VEH_AIRCRAFT && v->subtype != AIR_HELICOPTER) continue;
    00653         if (v->type == VEH_ROAD && !IsRoadVehFront(v)) continue;
    00654
    00655         v->motion_counter += (v->direction & 1) ? (v->cur_speed * 3) / 4 : v->cur_speed;
    00656         /* Play a running sound if the motion counter passes 256 (Do we not skip sounds?) */
    00657         if (GB(v->motion_counter, 0, 8) < v->cur_speed) PlayVehicleSound(v, VSE_RUNNING);
    00658
    00659         /* Play an alterate running sound every 16 ticks */
    00660         if (GB(v->tick_counter, 0, 4) == 0) PlayVehicleSound(v, v->cur_speed > 0 ? VSE_RUNNING_16 : VSE_STOPPED_16);
    00661     }
    00662   }
    00663
    00664   for (AutoreplaceMap::iterator it = _vehicles_to_autoreplace.Begin(); it != _vehicles_to_autoreplace.End(); it++) {
    00665     v = it->first;
    00666     /* Autoreplace needs the current company set as the vehicle owner */
    00667     _current_company = v->owner;
    00668
    00669     /* Start vehicle if we stopped them in VehicleEnteredDepotThisTick()
    00670      * We need to stop them between VehicleEnteredDepotThisTick() and here or we risk that
    00671      * they are already leaving the depot again before being replaced. */
    00672     if (it->second) v->vehstatus &= ~VS_STOPPED;
    00673
    00674     /* Store the position of the effect as the vehicle pointer will become invalid later */
    00675     int x = v->x_pos;
    00676     int y = v->y_pos;
    00677     int z = v->z_pos;
    00678
    00679     const Company *c = GetCompany(_current_company);
    00680     SubtractMoneyFromCompany(CommandCost(EXPENSES_NEW_VEHICLES, (Money)c->engine_renew_money));
    00681     CommandCost res = DoCommand(0, v->index, 0, DC_EXEC, CMD_AUTOREPLACE_VEHICLE);
    00682     SubtractMoneyFromCompany(CommandCost(EXPENSES_NEW_VEHICLES, -(Money)c->engine_renew_money));
    00683
    00684     if (!IsLocalCompany()) continue;
    00685
    00686     if (res.Succeeded()) {
    00687       ShowCostOrIncomeAnimation(x, y, z, res.GetCost());
    00688       continue;
    00689     }
    00690
    00691     StringID error_message = res.GetErrorMessage();
    00692     if (error_message == STR_AUTOREPLACE_NOTHING_TO_DO || error_message == INVALID_STRING_ID) continue;
    00693
    00694     if (error_message == STR_0003_NOT_ENOUGH_CASH_REQUIRES) error_message = STR_AUTOREPLACE_MONEY_LIMIT;
    00695
    00696     StringID message;
    00697     if (error_message == STR_TRAIN_TOO_LONG_AFTER_REPLACEMENT) {
    00698       message = error_message;
    00699     } else {
    00700       message = STR_VEHICLE_AUTORENEW_FAILED;
    00701     }
    00702
    00703     SetDParam(0, v->index);
    00704     SetDParam(1, error_message);
    00705     AddNewsItem(message, NS_ADVICE, v->index, 0);
    00706   }
    00707
    00708   _current_company = OWNER_NONE;
    00709 }
    00710
    00716 bool CanRefitTo(EngineID engine_type, CargoID cid_to)
    00717 {
    00718   return HasBit(EngInfo(engine_type)->refit_mask, cid_to);
    00719 }
    00720
    00725 CargoID FindFirstRefittableCargo(EngineID engine_type)
    00726 {
    00727   uint32 refit_mask = EngInfo(engine_type)->refit_mask;
    00728
    00729   if (refit_mask != 0) {
    00730     for (CargoID cid = 0; cid < NUM_CARGO; cid++) {
    00731       if (HasBit(refit_mask, cid)) return cid;
    00732     }
    00733   }
    00734
    00735   return CT_INVALID;
    00736 }
    00737
    00742 CommandCost GetRefitCost(EngineID engine_type)
    00743 {
    00744   Money base_cost;
    00745   ExpensesType expense_type;
    00746   switch (GetEngine(engine_type)->type) {
    00747     case VEH_SHIP:
    00748       base_cost = _price.ship_base;
    00749       expense_type = EXPENSES_SHIP_RUN;
    00750       break;
    00751
    00752     case VEH_ROAD:
    00753       base_cost = _price.roadveh_base;
    00754       expense_type = EXPENSES_ROADVEH_RUN;
    00755       break;
    00756
    00757     case VEH_AIRCRAFT:
    00758       base_cost = _price.aircraft_base;
    00759       expense_type = EXPENSES_AIRCRAFT_RUN;
    00760       break;
    00761
    00762     case VEH_TRAIN:
    00763       base_cost = 2 * ((RailVehInfo(engine_type)->railveh_type == RAILVEH_WAGON) ?
    00764                _price.build_railwagon : _price.build_railvehicle);
    00765       expense_type = EXPENSES_TRAIN_RUN;
    00766       break;
    00767
    00768     default: NOT_REACHED();
    00769   }
    00770   return CommandCost(expense_type, (EngInfo(engine_type)->refit_cost * base_cost) >> 10);
    00771 }
    00772
    00773 static void DoDrawVehicle(const Vehicle *v)
    00774 {
    00775   SpriteID image = v->cur_image;
    00776   SpriteID pal = PAL_NONE;
    00777
    00778   if (v->vehstatus & VS_DEFPAL) pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
    00779
    00780   AddSortableSpriteToDraw(image, pal, v->x_pos + v->x_offs, v->y_pos + v->y_offs,
    00781     v->x_extent, v->y_extent, v->z_extent, v->z_pos, (v->vehstatus & VS_SHADOW) != 0);
    00782 }
    00783
    00784 void ViewportAddVehicles(DrawPixelInfo *dpi)
    00785 {
    00786   /* The bounding rectangle */
    00787   const int l = dpi->left;
    00788   const int r = dpi->left + dpi->width;
    00789   const int t = dpi->top;
    00790   const int b = dpi->top + dpi->height;
    00791
    00792   /* The hash area to scan */
    00793   int xl, xu, yl, yu;
    00794
    00795   if (dpi->width + 70 < (1 << (7 + 6))) {
    00796     xl = GB(l - 70, 7, 6);
    00797     xu = GB(r,      7, 6);
    00798   } else {
    00799     /* scan whole hash row */
    00800     xl = 0;
    00801     xu = 0x3F;
    00802   }
    00803
    00804   if (dpi->height + 70 < (1 << (6 + 6))) {
    00805     yl = GB(t - 70, 6, 6) << 6;
    00806     yu = GB(b,      6, 6) << 6;
    00807   } else {
    00808     /* scan whole column */
    00809     yl = 0;
    00810     yu = 0x3F << 6;
    00811   }
    00812
    00813   for (int y = yl;; y = (y + (1 << 6)) & (0x3F << 6)) {
    00814     for (int x = xl;; x = (x + 1) & 0x3F) {
    00815       const Vehicle *v = _vehicle_position_hash[x + y]; // already masked & 0xFFF
    00816
    00817       while (v != NULL) {
    00818         if (!(v->vehstatus & VS_HIDDEN) &&
    00819             l <= v->right_coord &&
    00820             t <= v->bottom_coord &&
    00821             r >= v->left_coord &&
    00822             b >= v->top_coord) {
    00823           DoDrawVehicle(v);
    00824         }
    00825         v = v->next_hash;
    00826       }
    00827
    00828       if (x == xu) break;
    00829     }
    00830
    00831     if (y == yu) break;
    00832   }
    00833 }
    00834
    00835 Vehicle *CheckClickOnVehicle(const ViewPort *vp, int x, int y)
    00836 {
    00837   Vehicle *found = NULL, *v;
    00838   uint dist, best_dist = UINT_MAX;
    00839
    00840   if ((uint)(x -= vp->left) >= (uint)vp->width || (uint)(y -= vp->top) >= (uint)vp->height) return NULL;
    00841
    00842   x = ScaleByZoom(x, vp->zoom) + vp->virtual_left;
    00843   y = ScaleByZoom(y, vp->zoom) + vp->virtual_top;
    00844
    00845   FOR_ALL_VEHICLES(v) {
    00846     if ((v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) == 0 &&
    00847         x >= v->left_coord && x <= v->right_coord &&
    00848         y >= v->top_coord && y <= v->bottom_coord) {
    00849
    00850       dist = max(
    00851         abs(((v->left_coord + v->right_coord) >> 1) - x),
    00852         abs(((v->top_coord + v->bottom_coord) >> 1) - y)
    00853       );
    00854
    00855       if (dist < best_dist) {
    00856         found = v;
    00857         best_dist = dist;
    00858       }
    00859     }
    00860   }
    00861
    00862   return found;
    00863 }
    00864
    00865 void CheckVehicle32Day(Vehicle *v)
    00866 {
    00867   if ((v->day_counter & 0x1F) != 0) return;
    00868
    00869   uint16 callback = GetVehicleCallback(CBID_VEHICLE_32DAY_CALLBACK, 0, 0, v->engine_type, v);
    00870   if (callback == CALLBACK_FAILED) return;
    00871   if (HasBit(callback, 0)) TriggerVehicle(v, VEHICLE_TRIGGER_CALLBACK_32); // Trigger vehicle trigger 10
    00872   if (HasBit(callback, 1)) v->colourmap = PAL_NONE;                         // Update colourmap via callback 2D
    00873 }
    00874
    00875 void DecreaseVehicleValue(Vehicle *v)
    00876 {
    00877   v->value -= v->value >> 8;
    00878   InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
    00879 }
    00880
    00881 static const byte _breakdown_chance[64] = {
    00882     3,   3,   3,   3,   3,   3,   3,   3,
    00883     4,   4,   5,   5,   6,   6,   7,   7,
    00884     8,   8,   9,   9,  10,  10,  11,  11,
    00885    12,  13,  13,  13,  13,  14,  15,  16,
    00886    17,  19,  21,  25,  28,  31,  34,  37,
    00887    40,  44,  48,  52,  56,  60,  64,  68,
    00888    72,  80,  90, 100, 110, 120, 130, 140,
    00889   150, 170, 190, 210, 230, 250, 250, 250,
    00890 };
    00891
    00892 void CheckVehicleBreakdown(Vehicle *v)
    00893 {
    00894   int rel, rel_old;
    00895
    00896   /* decrease reliability */
    00897   v->reliability = rel = max((rel_old = v->reliability) - v->reliability_spd_dec, 0);
    00898   if ((rel_old >> 8) != (rel >> 8)) InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
    00899
    00900   if (v->breakdown_ctr != 0 || v->vehstatus & VS_STOPPED ||
    00901       _settings_game.difficulty.vehicle_breakdowns < 1 ||
    00902       v->cur_speed < 5 || _game_mode == GM_MENU) {
    00903     return;
    00904   }
    00905
    00906   uint32 r = Random();
    00907
    00908   /* increase chance of failure */
    00909   int chance = v->breakdown_chance + 1;
    00910   if (Chance16I(1, 25, r)) chance += 25;
    00911   v->breakdown_chance = min(255, chance);
    00912
    00913   /* calculate reliability value to use in comparison */
    00914   rel = v->reliability;
    00915   if (v->type == VEH_SHIP) rel += 0x6666;
    00916
    00917   /* reduced breakdowns? */
    00918   if (_settings_game.difficulty.vehicle_breakdowns == 1) rel += 0x6666;
    00919
    00920   /* check if to break down */
    00921   if (_breakdown_chance[(uint)min(rel, 0xffff) >> 10] <= v->breakdown_chance) {
    00922     v->breakdown_ctr    = GB(r, 16, 6) + 0x3F;
    00923     v->breakdown_delay  = GB(r, 24, 7) + 0x80;
    00924     v->breakdown_chance = 0;
    00925   }
    00926 }
    00927
    00928 void AgeVehicle(Vehicle *v)
    00929 {
    00930   if (v->age < 65535) v->age++;
    00931
    00932   int age = v->age - v->max_age;
    00933   if (age == DAYS_IN_LEAP_YEAR * 0 || age == DAYS_IN_LEAP_YEAR * 1 ||
    00934       age == DAYS_IN_LEAP_YEAR * 2 || age == DAYS_IN_LEAP_YEAR * 3 || age == DAYS_IN_LEAP_YEAR * 4) {
    00935     v->reliability_spd_dec <<= 1;
    00936   }
    00937
    00938   InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
    00939
    00940   /* Don't warn about non-primary or not ours vehicles */
    00941   if (v->Previous() != NULL || v->owner != _local_company) return;
    00942
    00943   /* Don't warn if a renew is active */
    00944   if (GetCompany(v->owner)->engine_renew && GetEngine(v->engine_type)->company_avail != 0) return;
    00945
    00946   StringID str;
    00947   if (age == -DAYS_IN_LEAP_YEAR) {
    00948     str = STR_01A0_IS_GETTING_OLD;
    00949   } else if (age == 0) {
    00950     str = STR_01A1_IS_GETTING_VERY_OLD;
    00951   } else if (age > 0 && (age % DAYS_IN_LEAP_YEAR) == 0) {
    00952     str = STR_01A2_IS_GETTING_VERY_OLD_AND;
    00953   } else {
    00954     return;
    00955   }
    00956
    00957   SetDParam(0, v->index);
    00958   AddNewsItem(str, NS_ADVICE, v->index, 0);
    00959 }
    00960
    00968 CommandCost CmdStartStopVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00969 {
    00970   /* Disable the effect of p2 bit 0, when DC_AUTOREPLACE is not set */
    00971   if ((flags & DC_AUTOREPLACE) == 0) SetBit(p2, 0);
    00972
    00973   if (!IsValidVehicleID(p1)) return CMD_ERROR;
    00974
    00975   Vehicle *v = GetVehicle(p1);
    00976
    00977   if (!CheckOwnership(v->owner)) return CMD_ERROR;
    00978   if (!v->IsPrimaryVehicle()) return CMD_ERROR;
    00979
    00980   switch (v->type) {
    00981     case VEH_TRAIN:
    00982       if (v->vehstatus & VS_STOPPED && v->u.rail.cached_power == 0) return_cmd_error(STR_TRAIN_START_NO_CATENARY);
    00983       break;
    00984
    00985     case VEH_SHIP:
    00986     case VEH_ROAD:
    00987       break;
    00988
    00989     case VEH_AIRCRAFT:
    00990       /* cannot stop airplane when in flight, or when taking off / landing */
    00991       if (v->u.air.state >= STARTTAKEOFF && v->u.air.state < TERM7) return_cmd_error(STR_A017_AIRCRAFT_IS_IN_FLIGHT);
    00992       break;
    00993
    00994     default: return CMD_ERROR;
    00995   }
    00996
    00997   /* Check if this vehicle can be started/stopped. The callback will fail or
    00998    * return 0xFF if it can. */
    00999   uint16 callback = GetVehicleCallback(CBID_VEHICLE_START_STOP_CHECK, 0, 0, v->engine_type, v);
    01000   if (callback != CALLBACK_FAILED && GB(callback, 0, 8) != 0xFF && HasBit(p2, 0)) {
    01001     StringID error = GetGRFStringID(GetEngineGRFID(v->engine_type), 0xD000 + callback);
    01002     return_cmd_error(error);
    01003   }
    01004
    01005   if (flags & DC_EXEC) {
    01006     static const StringID vehicle_waiting_in_depot[] = {
    01007       STR_8814_TRAIN_IS_WAITING_IN_DEPOT,
    01008       STR_9016_ROAD_VEHICLE_IS_WAITING,
    01009       STR_981C_SHIP_IS_WAITING_IN_DEPOT,
    01010       STR_A014_AIRCRAFT_IS_WAITING_IN,
    01011     };
    01012
    01013     static const WindowClass vehicle_list[] = {
    01014       WC_TRAINS_LIST,
    01015       WC_ROADVEH_LIST,
    01016       WC_SHIPS_LIST,
    01017       WC_AIRCRAFT_LIST,
    01018     };
    01019
    01020     if (v->IsStoppedInDepot() && (flags & DC_AUTOREPLACE) == 0) DeleteVehicleNews(p1, vehicle_waiting_in_depot[v->type]);
    01021
    01022     v->vehstatus ^= VS_STOPPED;
    01023     if (v->type != VEH_TRAIN) v->cur_speed = 0; // trains can stop 'slowly'
    01024     InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
    01025     InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
    01026     InvalidateWindowClasses(vehicle_list[v->type]);
    01027   }
    01028   return CommandCost();
    01029 }
    01030
    01041 CommandCost CmdMassStartStopVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    01042 {
    01043   VehicleList list;
    01044   CommandCost return_value = CMD_ERROR;
    01045   VehicleType vehicle_type = (VehicleType)GB(p2, 0, 5);
    01046   bool start_stop = HasBit(p2, 5);
    01047   bool vehicle_list_window = HasBit(p2, 6);
    01048
    01049   if (vehicle_list_window) {
    01050     uint32 id = p1;
    01051     uint16 window_type = p2 & VLW_MASK;
    01052
    01053     GenerateVehicleSortList(&list, vehicle_type, _current_company, id, window_type);
    01054   } else {
    01055     /* Get the list of vehicles in the depot */
    01056     BuildDepotVehicleList(vehicle_type, tile, &list, NULL);
    01057   }
    01058
    01059   for (uint i = 0; i < list.Length(); i++) {
    01060     const Vehicle *v = list[i];
    01061
    01062     if (!!(v->vehstatus & VS_STOPPED) != start_stop) continue;
    01063
    01064     if (!vehicle_list_window) {
    01065       if (vehicle_type == VEH_TRAIN) {
    01066         if (CheckTrainInDepot(v, false) == -1) continue;
    01067       } else {
    01068         if (!(v->vehstatus & VS_HIDDEN)) continue;
    01069       }
    01070     }
    01071
    01072     CommandCost ret = DoCommand(tile, v->index, 0, flags, CMD_START_STOP_VEHICLE);
    01073
    01074     if (CmdSucceeded(ret)) {
    01075       return_value = CommandCost();
    01076       /* We know that the command is valid for at least one vehicle.
    01077        * If we haven't set DC_EXEC, then there is no point in continueing because it will be valid */
    01078       if (!(flags & DC_EXEC)) break;
    01079     }
    01080   }
    01081
    01082   return return_value;
    01083 }
    01084
    01091 CommandCost CmdDepotSellAllVehicles(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    01092 {
    01093   VehicleList list;
    01094
    01095   CommandCost cost(EXPENSES_NEW_VEHICLES);
    01096   uint sell_command;
    01097   VehicleType vehicle_type = (VehicleType)GB(p1, 0, 8);
    01098
    01099   switch (vehicle_type) {
    01100     case VEH_TRAIN:    sell_command = CMD_SELL_RAIL_WAGON; break;
    01101     case VEH_ROAD:     sell_command = CMD_SELL_ROAD_VEH;   break;
    01102     case VEH_SHIP:     sell_command = CMD_SELL_SHIP;       break;
    01103     case VEH_AIRCRAFT: sell_command = CMD_SELL_AIRCRAFT;   break;
    01104     default: return CMD_ERROR;
    01105   }
    01106
    01107   /* Get the list of vehicles in the depot */
    01108   BuildDepotVehicleList(vehicle_type, tile, &list, &list);
    01109
    01110   for (uint i = 0; i < list.Length(); i++) {
    01111     CommandCost ret = DoCommand(tile, list[i]->index, 1, flags, sell_command);
    01112     if (CmdSucceeded(ret)) cost.AddCost(ret);
    01113   }
    01114
    01115   if (cost.GetCost() == 0) return CMD_ERROR; // no vehicles to sell
    01116   return cost;
    01117 }
    01118
    01128 CommandCost CmdDepotMassAutoReplace(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    01129 {
    01130   VehicleList list;
    01131   CommandCost cost = CommandCost(EXPENSES_NEW_VEHICLES);
    01132   VehicleType vehicle_type = (VehicleType)GB(p1, 0, 8);
    01133   bool all_or_nothing = HasBit(p2, 0);
    01134
    01135   if (!IsDepotTile(tile) || !IsTileOwner(tile, _current_company)) return CMD_ERROR;
    01136
    01137   /* Get the list of vehicles in the depot */
    01138   BuildDepotVehicleList(vehicle_type, tile, &list, &list, true);
    01139
    01140   bool did_something = false;
    01141
    01142   for (uint i = 0; i < list.Length(); i++) {
    01143     Vehicle *v = (Vehicle*)list[i];
    01144
    01145     /* Ensure that the vehicle completely in the depot */
    01146     if (!v->IsInDepot()) continue;
    01147
    01148     CommandCost ret = DoCommand(0, v->index, 0, flags, CMD_AUTOREPLACE_VEHICLE);
    01149
    01150     if (CmdSucceeded(ret)) {
    01151       did_something = true;
    01152       cost.AddCost(ret);
    01153     } else {
    01154       if (ret.GetErrorMessage() != STR_AUTOREPLACE_NOTHING_TO_DO && all_or_nothing) {
    01155         /* We failed to replace a vehicle even though we set all or nothing.
    01156          * We should never reach this if DC_EXEC is set since then it should
    01157          * have failed the estimation guess. */
    01158         assert(!(flags & DC_EXEC));
    01159         /* Now we will have to return an error. */
    01160         return CMD_ERROR;
    01161       }
    01162     }
    01163   }
    01164
    01165   if (!did_something) {
    01166     /* Either we didn't replace anything or something went wrong.
    01167      * Either way we want to return an error and not execute this command. */
    01168     cost = CMD_ERROR;
    01169   }
    01170
    01171   return cost;
    01172 }
    01173
    01178 static bool IsUniqueVehicleName(const char *name)
    01179 {
    01180   const Vehicle *v;
    01181
    01182   FOR_ALL_VEHICLES(v) {
    01183     if (v->name != NULL && strcmp(v->name, name) == 0) return false;
    01184   }
    01185
    01186   return true;
    01187 }
    01188
    01193 static void CloneVehicleName(const Vehicle *src, Vehicle *dst)
    01194 {
    01195   char buf[256];
    01196
    01197   /* Find the position of the first digit in the last group of digits. */
    01198   size_t number_position;
    01199   for (number_position = strlen(src->name); number_position > 0; number_position--) {
    01200     /* The design of UTF-8 lets this work simply without having to check
    01201      * for UTF-8 sequences. */
    01202     if (src->name[number_position - 1] < '0' || src->name[number_position - 1] > '9') break;
    01203   }
    01204
    01205   /* Format buffer and determine starting number. */
    01206   int num;
    01207   if (number_position == strlen(src->name)) {
    01208     /* No digit at the end, so start at number 2. */
    01209     strecpy(buf, src->name, lastof(buf));
    01210     strecat(buf, " ", lastof(buf));
    01211     number_position = strlen(buf);
    01212     num = 2;
    01213   } else {
    01214     /* Found digits, parse them and start at the next number. */
    01215     strecpy(buf, src->name, lastof(buf));
    01216     buf[number_position] = '\0';
    01217     num = strtol(&src->name[number_position], NULL, 10) + 1;
    01218   }
    01219
    01220   /* Check if this name is already taken. */
    01221   for (int max_iterations = 1000; max_iterations > 0; max_iterations--, num++) {
    01222     /* Attach the number to the temporary name. */
    01223     seprintf(&buf[number_position], lastof(buf), "%d", num);
    01224
    01225     /* Check the name is unique. */
    01226     if (IsUniqueVehicleName(buf)) {
    01227       dst->name = strdup(buf);
    01228       break;
    01229     }
    01230   }
    01231
    01232   /* All done. If we didn't find a name, it'll just use its default. */
    01233 }
    01234
    01241 CommandCost CmdCloneVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    01242 {
    01243   CommandCost total_cost(EXPENSES_NEW_VEHICLES);
    01244   uint32 build_argument = 2;
    01245
    01246   if (!IsValidVehicleID(p1)) return CMD_ERROR;
    01247
    01248   Vehicle *v = GetVehicle(p1);
    01249   Vehicle *v_front = v;
    01250   Vehicle *w = NULL;
    01251   Vehicle *w_front = NULL;
    01252   Vehicle *w_rear = NULL;
    01253
    01254   /*
    01255    * v_front is the front engine in the original vehicle
    01256    * v is the car/vehicle of the original vehicle, that is currently being copied
    01257    * w_front is the front engine of the cloned vehicle
    01258    * w is the car/vehicle currently being cloned
    01259    * w_rear is the rear end of the cloned train. It's used to add more cars and is only used by trains
    01260    */
    01261
    01262   if (!CheckOwnership(v->owner)) return CMD_ERROR;
    01263
    01264   if (v->type == VEH_TRAIN && (!IsFrontEngine(v) || v->u.rail.crash_anim_pos >= 4400)) return CMD_ERROR;
    01265
    01266   /* check that we can allocate enough vehicles */
    01267   if (!(flags & DC_EXEC)) {
    01268     int veh_counter = 0;
    01269     do {
    01270       veh_counter++;
    01271     } while ((v = v->Next()) != NULL);
    01272
    01273     if (!Vehicle::AllocateList(NULL, veh_counter)) {
    01274       return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
    01275     }
    01276   }
    01277
    01278   v = v_front;
    01279
    01280   do {
    01281     if (v->type == VEH_TRAIN && IsRearDualheaded(v)) {
    01282       /* we build the rear ends of multiheaded trains with the front ones */
    01283       continue;
    01284     }
    01285
    01286     CommandCost cost = DoCommand(tile, v->engine_type, build_argument, flags, GetCmdBuildVeh(v));
    01287     build_argument = 3; // ensure that we only assign a number to the first engine
    01288
    01289     if (CmdFailed(cost)) return cost;
    01290
    01291     total_cost.AddCost(cost);
    01292
    01293     if (flags & DC_EXEC) {
    01294       w = GetVehicle(_new_vehicle_id);
    01295
    01296       if (v->type == VEH_TRAIN && HasBit(v->u.rail.flags, VRF_REVERSE_DIRECTION)) {
    01297         SetBit(w->u.rail.flags, VRF_REVERSE_DIRECTION);
    01298       }
    01299
    01300       if (v->type == VEH_TRAIN && !IsFrontEngine(v)) {
    01301         /* this s a train car
    01302          * add this unit to the end of the train */
    01303         CommandCost result = DoCommand(0, (w_rear->index << 16) | w->index, 1, flags, CMD_MOVE_RAIL_VEHICLE);
    01304         if (CmdFailed(result)) {
    01305           /* The train can't be joined to make the same consist as the original.
    01306            * Sell what we already made (clean up) and return an error.           */
    01307           DoCommand(w_front->tile, w_front->index, 1, flags, GetCmdSellVeh(w_front));
    01308           DoCommand(w_front->tile, w->index,       1, flags, GetCmdSellVeh(w));
    01309           return result; // return error and the message returned from CMD_MOVE_RAIL_VEHICLE
    01310         }
    01311       } else {
    01312         /* this is a front engine or not a train. */
    01313         w_front = w;
    01314         w->service_interval = v->service_interval;
    01315       }
    01316       w_rear = w; // trains needs to know the last car in the train, so they can add more in next loop
    01317     }
    01318   } while (v->type == VEH_TRAIN && (v = GetNextVehicle(v)) != NULL);
    01319
    01320   if (flags & DC_EXEC && v_front->type == VEH_TRAIN) {
    01321     /* for trains this needs to be the front engine due to the callback function */
    01322     _new_vehicle_id = w_front->index;
    01323   }
    01324
    01325   if (flags & DC_EXEC) {
    01326     /* Cloned vehicles belong to the same group */
    01327     DoCommand(0, v_front->group_id, w_front->index, flags, CMD_ADD_VEHICLE_GROUP);
    01328   }
    01329
    01330
    01331   /* Take care of refitting. */
    01332   w = w_front;
    01333   v = v_front;
    01334
    01335   /* Both building and refitting are influenced by newgrf callbacks, which
    01336    * makes it impossible to accurately estimate the cloning costs. In
    01337    * particular, it is possible for engines of the same type to be built with
    01338    * different numbers of articulated parts, so when refitting we have to
    01339    * loop over real vehicles first, and then the articulated parts of those
    01340    * vehicles in a different loop. */
    01341   do {
    01342     do {
    01343       if (flags & DC_EXEC) {
    01344         assert(w != NULL);
    01345
    01346         if (w->cargo_type != v->cargo_type || w->cargo_subtype != v->cargo_subtype) {
    01347           CommandCost cost = DoCommand(0, w->index, v->cargo_type | (v->cargo_subtype << 8) | 1U << 16 , flags, GetCmdRefitVeh(v));
    01348           if (CmdSucceeded(cost)) total_cost.AddCost(cost);
    01349         }
    01350
    01351         if (w->type == VEH_TRAIN && EngineHasArticPart(w)) {
    01352           w = GetNextArticPart(w);
    01353         } else if (w->type == VEH_ROAD && RoadVehHasArticPart(w)) {
    01354           w = w->Next();
    01355         } else {
    01356           break;
    01357         }
    01358       } else {
    01359         const Engine *e = GetEngine(v->engine_type);
    01360         CargoID initial_cargo = (e->CanCarryCargo() ? e->GetDefaultCargoType() : (CargoID)CT_INVALID);
    01361
    01362         if (v->cargo_type != initial_cargo && initial_cargo != CT_INVALID) {
    01363           total_cost.AddCost(GetRefitCost(v->engine_type));
    01364         }
    01365       }
    01366
    01367       if (v->type == VEH_TRAIN && EngineHasArticPart(v)) {
    01368         v = GetNextArticPart(v);
    01369       } else if (v->type == VEH_ROAD && RoadVehHasArticPart(v)) {
    01370         v = v->Next();
    01371       } else {
    01372         break;
    01373       }
    01374     } while (v != NULL);
    01375
    01376     if ((flags & DC_EXEC) && v->type == VEH_TRAIN) w = GetNextVehicle(w);
    01377   } while (v->type == VEH_TRAIN && (v = GetNextVehicle(v)) != NULL);
    01378
    01379   if (flags & DC_EXEC) {
    01380     /*
    01381      * Set the orders of the vehicle. Cannot do it earlier as we need
    01382      * the vehicle refitted before doing this, otherwise the moved
    01383      * cargo types might not match (passenger vs non-passenger)
    01384      */
    01385     DoCommand(0, (v_front->index << 16) | w_front->index, p2 & 1 ? CO_SHARE : CO_COPY, flags, CMD_CLONE_ORDER);
    01386
    01387     /* Now clone the vehicle's name, if it has one. */
    01388     if (v_front->name != NULL) CloneVehicleName(v_front, w_front);
    01389   }
    01390
    01391   /* Since we can't estimate the cost of cloning a vehicle accurately we must
    01392    * check whether the company has enough money manually. */
    01393   if (!CheckCompanyHasMoney(total_cost)) {
    01394     if (flags & DC_EXEC) {
    01395       /* The vehicle has already been bought, so now it must be sold again. */
    01396       DoCommand(w_front->tile, w_front->index, 1, flags, GetCmdSellVeh(w_front));
    01397     }
    01398     return CMD_ERROR;
    01399   }
    01400
    01401   return total_cost;
    01402 }
    01403
    01413 CommandCost SendAllVehiclesToDepot(VehicleType type, DoCommandFlag flags, bool service, Owner owner, uint16 vlw_flag, uint32 id)
    01414 {
    01415   VehicleList list;
    01416
    01417   GenerateVehicleSortList(&list, type, owner, id, vlw_flag);
    01418
    01419   /* Send all the vehicles to a depot */
    01420   for (uint i = 0; i < list.Length(); i++) {
    01421     const Vehicle *v = list[i];
    01422     CommandCost ret = DoCommand(v->tile, v->index, (service ? 1 : 0) | DEPOT_DONT_CANCEL, flags, GetCmdSendToDepot(type));
    01423
    01424     /* Return 0 if DC_EXEC is not set this is a valid goto depot command)
    01425       * In this case we know that at least one vehicle can be sent to a depot
    01426       * and we will issue the command. We can now safely quit the loop, knowing
    01427       * it will succeed at least once. With DC_EXEC we really need to send them to the depot */
    01428     if (CmdSucceeded(ret) && !(flags & DC_EXEC)) {
    01429       return CommandCost();
    01430     }
    01431   }
    01432
    01433   return (flags & DC_EXEC) ? CommandCost() : CMD_ERROR;
    01434 }
    01435
    01442 uint8 CalcPercentVehicleFilled(const Vehicle *v, StringID *colour)
    01443 {
    01444   int count = 0;
    01445   int max = 0;
    01446   int cars = 0;
    01447   int unloading = 0;
    01448   bool loading = false;
    01449
    01450   const Vehicle *u = v;
    01451   const Station *st = v->last_station_visited != INVALID_STATION ? GetStation(v->last_station_visited) : NULL;
    01452
    01453   /* Count up max and used */
    01454   for (; v != NULL; v = v->Next()) {
    01455     count += v->cargo.Count();
    01456     max += v->cargo_cap;
    01457     if (v->cargo_cap != 0 && colour != NULL) {
    01458       unloading += HasBit(v->vehicle_flags, VF_CARGO_UNLOADING) ? 1 : 0;
    01459       loading |= !(u->current_order.GetUnloadType() & OUFB_UNLOAD) && st->goods[v->cargo_type].days_since_pickup != 255;
    01460       cars++;
    01461     }
    01462   }
    01463
    01464   if (colour != NULL) {
    01465     if (unloading == 0 && loading) {
    01466       *colour = STR_PERCENT_UP;
    01467     } else if (cars == unloading || !loading) {
    01468       *colour = STR_PERCENT_DOWN;
    01469     } else {
    01470       *colour = STR_PERCENT_UP_DOWN;
    01471     }
    01472   }
    01473
    01474   /* Train without capacity */
    01475   if (max == 0) return 100;
    01476
    01477   /* Return the percentage */
    01478   return (count * 100) / max;
    01479 }
    01480
    01481 void VehicleEnterDepot(Vehicle *v)
    01482 {
    01483   switch (v->type) {
    01484     case VEH_TRAIN:
    01485       InvalidateWindowClasses(WC_TRAINS_LIST);
    01486       /* Clear path reservation */
    01487       SetDepotWaypointReservation(v->tile, false);
    01488       if (_settings_client.gui.show_track_reservation) MarkTileDirtyByTile(v->tile);
    01489
    01490       if (!IsFrontEngine(v)) v = v->First();
    01491       UpdateSignalsOnSegment(v->tile, INVALID_DIAGDIR, v->owner);
    01492       v->load_unload_time_rem = 0;
    01493       ClrBit(v->u.rail.flags, VRF_TOGGLE_REVERSE);
    01494       TrainConsistChanged(v, true);
    01495       break;
    01496
    01497     case VEH_ROAD:
    01498       InvalidateWindowClasses(WC_ROADVEH_LIST);
    01499       if (!IsRoadVehFront(v)) v = v->First();
    01500       break;
    01501
    01502     case VEH_SHIP:
    01503       InvalidateWindowClasses(WC_SHIPS_LIST);
    01504       v->u.ship.state = TRACK_BIT_DEPOT;
    01505       RecalcShipStuff(v);
    01506       break;
    01507
    01508     case VEH_AIRCRAFT:
    01509       InvalidateWindowClasses(WC_AIRCRAFT_LIST);
    01510       HandleAircraftEnterHangar(v);
    01511       break;
    01512     default: NOT_REACHED();
    01513   }
    01514
    01515   if (v->type != VEH_TRAIN) {
    01516     /* Trains update the vehicle list when the first unit enters the depot and calls VehicleEnterDepot() when the last unit enters.
    01517      * 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 */
    01518     InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
    01519   }
    01520   InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
    01521
    01522   v->vehstatus |= VS_HIDDEN;
    01523   v->cur_speed = 0;
    01524
    01525   VehicleServiceInDepot(v);
    01526
    01527   TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);
    01528
    01529   if (v->current_order.IsType(OT_GOTO_DEPOT)) {
    01530     InvalidateWindow(WC_VEHICLE_VIEW, v->index);
    01531
    01532     Order t = v->current_order;
    01533     v->current_order.MakeDummy();
    01534
    01535     if (t.IsRefit()) {
    01536       _current_company = v->owner;
    01537       CommandCost cost = DoCommand(v->tile, v->index, t.GetRefitCargo() | t.GetRefitSubtype() << 8, DC_EXEC, GetCmdRefitVeh(v));
    01538
    01539       if (CmdFailed(cost)) {
    01540         _vehicles_to_autoreplace[v] = false;
    01541         if (v->owner == _local_company) {
    01542           /* Notify the user that we stopped the vehicle */
    01543           SetDParam(0, v->index);
    01544           AddNewsItem(STR_ORDER_REFIT_FAILED, NS_ADVICE, v->index, 0);
    01545         }
    01546       } else if (v->owner == _local_company && cost.GetCost() != 0) {
    01547         ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost.GetCost());
    01548       }
    01549     }
    01550
    01551     if (t.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) {
    01552       /* Part of orders */
    01553       UpdateVehicleTimetable(v, true);
    01554       v->cur_order_index++;
    01555     }
    01556     if (t.GetDepotActionType() & ODATFB_HALT) {
    01557       /* Force depot visit */
    01558       v->vehstatus |= VS_STOPPED;
    01559       if (v->owner == _local_company) {
    01560         StringID string;
    01561
    01562         switch (v->type) {
    01563           case VEH_TRAIN:    string = STR_8814_TRAIN_IS_WAITING_IN_DEPOT; break;
    01564           case VEH_ROAD:     string = STR_9016_ROAD_VEHICLE_IS_WAITING;   break;
    01565           case VEH_SHIP:     string = STR_981C_SHIP_IS_WAITING_IN_DEPOT;  break;
    01566           case VEH_AIRCRAFT: string = STR_A014_AIRCRAFT_IS_WAITING_IN;    break;
    01567           default: NOT_REACHED(); string = STR_EMPTY; // Set the string to something to avoid a compiler warning
    01568         }
    01569
    01570         SetDParam(0, v->index);
    01571         AddNewsItem(string, NS_ADVICE, v->index, 0);
    01572       }
    01573       AI::NewEvent(v->owner, new AIEventVehicleWaitingInDepot(v->index));
    01574     }
    01575   }
    01576 }
    01577
    01584 CommandCost CmdRenameVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    01585 {
    01586   if (!IsValidVehicleID(p1)) return CMD_ERROR;
    01587
    01588   Vehicle *v = GetVehicle(p1);
    01589   if (!CheckOwnership(v->owner)) return CMD_ERROR;
    01590
    01591   bool reset = StrEmpty(text);
    01592
    01593   if (!reset) {
    01594     if (strlen(text) >= MAX_LENGTH_VEHICLE_NAME_BYTES) return CMD_ERROR;
    01595     if (!(flags & DC_AUTOREPLACE) && !IsUniqueVehicleName(text)) return_cmd_error(STR_NAME_MUST_BE_UNIQUE);
    01596   }
    01597
    01598   if (flags & DC_EXEC) {
    01599     free(v->name);
    01600     v->name = reset ? NULL : strdup(text);
    01601     InvalidateWindowClassesData(WC_TRAINS_LIST, 1);
    01602     MarkWholeScreenDirty();
    01603   }
    01604
    01605   return CommandCost();
    01606 }
    01607
    01608
    01615 CommandCost CmdChangeServiceInt(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    01616 {
    01617   uint16 serv_int = GetServiceIntervalClamped(p2); /* Double check the service interval from the user-input */
    01618
    01619   if (serv_int != p2 || !IsValidVehicleID(p1)) return CMD_ERROR;
    01620
    01621   Vehicle *v = GetVehicle(p1);
    01622
    01623   if (!CheckOwnership(v->owner)) return CMD_ERROR;
    01624
    01625   if (flags & DC_EXEC) {
    01626     v->service_interval = serv_int;
    01627     InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
    01628   }
    01629
    01630   return CommandCost();
    01631 }
    01632
    01633
    01634 static Rect _old_vehicle_coords;
    01635
    01642 void BeginVehicleMove(const Vehicle *v)
    01643 {
    01644   _old_vehicle_coords.left   = v->left_coord;
    01645   _old_vehicle_coords.top    = v->top_coord;
    01646   _old_vehicle_coords.right  = v->right_coord;
    01647   _old_vehicle_coords.bottom = v->bottom_coord;
    01648 }
    01649
    01656 void EndVehicleMove(const Vehicle *v)
    01657 {
    01658   MarkAllViewportsDirty(
    01659     min(_old_vehicle_coords.left,   v->left_coord),
    01660     min(_old_vehicle_coords.top,    v->top_coord),
    01661     max(_old_vehicle_coords.right,  v->right_coord) + 1,
    01662     max(_old_vehicle_coords.bottom, v->bottom_coord) + 1
    01663   );
    01664 }
    01665
    01674 void MarkSingleVehicleDirty(const Vehicle *v)
    01675 {
    01676   MarkAllViewportsDirty(v->left_coord, v->top_coord, v->right_coord + 1, v->bottom_coord + 1);
    01677 }
    01678
    01683 GetNewVehiclePosResult GetNewVehiclePos(const Vehicle *v)
    01684 {
    01685   static const int8 _delta_coord[16] = {
    01686     -1,-1,-1, 0, 1, 1, 1, 0, /* x */
    01687     -1, 0, 1, 1, 1, 0,-1,-1, /* y */
    01688   };
    01689
    01690   int x = v->x_pos + _delta_coord[v->direction];
    01691   int y = v->y_pos + _delta_coord[v->direction + 8];
    01692
    01693   GetNewVehiclePosResult gp;
    01694   gp.x = x;
    01695   gp.y = y;
    01696   gp.old_tile = v->tile;
    01697   gp.new_tile = TileVirtXY(x, y);
    01698   return gp;
    01699 }
    01700
    01701 static const Direction _new_direction_table[] = {
    01702   DIR_N , DIR_NW, DIR_W ,
    01703   DIR_NE, DIR_SE, DIR_SW,
    01704   DIR_E , DIR_SE, DIR_S
    01705 };
    01706
    01707 Direction GetDirectionTowards(const Vehicle *v, int x, int y)
    01708 {
    01709   int i = 0;
    01710
    01711   if (y >= v->y_pos) {
    01712     if (y != v->y_pos) i += 3;
    01713     i += 3;
    01714   }
    01715
    01716   if (x >= v->x_pos) {
    01717     if (x != v->x_pos) i++;
    01718     i++;
    01719   }
    01720
    01721   Direction dir = v->direction;
    01722
    01723   DirDiff dirdiff = DirDifference(_new_direction_table[i], dir);
    01724   if (dirdiff == DIRDIFF_SAME) return dir;
    01725   return ChangeDir(dir, dirdiff > DIRDIFF_REVERSE ? DIRDIFF_45LEFT : DIRDIFF_45RIGHT);
    01726 }
    01727
    01728 Trackdir GetVehicleTrackdir(const Vehicle *v)
    01729 {
    01730   if (v->vehstatus & VS_CRASHED) return INVALID_TRACKDIR;
    01731
    01732   switch (v->type) {
    01733     case VEH_TRAIN:
    01734       if (v->u.rail.track == TRACK_BIT_DEPOT) // We'll assume the train is facing outwards
    01735         return DiagDirToDiagTrackdir(GetRailDepotDirection(v->tile)); // Train in depot
    01736
    01737       if (v->u.rail.track == TRACK_BIT_WORMHOLE) // train in tunnel or on bridge, so just use his direction and assume a diagonal track
    01738         return DiagDirToDiagTrackdir(DirToDiagDir(v->direction));
    01739
    01740       return TrackDirectionToTrackdir(FindFirstTrack(v->u.rail.track), v->direction);
    01741
    01742     case VEH_SHIP:
    01743       if (v->IsInDepot())
    01744         // We'll assume the ship is facing outwards
    01745         return DiagDirToDiagTrackdir(GetShipDepotDirection(v->tile));
    01746
    01747       if (v->u.ship.state == TRACK_BIT_WORMHOLE) // ship on aqueduct, so just use his direction and assume a diagonal track
    01748         return DiagDirToDiagTrackdir(DirToDiagDir(v->direction));
    01749
    01750       return TrackDirectionToTrackdir(FindFirstTrack(v->u.ship.state), v->direction);
    01751
    01752     case VEH_ROAD:
    01753       if (v->IsInDepot()) // We'll assume the road vehicle is facing outwards
    01754         return DiagDirToDiagTrackdir(GetRoadDepotDirection(v->tile));
    01755
    01756       if (IsStandardRoadStopTile(v->tile)) // We'll assume the road vehicle is facing outwards
    01757         return DiagDirToDiagTrackdir(GetRoadStopDir(v->tile)); // Road vehicle in a station
    01758
    01759       if (IsDriveThroughStopTile(v->tile)) return DiagDirToDiagTrackdir(DirToDiagDir(v->direction));
    01760
    01761       /* If vehicle's state is a valid track direction (vehicle is not turning around) return it */
    01762       if (!IsReversingRoadTrackdir((Trackdir)v->u.road.state)) return (Trackdir)v->u.road.state;
    01763
    01764       /* Vehicle is turning around, get the direction from vehicle's direction */
    01765       return DiagDirToDiagTrackdir(DirToDiagDir(v->direction));
    01766
    01767     /* case VEH_AIRCRAFT: case VEH_EFFECT: case VEH_DISASTER: */
    01768     default: return INVALID_TRACKDIR;
    01769   }
    01770 }
    01771
    01781 VehicleEnterTileStatus VehicleEnterTile(Vehicle *v, TileIndex tile, int x, int y)
    01782 {
    01783   return _tile_type_procs[GetTileType(tile)]->vehicle_enter_tile_proc(v, tile, x, y);
    01784 }
    01785
    01786 FreeUnitIDGenerator::FreeUnitIDGenerator(VehicleType type, CompanyID owner) : cache(NULL), maxid(0), curid(0)
    01787 {
    01788   /* Find maximum */
    01789   const Vehicle *v;
    01790   FOR_ALL_VEHICLES(v) {
    01791     if (v->type == type && v->owner == owner) {
    01792       this->maxid = max<UnitID>(this->maxid, v->unitnumber);
    01793     }
    01794   }
    01795
    01796   if (this->maxid == 0) return;
    01797
    01798   this->maxid++; // so there is space for last item (with v->unitnumber == maxid)
    01799   this->maxid++; // this one will always be free (well, it will fail when there are 65535 units, so this overflows)
    01800
    01801   this->cache = CallocT<bool>(this->maxid);
    01802
    01803   /* Fill the cache */
    01804   FOR_ALL_VEHICLES(v) {
    01805     if (v->type == type && v->owner == owner) {
    01806       this->cache[v->unitnumber] = true;
    01807     }
    01808   }
    01809 }
    01810
    01811 UnitID FreeUnitIDGenerator::NextID()
    01812 {
    01813   if (this->maxid <= this->curid) return ++this->curid;
    01814
    01815   while (this->cache[++this->curid]) { } // it will stop, we reserved more space than needed
    01816
    01817   return this->curid;
    01818 }
    01819
    01820 UnitID GetFreeUnitNumber(VehicleType type)
    01821 {
    01822   FreeUnitIDGenerator gen(type, _current_company);
    01823
    01824   return gen.NextID();
    01825 }
    01826
    01827
    01836 bool CanBuildVehicleInfrastructure(VehicleType type)
    01837 {
    01838   assert(IsCompanyBuildableVehicleType(type));
    01839
    01840   if (!IsValidCompanyID(_local_company)) return false;
    01841   if (_settings_client.gui.always_build_infrastructure) return true;
    01842
    01843   UnitID max;
    01844   switch (type) {
    01845     case VEH_TRAIN:    max = _settings_game.vehicle.max_trains; break;
    01846     case VEH_ROAD:     max = _settings_game.vehicle.max_roadveh; break;
    01847     case VEH_SHIP:     max = _settings_game.vehicle.max_ships; break;
    01848     case VEH_AIRCRAFT: max = _settings_game.vehicle.max_aircraft; break;
    01849     default: NOT_REACHED();
    01850   }
    01851
    01852   /* We can build vehicle infrastructure when we may build the vehicle type */
    01853   if (max > 0) {
    01854     /* Can we actually build the vehicle type? */
    01855     const Engine *e;
    01856     FOR_ALL_ENGINES_OF_TYPE(e, type) {
    01857       if (HasBit(e->company_avail, _local_company)) return true;
    01858     }
    01859     return false;
    01860   }
    01861
    01862   /* We should be able to build infrastructure when we have the actual vehicle type */
    01863   const Vehicle *v;
    01864   FOR_ALL_VEHICLES(v) {
    01865     if (v->owner == _local_company && v->type == type) return true;
    01866   }
    01867
    01868   return false;
    01869 }
    01870
    01871
    01872 const Livery *GetEngineLivery(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v)
    01873 {
    01874   const Company *c = GetCompany(company);
    01875   LiveryScheme scheme = LS_DEFAULT;
    01876   CargoID cargo_type = v == NULL ? (CargoID)CT_INVALID : v->cargo_type;
    01877
    01878   /* The default livery is always available for use, but its in_use flag determines
    01879    * whether any _other_ liveries are in use. */
    01880   if (c->livery[LS_DEFAULT].in_use && (_settings_client.gui.liveries == 2 || (_settings_client.gui.liveries == 1 && company == _local_company))) {
    01881     /* Determine the livery scheme to use */
    01882     const Engine *e = GetEngine(engine_type);
    01883     switch (e->type) {
    01884       default: NOT_REACHED();
    01885       case VEH_TRAIN: {
    01886         const RailVehicleInfo *rvi = RailVehInfo(engine_type);
    01887         if (v != NULL && parent_engine_type != INVALID_ENGINE && (UsesWagonOverride(v) || (IsArticulatedPart(v) && rvi->railveh_type != RAILVEH_WAGON))) {
    01888           /* Wagonoverrides use the coloir scheme of the front engine.
    01889            * Articulated parts use the colour scheme of the first part. (Not supported for articulated wagons) */
    01890           engine_type = parent_engine_type;
    01891           e = GetEngine(engine_type);
    01892           rvi = RailVehInfo(engine_type);
    01893           /* Note: Luckily cargo_type is not needed for engines */
    01894         }
    01895
    01896         if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
    01897         if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
    01898         if (rvi->railveh_type == RAILVEH_WAGON) {
    01899           if (!GetCargo(cargo_type)->is_freight) {
    01900             if (parent_engine_type == INVALID_ENGINE) {
    01901               scheme = LS_PASSENGER_WAGON_STEAM;
    01902             } else {
    01903               switch (RailVehInfo(parent_engine_type)->engclass) {
    01904                 default: NOT_REACHED();
    01905                 case EC_STEAM:    scheme = LS_PASSENGER_WAGON_STEAM;    break;
    01906                 case EC_DIESEL:   scheme = LS_PASSENGER_WAGON_DIESEL;   break;
    01907                 case EC_ELECTRIC: scheme = LS_PASSENGER_WAGON_ELECTRIC; break;
    01908                 case EC_MONORAIL: scheme = LS_PASSENGER_WAGON_MONORAIL; break;
    01909                 case EC_MAGLEV:   scheme = LS_PASSENGER_WAGON_MAGLEV;   break;
    01910               }
    01911             }
    01912           } else {
    01913             scheme = LS_FREIGHT_WAGON;
    01914           }
    01915         } else {
    01916           bool is_mu = HasBit(EngInfo(engine_type)->misc_flags, EF_RAIL_IS_MU);
    01917
    01918           switch (rvi->engclass) {
    01919             default: NOT_REACHED();
    01920             case EC_STEAM:    scheme = LS_STEAM; break;
    01921             case EC_DIESEL:   scheme = is_mu ? LS_DMU : LS_DIESEL;   break;
    01922             case EC_ELECTRIC: scheme = is_mu ? LS_EMU : LS_ELECTRIC; break;
    01923             case EC_MONORAIL: scheme = LS_MONORAIL; break;
    01924             case EC_MAGLEV:   scheme = LS_MAGLEV; break;
    01925           }
    01926         }
    01927         break;
    01928       }
    01929
    01930       case VEH_ROAD: {
    01931         /* Always use the livery of the front */
    01932         if (v != NULL && parent_engine_type != INVALID_ENGINE) {
    01933           engine_type = parent_engine_type;
    01934           e = GetEngine(engine_type);
    01935           cargo_type = v->First()->cargo_type;
    01936         }
    01937         if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
    01938         if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
    01939
    01940         /* Important: Use Tram Flag of front part. Luckily engine_type refers to the front part here. */
    01941         if (HasBit(EngInfo(engine_type)->misc_flags, EF_ROAD_TRAM)) {
    01942           /* Tram */
    01943           scheme = IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_TRAM : LS_FREIGHT_TRAM;
    01944         } else {
    01945           /* Bus or truck */
    01946           scheme = IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_BUS : LS_TRUCK;
    01947         }
    01948         break;
    01949       }
    01950
    01951       case VEH_SHIP: {
    01952         if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
    01953         if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
    01954         scheme = IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_SHIP : LS_FREIGHT_SHIP;
    01955         break;
    01956       }
    01957
    01958       case VEH_AIRCRAFT: {
    01959         switch (e->u.air.subtype) {
    01960           case AIR_HELI: scheme = LS_HELICOPTER; break;
    01961           case AIR_CTOL: scheme = LS_SMALL_PLANE; break;
    01962           case AIR_CTOL | AIR_FAST: scheme = LS_LARGE_PLANE; break;
    01963         }
    01964         break;
    01965       }
    01966     }
    01967
    01968     /* Switch back to the default scheme if the resolved scheme is not in use */
    01969     if (!c->livery[scheme].in_use) scheme = LS_DEFAULT;
    01970   }
    01971
    01972   return &c->livery[scheme];
    01973 }
    01974
    01975
    01976 static SpriteID GetEngineColourMap(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v)
    01977 {
    01978   SpriteID map = (v != NULL) ? v->colourmap : PAL_NONE;
    01979
    01980   /* Return cached value if any */
    01981   if (map != PAL_NONE) return map;
    01982
    01983   /* Check if we should use the colour map callback */
    01984   if (HasBit(EngInfo(engine_type)->callbackmask, CBM_VEHICLE_COLOUR_REMAP)) {
    01985     uint16 callback = GetVehicleCallback(CBID_VEHICLE_COLOUR_MAPPING, 0, 0, engine_type, v);
    01986     /* A return value of 0xC000 is stated to "use the default two-colour
    01987      * maps" which happens to be the failure action too... */
    01988     if (callback != CALLBACK_FAILED && callback != 0xC000) {
    01989       map = GB(callback, 0, 14);
    01990       /* If bit 14 is set, then the company colours are applied to the
    01991        * map else it's returned as-is. */
    01992       if (!HasBit(callback, 14)) {
    01993         /* Update cache */
    01994         if (v != NULL) ((Vehicle*)v)->colourmap = map;
    01995         return map;
    01996       }
    01997     }
    01998   }
    01999
    02000   bool twocc = HasBit(EngInfo(engine_type)->misc_flags, EF_USES_2CC);
    02001
    02002   if (map == PAL_NONE) map = twocc ? (SpriteID)SPR_2CCMAP_BASE : (SpriteID)PALETTE_RECOLOUR_START;
    02003
    02004   const Livery *livery = GetEngineLivery(engine_type, company, parent_engine_type, v);
    02005
    02006   map += livery->colour1;
    02007   if (twocc) map += livery->colour2 * 16;
    02008
    02009   /* Update cache */
    02010   if (v != NULL) ((Vehicle*)v)->colourmap = map;
    02011   return map;
    02012 }
    02013
    02014 SpriteID GetEnginePalette(EngineID engine_type, CompanyID company)
    02015 {
    02016   return GetEngineColourMap(engine_type, company, INVALID_ENGINE, NULL);
    02017 }
    02018
    02019 SpriteID GetVehiclePalette(const Vehicle *v)
    02020 {
    02021   if (v->type == VEH_TRAIN) {
    02022     return GetEngineColourMap(v->engine_type, v->owner, v->u.rail.first_engine, v);
    02023   } else if (v->type == VEH_ROAD) {
    02024     return GetEngineColourMap(v->engine_type, v->owner, v->u.road.first_engine, v);
    02025   }
    02026
    02027   return GetEngineColourMap(v->engine_type, v->owner, INVALID_ENGINE, v);
    02028 }
    02029
    02030
    02031 void Vehicle::BeginLoading()
    02032 {
    02033   assert(IsTileType(tile, MP_STATION) || type == VEH_SHIP);
    02034
    02035   if (this->current_order.IsType(OT_GOTO_STATION) &&
    02036       this->current_order.GetDestination() == this->last_station_visited) {
    02037     current_order.MakeLoading(true);
    02038     UpdateVehicleTimetable(this, true);
    02039
    02040     /* Furthermore add the Non Stop flag to mark that this station
    02041      * is the actual destination of the vehicle, which is (for example)
    02042      * necessary to be known for HandleTrainLoading to determine
    02043      * whether the train is lost or not; not marking a train lost
    02044      * that arrives at random stations is bad. */
    02045     this->current_order.SetNonStopType(ONSF_NO_STOP_AT_ANY_STATION);
    02046
    02047   } else {
    02048     current_order.MakeLoading(false);
    02049   }
    02050
    02051   GetStation(this->last_station_visited)->loading_vehicles.push_back(this);
    02052
    02053   VehiclePayment(this);
    02054
    02055   InvalidateWindow(GetWindowClassForVehicleType(this->type), this->owner);
    02056   InvalidateWindowWidget(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
    02057   InvalidateWindow(WC_VEHICLE_DETAILS, this->index);
    02058   InvalidateWindow(WC_STATION_VIEW, this->last_station_visited);
    02059
    02060   GetStation(this->last_station_visited)->MarkTilesDirty(true);
    02061   this->MarkDirty();
    02062 }
    02063
    02064 void Vehicle::LeaveStation()
    02065 {
    02066   assert(current_order.IsType(OT_LOADING));
    02067
    02068   /* Only update the timetable if the vehicle was supposed to stop here. */
    02069   if (current_order.GetNonStopType() != ONSF_STOP_EVERYWHERE) UpdateVehicleTimetable(this, false);
    02070
    02071   current_order.MakeLeaveStation();
    02072   Station *st = GetStation(this->last_station_visited);
    02073   st->loading_vehicles.remove(this);
    02074
    02075   HideFillingPercent(&this->fill_percent_te_id);
    02076
    02077   if (this->type == VEH_TRAIN) {
    02078     /* Trigger station animation (trains only) */
    02079     if (IsTileType(this->tile, MP_STATION)) StationAnimationTrigger(st, this->tile, STAT_ANIM_TRAIN_DEPARTS);
    02080
    02081     /* Try to reserve a path when leaving the station as we
    02082      * might not be marked as wanting a reservation, e.g.
    02083      * when an overlength train gets turned around in a station. */
    02084     if (UpdateSignalsOnSegment(this->tile, TrackdirToExitdir(GetVehicleTrackdir(this)), this->owner) == SIGSEG_PBS || _settings_game.pf.reserve_paths) {
    02085       TryPathReserve(this, true, true);
    02086     }
    02087   }
    02088 }
    02089
    02090
    02091 void Vehicle::HandleLoading(bool mode)
    02092 {
    02093   switch (this->current_order.GetType()) {
    02094     case OT_LOADING: {
    02095       uint wait_time = max(this->current_order.wait_time - this->lateness_counter, 0);
    02096
    02097       /* Not the first call for this tick, or still loading */
    02098       if (mode || !HasBit(this->vehicle_flags, VF_LOADING_FINISHED) ||
    02099           (_settings_game.order.timetabling && this->current_order_time < wait_time)) return;
    02100
    02101       this->PlayLeaveStationSound();
    02102
    02103       bool at_destination_station = this->current_order.GetNonStopType() != ONSF_STOP_EVERYWHERE;
    02104       this->LeaveStation();
    02105
    02106       /* If this was not the final order, don't remove it from the list. */
    02107       if (!at_destination_station) return;
    02108       break;
    02109     }
    02110
    02111     case OT_DUMMY: break;
    02112
    02113     default: return;
    02114   }
    02115
    02116   this->cur_order_index++;
    02117   InvalidateVehicleOrder(this, 0);
    02118 }
    02119
    02120 CommandCost Vehicle::SendToDepot(DoCommandFlag flags, DepotCommand command)
    02121 {
    02122   if (!CheckOwnership(this->owner)) return CMD_ERROR;
    02123   if (this->vehstatus & VS_CRASHED) return CMD_ERROR;
    02124   if (this->IsStoppedInDepot()) return CMD_ERROR;
    02125
    02126   if (this->current_order.IsType(OT_GOTO_DEPOT)) {
    02127     bool halt_in_depot = this->current_order.GetDepotActionType() & ODATFB_HALT;
    02128     if (!!(command & DEPOT_SERVICE) == halt_in_depot) {
    02129       /* We called with a different DEPOT_SERVICE setting.
    02130        * Now we change the setting to apply the new one and let the vehicle head for the same depot.
    02131        * Note: the if is (true for requesting service == true for ordered to stop in depot)          */
    02132       if (flags & DC_EXEC) {
    02133         this->current_order.SetDepotOrderType(ODTF_MANUAL);
    02134         this->current_order.SetDepotActionType(halt_in_depot ? ODATF_SERVICE_ONLY : ODATFB_HALT);
    02135         InvalidateWindowWidget(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
    02136       }
    02137       return CommandCost();
    02138     }
    02139
    02140     if (command & DEPOT_DONT_CANCEL) return CMD_ERROR; // Requested no cancelation of depot orders
    02141     if (flags & DC_EXEC) {
    02142       /* If the orders to 'goto depot' are in the orders list (forced servicing),
    02143        * then skip to the next order; effectively cancelling this forced service */
    02144       if (this->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) this->cur_order_index++;
    02145
    02146       this->current_order.MakeDummy();
    02147       InvalidateWindowWidget(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
    02148     }
    02149     return CommandCost();
    02150   }
    02151
    02152   TileIndex location;
    02153   DestinationID destination;
    02154   bool reverse;
    02155   static const StringID no_depot[] = {STR_883A_UNABLE_TO_FIND_ROUTE_TO, STR_9019_UNABLE_TO_FIND_LOCAL_DEPOT, STR_981A_UNABLE_TO_FIND_LOCAL_DEPOT, STR_A012_CAN_T_SEND_AIRCRAFT_TO};
    02156   if (!this->FindClosestDepot(&location, &destination, &reverse)) return_cmd_error(no_depot[this->type]);
    02157
    02158   if (flags & DC_EXEC) {
    02159     if (this->current_order.IsType(OT_LOADING)) this->LeaveStation();
    02160
    02161     this->dest_tile = location;
    02162     this->current_order.MakeGoToDepot(destination, ODTF_MANUAL);
    02163     if (!(command & DEPOT_SERVICE)) this->current_order.SetDepotActionType(ODATFB_HALT);
    02164     InvalidateWindowWidget(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
    02165
    02166     /* If there is no depot in front, reverse automatically (trains only) */
    02167     if (this->type == VEH_TRAIN && reverse) DoCommand(this->tile, this->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
    02168
    02169     if (this->type == VEH_AIRCRAFT && this->u.air.state == FLYING && this->u.air.targetairport != destination) {
    02170       /* The aircraft is now heading for a different hangar than the next in the orders */
    02171       extern void AircraftNextAirportPos_and_Order(Vehicle *v);
    02172       AircraftNextAirportPos_and_Order(this);
    02173     }
    02174   }
    02175
    02176   return CommandCost();
    02177
    02178 }
    02179
    02180 void Vehicle::SetNext(Vehicle *next)
    02181 {
    02182   if (this->next != NULL) {
    02183     /* We had an old next vehicle. Update the first and previous pointers */
    02184     for (Vehicle *v = this->next; v != NULL; v = v->Next()) {
    02185       v->first = this->next;
    02186     }
    02187     this->next->previous = NULL;
    02188   }
    02189
    02190   this->next = next;
    02191
    02192   if (this->next != NULL) {
    02193     /* A new next vehicle. Update the first and previous pointers */
    02194     if (this->next->previous != NULL) this->next->previous->next = NULL;
    02195     this->next->previous = this;
    02196     for (Vehicle *v = this->next; v != NULL; v = v->Next()) {
    02197       v->first = this->first;
    02198     }
    02199   }
    02200 }
    02201
    02202 void Vehicle::AddToShared(Vehicle *shared_chain)
    02203 {
    02204   assert(this->previous_shared == NULL && this->next_shared == NULL);
    02205
    02206   if (!shared_chain->orders.list) {
    02207     assert(shared_chain->previous_shared == NULL);
    02208     assert(shared_chain->next_shared == NULL);
    02209     this->orders.list = shared_chain->orders.list = new OrderList(NULL, shared_chain);
    02210   }
    02211
    02212   this->next_shared     = shared_chain->next_shared;
    02213   this->previous_shared = shared_chain;
    02214
    02215   shared_chain->next_shared = this;
    02216
    02217   if (this->next_shared != NULL) this->next_shared->previous_shared = this;
    02218
    02219   shared_chain->orders.list->AddVehicle(this);
    02220 }
    02221
    02222 void Vehicle::RemoveFromShared()
    02223 {
    02224   /* Remember if we were first and the old window number before RemoveVehicle()
    02225    * as this changes first if needed. */
    02226   bool were_first = (this->FirstShared() == this);
    02227   uint32 old_window_number = (this->FirstShared()->index << 16) | (this->type << 11) | VLW_SHARED_ORDERS | this->owner;
    02228
    02229   this->orders.list->RemoveVehicle(this);
    02230
    02231   if (!were_first) {
    02232     /* We are not the first shared one, so only relink our previous one. */
    02233     this->previous_shared->next_shared = this->NextShared();
    02234   }
    02235
    02236   if (this->next_shared != NULL) this->next_shared->previous_shared = this->previous_shared;
    02237
    02238
    02239   if (this->orders.list->GetNumVehicles() == 1) {
    02240     /* When there is only one vehicle, remove the shared order list window. */
    02241     DeleteWindowById(GetWindowClassForVehicleType(this->type), old_window_number);
    02242     InvalidateVehicleOrder(this->FirstShared(), 0);
    02243   } else if (were_first) {
    02244     /* If we were the first one, update to the new first one.
    02245      * Note: FirstShared() is already the new first */
    02246     InvalidateWindowData(GetWindowClassForVehicleType(this->type), old_window_number, (this->FirstShared()->index << 16) | (1 << 15));
    02247   }
    02248
    02249   this->next_shared     = NULL;
    02250   this->previous_shared = NULL;
    02251 }
    02252
    02253 void StopAllVehicles()
    02254 {
    02255   Vehicle *v;
    02256   FOR_ALL_VEHICLES(v) {
    02257     /* Code ripped from CmdStartStopTrain. Can't call it, because of
    02258      * ownership problems, so we'll duplicate some code, for now */
    02259     v->vehstatus |= VS_STOPPED;
    02260     InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
    02261     InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
    02262   }
    02263 }
    02264
    02265 void VehiclesYearlyLoop()
    02266 {
    02267   Vehicle *v;
    02268   FOR_ALL_VEHICLES(v) {
    02269     if (v->IsPrimaryVehicle()) {
    02270       /* show warning if vehicle is not generating enough income last 2 years (corresponds to a red icon in the vehicle list) */
    02271       Money profit = v->GetDisplayProfitThisYear();
    02272       if (v->age >= 730 && profit < 0) {
    02273         if (_settings_client.gui.vehicle_income_warn && v->owner == _local_company) {
    02274           SetDParam(0, v->index);
    02275           SetDParam(1, profit);
    02276           AddNewsItem(
    02277             STR_VEHICLE_IS_UNPROFITABLE,
    02278             NS_ADVICE,
    02279             v->index,
    02280             0);
    02281         }
    02282         AI::NewEvent(v->owner, new AIEventVehicleUnprofitable(v->index));
    02283       }
    02284
    02285       v->profit_last_year = v->profit_this_year;
    02286       v->profit_this_year = 0;
    02287       InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
    02288     }
    02289   }
    02290 }
    02291
    02292
    02302 bool CanVehicleUseStation(EngineID engine_type, const Station *st)
    02303 {
    02304   assert(IsEngineIndex(engine_type));
    02305   const Engine *e = GetEngine(engine_type);
    02306
    02307   switch (e->type) {
    02308     case VEH_TRAIN:
    02309       return (st->facilities & FACIL_TRAIN) != 0;
    02310
    02311     case VEH_ROAD:
    02312       /* For road vehicles we need the vehicle to know whether it can actually
    02313        * use the station, but if it doesn't have facilities for RVs it is
    02314        * certainly not possible that the station can be used. */
    02315       return (st->facilities & (FACIL_BUS_STOP | FACIL_TRUCK_STOP)) != 0;
    02316
    02317     case VEH_SHIP:
    02318       return (st->facilities & FACIL_DOCK) != 0;
    02319
    02320     case VEH_AIRCRAFT:
    02321       return (st->facilities & FACIL_AIRPORT) != 0 &&
    02322           (st->Airport()->flags & (e->u.air.subtype & AIR_CTOL ? AirportFTAClass::AIRPLANES : AirportFTAClass::HELICOPTERS)) != 0;
    02323
    02324     default:
    02325       return false;
    02326   }
    02327 }
    02328
    02335 bool CanVehicleUseStation(const Vehicle *v, const Station *st)
    02336 {
    02337   if (v->type == VEH_ROAD) return st->GetPrimaryRoadStop(v) != NULL;
    02338
    02339   return CanVehicleUseStation(v->engine_type, st);
    02340 }