# vehicle.cpp

Go to the documentation of this file.

    00001 /* $Id: vehicle.cpp 14385 2008-09-22 19:57:31Z rubidium $ */
    00002
    00005 #include "stdafx.h"
    00006 #include "openttd.h"
    00007 #include "road_map.h"
    00008 #include "roadveh.h"
    00009 #include "ship.h"
    00010 #include "spritecache.h"
    00011 #include "tile_cmd.h"
    00012 #include "landscape.h"
    00013 #include "timetable.h"
    00014 #include "viewport_func.h"
    00015 #include "gfx_func.h"
    00016 #include "news.h"
    00017 #include "command_func.h"
    00018 #include "saveload.h"
    00019 #include "player_func.h"
    00020 #include "engine.h"
    00021 #include "debug.h"
    00022 #include "vehicle_gui.h"
    00023 #include "depot.h"
    00024 #include "station.h"
    00025 #include "rail_type.h"
    00026 #include "train.h"
    00027 #include "aircraft.h"
    00028 #include "industry_map.h"
    00029 #include "station_map.h"
    00030 #include "water_map.h"
    00031 #include "network/network.h"
    00032 #include "yapf/yapf.h"
    00033 #include "newgrf_callbacks.h"
    00034 #include "newgrf_engine.h"
    00035 #include "newgrf_sound.h"
    00036 #include "group.h"
    00037 #include "order.h"
    00038 #include "strings_func.h"
    00039 #include "zoom_func.h"
    00040 #include "functions.h"
    00041 #include "date_func.h"
    00042 #include "window_func.h"
    00043 #include "vehicle_func.h"
    00044 #include "signal_func.h"
    00045 #include "sound_func.h"
    00046 #include "variables.h"
    00047 #include "autoreplace_func.h"
    00048 #include "autoreplace_gui.h"
    00049 #include "string_func.h"
    00050 #include "settings_type.h"
    00051
    00052 #include "table/sprites.h"
    00053 #include "table/strings.h"
    00054
    00055 #define INVALID_COORD (0x7fffffff)
    00056 #define GEN_HASH(x, y) ((GB((y), 6, 6) << 6) + GB((x), 7, 6))
    00057
    00058 VehicleID _vehicle_id_ctr_day;
    00059 Vehicle *_place_clicked_vehicle;
    00060 VehicleID _new_vehicle_id;
    00061 uint16 _returned_refit_capacity;
    00062
    00063
    00064 /* Tables used in vehicle.h to find the right command for a certain vehicle type */
    00065 const uint32 _veh_build_proc_table[] = {
    00066   CMD_BUILD_RAIL_VEHICLE,
    00067   CMD_BUILD_ROAD_VEH,
    00068   CMD_BUILD_SHIP,
    00069   CMD_BUILD_AIRCRAFT,
    00070 };
    00071 const uint32 _veh_sell_proc_table[] = {
    00072   CMD_SELL_RAIL_WAGON,
    00073   CMD_SELL_ROAD_VEH,
    00074   CMD_SELL_SHIP,
    00075   CMD_SELL_AIRCRAFT,
    00076 };
    00077
    00078 const uint32 _veh_refit_proc_table[] = {
    00079   CMD_REFIT_RAIL_VEHICLE,
    00080   CMD_REFIT_ROAD_VEH,
    00081   CMD_REFIT_SHIP,
    00082   CMD_REFIT_AIRCRAFT,
    00083 };
    00084
    00085 const uint32 _send_to_depot_proc_table[] = {
    00086   CMD_SEND_TRAIN_TO_DEPOT,
    00087   CMD_SEND_ROADVEH_TO_DEPOT,
    00088   CMD_SEND_SHIP_TO_DEPOT,
    00089   CMD_SEND_AIRCRAFT_TO_HANGAR,
    00090 };
    00091
    00092
    00093 /* Initialize the vehicle-pool */
    00094 DEFINE_OLD_POOL_GENERIC(Vehicle, Vehicle)
    00095
    00096
    00100 bool Vehicle::NeedsAutorenewing(const Player *p) const
    00101 {
    00102   /* We can always generate the Player pointer when we have the vehicle.
    00103    * However this takes time and since the Player pointer is often present
    00104    * when this function is called then it's faster to pass the pointer as an
    00105    * argument rather than finding it again. */
    00106   assert(p == GetPlayer(this->owner));
    00107
    00108   if (!p->engine_renew) return false;
    00109   if (this->age - this->max_age < (p->engine_renew_months * 30)) return false;
    00110
    00111   return true;
    00112 }
    00113
    00114 void VehicleServiceInDepot(Vehicle *v)
    00115 {
    00116   v->date_of_last_service = _date;
    00117   v->breakdowns_since_last_service = 0;
    00118   v->reliability = GetEngine(v->engine_type)->reliability;
    00119   InvalidateWindow(WC_VEHICLE_DETAILS, v->index); // ensure that last service date and reliability are updated
    00120 }
    00121
    00122 bool Vehicle::NeedsServicing() const
    00123 {
    00124   if (this->vehstatus & (VS_STOPPED | VS_CRASHED)) return false;
    00125
    00126   if (_patches.no_servicing_if_no_breakdowns && _opt.diff.vehicle_breakdowns == 0) {
    00127     /* Vehicles set for autoreplacing needs to go to a depot even if breakdowns are turned off.
    00128      * Note: If servicing is enabled, we postpone replacement till next service. */
    00129     return EngineHasReplacementForPlayer(GetPlayer(this->owner), this->engine_type, this->group_id);
    00130   }
    00131
    00132   return _patches.servint_ispercent ?
    00133     (this->reliability < GetEngine(this->engine_type)->reliability * (100 - this->service_interval) / 100) :
    00134     (this->date_of_last_service + this->service_interval < _date);
    00135 }
    00136
    00137 bool Vehicle::NeedsAutomaticServicing() const
    00138 {
    00139   if (_patches.gotodepot && VehicleHasDepotOrders(this)) return false;
    00140   if (this->current_order.type == OT_LOADING)            return false;
    00141   if (this->current_order.type == OT_GOTO_DEPOT && this->current_order.flags & OFB_HALT_IN_DEPOT) return false;
    00142   return NeedsServicing();
    00143 }
    00144
    00145 StringID VehicleInTheWayErrMsg(const Vehicle* v)
    00146 {
    00147   switch (v->type) {
    00148     case VEH_TRAIN:    return STR_8803_TRAIN_IN_THE_WAY;
    00149     case VEH_ROAD:     return STR_9000_ROAD_VEHICLE_IN_THE_WAY;
    00150     case VEH_AIRCRAFT: return STR_A015_AIRCRAFT_IN_THE_WAY;
    00151     default:           return STR_980E_SHIP_IN_THE_WAY;
    00152   }
    00153 }
    00154
    00155 static void *EnsureNoVehicleProcZ(Vehicle *v, void *data)
    00156 {
    00157   byte z = *(byte*)data;
    00158
    00159   if (v->type == VEH_DISASTER || (v->type == VEH_AIRCRAFT && v->subtype == AIR_SHADOW)) return NULL;
    00160   if (v->z_pos > z) return NULL;
    00161
    00162   _error_message = VehicleInTheWayErrMsg(v);
    00163   return v;
    00164 }
    00165
    00166 bool EnsureNoVehicleOnGround(TileIndex tile)
    00167 {
    00168   byte z = GetTileMaxZ(tile);
    00169   return !HasVehicleOnPos(tile, &z, &EnsureNoVehicleProcZ);
    00170 }
    00171
    00173 static void *GetVehicleTunnelBridgeProc(Vehicle *v, void *data)
    00174 {
    00175   if (v->type != VEH_TRAIN && v->type != VEH_ROAD) return NULL;
    00176
    00177   _error_message = VehicleInTheWayErrMsg(v);
    00178   return v;
    00179 }
    00180
    00187 bool HasVehicleOnTunnelBridge(TileIndex tile, TileIndex endtile)
    00188 {
    00189   return HasVehicleOnPos(tile, NULL, &GetVehicleTunnelBridgeProc) ||
    00190       HasVehicleOnPos(endtile, NULL, &GetVehicleTunnelBridgeProc);
    00191 }
    00192
    00193
    00194 static void UpdateVehiclePosHash(Vehicle* v, int x, int y);
    00195
    00196 void VehiclePositionChanged(Vehicle *v)
    00197 {
    00198   int img = v->cur_image;
    00199   Point pt = RemapCoords(v->x_pos + v->x_offs, v->y_pos + v->y_offs, v->z_pos);
    00200   const Sprite* spr = GetSprite(img);
    00201
    00202   pt.x += spr->x_offs;
    00203   pt.y += spr->y_offs;
    00204
    00205   UpdateVehiclePosHash(v, pt.x, pt.y);
    00206
    00207   v->left_coord = pt.x;
    00208   v->top_coord = pt.y;
    00209   v->right_coord = pt.x + spr->width + 2;
    00210   v->bottom_coord = pt.y + spr->height + 2;
    00211 }
    00212
    00214 void AfterLoadVehicles(bool clear_te_id)
    00215 {
    00216   Vehicle *v;
    00217
    00218   FOR_ALL_VEHICLES(v) {
    00219     /* Reinstate the previous pointer */
    00220     if (v->Next() != NULL) v->Next()->previous = v;
    00221
    00222     v->UpdateDeltaXY(v->direction);
    00223
    00224     if (clear_te_id) v->fill_percent_te_id = INVALID_TE_ID;
    00225     v->first = NULL;
    00226     if (v->type == VEH_TRAIN) v->u.rail.first_engine = INVALID_ENGINE;
    00227     if (v->type == VEH_ROAD)  v->u.road.first_engine = INVALID_ENGINE;
    00228
    00229     v->cargo.InvalidateCache();
    00230   }
    00231
    00232   FOR_ALL_VEHICLES(v) {
    00233     /* Fill the first pointers */
    00234     if (v->Previous() == NULL) {
    00235       for (Vehicle *u = v; u != NULL; u = u->Next()) {
    00236         u->first = v;
    00237       }
    00238     }
    00239   }
    00240
    00241   FOR_ALL_VEHICLES(v) {
    00242     assert(v->first != NULL);
    00243
    00244     if (v->type == VEH_TRAIN && (IsFrontEngine(v) || IsFreeWagon(v))) {
    00245       if (IsFrontEngine(v)) v->u.rail.last_speed = v->cur_speed; // update displayed train speed
    00246       TrainConsistChanged(v, false);
    00247     } else if (v->type == VEH_ROAD && IsRoadVehFront(v)) {
    00248       RoadVehUpdateCache(v);
    00249     }
    00250   }
    00251
    00252   FOR_ALL_VEHICLES(v) {
    00253     switch (v->type) {
    00254       case VEH_ROAD:
    00255         v->u.road.roadtype = HasBit(EngInfo(v->engine_type)->misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD;
    00256         v->u.road.compatible_roadtypes = RoadTypeToRoadTypes(v->u.road.roadtype);
    00257         /* FALL THROUGH */
    00258       case VEH_TRAIN:
    00259       case VEH_SHIP:
    00260         v->cur_image = v->GetImage(v->direction);
    00261         break;
    00262
    00263       case VEH_AIRCRAFT:
    00264         if (IsNormalAircraft(v)) {
    00265           v->cur_image = v->GetImage(v->direction);
    00266
    00267           /* The plane's shadow will have the same image as the plane */
    00268           Vehicle *shadow = v->Next();
    00269           shadow->cur_image = v->cur_image;
    00270
    00271           /* In the case of a helicopter we will update the rotor sprites */
    00272           if (v->subtype == AIR_HELICOPTER) {
    00273             Vehicle *rotor = shadow->Next();
    00274             rotor->cur_image = GetRotorImage(v);
    00275           }
    00276
    00277           UpdateAircraftCache(v);
    00278         }
    00279         break;
    00280       default: break;
    00281     }
    00282
    00283     v->left_coord = INVALID_COORD;
    00284     VehiclePositionChanged(v);
    00285   }
    00286 }
    00287
    00288 Vehicle::Vehicle()
    00289 {
    00290   this->type               = VEH_INVALID;
    00291   this->left_coord         = INVALID_COORD;
    00292   this->group_id           = DEFAULT_GROUP;
    00293   this->fill_percent_te_id = INVALID_TE_ID;
    00294   this->first              = this;
    00295   this->colormap           = PAL_NONE;
    00296 }
    00297
    00302 byte VehicleRandomBits()
    00303 {
    00304   return GB(Random(), 0, 8);
    00305 }
    00306
    00307
    00308 /* static */ bool Vehicle::AllocateList(Vehicle **vl, int num)
    00309 {
    00310   uint counter = _Vehicle_pool.first_free_index;
    00311
    00312   for (int i = 0; i != num; i++) {
    00313     Vehicle *v = AllocateRaw(counter);
    00314
    00315     if (v == NULL) return false;
    00316     v = new (v) InvalidVehicle();
    00317
    00318     if (vl != NULL) {
    00319       vl[i] = v;
    00320     }
    00321     counter++;
    00322   }
    00323
    00324   return true;
    00325 }
    00326
    00327 /* Size of the hash, 6 = 64 x 64, 7 = 128 x 128. Larger sizes will (in theory) reduce hash
    00328  * lookup times at the expense of memory usage. */
    00329 const int HASH_BITS = 7;
    00330 const int HASH_SIZE = 1 << HASH_BITS;
    00331 const int HASH_MASK = HASH_SIZE - 1;
    00332 const int TOTAL_HASH_SIZE = 1 << (HASH_BITS * 2);
    00333 const int TOTAL_HASH_MASK = TOTAL_HASH_SIZE - 1;
    00334
    00335 /* Resolution of the hash, 0 = 1*1 tile, 1 = 2*2 tiles, 2 = 4*4 tiles, etc.
    00336  * Profiling results show that 0 is fastest. */
    00337 const int HASH_RES = 0;
    00338
    00339 static Vehicle *_new_vehicle_position_hash[TOTAL_HASH_SIZE];
    00340
    00341 static void *VehicleFromHash(int xl, int yl, int xu, int yu, void *data, VehicleFromPosProc *proc, bool find_first)
    00342 {
    00343   for (int y = yl; ; y = (y + (1 << HASH_BITS)) & (HASH_MASK << HASH_BITS)) {
    00344     for (int x = xl; ; x = (x + 1) & HASH_MASK) {
    00345       Vehicle *v = _new_vehicle_position_hash[(x + y) & TOTAL_HASH_MASK];
    00346       for (; v != NULL; v = v->next_new_hash) {
    00347         void *a = proc(v, data);
    00348         if (find_first && a != NULL) return a;
    00349       }
    00350       if (x == xu) break;
    00351     }
    00352     if (y == yu) break;
    00353   }
    00354
    00355   return NULL;
    00356 }
    00357
    00358
    00370 static void *VehicleFromPosXY(int x, int y, void *data, VehicleFromPosProc *proc, bool find_first)
    00371 {
    00372   const int COLL_DIST = 6;
    00373
    00374   /* Hash area to scan is from xl,yl to xu,yu */
    00375   int xl = GB((x - COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS);
    00376   int xu = GB((x + COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS);
    00377   int yl = GB((y - COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS) << HASH_BITS;
    00378   int yu = GB((y + COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS) << HASH_BITS;
    00379
    00380   return VehicleFromHash(xl, yl, xu, yu, data, proc, find_first);
    00381 }
    00382
    00397 void FindVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc)
    00398 {
    00399   VehicleFromPosXY(x, y, data, proc, false);
    00400 }
    00401
    00413 bool HasVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc)
    00414 {
    00415   return VehicleFromPosXY(x, y, data, proc, true) != NULL;
    00416 }
    00417
    00428 static void *VehicleFromPos(TileIndex tile, void *data, VehicleFromPosProc *proc, bool find_first)
    00429 {
    00430   int x = GB(TileX(tile), HASH_RES, HASH_BITS);
    00431   int y = GB(TileY(tile), HASH_RES, HASH_BITS) << HASH_BITS;
    00432
    00433   Vehicle *v = _new_vehicle_position_hash[(x + y) & TOTAL_HASH_MASK];
    00434   for (; v != NULL; v = v->next_new_hash) {
    00435     if (v->tile != tile) continue;
    00436
    00437     void *a = proc(v, data);
    00438     if (find_first && a != NULL) return a;
    00439   }
    00440
    00441   return NULL;
    00442 }
    00443
    00457 void FindVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
    00458 {
    00459   VehicleFromPos(tile, data, proc, false);
    00460 }
    00461
    00472 bool HasVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
    00473 {
    00474   return VehicleFromPos(tile, data, proc, true) != NULL;
    00475 }
    00476
    00477
    00478 static void UpdateNewVehiclePosHash(Vehicle *v, bool remove)
    00479 {
    00480   Vehicle **old_hash = v->old_new_hash;
    00481   Vehicle **new_hash;
    00482
    00483   if (remove) {
    00484     new_hash = NULL;
    00485   } else {
    00486     int x = GB(TileX(v->tile), HASH_RES, HASH_BITS);
    00487     int y = GB(TileY(v->tile), HASH_RES, HASH_BITS) << HASH_BITS;
    00488     new_hash = &_new_vehicle_position_hash[(x + y) & TOTAL_HASH_MASK];
    00489   }
    00490
    00491   if (old_hash == new_hash) return;
    00492
    00493   /* Remove from the old position in the hash table */
    00494   if (old_hash != NULL) {
    00495     Vehicle *last = NULL;
    00496     Vehicle *u = *old_hash;
    00497     while (u != v) {
    00498       last = u;
    00499       u = u->next_new_hash;
    00500       assert(u != NULL);
    00501     }
    00502
    00503     if (last == NULL) {
    00504       *old_hash = v->next_new_hash;
    00505     } else {
    00506       last->next_new_hash = v->next_new_hash;
    00507     }
    00508   }
    00509
    00510   /* Insert vehicle at beginning of the new position in the hash table */
    00511   if (new_hash != NULL) {
    00512     v->next_new_hash = *new_hash;
    00513     *new_hash = v;
    00514     assert(v != v->next_new_hash);
    00515   }
    00516
    00517   /* Remember current hash position */
    00518   v->old_new_hash = new_hash;
    00519 }
    00520
    00521 static Vehicle *_vehicle_position_hash[0x1000];
    00522
    00523 static void UpdateVehiclePosHash(Vehicle* v, int x, int y)
    00524 {
    00525   UpdateNewVehiclePosHash(v, x == INVALID_COORD);
    00526
    00527   Vehicle **old_hash, **new_hash;
    00528   int old_x = v->left_coord;
    00529   int old_y = v->top_coord;
    00530
    00531   new_hash = (x == INVALID_COORD) ? NULL : &_vehicle_position_hash[GEN_HASH(x, y)];
    00532   old_hash = (old_x == INVALID_COORD) ? NULL : &_vehicle_position_hash[GEN_HASH(old_x, old_y)];
    00533
    00534   if (old_hash == new_hash) return;
    00535
    00536   /* remove from hash table? */
    00537   if (old_hash != NULL) {
    00538     Vehicle *last = NULL;
    00539     Vehicle *u = *old_hash;
    00540     while (u != v) {
    00541       last = u;
    00542       u = u->next_hash;
    00543       assert(u != NULL);
    00544     }
    00545
    00546     if (last == NULL) {
    00547       *old_hash = v->next_hash;
    00548     } else {
    00549       last->next_hash = v->next_hash;
    00550     }
    00551   }
    00552
    00553   /* insert into hash table? */
    00554   if (new_hash != NULL) {
    00555     v->next_hash = *new_hash;
    00556     *new_hash = v;
    00557   }
    00558 }
    00559
    00560 void ResetVehiclePosHash()
    00561 {
    00562   Vehicle *v;
    00563   FOR_ALL_VEHICLES(v) { v->old_new_hash = NULL; }
    00564   memset(_vehicle_position_hash, 0, sizeof(_vehicle_position_hash));
    00565   memset(_new_vehicle_position_hash, 0, sizeof(_new_vehicle_position_hash));
    00566 }
    00567
    00568 void ResetVehicleColorMap()
    00569 {
    00570   Vehicle *v;
    00571   FOR_ALL_VEHICLES(v) { v->colormap = PAL_NONE; }
    00572 }
    00573
    00574 void InitializeVehicles()
    00575 {
    00576   _Vehicle_pool.CleanPool();
    00577   _Vehicle_pool.AddBlockToPool();
    00578
    00579   ResetVehiclePosHash();
    00580 }
    00581
    00582 Vehicle *GetLastVehicleInChain(Vehicle *v)
    00583 {
    00584   while (v->Next() != NULL) v = v->Next();
    00585   return v;
    00586 }
    00587
    00588 uint CountVehiclesInChain(const Vehicle* v)
    00589 {
    00590   uint count = 0;
    00591   do count++; while ((v = v->Next()) != NULL);
    00592   return count;
    00593 }
    00594
    00599 bool IsEngineCountable(const Vehicle *v)
    00600 {
    00601   switch (v->type) {
    00602     case VEH_AIRCRAFT: return IsNormalAircraft(v); // don't count plane shadows and helicopter rotors
    00603     case VEH_TRAIN:
    00604       return !IsArticulatedPart(v) && // tenders and other articulated parts
    00605       !IsRearDualheaded(v); // rear parts of multiheaded engines
    00606     case VEH_ROAD: return IsRoadVehFront(v);
    00607     case VEH_SHIP: return true;
    00608     default: return false; // Only count player buildable vehicles
    00609   }
    00610 }
    00611
    00612 void Vehicle::PreDestructor()
    00613 {
    00614   if (CleaningPool()) return;
    00615
    00616   if (IsValidStationID(this->last_station_visited)) {
    00617     GetStation(this->last_station_visited)->loading_vehicles.remove(this);
    00618
    00619     HideFillingPercent(&this->fill_percent_te_id);
    00620   }
    00621
    00622   if (IsEngineCountable(this)) {
    00623     GetPlayer(this->owner)->num_engines[this->engine_type]--;
    00624     if (this->owner == _local_player) InvalidateAutoreplaceWindow(this->engine_type, this->group_id);
    00625
    00626     if (IsValidGroupID(this->group_id)) GetGroup(this->group_id)->num_engines[this->engine_type]--;
    00627     if (this->IsPrimaryVehicle()) DecreaseGroupNumVehicle(this->group_id);
    00628   }
    00629
    00630   if (this->type == VEH_ROAD) ClearSlot(this);
    00631   if (this->type == VEH_AIRCRAFT && this->IsPrimaryVehicle()) {
    00632     Station *st = GetTargetAirportIfValid(this);
    00633     if (st != NULL) {
    00634       const AirportFTA *layout = st->Airport()->layout;
    00635       CLRBITS(st->airport_flags, layout[this->u.air.previous_pos].block | layout[this->u.air.pos].block);
    00636     }
    00637   }
    00638
    00639   if (this->type != VEH_TRAIN || (this->type == VEH_TRAIN && (IsFrontEngine(this) || IsFreeWagon(this)))) {
    00640     InvalidateWindowData(WC_VEHICLE_DEPOT, this->tile);
    00641   }
    00642
    00643   this->cargo.Truncate(0);
    00644   DeleteVehicleOrders(this);
    00645
    00646   /* Now remove any artic part. This will trigger an other
    00647    *  destroy vehicle, which on his turn can remove any
    00648    *  other artic parts. */
    00649   if ((this->type == VEH_TRAIN && EngineHasArticPart(this)) || (this->type == VEH_ROAD && RoadVehHasArticPart(this))) {
    00650     delete this->Next();
    00651   }
    00652
    00653   Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
    00654   if (w != NULL && WP(w, vp_d).follow_vehicle == this->index) {
    00655     ScrollMainWindowTo(this->x_pos, this->y_pos, true); // lock the main view on the vehicle's last position
    00656     WP(w, vp_d).follow_vehicle = INVALID_VEHICLE;
    00657   }
    00658 }
    00659
    00660 Vehicle::~Vehicle()
    00661 {
    00662   free(this->name);
    00663
    00664   if (CleaningPool()) return;
    00665
    00666   this->SetNext(NULL);
    00667   UpdateVehiclePosHash(this, INVALID_COORD, 0);
    00668   this->next_hash = NULL;
    00669   this->next_new_hash = NULL;
    00670
    00671   DeleteVehicleNews(this->index, INVALID_STRING_ID);
    00672
    00673   new (this) InvalidVehicle();
    00674 }
    00675
    00680 void DeleteVehicleChain(Vehicle *v)
    00681 {
    00682   assert(v->First() == v);
    00683
    00684   do {
    00685     Vehicle *u = v;
    00686     /* sometimes, eg. for disaster vehicles, when company bankrupts, when removing crashed/flooded vehicles,
    00687      * it may happen that vehicle chain is deleted when visible */
    00688     if (!(v->vehstatus & VS_HIDDEN)) MarkSingleVehicleDirty(v);
    00689     v = v->Next();
    00690     delete u;
    00691   } while (v != NULL);
    00692 }
    00693
    00695 static Vehicle* _first_veh_in_depot_list;
    00696
    00700 void VehicleEnteredDepotThisTick(Vehicle *v)
    00701 {
    00702   /* We need to set v->leave_depot_instantly as we have no control of it's contents at this time.
    00703    * Vehicle should stop in the depot if it was in 'stopping' state - train intered depot while slowing down. */
    00704   if ((HasBit(v->current_order.flags, OF_HALT_IN_DEPOT) && !HasBit(v->current_order.flags, OF_PART_OF_ORDERS) && v->current_order.type == OT_GOTO_DEPOT) ||
    00705       (v->vehstatus & VS_STOPPED)) {
    00706     /* we keep the vehicle in the depot since the user ordered it to stay */
    00707     v->leave_depot_instantly = false;
    00708   } else {
    00709     /* the vehicle do not plan on stopping in the depot, so we stop it to ensure that it will not reserve the path
    00710      * out of the depot before we might autoreplace it to a different engine. The new engine would not own the reserved path
    00711      * we store that we stopped the vehicle, so autoreplace can start it again */
    00712     v->vehstatus |= VS_STOPPED;
    00713     v->leave_depot_instantly = true;
    00714   }
    00715
    00716   if (_first_veh_in_depot_list == NULL) {
    00717     _first_veh_in_depot_list = v;
    00718   } else {
    00719     Vehicle *w = _first_veh_in_depot_list;
    00720     while (w->depot_list != NULL) w = w->depot_list;
    00721     w->depot_list = v;
    00722   }
    00723 }
    00724
    00725 void CallVehicleTicks()
    00726 {
    00727   _first_veh_in_depot_list = NULL; // now we are sure it's initialized at the start of each tick
    00728
    00729   Station *st;
    00730   FOR_ALL_STATIONS(st) LoadUnloadStation(st);
    00731
    00732   Vehicle *v;
    00733   FOR_ALL_VEHICLES(v) {
    00734     v->Tick();
    00735
    00736     switch (v->type) {
    00737       default: break;
    00738
    00739       case VEH_TRAIN:
    00740       case VEH_ROAD:
    00741       case VEH_AIRCRAFT:
    00742       case VEH_SHIP:
    00743         if (v->type == VEH_TRAIN && IsTrainWagon(v)) continue;
    00744         if (v->type == VEH_AIRCRAFT && v->subtype != AIR_HELICOPTER) continue;
    00745         if (v->type == VEH_ROAD && !IsRoadVehFront(v)) continue;
    00746
    00747         v->motion_counter += (v->direction & 1) ? (v->cur_speed * 3) / 4 : v->cur_speed;
    00748         /* Play a running sound if the motion counter passes 256 (Do we not skip sounds?) */
    00749         if (GB(v->motion_counter, 0, 8) < v->cur_speed) PlayVehicleSound(v, VSE_RUNNING);
    00750
    00751         /* Play an alterate running sound every 16 ticks */
    00752         if (GB(v->tick_counter, 0, 4) == 0) PlayVehicleSound(v, v->cur_speed > 0 ? VSE_RUNNING_16 : VSE_STOPPED_16);
    00753     }
    00754   }
    00755
    00756   /* now we handle all the vehicles that entered a depot this tick */
    00757   v = _first_veh_in_depot_list;
    00758   while (v != NULL) {
    00759     Vehicle *w = v->depot_list;
    00760     v->depot_list = NULL; // it should always be NULL at the end of each tick
    00761     MaybeReplaceVehicle(v, false, true);
    00762     v = w;
    00763   }
    00764 }
    00765
    00771 bool CanRefitTo(EngineID engine_type, CargoID cid_to)
    00772 {
    00773   return HasBit(EngInfo(engine_type)->refit_mask, cid_to);
    00774 }
    00775
    00780 CargoID FindFirstRefittableCargo(EngineID engine_type)
    00781 {
    00782   uint32 refit_mask = EngInfo(engine_type)->refit_mask;
    00783
    00784   if (refit_mask != 0) {
    00785     for (CargoID cid = 0; cid < NUM_CARGO; cid++) {
    00786       if (HasBit(refit_mask, cid)) return cid;
    00787     }
    00788   }
    00789
    00790   return CT_INVALID;
    00791 }
    00792
    00797 CommandCost GetRefitCost(EngineID engine_type)
    00798 {
    00799   Money base_cost;
    00800   ExpensesType expense_type;
    00801   switch (GetEngine(engine_type)->type) {
    00802     case VEH_SHIP:
    00803       base_cost = _price.ship_base;
    00804       expense_type = EXPENSES_SHIP_RUN;
    00805       break;
    00806
    00807     case VEH_ROAD:
    00808       base_cost = _price.roadveh_base;
    00809       expense_type = EXPENSES_ROADVEH_RUN;
    00810       break;
    00811
    00812     case VEH_AIRCRAFT:
    00813       base_cost = _price.aircraft_base;
    00814       expense_type = EXPENSES_AIRCRAFT_RUN;
    00815       break;
    00816
    00817     case VEH_TRAIN:
    00818       base_cost = 2 * ((RailVehInfo(engine_type)->railveh_type == RAILVEH_WAGON) ?
    00819                _price.build_railwagon : _price.build_railvehicle);
    00820       expense_type = EXPENSES_TRAIN_RUN;
    00821       break;
    00822
    00823     default: NOT_REACHED();
    00824   }
    00825   return CommandCost(expense_type, (EngInfo(engine_type)->refit_cost * base_cost) >> 10);
    00826 }
    00827
    00828 static void DoDrawVehicle(const Vehicle *v)
    00829 {
    00830   SpriteID image = v->cur_image;
    00831   SpriteID pal;
    00832
    00833   if (v->vehstatus & VS_DEFPAL) {
    00834     pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
    00835   } else {
    00836     pal = PAL_NONE;
    00837   }
    00838
    00839   AddSortableSpriteToDraw(image, pal, v->x_pos + v->x_offs, v->y_pos + v->y_offs,
    00840     v->sprite_width, v->sprite_height, v->z_height, v->z_pos, (v->vehstatus & VS_SHADOW) != 0);
    00841 }
    00842
    00843 void ViewportAddVehicles(DrawPixelInfo *dpi)
    00844 {
    00845   /* The bounding rectangle */
    00846   const int l = dpi->left;
    00847   const int r = dpi->left + dpi->width;
    00848   const int t = dpi->top;
    00849   const int b = dpi->top + dpi->height;
    00850
    00851   /* The hash area to scan */
    00852   int xl, xu, yl, yu;
    00853
    00854   if (dpi->width + 70 < (1 << (7 + 6))) {
    00855     xl = GB(l - 70, 7, 6);
    00856     xu = GB(r,      7, 6);
    00857   } else {
    00858     /* scan whole hash row */
    00859     xl = 0;
    00860     xu = 0x3F;
    00861   }
    00862
    00863   if (dpi->height + 70 < (1 << (6 + 6))) {
    00864     yl = GB(t - 70, 6, 6) << 6;
    00865     yu = GB(b,      6, 6) << 6;
    00866   } else {
    00867     /* scan whole column */
    00868     yl = 0;
    00869     yu = 0x3F << 6;
    00870   }
    00871
    00872   for (int y = yl;; y = (y + (1 << 6)) & (0x3F << 6)) {
    00873     for (int x = xl;; x = (x + 1) & 0x3F) {
    00874       const Vehicle *v = _vehicle_position_hash[x + y]; // already masked & 0xFFF
    00875
    00876       while (v != NULL) {
    00877         if (!(v->vehstatus & VS_HIDDEN) &&
    00878             l <= v->right_coord &&
    00879             t <= v->bottom_coord &&
    00880             r >= v->left_coord &&
    00881             b >= v->top_coord) {
    00882           DoDrawVehicle(v);
    00883         }
    00884         v = v->next_hash;
    00885       }
    00886
    00887       if (x == xu) break;
    00888     }
    00889
    00890     if (y == yu) break;
    00891   }
    00892 }
    00893
    00894 static void ChimneySmokeInit(Vehicle *v)
    00895 {
    00896   uint32 r = Random();
    00897   v->cur_image = SPR_CHIMNEY_SMOKE_0 + GB(r, 0, 3);
    00898   v->progress = GB(r, 16, 3);
    00899 }
    00900
    00901 static void ChimneySmokeTick(Vehicle *v)
    00902 {
    00903   if (v->progress > 0) {
    00904     v->progress--;
    00905   } else {
    00906     TileIndex tile;
    00907
    00908     BeginVehicleMove(v);
    00909
    00910     tile = TileVirtXY(v->x_pos, v->y_pos);
    00911     if (!IsTileType(tile, MP_INDUSTRY)) {
    00912       EndVehicleMove(v);
    00913       delete v;
    00914       return;
    00915     }
    00916
    00917     if (v->cur_image != SPR_CHIMNEY_SMOKE_7) {
    00918       v->cur_image++;
    00919     } else {
    00920       v->cur_image = SPR_CHIMNEY_SMOKE_0;
    00921     }
    00922     v->progress = 7;
    00923     VehiclePositionChanged(v);
    00924     EndVehicleMove(v);
    00925   }
    00926 }
    00927
    00928 static void SteamSmokeInit(Vehicle *v)
    00929 {
    00930   v->cur_image = SPR_STEAM_SMOKE_0;
    00931   v->progress = 12;
    00932 }
    00933
    00934 static void SteamSmokeTick(Vehicle *v)
    00935 {
    00936   bool moved = false;
    00937
    00938   BeginVehicleMove(v);
    00939
    00940   v->progress++;
    00941
    00942   if ((v->progress & 7) == 0) {
    00943     v->z_pos++;
    00944     moved = true;
    00945   }
    00946
    00947   if ((v->progress & 0xF) == 4) {
    00948     if (v->cur_image != SPR_STEAM_SMOKE_4) {
    00949       v->cur_image++;
    00950     } else {
    00951       EndVehicleMove(v);
    00952       delete v;
    00953       return;
    00954     }
    00955     moved = true;
    00956   }
    00957
    00958   if (moved) {
    00959     VehiclePositionChanged(v);
    00960     EndVehicleMove(v);
    00961   }
    00962 }
    00963
    00964 static void DieselSmokeInit(Vehicle *v)
    00965 {
    00966   v->cur_image = SPR_DIESEL_SMOKE_0;
    00967   v->progress = 0;
    00968 }
    00969
    00970 static void DieselSmokeTick(Vehicle *v)
    00971 {
    00972   v->progress++;
    00973
    00974   if ((v->progress & 3) == 0) {
    00975     BeginVehicleMove(v);
    00976     v->z_pos++;
    00977     VehiclePositionChanged(v);
    00978     EndVehicleMove(v);
    00979   } else if ((v->progress & 7) == 1) {
    00980     BeginVehicleMove(v);
    00981     if (v->cur_image != SPR_DIESEL_SMOKE_5) {
    00982       v->cur_image++;
    00983       VehiclePositionChanged(v);
    00984       EndVehicleMove(v);
    00985     } else {
    00986       EndVehicleMove(v);
    00987       delete v;
    00988     }
    00989   }
    00990 }
    00991
    00992 static void ElectricSparkInit(Vehicle *v)
    00993 {
    00994   v->cur_image = SPR_ELECTRIC_SPARK_0;
    00995   v->progress = 1;
    00996 }
    00997
    00998 static void ElectricSparkTick(Vehicle *v)
    00999 {
    01000   if (v->progress < 2) {
    01001     v->progress++;
    01002   } else {
    01003     v->progress = 0;
    01004     BeginVehicleMove(v);
    01005     if (v->cur_image != SPR_ELECTRIC_SPARK_5) {
    01006       v->cur_image++;
    01007       VehiclePositionChanged(v);
    01008       EndVehicleMove(v);
    01009     } else {
    01010       EndVehicleMove(v);
    01011       delete v;
    01012     }
    01013   }
    01014 }
    01015
    01016 static void SmokeInit(Vehicle *v)
    01017 {
    01018   v->cur_image = SPR_SMOKE_0;
    01019   v->progress = 12;
    01020 }
    01021
    01022 static void SmokeTick(Vehicle *v)
    01023 {
    01024   bool moved = false;
    01025
    01026   BeginVehicleMove(v);
    01027
    01028   v->progress++;
    01029
    01030   if ((v->progress & 3) == 0) {
    01031     v->z_pos++;
    01032     moved = true;
    01033   }
    01034
    01035   if ((v->progress & 0xF) == 4) {
    01036     if (v->cur_image != SPR_SMOKE_4) {
    01037       v->cur_image++;
    01038     } else {
    01039       EndVehicleMove(v);
    01040       delete v;
    01041       return;
    01042     }
    01043     moved = true;
    01044   }
    01045
    01046   if (moved) {
    01047     VehiclePositionChanged(v);
    01048     EndVehicleMove(v);
    01049   }
    01050 }
    01051
    01052 static void ExplosionLargeInit(Vehicle *v)
    01053 {
    01054   v->cur_image = SPR_EXPLOSION_LARGE_0;
    01055   v->progress = 0;
    01056 }
    01057
    01058 static void ExplosionLargeTick(Vehicle *v)
    01059 {
    01060   v->progress++;
    01061   if ((v->progress & 3) == 0) {
    01062     BeginVehicleMove(v);
    01063     if (v->cur_image != SPR_EXPLOSION_LARGE_F) {
    01064       v->cur_image++;
    01065       VehiclePositionChanged(v);
    01066       EndVehicleMove(v);
    01067     } else {
    01068       EndVehicleMove(v);
    01069       delete v;
    01070     }
    01071   }
    01072 }
    01073
    01074 static void BreakdownSmokeInit(Vehicle *v)
    01075 {
    01076   v->cur_image = SPR_BREAKDOWN_SMOKE_0;
    01077   v->progress = 0;
    01078 }
    01079
    01080 static void BreakdownSmokeTick(Vehicle *v)
    01081 {
    01082   v->progress++;
    01083   if ((v->progress & 7) == 0) {
    01084     BeginVehicleMove(v);
    01085     if (v->cur_image != SPR_BREAKDOWN_SMOKE_3) {
    01086       v->cur_image++;
    01087     } else {
    01088       v->cur_image = SPR_BREAKDOWN_SMOKE_0;
    01089     }
    01090     VehiclePositionChanged(v);
    01091     EndVehicleMove(v);
    01092   }
    01093
    01094   v->u.special.animation_state--;
    01095   if (v->u.special.animation_state == 0) {
    01096     BeginVehicleMove(v);
    01097     EndVehicleMove(v);
    01098     delete v;
    01099   }
    01100 }
    01101
    01102 static void ExplosionSmallInit(Vehicle *v)
    01103 {
    01104   v->cur_image = SPR_EXPLOSION_SMALL_0;
    01105   v->progress = 0;
    01106 }
    01107
    01108 static void ExplosionSmallTick(Vehicle *v)
    01109 {
    01110   v->progress++;
    01111   if ((v->progress & 3) == 0) {
    01112     BeginVehicleMove(v);
    01113     if (v->cur_image != SPR_EXPLOSION_SMALL_B) {
    01114       v->cur_image++;
    01115       VehiclePositionChanged(v);
    01116       EndVehicleMove(v);
    01117     } else {
    01118       EndVehicleMove(v);
    01119       delete v;
    01120     }
    01121   }
    01122 }
    01123
    01124 static void BulldozerInit(Vehicle *v)
    01125 {
    01126   v->cur_image = SPR_BULLDOZER_NE;
    01127   v->progress = 0;
    01128   v->u.special.animation_state = 0;
    01129   v->u.special.animation_substate = 0;
    01130 }
    01131
    01132 struct BulldozerMovement {
    01133   byte direction:2;
    01134   byte image:2;
    01135   byte duration:3;
    01136 };
    01137
    01138 static const BulldozerMovement _bulldozer_movement[] = {
    01139   { 0, 0, 4 },
    01140   { 3, 3, 4 },
    01141   { 2, 2, 7 },
    01142   { 0, 2, 7 },
    01143   { 1, 1, 3 },
    01144   { 2, 2, 7 },
    01145   { 0, 2, 7 },
    01146   { 1, 1, 3 },
    01147   { 2, 2, 7 },
    01148   { 0, 2, 7 },
    01149   { 3, 3, 6 },
    01150   { 2, 2, 6 },
    01151   { 1, 1, 7 },
    01152   { 3, 1, 7 },
    01153   { 0, 0, 3 },
    01154   { 1, 1, 7 },
    01155   { 3, 1, 7 },
    01156   { 0, 0, 3 },
    01157   { 1, 1, 7 },
    01158   { 3, 1, 7 }
    01159 };
    01160
    01161 static const struct {
    01162   int8 x;
    01163   int8 y;
    01164 } _inc_by_dir[] = {
    01165   { -1,  0 },
    01166   {  0,  1 },
    01167   {  1,  0 },
    01168   {  0, -1 }
    01169 };
    01170
    01171 static void BulldozerTick(Vehicle *v)
    01172 {
    01173   v->progress++;
    01174   if ((v->progress & 7) == 0) {
    01175     const BulldozerMovement* b = &_bulldozer_movement[v->u.special.animation_state];
    01176
    01177     BeginVehicleMove(v);
    01178
    01179     v->cur_image = SPR_BULLDOZER_NE + b->image;
    01180
    01181     v->x_pos += _inc_by_dir[b->direction].x;
    01182     v->y_pos += _inc_by_dir[b->direction].y;
    01183
    01184     v->u.special.animation_substate++;
    01185     if (v->u.special.animation_substate >= b->duration) {
    01186       v->u.special.animation_substate = 0;
    01187       v->u.special.animation_state++;
    01188       if (v->u.special.animation_state == lengthof(_bulldozer_movement)) {
    01189         EndVehicleMove(v);
    01190         delete v;
    01191         return;
    01192       }
    01193     }
    01194     VehiclePositionChanged(v);
    01195     EndVehicleMove(v);
    01196   }
    01197 }
    01198
    01199 static void BubbleInit(Vehicle *v)
    01200 {
    01201   v->cur_image = SPR_BUBBLE_GENERATE_0;
    01202   v->spritenum = 0;
    01203   v->progress = 0;
    01204 }
    01205
    01206 struct BubbleMovement {
    01207   int8 x:4;
    01208   int8 y:4;
    01209   int8 z:4;
    01210   byte image:4;
    01211 };
    01212
    01213 #define MK(x, y, z, i) { x, y, z, i }
    01214 #define ME(i) { i, 4, 0, 0 }
    01215
    01216 static const BubbleMovement _bubble_float_sw[] = {
    01217   MK(0, 0, 1, 0),
    01218   MK(1, 0, 1, 1),
    01219   MK(0, 0, 1, 0),
    01220   MK(1, 0, 1, 2),
    01221   ME(1)
    01222 };
    01223
    01224
    01225 static const BubbleMovement _bubble_float_ne[] = {
    01226   MK( 0, 0, 1, 0),
    01227   MK(-1, 0, 1, 1),
    01228   MK( 0, 0, 1, 0),
    01229   MK(-1, 0, 1, 2),
    01230   ME(1)
    01231 };
    01232
    01233 static const BubbleMovement _bubble_float_se[] = {
    01234   MK(0, 0, 1, 0),
    01235   MK(0, 1, 1, 1),
    01236   MK(0, 0, 1, 0),
    01237   MK(0, 1, 1, 2),
    01238   ME(1)
    01239 };
    01240
    01241 static const BubbleMovement _bubble_float_nw[] = {
    01242   MK(0,  0, 1, 0),
    01243   MK(0, -1, 1, 1),
    01244   MK(0,  0, 1, 0),
    01245   MK(0, -1, 1, 2),
    01246   ME(1)
    01247 };
    01248
    01249 static const BubbleMovement _bubble_burst[] = {
    01250   MK(0, 0, 1, 2),
    01251   MK(0, 0, 1, 7),
    01252   MK(0, 0, 1, 8),
    01253   MK(0, 0, 1, 9),
    01254   ME(0)
    01255 };
    01256
    01257 static const BubbleMovement _bubble_absorb[] = {
    01258   MK(0, 0, 1, 0),
    01259   MK(0, 0, 1, 1),
    01260   MK(0, 0, 1, 0),
    01261   MK(0, 0, 1, 2),
    01262   MK(0, 0, 1, 0),
    01263   MK(0, 0, 1, 1),
    01264   MK(0, 0, 1, 0),
    01265   MK(0, 0, 1, 2),
    01266   MK(0, 0, 1, 0),
    01267   MK(0, 0, 1, 1),
    01268   MK(0, 0, 1, 0),
    01269   MK(0, 0, 1, 2),
    01270   MK(0, 0, 1, 0),
    01271   MK(0, 0, 1, 1),
    01272   MK(0, 0, 1, 0),
    01273   MK(0, 0, 1, 2),
    01274   MK(0, 0, 1, 0),
    01275   MK(0, 0, 1, 1),
    01276   MK(0, 0, 1, 0),
    01277   MK(0, 0, 1, 2),
    01278   MK(0, 0, 1, 0),
    01279   MK(0, 0, 1, 1),
    01280   MK(0, 0, 1, 0),
    01281   MK(0, 0, 1, 2),
    01282   MK(0, 0, 1, 0),
    01283   MK(0, 0, 1, 1),
    01284   MK(0, 0, 1, 0),
    01285   MK(0, 0, 1, 2),
    01286   MK(0, 0, 1, 0),
    01287   MK(0, 0, 1, 1),
    01288   MK(0, 0, 1, 0),
    01289   MK(0, 0, 1, 2),
    01290   MK(0, 0, 1, 0),
    01291   MK(0, 0, 1, 1),
    01292   MK(0, 0, 1, 0),
    01293   MK(0, 0, 1, 2),
    01294   MK(0, 0, 1, 0),
    01295   MK(0, 0, 1, 1),
    01296   MK(0, 0, 1, 0),
    01297   MK(0, 0, 1, 2),
    01298   MK(0, 0, 1, 0),
    01299   MK(0, 0, 1, 1),
    01300   MK(0, 0, 1, 0),
    01301   MK(0, 0, 1, 2),
    01302   MK(0, 0, 1, 0),
    01303   MK(0, 0, 1, 1),
    01304   MK(0, 0, 1, 0),
    01305   MK(0, 0, 1, 2),
    01306   MK(0, 0, 1, 0),
    01307   MK(0, 0, 1, 1),
    01308   MK(0, 0, 1, 0),
    01309   MK(0, 0, 1, 2),
    01310   MK(0, 0, 1, 0),
    01311   MK(0, 0, 1, 1),
    01312   MK(0, 0, 1, 0),
    01313   MK(0, 0, 1, 2),
    01314   MK(0, 0, 1, 0),
    01315   MK(0, 0, 1, 1),
    01316   MK(0, 0, 1, 0),
    01317   MK(0, 0, 1, 2),
    01318   MK(0, 0, 1, 0),
    01319   MK(0, 0, 1, 1),
    01320   MK(2, 1, 3, 0),
    01321   MK(1, 1, 3, 1),
    01322   MK(2, 1, 3, 0),
    01323   MK(1, 1, 3, 2),
    01324   MK(2, 1, 3, 0),
    01325   MK(1, 1, 3, 1),
    01326   MK(2, 1, 3, 0),
    01327   MK(1, 0, 1, 2),
    01328   MK(0, 0, 1, 0),
    01329   MK(1, 0, 1, 1),
    01330   MK(0, 0, 1, 0),
    01331   MK(1, 0, 1, 2),
    01332   MK(0, 0, 1, 0),
    01333   MK(1, 0, 1, 1),
    01334   MK(0, 0, 1, 0),
    01335   MK(1, 0, 1, 2),
    01336   ME(2),
    01337   MK(0, 0, 0, 0xA),
    01338   MK(0, 0, 0, 0xB),
    01339   MK(0, 0, 0, 0xC),
    01340   MK(0, 0, 0, 0xD),
    01341   MK(0, 0, 0, 0xE),
    01342   ME(0)
    01343 };
    01344 #undef ME
    01345 #undef MK
    01346
    01347 static const BubbleMovement * const _bubble_movement[] = {
    01348   _bubble_float_sw,
    01349   _bubble_float_ne,
    01350   _bubble_float_se,
    01351   _bubble_float_nw,
    01352   _bubble_burst,
    01353   _bubble_absorb,
    01354 };
    01355
    01356 static void BubbleTick(Vehicle *v)
    01357 {
    01358   uint et;
    01359   const BubbleMovement *b;
    01360
    01361   v->progress++;
    01362   if ((v->progress & 3) != 0)
    01363     return;
    01364
    01365   BeginVehicleMove(v);
    01366
    01367   if (v->spritenum == 0) {
    01368     v->cur_image++;
    01369     if (v->cur_image < SPR_BUBBLE_GENERATE_3) {
    01370       VehiclePositionChanged(v);
    01371       EndVehicleMove(v);
    01372       return;
    01373     }
    01374     if (v->u.special.animation_substate != 0) {
    01375       v->spritenum = GB(Random(), 0, 2) + 1;
    01376     } else {
    01377       v->spritenum = 6;
    01378     }
    01379     et = 0;
    01380   } else {
    01381     et = v->engine_type + 1;
    01382   }
    01383
    01384   b = &_bubble_movement[v->spritenum - 1][et];
    01385
    01386   if (b->y == 4 && b->x == 0) {
    01387     EndVehicleMove(v);
    01388     delete v;
    01389     return;
    01390   }
    01391
    01392   if (b->y == 4 && b->x == 1) {
    01393     if (v->z_pos > 180 || Chance16I(1, 96, Random())) {
    01394       v->spritenum = 5;
    01395       SndPlayVehicleFx(SND_2F_POP, v);
    01396     }
    01397     et = 0;
    01398   }
    01399
    01400   if (b->y == 4 && b->x == 2) {
    01401     TileIndex tile;
    01402
    01403     et++;
    01404     SndPlayVehicleFx(SND_31_EXTRACT, v);
    01405
    01406     tile = TileVirtXY(v->x_pos, v->y_pos);
    01407     if (IsTileType(tile, MP_INDUSTRY) && GetIndustryGfx(tile) == GFX_BUBBLE_CATCHER) AddAnimatedTile(tile);
    01408   }
    01409
    01410   v->engine_type = et;
    01411   b = &_bubble_movement[v->spritenum - 1][et];
    01412
    01413   v->x_pos += b->x;
    01414   v->y_pos += b->y;
    01415   v->z_pos += b->z;
    01416   v->cur_image = SPR_BUBBLE_0 + b->image;
    01417
    01418   VehiclePositionChanged(v);
    01419   EndVehicleMove(v);
    01420 }
    01421
    01422
    01423 typedef void EffectInitProc(Vehicle *v);
    01424 typedef void EffectTickProc(Vehicle *v);
    01425
    01426 static EffectInitProc * const _effect_init_procs[] = {
    01427   ChimneySmokeInit,
    01428   SteamSmokeInit,
    01429   DieselSmokeInit,
    01430   ElectricSparkInit,
    01431   SmokeInit,
    01432   ExplosionLargeInit,
    01433   BreakdownSmokeInit,
    01434   ExplosionSmallInit,
    01435   BulldozerInit,
    01436   BubbleInit,
    01437 };
    01438
    01439 static EffectTickProc * const _effect_tick_procs[] = {
    01440   ChimneySmokeTick,
    01441   SteamSmokeTick,
    01442   DieselSmokeTick,
    01443   ElectricSparkTick,
    01444   SmokeTick,
    01445   ExplosionLargeTick,
    01446   BreakdownSmokeTick,
    01447   ExplosionSmallTick,
    01448   BulldozerTick,
    01449   BubbleTick,
    01450 };
    01451
    01452
    01453 Vehicle *CreateEffectVehicle(int x, int y, int z, EffectVehicle type)
    01454 {
    01455   Vehicle *v;
    01456
    01457   v = new SpecialVehicle();
    01458   if (v != NULL) {
    01459     v->subtype = type;
    01460     v->x_pos = x;
    01461     v->y_pos = y;
    01462     v->z_pos = z;
    01463     v->tile = 0;
    01464     v->UpdateDeltaXY(INVALID_DIR);
    01465     v->vehstatus = VS_UNCLICKABLE;
    01466
    01467     _effect_init_procs[type](v);
    01468
    01469     VehiclePositionChanged(v);
    01470     BeginVehicleMove(v);
    01471     EndVehicleMove(v);
    01472   }
    01473   return v;
    01474 }
    01475
    01476 Vehicle *CreateEffectVehicleAbove(int x, int y, int z, EffectVehicle type)
    01477 {
    01478   int safe_x = Clamp(x, 0, MapMaxX() * TILE_SIZE);
    01479   int safe_y = Clamp(y, 0, MapMaxY() * TILE_SIZE);
    01480   return CreateEffectVehicle(x, y, GetSlopeZ(safe_x, safe_y) + z, type);
    01481 }
    01482
    01483 Vehicle *CreateEffectVehicleRel(const Vehicle *v, int x, int y, int z, EffectVehicle type)
    01484 {
    01485   return CreateEffectVehicle(v->x_pos + x, v->y_pos + y, v->z_pos + z, type);
    01486 }
    01487
    01488 void SpecialVehicle::Tick()
    01489 {
    01490   _effect_tick_procs[this->subtype](this);
    01491 }
    01492
    01493 Vehicle *CheckClickOnVehicle(const ViewPort *vp, int x, int y)
    01494 {
    01495   Vehicle *found = NULL, *v;
    01496   uint dist, best_dist = (uint)-1;
    01497
    01498   if ( (uint)(x -= vp->left) >= (uint)vp->width ||
    01499        (uint)(y -= vp->top) >= (uint)vp->height)
    01500         return NULL;
    01501
    01502   x = ScaleByZoom(x, vp->zoom) + vp->virtual_left;
    01503   y = ScaleByZoom(y, vp->zoom) + vp->virtual_top;
    01504
    01505   FOR_ALL_VEHICLES(v) {
    01506     if ((v->vehstatus & (VS_HIDDEN|VS_UNCLICKABLE)) == 0 &&
    01507         x >= v->left_coord && x <= v->right_coord &&
    01508         y >= v->top_coord && y <= v->bottom_coord) {
    01509
    01510       dist = max(
    01511         abs( ((v->left_coord + v->right_coord)>>1) - x ),
    01512         abs( ((v->top_coord + v->bottom_coord)>>1) - y )
    01513       );
    01514
    01515       if (dist < best_dist) {
    01516         found = v;
    01517         best_dist = dist;
    01518       }
    01519     }
    01520   }
    01521
    01522   return found;
    01523 }
    01524
    01525 void CheckVehicle32Day(Vehicle *v)
    01526 {
    01527   if ((v->day_counter & 0x1F) != 0) return;
    01528
    01529   uint16 callback = GetVehicleCallback(CBID_VEHICLE_32DAY_CALLBACK, 0, 0, v->engine_type, v);
    01530   if (callback == CALLBACK_FAILED) return;
    01531   if (HasBit(callback, 0)) TriggerVehicle(v, VEHICLE_TRIGGER_CALLBACK_32); // Trigger vehicle trigger 10
    01532   if (HasBit(callback, 1)) v->colormap = PAL_NONE;                         // Update colormap via callback 2D
    01533 }
    01534
    01535 void DecreaseVehicleValue(Vehicle *v)
    01536 {
    01537   v->value -= v->value >> 8;
    01538   InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
    01539 }
    01540
    01541 static const byte _breakdown_chance[64] = {
    01542     3,   3,   3,   3,   3,   3,   3,   3,
    01543     4,   4,   5,   5,   6,   6,   7,   7,
    01544     8,   8,   9,   9,  10,  10,  11,  11,
    01545    12,  13,  13,  13,  13,  14,  15,  16,
    01546    17,  19,  21,  25,  28,  31,  34,  37,
    01547    40,  44,  48,  52,  56,  60,  64,  68,
    01548    72,  80,  90, 100, 110, 120, 130, 140,
    01549   150, 170, 190, 210, 230, 250, 250, 250,
    01550 };
    01551
    01552 void CheckVehicleBreakdown(Vehicle *v)
    01553 {
    01554   int rel, rel_old;
    01555   uint32 r;
    01556   int chance;
    01557
    01558   /* decrease reliability */
    01559   v->reliability = rel = max((rel_old = v->reliability) - v->reliability_spd_dec, 0);
    01560   if ((rel_old >> 8) != (rel >> 8))
    01561     InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
    01562
    01563   if (v->breakdown_ctr != 0 || v->vehstatus & VS_STOPPED ||
    01564       v->cur_speed < 5 || _game_mode == GM_MENU) {
    01565     return;
    01566   }
    01567
    01568   r = Random();
    01569
    01570   /* increase chance of failure */
    01571   chance = v->breakdown_chance + 1;
    01572   if (Chance16I(1,25,r)) chance += 25;
    01573   v->breakdown_chance = min(255, chance);
    01574
    01575   /* calculate reliability value to use in comparison */
    01576   rel = v->reliability;
    01577   if (v->type == VEH_SHIP) rel += 0x6666;
    01578
    01579   /* disabled breakdowns? */
    01580   if (_opt.diff.vehicle_breakdowns < 1) return;
    01581
    01582   /* reduced breakdowns? */
    01583   if (_opt.diff.vehicle_breakdowns == 1) rel += 0x6666;
    01584
    01585   /* check if to break down */
    01586   if (_breakdown_chance[(uint)min(rel, 0xffff) >> 10] <= v->breakdown_chance) {
    01587     v->breakdown_ctr    = GB(r, 16, 6) + 0x3F;
    01588     v->breakdown_delay  = GB(r, 24, 7) + 0x80;
    01589     v->breakdown_chance = 0;
    01590   }
    01591 }
    01592
    01593 static const StringID _vehicle_type_names[4] = {
    01594   STR_019F_TRAIN,
    01595   STR_019C_ROAD_VEHICLE,
    01596   STR_019E_SHIP,
    01597   STR_019D_AIRCRAFT,
    01598 };
    01599
    01600 static void ShowVehicleGettingOld(Vehicle *v, StringID msg)
    01601 {
    01602   if (v->owner != _local_player) return;
    01603
    01604   /* Do not show getting-old message if autorenew is active (and it can replace the vehicle) */
    01605   if (GetPlayer(v->owner)->engine_renew && GetEngine(v->engine_type)->player_avail != 0) return;
    01606
    01607   SetDParam(0, _vehicle_type_names[v->type]);
    01608   SetDParam(1, v->unitnumber);
    01609   AddNewsItem(msg, NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0), v->index, 0);
    01610 }
    01611
    01612 void AgeVehicle(Vehicle *v)
    01613 {
    01614   if (v->age < 65535) v->age++;
    01615
    01616   int age = v->age - v->max_age;
    01617   if (age == 366*0 || age == 366*1 || age == 366*2 || age == 366*3 || age == 366*4) v->reliability_spd_dec <<= 1;
    01618
    01619   InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
    01620
    01621   if (age == -366) {
    01622     ShowVehicleGettingOld(v, STR_01A0_IS_GETTING_OLD);
    01623   } else if (age == 0) {
    01624     ShowVehicleGettingOld(v, STR_01A1_IS_GETTING_VERY_OLD);
    01625   } else if (age > 0 && (age % 366) == 0) {
    01626     ShowVehicleGettingOld(v, STR_01A2_IS_GETTING_VERY_OLD_AND);
    01627   }
    01628 }
    01629
    01640 CommandCost CmdMassStartStopVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
    01641 {
    01642   Vehicle **vl = NULL;
    01643   uint16 engine_list_length = 0;
    01644   uint16 engine_count = 0;
    01645   CommandCost return_value = CMD_ERROR;
    01646   uint i;
    01647   uint stop_command;
    01648   VehicleType vehicle_type = (VehicleType)GB(p2, 0, 5);
    01649   bool start_stop = HasBit(p2, 5);
    01650   bool vehicle_list_window = HasBit(p2, 6);
    01651
    01652   switch (vehicle_type) {
    01653     case VEH_TRAIN:    stop_command = CMD_START_STOP_TRAIN;    break;
    01654     case VEH_ROAD:     stop_command = CMD_START_STOP_ROADVEH;  break;
    01655     case VEH_SHIP:     stop_command = CMD_START_STOP_SHIP;     break;
    01656     case VEH_AIRCRAFT: stop_command = CMD_START_STOP_AIRCRAFT; break;
    01657     default: return CMD_ERROR;
    01658   }
    01659
    01660   if (vehicle_list_window) {
    01661     uint32 id = p1;
    01662     uint16 window_type = p2 & VLW_MASK;
    01663
    01664     engine_count = GenerateVehicleSortList((const Vehicle***)&vl, &engine_list_length, vehicle_type, _current_player, id, window_type);
    01665   } else {
    01666     /* Get the list of vehicles in the depot */
    01667     BuildDepotVehicleList(vehicle_type, tile, &vl, &engine_list_length, &engine_count, NULL, NULL, NULL);
    01668   }
    01669
    01670   for (i = 0; i < engine_count; i++) {
    01671     const Vehicle *v = vl[i];
    01672     CommandCost ret;
    01673
    01674     if (!!(v->vehstatus & VS_STOPPED) != start_stop) continue;
    01675
    01676     if (!vehicle_list_window) {
    01677       if (vehicle_type == VEH_TRAIN) {
    01678         if (CheckTrainInDepot(v, false) == -1) continue;
    01679       } else {
    01680         if (!(v->vehstatus & VS_HIDDEN)) continue;
    01681       }
    01682     }
    01683
    01684     ret = DoCommand(tile, v->index, 0, flags, stop_command);
    01685
    01686     if (CmdSucceeded(ret)) {
    01687       return_value = CommandCost();
    01688       /* We know that the command is valid for at least one vehicle.
    01689        * If we haven't set DC_EXEC, then there is no point in continueing because it will be valid */
    01690       if (!(flags & DC_EXEC)) break;
    01691     }
    01692   }
    01693
    01694   free(vl);
    01695   return return_value;
    01696 }
    01697
    01704 CommandCost CmdDepotSellAllVehicles(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
    01705 {
    01706   Vehicle **engines = NULL;
    01707   Vehicle **wagons = NULL;
    01708   uint16 engine_list_length = 0;
    01709   uint16 engine_count = 0;
    01710   uint16 wagon_list_length = 0;
    01711   uint16 wagon_count = 0;
    01712
    01713   CommandCost cost(EXPENSES_NEW_VEHICLES);
    01714   uint i, sell_command, total_number_vehicles;
    01715   VehicleType vehicle_type = (VehicleType)GB(p1, 0, 8);
    01716
    01717   switch (vehicle_type) {
    01718     case VEH_TRAIN:    sell_command = CMD_SELL_RAIL_WAGON; break;
    01719     case VEH_ROAD:     sell_command = CMD_SELL_ROAD_VEH;   break;
    01720     case VEH_SHIP:     sell_command = CMD_SELL_SHIP;       break;
    01721     case VEH_AIRCRAFT: sell_command = CMD_SELL_AIRCRAFT;   break;
    01722     default: return CMD_ERROR;
    01723   }
    01724
    01725   /* Get the list of vehicles in the depot */
    01726   BuildDepotVehicleList(vehicle_type, tile, &engines, &engine_list_length, &engine_count,
    01727                                   &wagons,  &wagon_list_length,  &wagon_count);
    01728
    01729   total_number_vehicles = engine_count + wagon_count;
    01730   for (i = 0; i < total_number_vehicles; i++) {
    01731     const Vehicle *v;
    01732     CommandCost ret;
    01733
    01734     if (i < engine_count) {
    01735       v = engines[i];
    01736     } else {
    01737       v = wagons[i - engine_count];
    01738     }
    01739
    01740     ret = DoCommand(tile, v->index, 1, flags, sell_command);
    01741
    01742     if (CmdSucceeded(ret)) cost.AddCost(ret);
    01743   }
    01744
    01745   free(engines);
    01746   free(wagons);
    01747   if (cost.GetCost() == 0) return CMD_ERROR; // no vehicles to sell
    01748   return cost;
    01749 }
    01750
    01757 CommandCost CmdDepotMassAutoReplace(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
    01758 {
    01759   Vehicle **vl = NULL;
    01760   uint16 engine_list_length = 0;
    01761   uint16 engine_count = 0;
    01762   uint i, x = 0, y = 0, z = 0;
    01763   CommandCost cost;
    01764   VehicleType vehicle_type = (VehicleType)GB(p1, 0, 8);
    01765
    01766   if (!IsDepotTile(tile) || !IsTileOwner(tile, _current_player)) return CMD_ERROR;
    01767
    01768   /* Get the list of vehicles in the depot */
    01769   BuildDepotVehicleList(vehicle_type, tile, &vl, &engine_list_length, &engine_count, NULL, NULL, NULL);
    01770
    01771
    01772   for (i = 0; i < engine_count; i++) {
    01773     Vehicle *v = vl[i];
    01774     bool stopped = !(v->vehstatus & VS_STOPPED);
    01775     CommandCost ret;
    01776
    01777     /* Ensure that the vehicle completely in the depot */
    01778     if (!v->IsInDepot()) continue;
    01779
    01780     x = v->x_pos;
    01781     y = v->y_pos;
    01782     z = v->z_pos;
    01783
    01784     if (stopped) {
    01785       v->vehstatus |= VS_STOPPED; // Stop the vehicle
    01786       v->leave_depot_instantly = true;
    01787     }
    01788     ret = MaybeReplaceVehicle(v, !(flags & DC_EXEC), false);
    01789
    01790     if (CmdSucceeded(ret)) {
    01791       cost.AddCost(ret);
    01792       if (!(flags & DC_EXEC)) break;
    01793       /* There is a problem with autoreplace and newgrf
    01794        * It's impossible to tell the length of a train after it's being replaced before it's actually done
    01795        * Because of this, we can't estimate costs due to wagon removal and we will have to always return 0 and pay manually
    01796        * Since we pay after each vehicle is replaced and MaybeReplaceVehicle() check if the player got enough money
    01797        * we should never reach a condition where the player will end up with negative money from doing this */
    01798       SubtractMoneyFromPlayer(ret);
    01799     }
    01800   }
    01801
    01802   if (cost.GetCost() == 0) {
    01803     cost = CMD_ERROR;
    01804   } else {
    01805     if (flags & DC_EXEC) {
    01806       /* Display the cost animation now that DoCommandP() can't do it for us (see previous comments) */
    01807       if (IsLocalPlayer()) ShowCostOrIncomeAnimation(x, y, z, cost.GetCost());
    01808     }
    01809     cost = CommandCost();
    01810   }
    01811
    01812   free(vl);
    01813   return cost;
    01814 }
    01815
    01822 CommandCost CmdCloneVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
    01823 {
    01824   Vehicle *v_front, *v;
    01825   Vehicle *w_front, *w, *w_rear;
    01826   CommandCost cost, total_cost(EXPENSES_NEW_VEHICLES);
    01827   uint32 build_argument = 2;
    01828
    01829   if (!IsValidVehicleID(p1)) return CMD_ERROR;
    01830   v = GetVehicle(p1);
    01831   v_front = v;
    01832   w = NULL;
    01833   w_front = NULL;
    01834   w_rear = NULL;
    01835
    01836
    01837   /*
    01838    * v_front is the front engine in the original vehicle
    01839    * v is the car/vehicle of the original vehicle, that is currently being copied
    01840    * w_front is the front engine of the cloned vehicle
    01841    * w is the car/vehicle currently being cloned
    01842    * w_rear is the rear end of the cloned train. It's used to add more cars and is only used by trains
    01843    */
    01844
    01845   if (!CheckOwnership(v->owner)) return CMD_ERROR;
    01846
    01847   if (v->type == VEH_TRAIN && (!IsFrontEngine(v) || v->u.rail.crash_anim_pos >= 4400)) return CMD_ERROR;
    01848
    01849   /* check that we can allocate enough vehicles */
    01850   if (!(flags & DC_EXEC)) {
    01851     int veh_counter = 0;
    01852     do {
    01853       veh_counter++;
    01854     } while ((v = v->Next()) != NULL);
    01855
    01856     if (!Vehicle::AllocateList(NULL, veh_counter)) {
    01857       return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
    01858     }
    01859   }
    01860
    01861   v = v_front;
    01862
    01863   do {
    01864     if (v->type == VEH_TRAIN && IsRearDualheaded(v)) {
    01865       /* we build the rear ends of multiheaded trains with the front ones */
    01866       continue;
    01867     }
    01868
    01869     cost = DoCommand(tile, v->engine_type, build_argument, flags, GetCmdBuildVeh(v));
    01870     build_argument = 3; // ensure that we only assign a number to the first engine
    01871
    01872     if (CmdFailed(cost)) return cost;
    01873
    01874     total_cost.AddCost(cost);
    01875
    01876     if (flags & DC_EXEC) {
    01877       w = GetVehicle(_new_vehicle_id);
    01878
    01879       if (v->type == VEH_TRAIN && HasBit(v->u.rail.flags, VRF_REVERSE_DIRECTION)) {
    01880         SetBit(w->u.rail.flags, VRF_REVERSE_DIRECTION);
    01881       }
    01882
    01883       if (v->type == VEH_TRAIN && !IsFrontEngine(v)) {
    01884         /* this s a train car
    01885          * add this unit to the end of the train */
    01886         CommandCost result = DoCommand(0, (w_rear->index << 16) | w->index, 1, flags, CMD_MOVE_RAIL_VEHICLE);
    01887         if (CmdFailed(result)) {
    01888           /* The train can't be joined to make the same consist as the original.
    01889            * Sell what we already made (clean up) and return an error.           */
    01890           DoCommand(w_front->tile, w_front->index, 1, flags, GetCmdSellVeh(w_front));
    01891           DoCommand(w_front->tile, w->index,       1, flags, GetCmdSellVeh(w));
    01892           return result; // return error and the message returned from CMD_MOVE_RAIL_VEHICLE
    01893         }
    01894       } else {
    01895         /* this is a front engine or not a train. */
    01896         w_front = w;
    01897         w->service_interval = v->service_interval;
    01898       }
    01899       w_rear = w; // trains needs to know the last car in the train, so they can add more in next loop
    01900     }
    01901   } while (v->type == VEH_TRAIN && (v = GetNextVehicle(v)) != NULL);
    01902
    01903   if (flags & DC_EXEC && v_front->type == VEH_TRAIN) {
    01904     /* for trains this needs to be the front engine due to the callback function */
    01905     _new_vehicle_id = w_front->index;
    01906   }
    01907
    01908   if (flags & DC_EXEC) {
    01909     /* Cloned vehicles belong to the same group */
    01910     DoCommand(0, v_front->group_id, w_front->index, flags, CMD_ADD_VEHICLE_GROUP);
    01911   }
    01912
    01913
    01914   /* Take care of refitting. */
    01915   w = w_front;
    01916   v = v_front;
    01917
    01918   /* Both building and refitting are influenced by newgrf callbacks, which
    01919    * makes it impossible to accurately estimate the cloning costs. In
    01920    * particular, it is possible for engines of the same type to be built with
    01921    * different numbers of articulated parts, so when refitting we have to
    01922    * loop over real vehicles first, and then the articulated parts of those
    01923    * vehicles in a different loop. */
    01924   do {
    01925     do {
    01926       if (flags & DC_EXEC) {
    01927         assert(w != NULL);
    01928
    01929         if (w->cargo_type != v->cargo_type || w->cargo_subtype != v->cargo_subtype) {
    01930           cost = DoCommand(0, w->index, v->cargo_type | (v->cargo_subtype << 8) | 1U << 16 , flags, GetCmdRefitVeh(v));
    01931           if (CmdSucceeded(cost)) total_cost.AddCost(cost);
    01932         }
    01933
    01934         if (w->type == VEH_TRAIN && EngineHasArticPart(w)) {
    01935           w = GetNextArticPart(w);
    01936         } else if (w->type == VEH_ROAD && RoadVehHasArticPart(w)) {
    01937           w = w->Next();
    01938         } else {
    01939           break;
    01940         }
    01941       } else {
    01942         CargoID initial_cargo = GetEngineCargoType(v->engine_type);
    01943
    01944         if (v->cargo_type != initial_cargo && initial_cargo != CT_INVALID) {
    01945           total_cost.AddCost(GetRefitCost(v->engine_type));
    01946         }
    01947       }
    01948
    01949       if (v->type == VEH_TRAIN && EngineHasArticPart(v)) {
    01950         v = GetNextArticPart(v);
    01951       } else if (v->type == VEH_ROAD && RoadVehHasArticPart(v)) {
    01952         v = v->Next();
    01953       } else {
    01954         break;
    01955       }
    01956     } while (v != NULL);
    01957
    01958     if ((flags & DC_EXEC) && v->type == VEH_TRAIN) w = GetNextVehicle(w);
    01959   } while (v->type == VEH_TRAIN && (v = GetNextVehicle(v)) != NULL);
    01960
    01961   if (flags & DC_EXEC) {
    01962     /*
    01963      * Set the orders of the vehicle. Cannot do it earlier as we need
    01964      * the vehicle refitted before doing this, otherwise the moved
    01965      * cargo types might not match (passenger vs non-passenger)
    01966      */
    01967     DoCommand(0, (v_front->index << 16) | w_front->index, p2 & 1 ? CO_SHARE : CO_COPY, flags, CMD_CLONE_ORDER);
    01968   }
    01969
    01970   /* Since we can't estimate the cost of cloning a vehicle accurately we must
    01971    * check whether the player has enough money manually. */
    01972   if (!CheckPlayerHasMoney(total_cost)) {
    01973     if (flags & DC_EXEC) {
    01974       /* The vehicle has already been bought, so now it must be sold again. */
    01975       DoCommand(w_front->tile, w_front->index, 1, flags, GetCmdSellVeh(w_front));
    01976     }
    01977     return CMD_ERROR;
    01978   }
    01979
    01980   return total_cost;
    01981 }
    01982
    01983
    01984 /* Extend the list size for BuildDepotVehicleList() */
    01985 static inline void ExtendVehicleListSize(const Vehicle ***engine_list, uint16 *engine_list_length, uint16 step_size)
    01986 {
    01987   *engine_list_length = min(*engine_list_length + step_size, GetMaxVehicleIndex() + 1);
    01988   *engine_list = ReallocT(*engine_list, *engine_list_length);
    01989 }
    01990
    02003 void BuildDepotVehicleList(VehicleType type, TileIndex tile, Vehicle ***engine_list, uint16 *engine_list_length, uint16 *engine_count, Vehicle ***wagon_list, uint16 *wagon_list_length, uint16 *wagon_count)
    02004 {
    02005   Vehicle *v;
    02006
    02007   /* This function should never be called without an array to store results */
    02008   assert(!(engine_list == NULL && type != VEH_TRAIN));
    02009   assert(!(type == VEH_TRAIN && engine_list == NULL && wagon_list == NULL));
    02010
    02011   /* Both array and the length should either be NULL to disable the list or both should not be NULL */
    02012   assert((engine_list == NULL && engine_list_length == NULL) || (engine_list != NULL && engine_list_length != NULL));
    02013   assert((wagon_list == NULL && wagon_list_length == NULL) || (wagon_list != NULL && wagon_list_length != NULL));
    02014
    02015   assert(!(engine_list != NULL && engine_count == NULL));
    02016   assert(!(wagon_list != NULL && wagon_count == NULL));
    02017
    02018   if (engine_count != NULL) *engine_count = 0;
    02019   if (wagon_count != NULL) *wagon_count = 0;
    02020
    02021   switch (type) {
    02022     case VEH_TRAIN:
    02023       FOR_ALL_VEHICLES(v) {
    02024         if (v->tile == tile && v->type == VEH_TRAIN && v->u.rail.track == TRACK_BIT_DEPOT) {
    02025           if (IsFrontEngine(v)) {
    02026             if (engine_list == NULL) continue;
    02027             if (*engine_count == *engine_list_length) ExtendVehicleListSize((const Vehicle***)engine_list, engine_list_length, 25);
    02028             (*engine_list)[(*engine_count)++] = v;
    02029           } else if (IsFreeWagon(v)) {
    02030             if (wagon_list == NULL) continue;
    02031             if (*wagon_count == *wagon_list_length) ExtendVehicleListSize((const Vehicle***)wagon_list, wagon_list_length, 25);
    02032             (*wagon_list)[(*wagon_count)++] = v;
    02033           }
    02034         }
    02035       }
    02036       break;
    02037
    02038     case VEH_ROAD:
    02039       FOR_ALL_VEHICLES(v) {
    02040         if (v->tile == tile && v->type == VEH_ROAD && v->IsInDepot() && IsRoadVehFront(v)) {
    02041           if (*engine_count == *engine_list_length) ExtendVehicleListSize((const Vehicle***)engine_list, engine_list_length, 25);
    02042           (*engine_list)[(*engine_count)++] = v;
    02043         }
    02044       }
    02045       break;
    02046
    02047     case VEH_SHIP:
    02048       FOR_ALL_VEHICLES(v) {
    02049         if (v->tile == tile && v->type == VEH_SHIP && v->IsInDepot()) {
    02050           if (*engine_count == *engine_list_length) ExtendVehicleListSize((const Vehicle***)engine_list, engine_list_length, 25);
    02051           (*engine_list)[(*engine_count)++] = v;
    02052         }
    02053       }
    02054       break;
    02055
    02056     case VEH_AIRCRAFT:
    02057       FOR_ALL_VEHICLES(v) {
    02058         if (v->tile == tile &&
    02059             v->type == VEH_AIRCRAFT && IsNormalAircraft(v) &&
    02060             v->IsInDepot()) {
    02061           if (*engine_count == *engine_list_length) ExtendVehicleListSize((const Vehicle***)engine_list, engine_list_length, 25);
    02062           (*engine_list)[(*engine_count)++] = v;
    02063         }
    02064       }
    02065       break;
    02066
    02067     default: NOT_REACHED();
    02068   }
    02069 }
    02070
    02087 uint GenerateVehicleSortList(const Vehicle ***sort_list, uint16 *length_of_array, VehicleType type, PlayerID owner, uint32 index, uint16 window_type)
    02088 {
    02089   uint n = 0;
    02090   const Vehicle *v;
    02091
    02092   switch (window_type) {
    02093     case VLW_STATION_LIST: {
    02094       FOR_ALL_VEHICLES(v) {
    02095         if (v->type == type && v->IsPrimaryVehicle()) {
    02096           const Order *order;
    02097
    02098           FOR_VEHICLE_ORDERS(v, order) {
    02099             if (order->type == OT_GOTO_STATION && order->dest == index) {
    02100               if (n == *length_of_array) ExtendVehicleListSize(sort_list, length_of_array, 50);
    02101               (*sort_list)[n++] = v;
    02102               break;
    02103             }
    02104           }
    02105         }
    02106       }
    02107       break;
    02108     }
    02109
    02110     case VLW_SHARED_ORDERS: {
    02111       FOR_ALL_VEHICLES(v) {
    02112         /* Find a vehicle with the order in question */
    02113         if (v->orders != NULL && v->orders->index == index) break;
    02114       }
    02115
    02116       if (v != NULL && v->orders != NULL && v->orders->index == index) {
    02117         /* Only try to make the list if we found a vehicle using the order in question */
    02118         for (v = GetFirstVehicleFromSharedList(v); v != NULL; v = v->next_shared) {
    02119           if (n == *length_of_array) ExtendVehicleListSize(sort_list, length_of_array, 25);
    02120           (*sort_list)[n++] = v;
    02121         }
    02122       }
    02123       break;
    02124     }
    02125
    02126     case VLW_STANDARD: {
    02127       FOR_ALL_VEHICLES(v) {
    02128         if (v->type == type && v->owner == owner && v->IsPrimaryVehicle()) {
    02129           /* TODO find a better estimate on the total number of vehicles for current player */
    02130           if (n == *length_of_array) ExtendVehicleListSize(sort_list, length_of_array, GetNumVehicles()/4);
    02131           (*sort_list)[n++] = v;
    02132         }
    02133       }
    02134       break;
    02135     }
    02136
    02137     case VLW_DEPOT_LIST: {
    02138       FOR_ALL_VEHICLES(v) {
    02139         if (v->type == type && v->IsPrimaryVehicle()) {
    02140           const Order *order;
    02141
    02142           FOR_VEHICLE_ORDERS(v, order) {
    02143             if (order->type == OT_GOTO_DEPOT && order->dest == index) {
    02144               if (n == *length_of_array) ExtendVehicleListSize(sort_list, length_of_array, 25);
    02145               (*sort_list)[n++] = v;
    02146               break;
    02147             }
    02148           }
    02149         }
    02150       }
    02151       break;
    02152     }
    02153
    02154     case VLW_GROUP_LIST:
    02155       FOR_ALL_VEHICLES(v) {
    02156         if (v->type == type && v->IsPrimaryVehicle() &&
    02157             v->owner == owner && v->group_id == index) {
    02158           if (n == *length_of_array) ExtendVehicleListSize(sort_list, length_of_array, GetNumVehicles() / 4);
    02159
    02160           (*sort_list)[n++] = v;
    02161         }
    02162       }
    02163       break;
    02164
    02165     default: NOT_REACHED(); break;
    02166   }
    02167
    02168   if ((n + 100) < *length_of_array) {
    02169     /* We allocated way too much for sort_list.
    02170      * Now we will reduce how much we allocated.
    02171      * We will still make it have room for 50 extra vehicles to prevent having
    02172      * to move the whole array if just one vehicle is added later */
    02173     *length_of_array = n + 50;
    02174     *sort_list = ReallocT(*sort_list, (*length_of_array) * sizeof((*sort_list)[0]));
    02175   }
    02176
    02177   return n;
    02178 }
    02179
    02188 CommandCost SendAllVehiclesToDepot(VehicleType type, uint32 flags, bool service, PlayerID owner, uint16 vlw_flag, uint32 id)
    02189 {
    02190   const Vehicle **sort_list = NULL;
    02191   uint n, i;
    02192   uint16 array_length = 0;
    02193
    02194   n = GenerateVehicleSortList(&sort_list, &array_length, type, owner, id, vlw_flag);
    02195
    02196   /* Send all the vehicles to a depot */
    02197   for (i = 0; i < n; i++) {
    02198     const Vehicle *v = sort_list[i];
    02199     CommandCost ret = DoCommand(v->tile, v->index, (service ? 1 : 0) | DEPOT_DONT_CANCEL, flags, GetCmdSendToDepot(type));
    02200
    02201     /* Return 0 if DC_EXEC is not set this is a valid goto depot command)
    02202       * In this case we know that at least one vehicle can be sent to a depot
    02203       * and we will issue the command. We can now safely quit the loop, knowing
    02204       * it will succeed at least once. With DC_EXEC we really need to send them to the depot */
    02205     if (CmdSucceeded(ret) && !(flags & DC_EXEC)) {
    02206       free((void*)sort_list);
    02207       return CommandCost();
    02208     }
    02209   }
    02210
    02211   free((void*)sort_list);
    02212   return (flags & DC_EXEC) ? CommandCost() : CMD_ERROR;
    02213 }
    02214
    02221 uint8 CalcPercentVehicleFilled(Vehicle *v, StringID *color)
    02222 {
    02223   int count = 0;
    02224   int max = 0;
    02225   int cars = 0;
    02226   int unloading = 0;
    02227   bool loading = false;
    02228
    02229   assert(color != NULL);
    02230
    02231   const Vehicle *u = v;
    02232   const Station *st = GetStation(v->last_station_visited);
    02233
    02234   /* Count up max and used */
    02235   for (; v != NULL; v = v->Next()) {
    02236     count += v->cargo.Count();
    02237     max += v->cargo_cap;
    02238     if (v->cargo_cap != 0) {
    02239       unloading += HasBit(v->vehicle_flags, VF_CARGO_UNLOADING) ? 1 : 0;
    02240       loading |= (u->current_order.flags & OFB_UNLOAD) == 0 && st->goods[v->cargo_type].days_since_pickup != 255;
    02241       cars++;
    02242     }
    02243   }
    02244
    02245   if (unloading == 0 && loading)          *color = STR_PERCENT_UP;
    02246   else if (cars == unloading || !loading) *color = STR_PERCENT_DOWN;
    02247   else                                    *color = STR_PERCENT_UP_DOWN;
    02248
    02249   /* Train without capacity */
    02250   if (max == 0) return 100;
    02251
    02252   /* Return the percentage */
    02253   return (count * 100) / max;
    02254 }
    02255
    02256 void VehicleEnterDepot(Vehicle *v)
    02257 {
    02258   switch (v->type) {
    02259     case VEH_TRAIN:
    02260       InvalidateWindowClasses(WC_TRAINS_LIST);
    02261       if (!IsFrontEngine(v)) v = v->First();
    02262       UpdateSignalsOnSegment(v->tile, INVALID_DIAGDIR, v->owner);
    02263       v->load_unload_time_rem = 0;
    02264       /* Reset reversed flag */
    02265       for (Vehicle *u = v; u != NULL; u = u->Next()) ClrBit(u->u.rail.flags, VRF_TOGGLE_REVERSE);
    02266       TrainConsistChanged(v, true);
    02267       break;
    02268
    02269     case VEH_ROAD:
    02270       InvalidateWindowClasses(WC_ROADVEH_LIST);
    02271       if (!IsRoadVehFront(v)) v = v->First();
    02272       break;
    02273
    02274     case VEH_SHIP:
    02275       InvalidateWindowClasses(WC_SHIPS_LIST);
    02276       v->u.ship.state = TRACK_BIT_DEPOT;
    02277       RecalcShipStuff(v);
    02278       break;
    02279
    02280     case VEH_AIRCRAFT:
    02281       InvalidateWindowClasses(WC_AIRCRAFT_LIST);
    02282       HandleAircraftEnterHangar(v);
    02283       break;
    02284     default: NOT_REACHED();
    02285   }
    02286
    02287   if (v->type != VEH_TRAIN) {
    02288     /* Trains update the vehicle list when the first unit enters the depot and calls VehicleEnterDepot() when the last unit enters.
    02289      * 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 */
    02290     InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
    02291   }
    02292   InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
    02293
    02294   v->vehstatus |= VS_HIDDEN;
    02295   v->cur_speed = 0;
    02296
    02297   VehicleServiceInDepot(v);
    02298
    02299   TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);
    02300
    02301   if (v->current_order.type == OT_GOTO_DEPOT) {
    02302     Order t;
    02303
    02304     InvalidateWindow(WC_VEHICLE_VIEW, v->index);
    02305
    02306     t = v->current_order;
    02307     v->current_order.type = OT_DUMMY;
    02308     v->current_order.flags = 0;
    02309
    02310     if (t.refit_cargo < NUM_CARGO) {
    02311       CommandCost cost;
    02312
    02313       _current_player = v->owner;
    02314       cost = DoCommand(v->tile, v->index, t.refit_cargo | t.refit_subtype << 8, DC_EXEC, GetCmdRefitVeh(v));
    02315
    02316       if (CmdFailed(cost)) {
    02317         v->leave_depot_instantly = false; // We ensure that the vehicle stays in the depot
    02318         if (v->owner == _local_player) {
    02319           /* Notify the user that we stopped the vehicle */
    02320           SetDParam(0, _vehicle_type_names[v->type]);
    02321           SetDParam(1, v->unitnumber);
    02322           AddNewsItem(STR_ORDER_REFIT_FAILED, NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0), v->index, 0);
    02323         }
    02324       } else if (v->owner == _local_player && cost.GetCost() != 0) {
    02325         ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost.GetCost());
    02326       }
    02327     }
    02328
    02329     if (HasBit(t.flags, OF_PART_OF_ORDERS)) {
    02330       /* Part of orders */
    02331       UpdateVehicleTimetable(v, true);
    02332       v->cur_order_index++;
    02333     } else if (HasBit(t.flags, OF_HALT_IN_DEPOT)) {
    02334       /* Force depot visit */
    02335       v->vehstatus |= VS_STOPPED;
    02336       if (v->owner == _local_player) {
    02337         StringID string;
    02338
    02339         switch (v->type) {
    02340           case VEH_TRAIN:    string = STR_8814_TRAIN_IS_WAITING_IN_DEPOT; break;
    02341           case VEH_ROAD:     string = STR_9016_ROAD_VEHICLE_IS_WAITING;   break;
    02342           case VEH_SHIP:     string = STR_981C_SHIP_IS_WAITING_IN_DEPOT;  break;
    02343           case VEH_AIRCRAFT: string = STR_A014_AIRCRAFT_IS_WAITING_IN;    break;
    02344           default: NOT_REACHED(); string = STR_EMPTY; // Set the string to something to avoid a compiler warning
    02345         }
    02346
    02347         SetDParam(0, v->unitnumber);
    02348         AddNewsItem(string, NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0), v->index, 0);
    02349       }
    02350     }
    02351   }
    02352 }
    02353
    02354 static bool IsUniqueVehicleName(const char *name)
    02355 {
    02356   const Vehicle *v;
    02357   char buf[512];
    02358
    02359   FOR_ALL_VEHICLES(v) {
    02360     switch (v->type) {
    02361       case VEH_TRAIN:
    02362         if (!IsTrainEngine(v)) continue;
    02363         break;
    02364
    02365       case VEH_ROAD:
    02366         if (!IsRoadVehFront(v)) continue;
    02367         break;
    02368
    02369       case VEH_AIRCRAFT:
    02370         if (!IsNormalAircraft(v)) continue;
    02371         break;
    02372
    02373       case VEH_SHIP:
    02374         break;
    02375
    02376       default:
    02377         continue;
    02378     }
    02379
    02380     SetDParam(0, v->index);
    02381     GetString(buf, STR_VEHICLE_NAME, lastof(buf));
    02382     if (strcmp(buf, name) == 0) return false;
    02383   }
    02384
    02385   return true;
    02386 }
    02387
    02394 CommandCost CmdNameVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
    02395 {
    02396   Vehicle *v;
    02397
    02398   if (!IsValidVehicleID(p1) || StrEmpty(_cmd_text)) return CMD_ERROR;
    02399
    02400   v = GetVehicle(p1);
    02401
    02402   if (!CheckOwnership(v->owner)) return CMD_ERROR;
    02403
    02404   if (!IsUniqueVehicleName(_cmd_text)) return_cmd_error(STR_NAME_MUST_BE_UNIQUE);
    02405
    02406   if (flags & DC_EXEC) {
    02407     free(v->name);
    02408     v->name = strdup(_cmd_text);
    02409     ResortVehicleLists();
    02410     MarkWholeScreenDirty();
    02411   }
    02412
    02413   return CommandCost();
    02414 }
    02415
    02416
    02423 CommandCost CmdChangeServiceInt(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
    02424 {
    02425   Vehicle* v;
    02426   uint16 serv_int = GetServiceIntervalClamped(p2); /* Double check the service interval from the user-input */
    02427
    02428   if (serv_int != p2 || !IsValidVehicleID(p1)) return CMD_ERROR;
    02429
    02430   v = GetVehicle(p1);
    02431
    02432   if (!CheckOwnership(v->owner)) return CMD_ERROR;
    02433
    02434   if (flags & DC_EXEC) {
    02435     v->service_interval = serv_int;
    02436     InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
    02437   }
    02438
    02439   return CommandCost();
    02440 }
    02441
    02442
    02443 static Rect _old_vehicle_coords;
    02444
    02451 void BeginVehicleMove(const Vehicle *v)
    02452 {
    02453   _old_vehicle_coords.left   = v->left_coord;
    02454   _old_vehicle_coords.top    = v->top_coord;
    02455   _old_vehicle_coords.right  = v->right_coord;
    02456   _old_vehicle_coords.bottom = v->bottom_coord;
    02457 }
    02458
    02465 void EndVehicleMove(const Vehicle *v)
    02466 {
    02467   MarkAllViewportsDirty(
    02468     min(_old_vehicle_coords.left,   v->left_coord),
    02469     min(_old_vehicle_coords.top,    v->top_coord),
    02470     max(_old_vehicle_coords.right,  v->right_coord) + 1,
    02471     max(_old_vehicle_coords.bottom, v->bottom_coord) + 1
    02472   );
    02473 }
    02474
    02483 void MarkSingleVehicleDirty(const Vehicle *v)
    02484 {
    02485   MarkAllViewportsDirty(v->left_coord, v->top_coord, v->right_coord + 1, v->bottom_coord + 1);
    02486 }
    02487
    02488 /* returns true if staying in the same tile */
    02489 GetNewVehiclePosResult GetNewVehiclePos(const Vehicle *v)
    02490 {
    02491   static const int8 _delta_coord[16] = {
    02492     -1,-1,-1, 0, 1, 1, 1, 0, /* x */
    02493     -1, 0, 1, 1, 1, 0,-1,-1, /* y */
    02494   };
    02495
    02496   int x = v->x_pos + _delta_coord[v->direction];
    02497   int y = v->y_pos + _delta_coord[v->direction + 8];
    02498
    02499   GetNewVehiclePosResult gp;
    02500   gp.x = x;
    02501   gp.y = y;
    02502   gp.old_tile = v->tile;
    02503   gp.new_tile = TileVirtXY(x, y);
    02504   return gp;
    02505 }
    02506
    02507 static const Direction _new_direction_table[] = {
    02508   DIR_N , DIR_NW, DIR_W ,
    02509   DIR_NE, DIR_SE, DIR_SW,
    02510   DIR_E , DIR_SE, DIR_S
    02511 };
    02512
    02513 Direction GetDirectionTowards(const Vehicle* v, int x, int y)
    02514 {
    02515   Direction dir;
    02516   DirDiff dirdiff;
    02517   int i = 0;
    02518
    02519   if (y >= v->y_pos) {
    02520     if (y != v->y_pos) i+=3;
    02521     i+=3;
    02522   }
    02523
    02524   if (x >= v->x_pos) {
    02525     if (x != v->x_pos) i++;
    02526     i++;
    02527   }
    02528
    02529   dir = v->direction;
    02530
    02531   dirdiff = DirDifference(_new_direction_table[i], dir);
    02532   if (dirdiff == DIRDIFF_SAME) return dir;
    02533   return ChangeDir(dir, dirdiff > DIRDIFF_REVERSE ? DIRDIFF_45LEFT : DIRDIFF_45RIGHT);
    02534 }
    02535
    02536 Trackdir GetVehicleTrackdir(const Vehicle* v)
    02537 {
    02538   if (v->vehstatus & VS_CRASHED) return INVALID_TRACKDIR;
    02539
    02540   switch (v->type) {
    02541     case VEH_TRAIN:
    02542       if (v->u.rail.track == TRACK_BIT_DEPOT) // We'll assume the train is facing outwards
    02543         return DiagdirToDiagTrackdir(GetRailDepotDirection(v->tile)); // Train in depot
    02544
    02545       if (v->u.rail.track == TRACK_BIT_WORMHOLE) // train in tunnel, so just use his direction and assume a diagonal track
    02546         return DiagdirToDiagTrackdir(DirToDiagDir(v->direction));
    02547
    02548       return TrackDirectionToTrackdir(FindFirstTrack(v->u.rail.track), v->direction);
    02549
    02550     case VEH_SHIP:
    02551       if (v->IsInDepot())
    02552         // We'll assume the ship is facing outwards
    02553         return DiagdirToDiagTrackdir(GetShipDepotDirection(v->tile));
    02554
    02555       return TrackDirectionToTrackdir(FindFirstTrack(v->u.ship.state), v->direction);
    02556
    02557     case VEH_ROAD:
    02558       if (v->IsInDepot()) // We'll assume the road vehicle is facing outwards
    02559         return DiagdirToDiagTrackdir(GetRoadDepotDirection(v->tile));
    02560
    02561       if (IsStandardRoadStopTile(v->tile)) // We'll assume the road vehicle is facing outwards
    02562         return DiagdirToDiagTrackdir(GetRoadStopDir(v->tile)); // Road vehicle in a station
    02563
    02564       if (IsDriveThroughStopTile(v->tile)) return DiagdirToDiagTrackdir(DirToDiagDir(v->direction));
    02565
    02566       /* If vehicle's state is a valid track direction (vehicle is not turning around) return it */
    02567       if (!IsReversingRoadTrackdir((Trackdir)v->u.road.state)) return (Trackdir)v->u.road.state;
    02568
    02569       /* Vehicle is turning around, get the direction from vehicle's direction */
    02570       return DiagdirToDiagTrackdir(DirToDiagDir(v->direction));
    02571
    02572     /* case VEH_AIRCRAFT: case VEH_SPECIAL: case VEH_DISASTER: */
    02573     default: return INVALID_TRACKDIR;
    02574   }
    02575 }
    02576
    02581 uint32 VehicleEnterTile(Vehicle *v, TileIndex tile, int x, int y)
    02582 {
    02583   return _tile_type_procs[GetTileType(tile)]->vehicle_enter_tile_proc(v, tile, x, y);
    02584 }
    02585
    02586 UnitID GetFreeUnitNumber(VehicleType type)
    02587 {
    02588   UnitID unit, max = 0;
    02589   const Vehicle *u;
    02590   static bool *cache = NULL;
    02591   static UnitID gmax = 0;
    02592
    02593   switch (type) {
    02594     case VEH_TRAIN:    max = _patches.max_trains; break;
    02595     case VEH_ROAD:     max = _patches.max_roadveh; break;
    02596     case VEH_SHIP:     max = _patches.max_ships; break;
    02597     case VEH_AIRCRAFT: max = _patches.max_aircraft; break;
    02598     default: NOT_REACHED();
    02599   }
    02600
    02601   if (max == 0) {
    02602     /* we can't build any of this kind of vehicle, so we just return 1 instead of looking for a free number
    02603      * a max of 0 will cause the following code to write to a NULL pointer
    02604      * We know that 1 is bigger than the max allowed vehicle number, so it's the same as returning something, that is too big
    02605      */
    02606     return 1;
    02607   }
    02608
    02609   if (max > gmax) {
    02610     gmax = max;
    02611     free(cache);
    02612     cache = MallocT<bool>(max + 1);
    02613   }
    02614
    02615   /* Clear the cache */
    02616   memset(cache, 0, (max + 1) * sizeof(*cache));
    02617
    02618   /* Fill the cache */
    02619   FOR_ALL_VEHICLES(u) {
    02620     if (u->type == type && u->owner == _current_player && u->unitnumber != 0 && u->unitnumber <= max)
    02621       cache[u->unitnumber] = true;
    02622   }
    02623
    02624   /* Find the first unused unit number */
    02625   for (unit = 1; unit <= max; unit++) {
    02626     if (!cache[unit]) break;
    02627   }
    02628
    02629   return unit;
    02630 }
    02631
    02632
    02641 bool CanBuildVehicleInfrastructure(VehicleType type)
    02642 {
    02643   assert(IsPlayerBuildableVehicleType(type));
    02644
    02645   if (!IsValidPlayer(_current_player)) return false;
    02646   if (_patches.always_build_infrastructure) return true;
    02647
    02648   UnitID max;
    02649   switch (type) {
    02650     case VEH_TRAIN:    max = _patches.max_trains; break;
    02651     case VEH_ROAD:     max = _patches.max_roadveh; break;
    02652     case VEH_SHIP:     max = _patches.max_ships; break;
    02653     case VEH_AIRCRAFT: max = _patches.max_aircraft; break;
    02654     default: NOT_REACHED();
    02655   }
    02656
    02657   /* We can build vehicle infrastructure when we may build the vehicle type */
    02658   if (max > 0) {
    02659
    02660     /* Can we actually build the vehicle type? */
    02661     EngineID e;
    02662     FOR_ALL_ENGINEIDS_OF_TYPE(e, type) {
    02663       if (HasBit(GetEngine(e)->player_avail, _local_player)) return true;
    02664     }
    02665     return false;
    02666   }
    02667
    02668   /* We should be able to build infrastructure when we have the actual vehicle type */
    02669   const Vehicle *v;
    02670   FOR_ALL_VEHICLES(v) {
    02671     if (v->owner == _local_player && v->type == type) return true;
    02672   }
    02673
    02674   return false;
    02675 }
    02676
    02677
    02678 const Livery *GetEngineLivery(EngineID engine_type, PlayerID player, EngineID parent_engine_type, const Vehicle *v)
    02679 {
    02680   const Player *p = GetPlayer(player);
    02681   LiveryScheme scheme = LS_DEFAULT;
    02682   CargoID cargo_type = v == NULL ? (CargoID)CT_INVALID : v->cargo_type;
    02683
    02684   /* The default livery is always available for use, but its in_use flag determines
    02685    * whether any _other_ liveries are in use. */
    02686   if (p->livery[LS_DEFAULT].in_use && (_patches.liveries == 2 || (_patches.liveries == 1 && player == _local_player))) {
    02687     /* Determine the livery scheme to use */
    02688     switch (GetEngine(engine_type)->type) {
    02689       default: NOT_REACHED();
    02690       case VEH_TRAIN: {
    02691         const RailVehicleInfo *rvi = RailVehInfo(engine_type);
    02692
    02693         if (cargo_type == CT_INVALID) cargo_type = rvi->cargo_type;
    02694         if (rvi->railveh_type == RAILVEH_WAGON) {
    02695           if (!GetCargo(cargo_type)->is_freight) {
    02696             if (parent_engine_type == INVALID_ENGINE) {
    02697               scheme = LS_PASSENGER_WAGON_STEAM;
    02698             } else {
    02699               switch (RailVehInfo(parent_engine_type)->engclass) {
    02700                 default: NOT_REACHED();
    02701                 case EC_STEAM:    scheme = LS_PASSENGER_WAGON_STEAM;    break;
    02702                 case EC_DIESEL:   scheme = LS_PASSENGER_WAGON_DIESEL;   break;
    02703                 case EC_ELECTRIC: scheme = LS_PASSENGER_WAGON_ELECTRIC; break;
    02704                 case EC_MONORAIL: scheme = LS_PASSENGER_WAGON_MONORAIL; break;
    02705                 case EC_MAGLEV:   scheme = LS_PASSENGER_WAGON_MAGLEV;   break;
    02706               }
    02707             }
    02708           } else {
    02709             scheme = LS_FREIGHT_WAGON;
    02710           }
    02711         } else {
    02712           bool is_mu = HasBit(EngInfo(engine_type)->misc_flags, EF_RAIL_IS_MU);
    02713
    02714           switch (rvi->engclass) {
    02715             default: NOT_REACHED();
    02716             case EC_STEAM:    scheme = LS_STEAM; break;
    02717             case EC_DIESEL:   scheme = is_mu ? LS_DMU : LS_DIESEL;   break;
    02718             case EC_ELECTRIC: scheme = is_mu ? LS_EMU : LS_ELECTRIC; break;
    02719             case EC_MONORAIL: scheme = LS_MONORAIL; break;
    02720             case EC_MAGLEV:   scheme = LS_MAGLEV; break;
    02721           }
    02722         }
    02723         break;
    02724       }
    02725
    02726       case VEH_ROAD: {
    02727         const RoadVehicleInfo *rvi = RoadVehInfo(engine_type);
    02728         if (cargo_type == CT_INVALID) cargo_type = rvi->cargo_type;
    02729         if (HasBit(EngInfo(engine_type)->misc_flags, EF_ROAD_TRAM)) {
    02730           /* Tram */
    02731           scheme = IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_TRAM : LS_FREIGHT_TRAM;
    02732         } else {
    02733           /* Bus or truck */
    02734           scheme = IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_BUS : LS_TRUCK;
    02735         }
    02736         break;
    02737       }
    02738
    02739       case VEH_SHIP: {
    02740         const ShipVehicleInfo *svi = ShipVehInfo(engine_type);
    02741         if (cargo_type == CT_INVALID) cargo_type = svi->cargo_type;
    02742         scheme = IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_SHIP : LS_FREIGHT_SHIP;
    02743         break;
    02744       }
    02745
    02746       case VEH_AIRCRAFT: {
    02747         const AircraftVehicleInfo *avi = AircraftVehInfo(engine_type);
    02748         if (cargo_type == CT_INVALID) cargo_type = CT_PASSENGERS;
    02749         switch (avi->subtype) {
    02750           case AIR_HELI: scheme = LS_HELICOPTER; break;
    02751           case AIR_CTOL: scheme = LS_SMALL_PLANE; break;
    02752           case AIR_CTOL | AIR_FAST: scheme = LS_LARGE_PLANE; break;
    02753         }
    02754         break;
    02755       }
    02756     }
    02757
    02758     /* Switch back to the default scheme if the resolved scheme is not in use */
    02759     if (!p->livery[scheme].in_use) scheme = LS_DEFAULT;
    02760   }
    02761
    02762   return &p->livery[scheme];
    02763 }
    02764
    02765
    02766 static SpriteID GetEngineColourMap(EngineID engine_type, PlayerID player, EngineID parent_engine_type, const Vehicle *v)
    02767 {
    02768   SpriteID map = (v != NULL) ? v->colormap : PAL_NONE;
    02769
    02770   /* Return cached value if any */
    02771   if (map != PAL_NONE) return map;
    02772
    02773   /* Check if we should use the colour map callback */
    02774   if (HasBit(EngInfo(engine_type)->callbackmask, CBM_VEHICLE_COLOUR_REMAP)) {
    02775     uint16 callback = GetVehicleCallback(CBID_VEHICLE_COLOUR_MAPPING, 0, 0, engine_type, v);
    02776     /* A return value of 0xC000 is stated to "use the default two-color
    02777      * maps" which happens to be the failure action too... */
    02778     if (callback != CALLBACK_FAILED && callback != 0xC000) {
    02779       map = GB(callback, 0, 14);
    02780       /* If bit 14 is set, then the company colours are applied to the
    02781        * map else it's returned as-is. */
    02782       if (!HasBit(callback, 14)) {
    02783         /* Update cache */
    02784         if (v != NULL) ((Vehicle*)v)->colormap = map;
    02785         return map;
    02786       }
    02787     }
    02788   }
    02789
    02790   bool twocc = HasBit(EngInfo(engine_type)->misc_flags, EF_USES_2CC);
    02791
    02792   if (map == PAL_NONE) map = twocc ? (SpriteID)SPR_2CCMAP_BASE : (SpriteID)PALETTE_RECOLOR_START;
    02793
    02794   const Livery *livery = GetEngineLivery(engine_type, player, parent_engine_type, v);
    02795
    02796   map += livery->colour1;
    02797   if (twocc) map += livery->colour2 * 16;
    02798
    02799   /* Update cache */
    02800   if (v != NULL) ((Vehicle*)v)->colormap = map;
    02801   return map;
    02802 }
    02803
    02804 SpriteID GetEnginePalette(EngineID engine_type, PlayerID player)
    02805 {
    02806   return GetEngineColourMap(engine_type, player, INVALID_ENGINE, NULL);
    02807 }
    02808
    02809 SpriteID GetVehiclePalette(const Vehicle *v)
    02810 {
    02811   if (v->type == VEH_TRAIN) {
    02812     return GetEngineColourMap(
    02813       (v->u.rail.first_engine != INVALID_ENGINE && (UsesWagonOverride(v) || (IsArticulatedPart(v) && RailVehInfo(v->engine_type)->railveh_type != RAILVEH_WAGON))) ?
    02814         v->u.rail.first_engine : v->engine_type,
    02815       v->owner, v->u.rail.first_engine, v);
    02816   }
    02817
    02818   return GetEngineColourMap(v->engine_type, v->owner, INVALID_ENGINE, v);
    02819 }
    02820
    02821 static uint8  _cargo_days;
    02822 static uint16 _cargo_source;
    02823 static uint32 _cargo_source_xy;
    02824 static uint16 _cargo_count;
    02825 static uint16 _cargo_paid_for;
    02826 static Money  _cargo_feeder_share;
    02827 static uint32 _cargo_loaded_at_xy;
    02828
    02834 const SaveLoad *GetVehicleDescription(VehicleType vt)
    02835 {
    02837 static const SaveLoad _common_veh_desc[] = {
    02838       SLE_VAR(Vehicle, subtype,              SLE_UINT8),
    02839
    02840       SLE_REF(Vehicle, next,                 REF_VEHICLE_OLD),
    02841   SLE_CONDVAR(Vehicle, name,                 SLE_NAME,                    0, 83),
    02842   SLE_CONDSTR(Vehicle, name,                 SLE_STR, 0,                 84, SL_MAX_VERSION),
    02843   SLE_CONDVAR(Vehicle, unitnumber,           SLE_FILE_U8  | SLE_VAR_U16,  0, 7),
    02844   SLE_CONDVAR(Vehicle, unitnumber,           SLE_UINT16,                  8, SL_MAX_VERSION),
    02845       SLE_VAR(Vehicle, owner,                SLE_UINT8),
    02846   SLE_CONDVAR(Vehicle, tile,                 SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
    02847   SLE_CONDVAR(Vehicle, tile,                 SLE_UINT32,                  6, SL_MAX_VERSION),
    02848   SLE_CONDVAR(Vehicle, dest_tile,            SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
    02849   SLE_CONDVAR(Vehicle, dest_tile,            SLE_UINT32,                  6, SL_MAX_VERSION),
    02850
    02851   SLE_CONDVAR(Vehicle, x_pos,                SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
    02852   SLE_CONDVAR(Vehicle, x_pos,                SLE_UINT32,                  6, SL_MAX_VERSION),
    02853   SLE_CONDVAR(Vehicle, y_pos,                SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
    02854   SLE_CONDVAR(Vehicle, y_pos,                SLE_UINT32,                  6, SL_MAX_VERSION),
    02855       SLE_VAR(Vehicle, z_pos,                SLE_UINT8),
    02856       SLE_VAR(Vehicle, direction,            SLE_UINT8),
    02857
    02858   SLE_CONDNULL(2,                                                         0, 57),
    02859       SLE_VAR(Vehicle, spritenum,            SLE_UINT8),
    02860   SLE_CONDNULL(5,                                                         0, 57),
    02861       SLE_VAR(Vehicle, engine_type,          SLE_UINT16),
    02862
    02863       SLE_VAR(Vehicle, max_speed,            SLE_UINT16),
    02864       SLE_VAR(Vehicle, cur_speed,            SLE_UINT16),
    02865       SLE_VAR(Vehicle, subspeed,             SLE_UINT8),
    02866       SLE_VAR(Vehicle, acceleration,         SLE_UINT8),
    02867       SLE_VAR(Vehicle, progress,             SLE_UINT8),
    02868
    02869       SLE_VAR(Vehicle, vehstatus,            SLE_UINT8),
    02870   SLE_CONDVAR(Vehicle, last_station_visited, SLE_FILE_U8  | SLE_VAR_U16,  0, 4),
    02871   SLE_CONDVAR(Vehicle, last_station_visited, SLE_UINT16,                  5, SL_MAX_VERSION),
    02872
    02873        SLE_VAR(Vehicle, cargo_type,           SLE_UINT8),
    02874    SLE_CONDVAR(Vehicle, cargo_subtype,        SLE_UINT8,                  35, SL_MAX_VERSION),
    02875   SLEG_CONDVAR(         _cargo_days,          SLE_UINT8,                   0, 67),
    02876   SLEG_CONDVAR(         _cargo_source,        SLE_FILE_U8  | SLE_VAR_U16,  0, 6),
    02877   SLEG_CONDVAR(         _cargo_source,        SLE_UINT16,                  7, 67),
    02878   SLEG_CONDVAR(         _cargo_source_xy,     SLE_UINT32,                 44, 67),
    02879        SLE_VAR(Vehicle, cargo_cap,            SLE_UINT16),
    02880   SLEG_CONDVAR(         _cargo_count,         SLE_UINT16,                  0, 67),
    02881    SLE_CONDLST(Vehicle, cargo,                REF_CARGO_PACKET,           68, SL_MAX_VERSION),
    02882
    02883       SLE_VAR(Vehicle, day_counter,          SLE_UINT8),
    02884       SLE_VAR(Vehicle, tick_counter,         SLE_UINT8),
    02885   SLE_CONDVAR(Vehicle, running_ticks,        SLE_UINT8,                   88, SL_MAX_VERSION),
    02886
    02887       SLE_VAR(Vehicle, cur_order_index,      SLE_UINT8),
    02888       SLE_VAR(Vehicle, num_orders,           SLE_UINT8),
    02889
    02890   /* This next line is for version 4 and prior compatibility.. it temporarily reads
    02891       type and flags (which were both 4 bits) into type. Later on this is
    02892       converted correctly */
    02893   SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, type), SLE_UINT8,                 0, 4),
    02894   SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, dest), SLE_FILE_U8 | SLE_VAR_U16, 0, 4),
    02895
    02896   /* Orders for version 5 and on */
    02897   SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, type),  SLE_UINT8,  5, SL_MAX_VERSION),
    02898   SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, flags), SLE_UINT8,  5, SL_MAX_VERSION),
    02899   SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, dest),  SLE_UINT16, 5, SL_MAX_VERSION),
    02900
    02901   /* Refit in current order */
    02902   SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, refit_cargo),    SLE_UINT8, 36, SL_MAX_VERSION),
    02903   SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, refit_subtype),  SLE_UINT8, 36, SL_MAX_VERSION),
    02904
    02905   /* Timetable in current order */
    02906   SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, wait_time),      SLE_UINT16, 67, SL_MAX_VERSION),
    02907   SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, travel_time),    SLE_UINT16, 67, SL_MAX_VERSION),
    02908
    02909       SLE_REF(Vehicle, orders,               REF_ORDER),
    02910
    02911   SLE_CONDVAR(Vehicle, age,                  SLE_FILE_U16 | SLE_VAR_I32,  0, 30),
    02912   SLE_CONDVAR(Vehicle, age,                  SLE_INT32,                  31, SL_MAX_VERSION),
    02913   SLE_CONDVAR(Vehicle, max_age,              SLE_FILE_U16 | SLE_VAR_I32,  0, 30),
    02914   SLE_CONDVAR(Vehicle, max_age,              SLE_INT32,                  31, SL_MAX_VERSION),
    02915   SLE_CONDVAR(Vehicle, date_of_last_service, SLE_FILE_U16 | SLE_VAR_I32,  0, 30),
    02916   SLE_CONDVAR(Vehicle, date_of_last_service, SLE_INT32,                  31, SL_MAX_VERSION),
    02917   SLE_CONDVAR(Vehicle, service_interval,     SLE_FILE_U16 | SLE_VAR_I32,  0, 30),
    02918   SLE_CONDVAR(Vehicle, service_interval,     SLE_INT32,                  31, SL_MAX_VERSION),
    02919       SLE_VAR(Vehicle, reliability,          SLE_UINT16),
    02920       SLE_VAR(Vehicle, reliability_spd_dec,  SLE_UINT16),
    02921       SLE_VAR(Vehicle, breakdown_ctr,        SLE_UINT8),
    02922       SLE_VAR(Vehicle, breakdown_delay,      SLE_UINT8),
    02923       SLE_VAR(Vehicle, breakdowns_since_last_service, SLE_UINT8),
    02924       SLE_VAR(Vehicle, breakdown_chance,     SLE_UINT8),
    02925   SLE_CONDVAR(Vehicle, build_year,           SLE_FILE_U8 | SLE_VAR_I32,  0, 30),
    02926   SLE_CONDVAR(Vehicle, build_year,           SLE_INT32,                 31, SL_MAX_VERSION),
    02927
    02928        SLE_VAR(Vehicle, load_unload_time_rem, SLE_UINT16),
    02929   SLEG_CONDVAR(         _cargo_paid_for,      SLE_UINT16,                45, SL_MAX_VERSION),
    02930    SLE_CONDVAR(Vehicle, vehicle_flags,        SLE_UINT8,                 40, SL_MAX_VERSION),
    02931
    02932    SLE_CONDVAR(Vehicle, profit_this_year,     SLE_FILE_I32 | SLE_VAR_I64, 0, 64),
    02933    SLE_CONDVAR(Vehicle, profit_this_year,     SLE_INT64,                 65, SL_MAX_VERSION),
    02934    SLE_CONDVAR(Vehicle, profit_last_year,     SLE_FILE_I32 | SLE_VAR_I64, 0, 64),
    02935    SLE_CONDVAR(Vehicle, profit_last_year,     SLE_INT64,                 65, SL_MAX_VERSION),
    02936   SLEG_CONDVAR(         _cargo_feeder_share,  SLE_FILE_I32 | SLE_VAR_I64,51, 64),
    02937   SLEG_CONDVAR(         _cargo_feeder_share,  SLE_INT64,                 65, 67),
    02938   SLEG_CONDVAR(         _cargo_loaded_at_xy,  SLE_UINT32,                51, 67),
    02939    SLE_CONDVAR(Vehicle, value,                SLE_FILE_I32 | SLE_VAR_I64, 0, 64),
    02940    SLE_CONDVAR(Vehicle, value,                SLE_INT64,                 65, SL_MAX_VERSION),
    02941
    02942    SLE_CONDVAR(Vehicle, random_bits,          SLE_UINT8,                 2, SL_MAX_VERSION),
    02943    SLE_CONDVAR(Vehicle, waiting_triggers,     SLE_UINT8,                 2, SL_MAX_VERSION),
    02944
    02945    SLE_CONDREF(Vehicle, next_shared,        REF_VEHICLE,                 2, SL_MAX_VERSION),
    02946    SLE_CONDREF(Vehicle, prev_shared,        REF_VEHICLE,                 2, SL_MAX_VERSION),
    02947
    02948   SLE_CONDVAR(Vehicle, group_id,             SLE_UINT16,                60, SL_MAX_VERSION),
    02949
    02950   SLE_CONDVAR(Vehicle, current_order_time,   SLE_UINT32,                67, SL_MAX_VERSION),
    02951   SLE_CONDVAR(Vehicle, lateness_counter,     SLE_INT32,                 67, SL_MAX_VERSION),
    02952
    02953   /* reserve extra space in savegame here. (currently 10 bytes) */
    02954   SLE_CONDNULL(10,                                                       2, SL_MAX_VERSION),
    02955
    02956   SLE_END()
    02957 };
    02958
    02959
    02960 static const SaveLoad _train_desc[] = {
    02961   SLE_WRITEBYTE(Vehicle, type, VEH_TRAIN),
    02962   SLE_VEH_INCLUDEX(),
    02963       SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRail, crash_anim_pos),         SLE_UINT16),
    02964       SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRail, force_proceed),          SLE_UINT8),
    02965       SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRail, railtype),               SLE_UINT8),
    02966       SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRail, track),                  SLE_UINT8),
    02967
    02968   SLE_CONDVARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRail, flags),                  SLE_UINT8,  2, SL_MAX_VERSION),
    02969   SLE_CONDNULL(2, 2, 59),
    02970
    02971   SLE_CONDNULL(2, 2, 19),
    02972   /* reserve extra space in savegame here. (currently 11 bytes) */
    02973   SLE_CONDNULL(11, 2, SL_MAX_VERSION),
    02974
    02975   SLE_END()
    02976 };
    02977
    02978 static const SaveLoad _roadveh_desc[] = {
    02979   SLE_WRITEBYTE(Vehicle, type, VEH_ROAD),
    02980   SLE_VEH_INCLUDEX(),
    02981       SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, state),          SLE_UINT8),
    02982       SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, frame),          SLE_UINT8),
    02983       SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, blocked_ctr),    SLE_UINT16),
    02984       SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, overtaking),     SLE_UINT8),
    02985       SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, overtaking_ctr), SLE_UINT8),
    02986       SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, crashed_ctr),    SLE_UINT16),
    02987       SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, reverse_ctr),    SLE_UINT8),
    02988
    02989   SLE_CONDREFX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, slot),     REF_ROADSTOPS, 6, SL_MAX_VERSION),
    02990   SLE_CONDNULL(1,                                                                     6, SL_MAX_VERSION),
    02991   SLE_CONDVARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, slot_age), SLE_UINT8,     6, SL_MAX_VERSION),
    02992   /* reserve extra space in savegame here. (currently 16 bytes) */
    02993   SLE_CONDNULL(16,                                                                    2, SL_MAX_VERSION),
    02994
    02995   SLE_END()
    02996 };
    02997
    02998 static const SaveLoad _ship_desc[] = {
    02999   SLE_WRITEBYTE(Vehicle, type, VEH_SHIP),
    03000   SLE_VEH_INCLUDEX(),
    03001   SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleShip, state), SLE_UINT8),
    03002
    03003   /* reserve extra space in savegame here. (currently 16 bytes) */
    03004   SLE_CONDNULL(16, 2, SL_MAX_VERSION),
    03005
    03006   SLE_END()
    03007 };
    03008
    03009 static const SaveLoad _aircraft_desc[] = {
    03010   SLE_WRITEBYTE(Vehicle, type, VEH_AIRCRAFT),
    03011   SLE_VEH_INCLUDEX(),
    03012       SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleAir, crashed_counter), SLE_UINT16),
    03013       SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleAir, pos),             SLE_UINT8),
    03014
    03015   SLE_CONDVARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleAir, targetairport),   SLE_FILE_U8 | SLE_VAR_U16, 0, 4),
    03016   SLE_CONDVARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleAir, targetairport),   SLE_UINT16,                5, SL_MAX_VERSION),
    03017
    03018       SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleAir, state),           SLE_UINT8),
    03019
    03020   SLE_CONDVARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleAir, previous_pos),    SLE_UINT8,                 2, SL_MAX_VERSION),
    03021
    03022   /* reserve extra space in savegame here. (currently 15 bytes) */
    03023   SLE_CONDNULL(15,                                                                                      2, SL_MAX_VERSION),
    03024
    03025   SLE_END()
    03026 };
    03027
    03028 static const SaveLoad _special_desc[] = {
    03029   SLE_WRITEBYTE(Vehicle, type, VEH_SPECIAL),
    03030
    03031       SLE_VAR(Vehicle, subtype,       SLE_UINT8),
    03032
    03033   SLE_CONDVAR(Vehicle, tile,          SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
    03034   SLE_CONDVAR(Vehicle, tile,          SLE_UINT32,                 6, SL_MAX_VERSION),
    03035
    03036   SLE_CONDVAR(Vehicle, x_pos,         SLE_FILE_I16 | SLE_VAR_I32, 0, 5),
    03037   SLE_CONDVAR(Vehicle, x_pos,         SLE_INT32,                  6, SL_MAX_VERSION),
    03038   SLE_CONDVAR(Vehicle, y_pos,         SLE_FILE_I16 | SLE_VAR_I32, 0, 5),
    03039   SLE_CONDVAR(Vehicle, y_pos,         SLE_INT32,                  6, SL_MAX_VERSION),
    03040       SLE_VAR(Vehicle, z_pos,         SLE_UINT8),
    03041
    03042       SLE_VAR(Vehicle, cur_image,     SLE_UINT16),
    03043   SLE_CONDNULL(5,                                                 0, 57),
    03044       SLE_VAR(Vehicle, progress,      SLE_UINT8),
    03045       SLE_VAR(Vehicle, vehstatus,     SLE_UINT8),
    03046
    03047       SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleSpecial, animation_state),    SLE_UINT16),
    03048       SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleSpecial, animation_substate), SLE_UINT8),
    03049
    03050   SLE_CONDVAR(Vehicle, spritenum,     SLE_UINT8, 2, SL_MAX_VERSION),
    03051
    03052   /* reserve extra space in savegame here. (currently 15 bytes) */
    03053   SLE_CONDNULL(15, 2, SL_MAX_VERSION),
    03054
    03055   SLE_END()
    03056 };
    03057
    03058 static const SaveLoad _disaster_desc[] = {
    03059   SLE_WRITEBYTE(Vehicle, type, VEH_DISASTER),
    03060
    03061       SLE_REF(Vehicle, next,          REF_VEHICLE_OLD),
    03062
    03063       SLE_VAR(Vehicle, subtype,       SLE_UINT8),
    03064   SLE_CONDVAR(Vehicle, tile,          SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
    03065   SLE_CONDVAR(Vehicle, tile,          SLE_UINT32,                  6, SL_MAX_VERSION),
    03066   SLE_CONDVAR(Vehicle, dest_tile,     SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
    03067   SLE_CONDVAR(Vehicle, dest_tile,     SLE_UINT32,                  6, SL_MAX_VERSION),
    03068
    03069   SLE_CONDVAR(Vehicle, x_pos,         SLE_FILE_I16 | SLE_VAR_I32,  0, 5),
    03070   SLE_CONDVAR(Vehicle, x_pos,         SLE_INT32,                   6, SL_MAX_VERSION),
    03071   SLE_CONDVAR(Vehicle, y_pos,         SLE_FILE_I16 | SLE_VAR_I32,  0, 5),
    03072   SLE_CONDVAR(Vehicle, y_pos,         SLE_INT32,                   6, SL_MAX_VERSION),
    03073       SLE_VAR(Vehicle, z_pos,         SLE_UINT8),
    03074       SLE_VAR(Vehicle, direction,     SLE_UINT8),
    03075
    03076   SLE_CONDNULL(5,                                                  0, 57),
    03077       SLE_VAR(Vehicle, owner,         SLE_UINT8),
    03078       SLE_VAR(Vehicle, vehstatus,     SLE_UINT8),
    03079   SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, dest), SLE_FILE_U8 | SLE_VAR_U16, 0, 4),
    03080   SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, dest), SLE_UINT16,                5, SL_MAX_VERSION),
    03081
    03082       SLE_VAR(Vehicle, cur_image,     SLE_UINT16),
    03083   SLE_CONDVAR(Vehicle, age,           SLE_FILE_U16 | SLE_VAR_I32,  0, 30),
    03084   SLE_CONDVAR(Vehicle, age,           SLE_INT32,                  31, SL_MAX_VERSION),
    03085       SLE_VAR(Vehicle, tick_counter,  SLE_UINT8),
    03086
    03087      SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleDisaster, image_override),           SLE_UINT16),
    03088      SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleDisaster, big_ufo_destroyer_target), SLE_UINT16),
    03089
    03090   /* reserve extra space in savegame here. (currently 16 bytes) */
    03091   SLE_CONDNULL(16,                                                 2, SL_MAX_VERSION),
    03092
    03093   SLE_END()
    03094 };
    03095
    03096
    03097 static const SaveLoad *_veh_descs[] = {
    03098   _train_desc,
    03099   _roadveh_desc,
    03100   _ship_desc,
    03101   _aircraft_desc,
    03102   _special_desc,
    03103   _disaster_desc,
    03104   _common_veh_desc,
    03105 };
    03106
    03107   return _veh_descs[vt];
    03108 }
    03109
    03111 static void Save_VEHS()
    03112 {
    03113   Vehicle *v;
    03114   /* Write the vehicles */
    03115   FOR_ALL_VEHICLES(v) {
    03116     SlSetArrayIndex(v->index);
    03117     SlObject(v, GetVehicleDescription(v->type));
    03118   }
    03119 }
    03120
    03122 static void Load_VEHS()
    03123 {
    03124   int index;
    03125   Vehicle *v;
    03126
    03127   _cargo_count = 0;
    03128
    03129   while ((index = SlIterateArray()) != -1) {
    03130     Vehicle *v;
    03131     VehicleType vtype = (VehicleType)SlReadByte();
    03132
    03133     switch (vtype) {
    03134       case VEH_TRAIN:    v = new (index) Train();           break;
    03135       case VEH_ROAD:     v = new (index) RoadVehicle();     break;
    03136       case VEH_SHIP:     v = new (index) Ship();            break;
    03137       case VEH_AIRCRAFT: v = new (index) Aircraft();        break;
    03138       case VEH_SPECIAL:  v = new (index) SpecialVehicle();  break;
    03139       case VEH_DISASTER: v = new (index) DisasterVehicle(); break;
    03140       case VEH_INVALID:  v = new (index) InvalidVehicle();  break;
    03141       default: NOT_REACHED();
    03142     }
    03143
    03144     SlObject(v, GetVehicleDescription(vtype));
    03145
    03146     if (_cargo_count != 0 && IsPlayerBuildableVehicleType(v)) {
    03147       /* Don't construct the packet with station here, because that'll fail with old savegames */
    03148       CargoPacket *cp = new CargoPacket();
    03149       cp->source          = _cargo_source;
    03150       cp->source_xy       = _cargo_source_xy;
    03151       cp->count           = _cargo_count;
    03152       cp->days_in_transit = _cargo_days;
    03153       cp->feeder_share    = _cargo_feeder_share;
    03154       cp->loaded_at_xy    = _cargo_loaded_at_xy;
    03155       v->cargo.Append(cp);
    03156     }
    03157
    03158     /* Old savegames used 'last_station_visited = 0xFF' */
    03159     if (CheckSavegameVersion(5) && v->last_station_visited == 0xFF)
    03160       v->last_station_visited = INVALID_STATION;
    03161
    03162     if (CheckSavegameVersion(5)) {
    03163       /* Convert the current_order.type (which is a mix of type and flags, because
    03164        *  in those versions, they both were 4 bits big) to type and flags */
    03165       v->current_order.flags = (v->current_order.type & 0xF0) >> 4;
    03166       v->current_order.type.m_val &= 0x0F;
    03167     }
    03168
    03169     /* Advanced vehicle lists got added */
    03170     if (CheckSavegameVersion(60)) v->group_id = DEFAULT_GROUP;
    03171   }
    03172
    03173   /* Check for shared order-lists (we now use pointers for that) */
    03174   if (CheckSavegameVersionOldStyle(5, 2)) {
    03175     FOR_ALL_VEHICLES(v) {
    03176       Vehicle *u;
    03177
    03178       FOR_ALL_VEHICLES_FROM(u, v->index + 1) {
    03179         /* If a vehicle has the same orders, add the link to eachother
    03180          *  in both vehicles */
    03181         if (v->orders == u->orders) {
    03182           v->next_shared = u;
    03183           u->prev_shared = v;
    03184           break;
    03185         }
    03186       }
    03187     }
    03188   }
    03189 }
    03190
    03191 extern const ChunkHandler _veh_chunk_handlers[] = {
    03192   { 'VEHS', Save_VEHS, Load_VEHS, CH_SPARSE_ARRAY | CH_LAST},
    03193 };
    03194
    03195 void Vehicle::BeginLoading()
    03196 {
    03197   assert(IsTileType(tile, MP_STATION) || type == VEH_SHIP);
    03198
    03199   if (this->current_order.type == OT_GOTO_STATION &&
    03200       this->current_order.dest == this->last_station_visited) {
    03201     /* Arriving at the ordered station.
    03202      * Keep the load/unload flags, as we (obviously) still need them. */
    03203     this->current_order.flags &= OFB_FULL_LOAD | OFB_UNLOAD | OFB_TRANSFER;
    03204
    03205     /* Furthermore add the Non Stop flag to mark that this station
    03206      * is the actual destination of the vehicle, which is (for example)
    03207      * necessary to be known for HandleTrainLoading to determine
    03208      * whether the train is lost or not; not marking a train lost
    03209      * that arrives at random stations is bad. */
    03210     this->current_order.flags |= OFB_NON_STOP;
    03211     UpdateVehicleTimetable(this, true);
    03212   } else {
    03213     /* This is just an unordered intermediate stop */
    03214     this->current_order.flags = 0;
    03215   }
    03216
    03217   current_order.type = OT_LOADING;
    03218   GetStation(this->last_station_visited)->loading_vehicles.push_back(this);
    03219
    03220   VehiclePayment(this);
    03221
    03222   InvalidateWindow(this->GetVehicleListWindowClass(), this->owner);
    03223   InvalidateWindowWidget(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
    03224   InvalidateWindow(WC_VEHICLE_DETAILS, this->index);
    03225   InvalidateWindow(WC_STATION_VIEW, this->last_station_visited);
    03226
    03227   GetStation(this->last_station_visited)->MarkTilesDirty(true);
    03228   this->MarkDirty();
    03229 }
    03230
    03231 void Vehicle::LeaveStation()
    03232 {
    03233   assert(current_order.type == OT_LOADING);
    03234
    03235   /* Only update the timetable if the vehicle was supposed to stop here. */
    03236   if (current_order.flags & OFB_NON_STOP) UpdateVehicleTimetable(this, false);
    03237
    03238   current_order.type = OT_LEAVESTATION;
    03239   current_order.flags = 0;
    03240   GetStation(this->last_station_visited)->loading_vehicles.remove(this);
    03241
    03242   HideFillingPercent(&this->fill_percent_te_id);
    03243 }
    03244
    03245
    03246 void Vehicle::HandleLoading(bool mode)
    03247 {
    03248   switch (this->current_order.type) {
    03249     case OT_LOADING: {
    03250       uint wait_time = max(this->current_order.wait_time - this->lateness_counter, 0);
    03251
    03252       /* Not the first call for this tick, or still loading */
    03253       if (mode || !HasBit(this->vehicle_flags, VF_LOADING_FINISHED) ||
    03254           (_patches.timetabling && this->current_order_time < wait_time)) return;
    03255
    03256       this->PlayLeaveStationSound();
    03257
    03258       Order b = this->current_order;
    03259       this->LeaveStation();
    03260
    03261       /* If this was not the final order, don't remove it from the list. */
    03262       if (!(b.flags & OFB_NON_STOP)) return;
    03263       break;
    03264     }
    03265
    03266     case OT_DUMMY: break;
    03267
    03268     default: return;
    03269   }
    03270
    03271   this->cur_order_index++;
    03272   InvalidateVehicleOrder(this);
    03273 }
    03274
    03275 void Vehicle::SetNext(Vehicle *next)
    03276 {
    03277   if (this->next != NULL) {
    03278     /* We had an old next vehicle. Update the first and previous pointers */
    03279     for (Vehicle *v = this->next; v != NULL; v = v->Next()) {
    03280       v->first = this->next;
    03281     }
    03282     this->next->previous = NULL;
    03283   }
    03284
    03285   this->next = next;
    03286
    03287   if (this->next != NULL) {
    03288     /* A new next vehicle. Update the first and previous pointers */
    03289     if (this->next->previous != NULL) this->next->previous->next = NULL;
    03290     this->next->previous = this;
    03291     for (Vehicle *v = this->next; v != NULL; v = v->Next()) {
    03292       v->first = this->first;
    03293     }
    03294   }
    03295 }
    03296
    03297 void SpecialVehicle::UpdateDeltaXY(Direction direction)
    03298 {
    03299   this->x_offs        = 0;
    03300   this->y_offs        = 0;
    03301   this->sprite_width  = 1;
    03302   this->sprite_height = 1;
    03303   this->z_height      = 1;
    03304 }
    03305
    03306 void StopAllVehicles()
    03307 {
    03308   Vehicle *v;
    03309   FOR_ALL_VEHICLES(v) {
    03310     /* Code ripped from CmdStartStopTrain. Can't call it, because of
    03311      * ownership problems, so we'll duplicate some code, for now */
    03312     v->vehstatus |= VS_STOPPED;
    03313     InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
    03314     InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
    03315   }
    03316 }