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 }

Generated on Mon Mar 9 23:33:52 2009 for openttd by  doxygen 1.5.6