vehicle.cpp

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

Generated on Mon Feb 16 23:12:12 2009 for openttd by  doxygen 1.5.6