train_cmd.cpp

Go to the documentation of this file.
00001 /* $Id: train_cmd.cpp 18478 2009-12-13 00:33:00Z rubidium $ */
00002 
00005 #include "stdafx.h"
00006 #include "gui.h"
00007 #include "articulated_vehicles.h"
00008 #include "command_func.h"
00009 #include "npf.h"
00010 #include "news_func.h"
00011 #include "engine_func.h"
00012 #include "engine_base.h"
00013 #include "company_func.h"
00014 #include "depot_base.h"
00015 #include "vehicle_gui.h"
00016 #include "train.h"
00017 #include "newgrf_engine.h"
00018 #include "newgrf_sound.h"
00019 #include "newgrf_text.h"
00020 #include "yapf/follow_track.hpp"
00021 #include "group.h"
00022 #include "table/sprites.h"
00023 #include "strings_func.h"
00024 #include "functions.h"
00025 #include "window_func.h"
00026 #include "vehicle_func.h"
00027 #include "sound_func.h"
00028 #include "variables.h"
00029 #include "autoreplace_gui.h"
00030 #include "gfx_func.h"
00031 #include "ai/ai.hpp"
00032 #include "newgrf_station.h"
00033 #include "effectvehicle_func.h"
00034 #include "gamelog.h"
00035 #include "network/network.h"
00036 
00037 #include "table/strings.h"
00038 #include "table/train_cmd.h"
00039 
00040 static Track ChooseTrainTrack(Vehicle *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool force_res, bool *got_reservation, bool mark_stuck);
00041 static bool TrainCheckIfLineEnds(Vehicle *v);
00042 static void TrainController(Vehicle *v, Vehicle *nomove);
00043 static TileIndex TrainApproachingCrossingTile(const Vehicle *v);
00044 static void CheckIfTrainNeedsService(Vehicle *v);
00045 static void CheckNextTrainTile(Vehicle *v);
00046 
00047 static const byte _vehicle_initial_x_fract[4] = {10, 8, 4,  8};
00048 static const byte _vehicle_initial_y_fract[4] = { 8, 4, 8, 10};
00049 
00050 
00058 static inline DiagDirection TrainExitDir(Direction direction, TrackBits track)
00059 {
00060   static const TrackBits state_dir_table[DIAGDIR_END] = { TRACK_BIT_RIGHT, TRACK_BIT_LOWER, TRACK_BIT_LEFT, TRACK_BIT_UPPER };
00061 
00062   DiagDirection diagdir = DirToDiagDir(direction);
00063 
00064   /* Determine the diagonal direction in which we will exit this tile */
00065   if (!HasBit(direction, 0) && track != state_dir_table[diagdir]) {
00066     diagdir = ChangeDiagDir(diagdir, DIAGDIRDIFF_90LEFT);
00067   }
00068 
00069   return diagdir;
00070 }
00071 
00072 
00077 byte FreightWagonMult(CargoID cargo)
00078 {
00079   if (!GetCargo(cargo)->is_freight) return 1;
00080   return _settings_game.vehicle.freight_trains;
00081 }
00082 
00083 
00088 void TrainPowerChanged(Vehicle *v)
00089 {
00090   uint32 total_power = 0;
00091   uint32 max_te = 0;
00092 
00093   for (const Vehicle *u = v; u != NULL; u = u->Next()) {
00094     RailType railtype = GetRailType(u->tile);
00095 
00096     /* Power is not added for articulated parts */
00097     if (!IsArticulatedPart(u)) {
00098       bool engine_has_power = HasPowerOnRail(u->u.rail.railtype, railtype);
00099 
00100       const RailVehicleInfo *rvi_u = RailVehInfo(u->engine_type);
00101 
00102       if (engine_has_power) {
00103         uint16 power = GetVehicleProperty(u, 0x0B, rvi_u->power);
00104         if (power != 0) {
00105           /* Halve power for multiheaded parts */
00106           if (IsMultiheaded(u)) power /= 2;
00107 
00108           total_power += power;
00109           /* Tractive effort in (tonnes * 1000 * 10 =) N */
00110           max_te += (u->u.rail.cached_veh_weight * 10000 * GetVehicleProperty(u, 0x1F, rvi_u->tractive_effort)) / 256;
00111         }
00112       }
00113     }
00114 
00115     if (HasBit(u->u.rail.flags, VRF_POWEREDWAGON) && HasPowerOnRail(v->u.rail.railtype, railtype)) {
00116       total_power += RailVehInfo(u->u.rail.first_engine)->pow_wag_power;
00117     }
00118   }
00119 
00120   if (v->u.rail.cached_power != total_power || v->u.rail.cached_max_te != max_te) {
00121     /* If it has no power (no catenary), stop the train */
00122     if (total_power == 0) v->vehstatus |= VS_STOPPED;
00123 
00124     v->u.rail.cached_power = total_power;
00125     v->u.rail.cached_max_te = max_te;
00126     InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
00127     InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
00128   }
00129 }
00130 
00131 
00137 static void TrainCargoChanged(Vehicle *v)
00138 {
00139   uint32 weight = 0;
00140 
00141   for (Vehicle *u = v; u != NULL; u = u->Next()) {
00142     uint32 vweight = GetCargo(u->cargo_type)->weight * u->cargo.Count() * FreightWagonMult(u->cargo_type) / 16;
00143 
00144     /* Vehicle weight is not added for articulated parts. */
00145     if (!IsArticulatedPart(u)) {
00146       /* vehicle weight is the sum of the weight of the vehicle and the weight of its cargo */
00147       vweight += GetVehicleProperty(u, 0x16, RailVehInfo(u->engine_type)->weight);
00148     }
00149 
00150     /* powered wagons have extra weight added */
00151     if (HasBit(u->u.rail.flags, VRF_POWEREDWAGON)) {
00152       vweight += RailVehInfo(u->u.rail.first_engine)->pow_wag_weight;
00153     }
00154 
00155     /* consist weight is the sum of the weight of all vehicles in the consist */
00156     weight += vweight;
00157 
00158     /* store vehicle weight in cache */
00159     u->u.rail.cached_veh_weight = vweight;
00160   }
00161 
00162   /* store consist weight in cache */
00163   v->u.rail.cached_weight = weight;
00164 
00165   /* Now update train power (tractive effort is dependent on weight) */
00166   TrainPowerChanged(v);
00167 }
00168 
00169 
00174 static void RailVehicleLengthChanged(const Vehicle *u)
00175 {
00176   /* show a warning once for each engine in whole game and once for each GRF after each game load */
00177   const Engine *engine = GetEngine(u->engine_type);
00178   uint32 grfid = engine->grffile->grfid;
00179   GRFConfig *grfconfig = GetGRFConfig(grfid);
00180   if (GamelogGRFBugReverse(grfid, engine->internal_id) || !HasBit(grfconfig->grf_bugs, GBUG_VEH_LENGTH)) {
00181     ShowNewGrfVehicleError(u->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_VEHICLE_LENGTH, GBUG_VEH_LENGTH, true);
00182   }
00183 }
00184 
00186 void CheckTrainsLengths()
00187 {
00188   const Vehicle *v;
00189 
00190   FOR_ALL_VEHICLES(v) {
00191     if (v->type == VEH_TRAIN && v->First() == v && !(v->vehstatus & VS_CRASHED)) {
00192       for (const Vehicle *u = v, *w = v->Next(); w != NULL; u = w, w = w->Next()) {
00193         if (u->u.rail.track != TRACK_BIT_DEPOT) {
00194           if ((w->u.rail.track != TRACK_BIT_DEPOT &&
00195               max(abs(u->x_pos - w->x_pos), abs(u->y_pos - w->y_pos)) != u->u.rail.cached_veh_length) ||
00196               (w->u.rail.track == TRACK_BIT_DEPOT && TicksToLeaveDepot(u) <= 0)) {
00197             SetDParam(0, v->index);
00198             SetDParam(1, v->owner);
00199             ShowErrorMessage(INVALID_STRING_ID, STR_BROKEN_VEHICLE_LENGTH, 0, 0);
00200 
00201             if (!_networking) _pause_game = -1;
00202           }
00203         }
00204       }
00205     }
00206   }
00207 }
00208 
00216 void TrainConsistChanged(Vehicle *v, bool same_length)
00217 {
00218   uint16 max_speed = UINT16_MAX;
00219 
00220   assert(v->type == VEH_TRAIN);
00221   assert(IsFrontEngine(v) || IsFreeWagon(v));
00222 
00223   const RailVehicleInfo *rvi_v = RailVehInfo(v->engine_type);
00224   EngineID first_engine = IsFrontEngine(v) ? v->engine_type : INVALID_ENGINE;
00225   v->u.rail.cached_total_length = 0;
00226   v->u.rail.compatible_railtypes = RAILTYPES_NONE;
00227 
00228   bool train_can_tilt = true;
00229 
00230   for (Vehicle *u = v; u != NULL; u = u->Next()) {
00231     const RailVehicleInfo *rvi_u = RailVehInfo(u->engine_type);
00232 
00233     /* Check the v->first cache. */
00234     assert(u->First() == v);
00235 
00236     /* update the 'first engine' */
00237     u->u.rail.first_engine = v == u ? INVALID_ENGINE : first_engine;
00238     u->u.rail.railtype = rvi_u->railtype;
00239 
00240     if (IsTrainEngine(u)) first_engine = u->engine_type;
00241 
00242     /* Set user defined data to its default value */
00243     u->u.rail.user_def_data = rvi_u->user_def_data;
00244     v->InvalidateNewGRFCache();
00245     u->InvalidateNewGRFCache();
00246   }
00247 
00248   for (Vehicle *u = v; u != NULL; u = u->Next()) {
00249     /* Update user defined data (must be done before other properties) */
00250     u->u.rail.user_def_data = GetVehicleProperty(u, 0x25, u->u.rail.user_def_data);
00251     v->InvalidateNewGRFCache();
00252     u->InvalidateNewGRFCache();
00253   }
00254 
00255   for (Vehicle *u = v; u != NULL; u = u->Next()) {
00256     const Engine *e_u = GetEngine(u->engine_type);
00257     const RailVehicleInfo *rvi_u = &e_u->u.rail;
00258 
00259     if (!HasBit(EngInfo(u->engine_type)->misc_flags, EF_RAIL_TILTS)) train_can_tilt = false;
00260 
00261     /* Cache wagon override sprite group. NULL is returned if there is none */
00262     u->u.rail.cached_override = GetWagonOverrideSpriteSet(u->engine_type, u->cargo_type, u->u.rail.first_engine);
00263 
00264     /* Reset colour map */
00265     u->colourmap = PAL_NONE;
00266 
00267     if (rvi_u->visual_effect != 0) {
00268       u->u.rail.cached_vis_effect = rvi_u->visual_effect;
00269     } else {
00270       if (IsTrainWagon(u) || IsArticulatedPart(u)) {
00271         /* Wagons and articulated parts have no effect by default */
00272         u->u.rail.cached_vis_effect = 0x40;
00273       } else if (rvi_u->engclass == 0) {
00274         /* Steam is offset by -4 units */
00275         u->u.rail.cached_vis_effect = 4;
00276       } else {
00277         /* Diesel fumes and sparks come from the centre */
00278         u->u.rail.cached_vis_effect = 8;
00279       }
00280     }
00281 
00282     /* Check powered wagon / visual effect callback */
00283     if (HasBit(EngInfo(u->engine_type)->callbackmask, CBM_TRAIN_WAGON_POWER)) {
00284       uint16 callback = GetVehicleCallback(CBID_TRAIN_WAGON_POWER, 0, 0, u->engine_type, u);
00285 
00286       if (callback != CALLBACK_FAILED) u->u.rail.cached_vis_effect = GB(callback, 0, 8);
00287     }
00288 
00289     if (rvi_v->pow_wag_power != 0 && rvi_u->railveh_type == RAILVEH_WAGON &&
00290       UsesWagonOverride(u) && !HasBit(u->u.rail.cached_vis_effect, 7)) {
00291       /* wagon is powered */
00292       SetBit(u->u.rail.flags, VRF_POWEREDWAGON); // cache 'powered' status
00293     } else {
00294       ClrBit(u->u.rail.flags, VRF_POWEREDWAGON);
00295     }
00296 
00297     if (!IsArticulatedPart(u)) {
00298       /* Do not count powered wagons for the compatible railtypes, as wagons always
00299          have railtype normal */
00300       if (rvi_u->power > 0) {
00301         v->u.rail.compatible_railtypes |= GetRailTypeInfo(u->u.rail.railtype)->powered_railtypes;
00302       }
00303 
00304       /* Some electric engines can be allowed to run on normal rail. It happens to all
00305        * existing electric engines when elrails are disabled and then re-enabled */
00306       if (HasBit(u->u.rail.flags, VRF_EL_ENGINE_ALLOWED_NORMAL_RAIL)) {
00307         u->u.rail.railtype = RAILTYPE_RAIL;
00308         u->u.rail.compatible_railtypes |= RAILTYPES_RAIL;
00309       }
00310 
00311       /* max speed is the minimum of the speed limits of all vehicles in the consist */
00312       if ((rvi_u->railveh_type != RAILVEH_WAGON || _settings_game.vehicle.wagon_speed_limits) && !UsesWagonOverride(u)) {
00313         uint16 speed = GetVehicleProperty(u, 0x09, rvi_u->max_speed);
00314         if (speed != 0) max_speed = min(speed, max_speed);
00315       }
00316     }
00317 
00318     if (e_u->CanCarryCargo() && u->cargo_type == e_u->GetDefaultCargoType() && u->cargo_subtype == 0) {
00319       /* Set cargo capacity if we've not been refitted */
00320       u->cargo_cap = GetVehicleProperty(u, 0x14, rvi_u->capacity);
00321     }
00322 
00323     /* check the vehicle length (callback) */
00324     uint16 veh_len = CALLBACK_FAILED;
00325     if (HasBit(EngInfo(u->engine_type)->callbackmask, CBM_VEHICLE_LENGTH)) {
00326       veh_len = GetVehicleCallback(CBID_VEHICLE_LENGTH, 0, 0, u->engine_type, u);
00327     }
00328     if (veh_len == CALLBACK_FAILED) veh_len = rvi_u->shorten_factor;
00329     veh_len = 8 - Clamp(veh_len, 0, u->Next() == NULL ? 7 : 5); // the clamp on vehicles not the last in chain is stricter, as too short wagons can break the 'follow next vehicle' code
00330 
00331     /* verify length hasn't changed */
00332     if (same_length && veh_len != u->u.rail.cached_veh_length) RailVehicleLengthChanged(u);
00333 
00334     /* update vehicle length? */
00335     if (!same_length) u->u.rail.cached_veh_length = veh_len;
00336 
00337     v->u.rail.cached_total_length += u->u.rail.cached_veh_length;
00338     v->InvalidateNewGRFCache();
00339     u->InvalidateNewGRFCache();
00340   }
00341 
00342   /* store consist weight/max speed in cache */
00343   v->u.rail.cached_max_speed = max_speed;
00344   v->u.rail.cached_tilt = train_can_tilt;
00345 
00346   /* recalculate cached weights and power too (we do this *after* the rest, so it is known which wagons are powered and need extra weight added) */
00347   TrainCargoChanged(v);
00348 
00349   if (IsFrontEngine(v)) {
00350     UpdateTrainAcceleration(v);
00351     InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
00352   }
00353 }
00354 
00355 enum AccelType {
00356   AM_ACCEL,
00357   AM_BRAKE
00358 };
00359 
00361 static int GetTrainAcceleration(Vehicle *v, bool mode)
00362 {
00363   static const int absolute_max_speed = UINT16_MAX;
00364   int max_speed = absolute_max_speed;
00365   int speed = v->cur_speed * 10 / 16; // km-ish/h -> mp/h
00366   int curvecount[2] = {0, 0};
00367 
00368   /* first find the curve speed limit */
00369   int numcurve = 0;
00370   int sum = 0;
00371   int pos = 0;
00372   int lastpos = -1;
00373   for (const Vehicle *u = v; u->Next() != NULL; u = u->Next(), pos++) {
00374     Direction this_dir = u->direction;
00375     Direction next_dir = u->Next()->direction;
00376 
00377     DirDiff dirdiff = DirDifference(this_dir, next_dir);
00378     if (dirdiff == DIRDIFF_SAME) continue;
00379 
00380     if (dirdiff == DIRDIFF_45LEFT) curvecount[0]++;
00381     if (dirdiff == DIRDIFF_45RIGHT) curvecount[1]++;
00382     if (dirdiff == DIRDIFF_45LEFT || dirdiff == DIRDIFF_45RIGHT) {
00383       if (lastpos != -1) {
00384         numcurve++;
00385         sum += pos - lastpos;
00386         if (pos - lastpos == 1) {
00387           max_speed = 88;
00388         }
00389       }
00390       lastpos = pos;
00391     }
00392 
00393     /* if we have a 90 degree turn, fix the speed limit to 60 */
00394     if (dirdiff == DIRDIFF_90LEFT || dirdiff == DIRDIFF_90RIGHT) {
00395       max_speed = 61;
00396     }
00397   }
00398 
00399   if ((curvecount[0] != 0 || curvecount[1] != 0) && max_speed > 88) {
00400     int total = curvecount[0] + curvecount[1];
00401 
00402     if (curvecount[0] == 1 && curvecount[1] == 1) {
00403       max_speed = absolute_max_speed;
00404     } else if (total > 1) {
00405       if (numcurve > 0) sum /= numcurve;
00406       max_speed = 232 - (13 - Clamp(sum, 1, 12)) * (13 - Clamp(sum, 1, 12));
00407     }
00408   }
00409 
00410   if (max_speed != absolute_max_speed) {
00411     /* Apply the engine's rail type curve speed advantage, if it slowed by curves */
00412     const RailtypeInfo *rti = GetRailTypeInfo(v->u.rail.railtype);
00413     max_speed += (max_speed / 2) * rti->curve_speed;
00414 
00415     if (v->u.rail.cached_tilt) {
00416       /* Apply max_speed bonus of 20% for a tilting train */
00417       max_speed += max_speed / 5;
00418     }
00419   }
00420 
00421   if (IsTileType(v->tile, MP_STATION) && IsFrontEngine(v)) {
00422     if (v->current_order.ShouldStopAtStation(v, GetStationIndex(v->tile))) {
00423       int station_length = GetStationByTile(v->tile)->GetPlatformLength(v->tile, DirToDiagDir(v->direction));
00424 
00425       int st_max_speed = 120;
00426 
00427       int delta_v = v->cur_speed / (station_length + 1);
00428       if (v->max_speed > (v->cur_speed - delta_v)) {
00429         st_max_speed = v->cur_speed - (delta_v / 10);
00430       }
00431 
00432       st_max_speed = max(st_max_speed, 25 * station_length);
00433       max_speed = min(max_speed, st_max_speed);
00434     }
00435   }
00436 
00437   int mass = v->u.rail.cached_weight;
00438   int power = v->u.rail.cached_power * 746;
00439   max_speed = min(max_speed, v->u.rail.cached_max_speed);
00440 
00441   int num = 0; // number of vehicles, change this into the number of axles later
00442   int incl = 0;
00443   int drag_coeff = 20; //[1e-4]
00444   for (const Vehicle *u = v; u != NULL; u = u->Next()) {
00445     num++;
00446     drag_coeff += 3;
00447 
00448     if (u->u.rail.track == TRACK_BIT_DEPOT) max_speed = min(max_speed, 61);
00449 
00450     if (HasBit(u->u.rail.flags, VRF_GOINGUP)) {
00451       incl += u->u.rail.cached_veh_weight * 60; // 3% slope, quite a bit actually
00452     } else if (HasBit(u->u.rail.flags, VRF_GOINGDOWN)) {
00453       incl -= u->u.rail.cached_veh_weight * 60;
00454     }
00455   }
00456 
00457   v->max_speed = max_speed;
00458 
00459   const int area = 120;
00460   const int friction = 35; //[1e-3]
00461   int resistance;
00462   if (v->u.rail.railtype != RAILTYPE_MAGLEV) {
00463     resistance = 13 * mass / 10;
00464     resistance += 60 * num;
00465     resistance += friction * mass * speed / 1000;
00466     resistance += (area * drag_coeff * speed * speed) / 10000;
00467   } else {
00468     resistance = (area * (drag_coeff / 2) * speed * speed) / 10000;
00469   }
00470   resistance += incl;
00471   resistance *= 4; //[N]
00472 
00473   const int max_te = v->u.rail.cached_max_te; // [N]
00474   int force;
00475   if (speed > 0) {
00476     switch (v->u.rail.railtype) {
00477       case RAILTYPE_RAIL:
00478       case RAILTYPE_ELECTRIC:
00479       case RAILTYPE_MONO:
00480         force = power / speed; //[N]
00481         force *= 22;
00482         force /= 10;
00483         if (mode == AM_ACCEL && force > max_te) force = max_te;
00484         break;
00485 
00486       default: NOT_REACHED();
00487       case RAILTYPE_MAGLEV:
00488         force = power / 25;
00489         break;
00490     }
00491   } else {
00492     /* "kickoff" acceleration */
00493     force = (mode == AM_ACCEL && v->u.rail.railtype != RAILTYPE_MAGLEV) ? min(max_te, power) : power;
00494     force = max(force, (mass * 8) + resistance);
00495   }
00496 
00497   if (mode == AM_ACCEL) {
00498     return (force - resistance) / (mass * 2);
00499   } else {
00500     return min(-force - resistance, -10000) / mass;
00501   }
00502 }
00503 
00504 void UpdateTrainAcceleration(Vehicle *v)
00505 {
00506   assert(IsFrontEngine(v));
00507 
00508   v->max_speed = v->u.rail.cached_max_speed;
00509 
00510   uint power = v->u.rail.cached_power;
00511   uint weight = v->u.rail.cached_weight;
00512   assert(weight != 0);
00513   v->acceleration = Clamp(power / weight * 4, 1, 255);
00514 }
00515 
00516 SpriteID Train::GetImage(Direction direction) const
00517 {
00518   uint8 spritenum = this->spritenum;
00519   SpriteID sprite;
00520 
00521   if (HasBit(this->u.rail.flags, VRF_REVERSE_DIRECTION)) direction = ReverseDir(direction);
00522 
00523   if (is_custom_sprite(spritenum)) {
00524     sprite = GetCustomVehicleSprite(this, (Direction)(direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(spritenum)));
00525     if (sprite != 0) return sprite;
00526 
00527     spritenum = GetEngine(this->engine_type)->image_index;
00528   }
00529 
00530   sprite = _engine_sprite_base[spritenum] + ((direction + _engine_sprite_add[spritenum]) & _engine_sprite_and[spritenum]);
00531 
00532   if (this->cargo.Count() >= this->cargo_cap / 2U) sprite += _wagon_full_adder[spritenum];
00533 
00534   return sprite;
00535 }
00536 
00537 static SpriteID GetRailIcon(EngineID engine, bool rear_head, int &y)
00538 {
00539   Direction dir = rear_head ? DIR_E : DIR_W;
00540   uint8 spritenum = RailVehInfo(engine)->image_index;
00541 
00542   if (is_custom_sprite(spritenum)) {
00543     SpriteID sprite = GetCustomVehicleIcon(engine, dir);
00544     if (sprite != 0) {
00545       y += _traininfo_vehicle_pitch; // TODO Make this per-GRF
00546       return sprite;
00547     }
00548 
00549     spritenum = GetEngine(engine)->image_index;
00550   }
00551 
00552   if (rear_head) spritenum++;
00553 
00554   return ((6 + _engine_sprite_add[spritenum]) & _engine_sprite_and[spritenum]) + _engine_sprite_base[spritenum];
00555 }
00556 
00557 void DrawTrainEngine(int x, int y, EngineID engine, SpriteID pal)
00558 {
00559   if (RailVehInfo(engine)->railveh_type == RAILVEH_MULTIHEAD) {
00560     int yf = y;
00561     int yr = y;
00562 
00563     SpriteID spritef = GetRailIcon(engine, false, yf);
00564     SpriteID spriter = GetRailIcon(engine, true, yr);
00565     DrawSprite(spritef, pal, x - 14, yf);
00566     DrawSprite(spriter, pal, x + 15, yr);
00567   } else {
00568     SpriteID sprite = GetRailIcon(engine, false, y);
00569     DrawSprite(sprite, pal, x, y);
00570   }
00571 }
00572 
00573 static CommandCost CmdBuildRailWagon(EngineID engine, TileIndex tile, DoCommandFlag flags)
00574 {
00575   const Engine *e = GetEngine(engine);
00576   const RailVehicleInfo *rvi = &e->u.rail;
00577   CommandCost value(EXPENSES_NEW_VEHICLES, e->GetCost());
00578 
00579   /* Engines without valid cargo should not be available */
00580   if (e->GetDefaultCargoType() == CT_INVALID) return CMD_ERROR;
00581 
00582   if (flags & DC_QUERY_COST) return value;
00583 
00584   /* Check that the wagon can drive on the track in question */
00585   if (!IsCompatibleRail(rvi->railtype, GetRailType(tile))) return CMD_ERROR;
00586 
00587   uint num_vehicles = 1 + CountArticulatedParts(engine, false);
00588 
00589   /* Allow for the wagon and the articulated parts, plus one to "terminate" the list. */
00590   Vehicle **vl = AllocaM(Vehicle*, num_vehicles + 1);
00591   memset(vl, 0, sizeof(*vl) * (num_vehicles + 1));
00592 
00593   if (!Vehicle::AllocateList(vl, num_vehicles)) {
00594     return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
00595   }
00596 
00597   if (flags & DC_EXEC) {
00598     Vehicle *v = vl[0];
00599     v->spritenum = rvi->image_index;
00600 
00601     Vehicle *u = NULL;
00602 
00603     Vehicle *w;
00604     FOR_ALL_VEHICLES(w) {
00605       if (w->type == VEH_TRAIN && w->tile == tile &&
00606           IsFreeWagon(w) && w->engine_type == engine &&
00607           !HASBITS(w->vehstatus, VS_CRASHED)) {          
00608         u = GetLastVehicleInChain(w);
00609         break;
00610       }
00611     }
00612 
00613     v = new (v) Train();
00614     v->engine_type = engine;
00615 
00616     DiagDirection dir = GetRailDepotDirection(tile);
00617 
00618     v->direction = DiagDirToDir(dir);
00619     v->tile = tile;
00620 
00621     int x = TileX(tile) * TILE_SIZE | _vehicle_initial_x_fract[dir];
00622     int y = TileY(tile) * TILE_SIZE | _vehicle_initial_y_fract[dir];
00623 
00624     v->x_pos = x;
00625     v->y_pos = y;
00626     v->z_pos = GetSlopeZ(x, y);
00627     v->owner = _current_company;
00628     v->u.rail.track = TRACK_BIT_DEPOT;
00629     v->vehstatus = VS_HIDDEN | VS_DEFPAL;
00630 
00631 //    v->subtype = 0;
00632     SetTrainWagon(v);
00633 
00634     if (u != NULL) {
00635       u->SetNext(v);
00636     } else {
00637       SetFreeWagon(v);
00638       InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
00639     }
00640 
00641     v->cargo_type = e->GetDefaultCargoType();
00642 //    v->cargo_subtype = 0;
00643     v->cargo_cap = rvi->capacity;
00644     v->value = value.GetCost();
00645 //    v->day_counter = 0;
00646 
00647     v->u.rail.railtype = rvi->railtype;
00648 
00649     v->build_year = _cur_year;
00650     v->cur_image = 0xAC2;
00651     v->random_bits = VehicleRandomBits();
00652 
00653     v->group_id = DEFAULT_GROUP;
00654 
00655     AddArticulatedParts(vl, VEH_TRAIN);
00656 
00657     _new_vehicle_id = v->index;
00658 
00659     VehicleMove(v, false);
00660     TrainConsistChanged(v->First(), false);
00661     UpdateTrainGroupID(v->First());
00662 
00663     InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
00664     if (IsLocalCompany()) {
00665       InvalidateAutoreplaceWindow(v->engine_type, v->group_id); // updates the replace Train window
00666     }
00667     GetCompany(_current_company)->num_engines[engine]++;
00668 
00669     CheckConsistencyOfArticulatedVehicle(v);
00670   }
00671 
00672   return value;
00673 }
00674 
00676 static void NormalizeTrainVehInDepot(const Vehicle *u)
00677 {
00678   const Vehicle *v;
00679 
00680   FOR_ALL_VEHICLES(v) {
00681     if (v->type == VEH_TRAIN && IsFreeWagon(v) &&
00682         v->tile == u->tile &&
00683         v->u.rail.track == TRACK_BIT_DEPOT) {
00684       if (CmdFailed(DoCommand(0, v->index | (u->index << 16), 1, DC_EXEC,
00685           CMD_MOVE_RAIL_VEHICLE)))
00686         break;
00687     }
00688   }
00689 }
00690 
00691 static void AddRearEngineToMultiheadedTrain(Vehicle *v, Vehicle *u, bool building)
00692 {
00693   u = new (u) Train();
00694   u->direction = v->direction;
00695   u->owner = v->owner;
00696   u->tile = v->tile;
00697   u->x_pos = v->x_pos;
00698   u->y_pos = v->y_pos;
00699   u->z_pos = v->z_pos;
00700   u->u.rail.track = TRACK_BIT_DEPOT;
00701   u->vehstatus = v->vehstatus & ~VS_STOPPED;
00702 //  u->subtype = 0;
00703   SetMultiheaded(u);
00704   u->spritenum = v->spritenum + 1;
00705   u->cargo_type = v->cargo_type;
00706   u->cargo_subtype = v->cargo_subtype;
00707   u->cargo_cap = v->cargo_cap;
00708   u->u.rail.railtype = v->u.rail.railtype;
00709   if (building) v->SetNext(u);
00710   u->engine_type = v->engine_type;
00711   u->build_year = v->build_year;
00712   if (building) v->value >>= 1;
00713   u->value = v->value;
00714   u->cur_image = 0xAC2;
00715   u->random_bits = VehicleRandomBits();
00716   VehicleMove(u, false);
00717 }
00718 
00725 CommandCost CmdBuildRailVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00726 {
00727   /* Check if the engine-type is valid (for the company) */
00728   if (!IsEngineBuildable(p1, VEH_TRAIN, _current_company)) return_cmd_error(STR_RAIL_VEHICLE_NOT_AVAILABLE);
00729 
00730   const Engine *e = GetEngine(p1);
00731   CommandCost value(EXPENSES_NEW_VEHICLES, e->GetCost());
00732 
00733   /* Engines with CT_INVALID should not be available */
00734   if (e->GetDefaultCargoType() == CT_INVALID) return CMD_ERROR;
00735 
00736   if (flags & DC_QUERY_COST) return value;
00737 
00738   /* Check if the train is actually being built in a depot belonging
00739    * to the company. Doesn't matter if only the cost is queried */
00740   if (!IsRailDepotTile(tile)) return CMD_ERROR;
00741   if (!IsTileOwner(tile, _current_company)) return CMD_ERROR;
00742 
00743   const RailVehicleInfo *rvi = RailVehInfo(p1);
00744   if (rvi->railveh_type == RAILVEH_WAGON) return CmdBuildRailWagon(p1, tile, flags);
00745 
00746   uint num_vehicles =
00747     (rvi->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1) +
00748     CountArticulatedParts(p1, false);
00749 
00750   /* Check if depot and new engine uses the same kind of tracks *
00751    * We need to see if the engine got power on the tile to avoid eletric engines in non-electric depots */
00752   if (!HasPowerOnRail(rvi->railtype, GetRailType(tile))) return CMD_ERROR;
00753 
00754   /* Allow for the dual-heads and the articulated parts, plus one to "terminate" the list. */
00755   Vehicle **vl = AllocaM(Vehicle*, num_vehicles + 1);
00756   memset(vl, 0, sizeof(*vl) * (num_vehicles + 1));
00757 
00758   if (!Vehicle::AllocateList(vl, num_vehicles)) {
00759     return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
00760   }
00761 
00762   Vehicle *v = vl[0];
00763 
00764   UnitID unit_num = (flags & DC_AUTOREPLACE) ? 0 : GetFreeUnitNumber(VEH_TRAIN);
00765   if (unit_num > _settings_game.vehicle.max_trains) {
00766     return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
00767   }
00768 
00769   if (flags & DC_EXEC) {
00770     DiagDirection dir = GetRailDepotDirection(tile);
00771     int x = TileX(tile) * TILE_SIZE + _vehicle_initial_x_fract[dir];
00772     int y = TileY(tile) * TILE_SIZE + _vehicle_initial_y_fract[dir];
00773 
00774     v = new (v) Train();
00775     v->unitnumber = unit_num;
00776     v->direction = DiagDirToDir(dir);
00777     v->tile = tile;
00778     v->owner = _current_company;
00779     v->x_pos = x;
00780     v->y_pos = y;
00781     v->z_pos = GetSlopeZ(x, y);
00782 //    v->running_ticks = 0;
00783     v->u.rail.track = TRACK_BIT_DEPOT;
00784     v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL;
00785     v->spritenum = rvi->image_index;
00786     v->cargo_type = e->GetDefaultCargoType();
00787 //    v->cargo_subtype = 0;
00788     v->cargo_cap = rvi->capacity;
00789     v->max_speed = rvi->max_speed;
00790     v->value = value.GetCost();
00791     v->last_station_visited = INVALID_STATION;
00792 //    v->dest_tile = 0;
00793 
00794     v->engine_type = p1;
00795 
00796     v->reliability = e->reliability;
00797     v->reliability_spd_dec = e->reliability_spd_dec;
00798     v->max_age = e->lifelength * DAYS_IN_LEAP_YEAR;
00799 
00800     v->name = NULL;
00801     v->u.rail.railtype = rvi->railtype;
00802     _new_vehicle_id = v->index;
00803 
00804     v->service_interval = _settings_game.vehicle.servint_trains;
00805     v->date_of_last_service = _date;
00806     v->build_year = _cur_year;
00807     v->cur_image = 0xAC2;
00808     v->random_bits = VehicleRandomBits();
00809 
00810 //    v->vehicle_flags = 0;
00811     if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) SetBit(v->vehicle_flags, VF_BUILT_AS_PROTOTYPE);
00812 
00813     v->group_id = DEFAULT_GROUP;
00814 
00815 //    v->subtype = 0;
00816     SetFrontEngine(v);
00817     SetTrainEngine(v);
00818 
00819     VehicleMove(v, false);
00820 
00821     if (rvi->railveh_type == RAILVEH_MULTIHEAD) {
00822       SetMultiheaded(v);
00823       AddRearEngineToMultiheadedTrain(vl[0], vl[1], true);
00824       /* Now we need to link the front and rear engines together
00825        * other_multiheaded_part is the pointer that links to the other half of the engine
00826        * vl[0] is the front and vl[1] is the rear
00827        */
00828       vl[0]->u.rail.other_multiheaded_part = vl[1];
00829       vl[1]->u.rail.other_multiheaded_part = vl[0];
00830     } else {
00831       AddArticulatedParts(vl, VEH_TRAIN);
00832     }
00833 
00834     TrainConsistChanged(v, false);
00835     UpdateTrainGroupID(v);
00836 
00837     if (!HasBit(p2, 1) && !(flags & DC_AUTOREPLACE)) { // check if the cars should be added to the new vehicle
00838       NormalizeTrainVehInDepot(v);
00839     }
00840 
00841     InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
00842     InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
00843     InvalidateWindow(WC_COMPANY, v->owner);
00844     if (IsLocalCompany()) {
00845       InvalidateAutoreplaceWindow(v->engine_type, v->group_id); // updates the replace Train window
00846     }
00847 
00848     GetCompany(_current_company)->num_engines[p1]++;
00849 
00850     CheckConsistencyOfArticulatedVehicle(v);
00851   }
00852 
00853   return value;
00854 }
00855 
00856 
00857 /* Check if all the wagons of the given train are in a depot, returns the
00858  * number of cars (including loco) then. If not it returns -1 */
00859 int CheckTrainInDepot(const Vehicle *v, bool needs_to_be_stopped)
00860 {
00861   TileIndex tile = v->tile;
00862 
00863   /* check if stopped in a depot */
00864   if (!IsRailDepotTile(tile) || v->cur_speed != 0) return -1;
00865 
00866   int count = 0;
00867   for (; v != NULL; v = v->Next()) {
00868     /* This count is used by the depot code to determine the number of engines
00869      * in the consist. Exclude articulated parts so that autoreplacing to
00870      * engines with more articulated parts than before works correctly.
00871      *
00872      * Also skip counting rear ends of multiheaded engines */
00873     if (!IsArticulatedPart(v) && !IsRearDualheaded(v)) count++;
00874     if (v->u.rail.track != TRACK_BIT_DEPOT || v->tile != tile ||
00875         (IsFrontEngine(v) && needs_to_be_stopped && !(v->vehstatus & VS_STOPPED))) {
00876       return -1;
00877     }
00878   }
00879 
00880   return count;
00881 }
00882 
00883 /* Used to check if the train is inside the depot and verifying that the VS_STOPPED flag is set */
00884 int CheckTrainStoppedInDepot(const Vehicle *v)
00885 {
00886   return CheckTrainInDepot(v, true);
00887 }
00888 
00889 /* Used to check if the train is inside the depot, but not checking the VS_STOPPED flag */
00890 inline bool CheckTrainIsInsideDepot(const Vehicle *v)
00891 {
00892   return CheckTrainInDepot(v, false) > 0;
00893 }
00894 
00901 static Vehicle *UnlinkWagon(Vehicle *v, Vehicle *first)
00902 {
00903   /* unlinking the first vehicle of the chain? */
00904   if (v == first) {
00905     v = GetNextVehicle(v);
00906     if (v == NULL) return NULL;
00907 
00908     if (IsTrainWagon(v)) SetFreeWagon(v);
00909 
00910     /* First can be an articulated engine, meaning GetNextVehicle() isn't
00911      * v->Next(). Thus set the next vehicle of the last articulated part
00912      * and the last articulated part is just before the next vehicle (v). */
00913     v->Previous()->SetNext(NULL);
00914 
00915     return v;
00916   }
00917 
00918   Vehicle *u;
00919   for (u = first; GetNextVehicle(u) != v; u = GetNextVehicle(u)) {}
00920   GetLastEnginePart(u)->SetNext(GetNextVehicle(v));
00921   return first;
00922 }
00923 
00924 static Vehicle *FindGoodVehiclePos(const Vehicle *src)
00925 {
00926   Vehicle *dst;
00927   EngineID eng = src->engine_type;
00928   TileIndex tile = src->tile;
00929 
00930   FOR_ALL_VEHICLES(dst) {
00931     if (dst->type == VEH_TRAIN && IsFreeWagon(dst) && dst->tile == tile && !HASBITS(dst->vehstatus, VS_CRASHED)) {
00932       /* check so all vehicles in the line have the same engine. */
00933       Vehicle *v = dst;
00934 
00935       while (v->engine_type == eng) {
00936         v = v->Next();
00937         if (v == NULL) return dst;
00938       }
00939     }
00940   }
00941 
00942   return NULL;
00943 }
00944 
00945 /*
00946  * add a vehicle v behind vehicle dest
00947  * use this function since it sets flags as needed
00948  */
00949 static void AddWagonToConsist(Vehicle *v, Vehicle *dest)
00950 {
00951   UnlinkWagon(v, v->First());
00952   if (dest == NULL) return;
00953 
00954   Vehicle *next = dest->Next();
00955   v->SetNext(NULL);
00956   dest->SetNext(v);
00957   v->SetNext(next);
00958   ClearFreeWagon(v);
00959   ClearFrontEngine(v);
00960 }
00961 
00962 /*
00963  * move around on the train so rear engines are placed correctly according to the other engines
00964  * always call with the front engine
00965  */
00966 static void NormaliseTrainConsist(Vehicle *v)
00967 {
00968   for (; v != NULL; v = GetNextVehicle(v)) {
00969     if (!IsMultiheaded(v) || !IsTrainEngine(v)) continue;
00970 
00971     /* make sure that there are no free cars before next engine */
00972     Vehicle *u;
00973     for (u = v; u->Next() != NULL && !IsTrainEngine(u->Next()); u = u->Next()) {}
00974 
00975     if (u == v->u.rail.other_multiheaded_part) continue;
00976     AddWagonToConsist(v->u.rail.other_multiheaded_part, u);
00977   }
00978 }
00979 
00989 CommandCost CmdMoveRailVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00990 {
00991   VehicleID s = GB(p1, 0, 16);
00992   VehicleID d = GB(p1, 16, 16);
00993 
00994   if (!IsValidVehicleID(s)) return CMD_ERROR;
00995 
00996   Vehicle *src = GetVehicle(s);
00997 
00998   if (src->type != VEH_TRAIN || !CheckOwnership(src->owner)) return CMD_ERROR;
00999 
01000   /* Do not allow moving crashed vehicles inside the depot, it is likely to cause asserts later */
01001   if (HASBITS(src->vehstatus, VS_CRASHED)) return CMD_ERROR;
01002 
01003   /* if nothing is selected as destination, try and find a matching vehicle to drag to. */
01004   Vehicle *dst;
01005   if (d == INVALID_VEHICLE) {
01006     dst = IsTrainEngine(src) ? NULL : FindGoodVehiclePos(src);
01007   } else {
01008     if (!IsValidVehicleID(d)) return CMD_ERROR;
01009     dst = GetVehicle(d);
01010     if (dst->type != VEH_TRAIN || !CheckOwnership(dst->owner)) return CMD_ERROR;
01011 
01012     /* Do not allow appending to crashed vehicles, too */
01013     if (HASBITS(dst->vehstatus, VS_CRASHED)) return CMD_ERROR;
01014   }
01015 
01016   /* if an articulated part is being handled, deal with its parent vehicle */
01017   while (IsArticulatedPart(src)) src = src->Previous();
01018   if (dst != NULL) {
01019     while (IsArticulatedPart(dst)) dst = dst->Previous();
01020   }
01021 
01022   /* don't move the same vehicle.. */
01023   if (src == dst) return CommandCost();
01024 
01025   /* locate the head of the two chains */
01026   Vehicle *src_head = src->First();
01027   Vehicle *dst_head;
01028   if (dst != NULL) {
01029     dst_head = dst->First();
01030     if (dst_head->tile != src_head->tile) return CMD_ERROR;
01031     /* Now deal with articulated part of destination wagon */
01032     dst = GetLastEnginePart(dst);
01033   } else {
01034     dst_head = NULL;
01035   }
01036 
01037   if (IsRearDualheaded(src)) return_cmd_error(STR_REAR_ENGINE_FOLLOW_FRONT_ERROR);
01038 
01039   /* when moving all wagons, we can't have the same src_head and dst_head */
01040   if (HasBit(p2, 0) && src_head == dst_head) return CommandCost();
01041 
01042   /* check if all vehicles in the source train are stopped inside a depot. */
01043   int src_len = CheckTrainStoppedInDepot(src_head);
01044   if (src_len < 0) return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED);
01045 
01046   if ((flags & DC_AUTOREPLACE) == 0) {
01047     /* Check whether there are more than 'max_len' train units (articulated parts and rear heads do not count) in the new chain */
01048     int max_len = _settings_game.vehicle.mammoth_trains ? 100 : 10;
01049 
01050     /* check the destination row if the source and destination aren't the same. */
01051     if (src_head != dst_head) {
01052       int dst_len = 0;
01053 
01054       if (dst_head != NULL) {
01055         /* check if all vehicles in the dest train are stopped. */
01056         dst_len = CheckTrainStoppedInDepot(dst_head);
01057         if (dst_len < 0) return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED);
01058       }
01059 
01060       if (src_head == src && !HasBit(p2, 0)) {
01061         /* Moving of a *single* vehicle at the front of the train.
01062          * If the next vehicle is an engine a new train will be created
01063          * instead of removing a vehicle from a free chain. The newly
01064          * created train may not be too long. */
01065         const Vehicle *u = GetNextVehicle(src_head);
01066         if (u != NULL && IsTrainEngine(u) && (src_len - 1) > max_len) return_cmd_error(STR_8819_TRAIN_TOO_LONG);
01067       }
01068 
01069       /* We are moving between rows, so only count the wagons from the source
01070        * row that are being moved. */
01071       if (HasBit(p2, 0)) {
01072         const Vehicle *u;
01073         for (u = src_head; u != src && u != NULL; u = GetNextVehicle(u))
01074           src_len--;
01075       } else {
01076         /* If moving only one vehicle, just count that. */
01077         src_len = 1;
01078       }
01079 
01080       if (src_len + dst_len > max_len) {
01081         /* Abort if we're adding too many wagons to a train. */
01082         if (dst_head != NULL && IsFrontEngine(dst_head)) return_cmd_error(STR_8819_TRAIN_TOO_LONG);
01083         /* Abort if we're making a train on a new row. */
01084         if (dst_head == NULL && IsTrainEngine(src)) return_cmd_error(STR_8819_TRAIN_TOO_LONG);
01085       }
01086     } else {
01087       /* Abort if we're creating a new train on an existing row. */
01088       if (src_len > max_len && src == src_head && IsTrainEngine(GetNextVehicle(src_head)))
01089         return_cmd_error(STR_8819_TRAIN_TOO_LONG);
01090     }
01091   }
01092 
01093   /* moving a loco to a new line?, then we need to assign a unitnumber. */
01094   if (dst == NULL && !IsFrontEngine(src) && IsTrainEngine(src)) {
01095     UnitID unit_num = ((flags & DC_AUTOREPLACE) != 0 ? 0 : GetFreeUnitNumber(VEH_TRAIN));
01096     if (unit_num > _settings_game.vehicle.max_trains)
01097       return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
01098 
01099     if (flags & DC_EXEC) src->unitnumber = unit_num;
01100   }
01101 
01102   /* When we move the front vehicle, the second vehicle might need a unitnumber */
01103   if (!HasBit(p2, 0) && (IsFreeWagon(src) || (IsFrontEngine(src) && dst == NULL)) && (flags & DC_AUTOREPLACE) == 0) {
01104     Vehicle *second = GetNextUnit(src);
01105     if (second != NULL && IsTrainEngine(second) && GetFreeUnitNumber(VEH_TRAIN) > _settings_game.vehicle.max_trains) {
01106       return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
01107     }
01108   }
01109 
01110   /*
01111    * Check whether the vehicles in the source chain are in the destination
01112    * chain. This can easily be done by checking whether the first vehicle
01113    * of the source chain is in the destination chain as the Next/Previous
01114    * pointers always make a doubly linked list of it where the assumption
01115    * v->Next()->Previous() == v holds (assuming v->Next() != NULL).
01116    */
01117   bool src_in_dst = false;
01118   for (Vehicle *v = dst_head; !src_in_dst && v != NULL; v = v->Next()) src_in_dst = v == src;
01119 
01120   /*
01121    * If the source chain is in the destination chain then the user is
01122    * only reordering the vehicles, thus not attaching a new vehicle.
01123    * Therefor the 'allow wagon attach' callback does not need to be
01124    * called. If it would be called strange things would happen because
01125    * one 'attaches' an already 'attached' vehicle causing more trouble
01126    * than it actually solves (infinite loops and such).
01127    */
01128   if (dst_head != NULL && !src_in_dst && (flags & DC_AUTOREPLACE) == 0) {
01129     /*
01130      * When performing the 'allow wagon attach' callback, we have to check
01131      * that for each and every wagon, not only the first one. This means
01132      * that we have to test one wagon, attach it to the train and then test
01133      * the next wagon till we have reached the end. We have to restore it
01134      * to the state it was before we 'tried' attaching the train when the
01135      * attaching fails or succeeds because we are not 'only' doing this
01136      * in the DC_EXEC state.
01137      */
01138     Vehicle *dst_tail = dst_head;
01139     while (dst_tail->Next() != NULL) dst_tail = dst_tail->Next();
01140 
01141     Vehicle *orig_tail = dst_tail;
01142     Vehicle *next_to_attach = src;
01143     Vehicle *src_previous = src->Previous();
01144 
01145     while (next_to_attach != NULL) {
01146       /* Don't check callback for articulated or rear dual headed parts */
01147       if (!IsArticulatedPart(next_to_attach) && !IsRearDualheaded(next_to_attach)) {
01148         /* Back up and clear the first_engine data to avoid using wagon override group */
01149         EngineID first_engine = next_to_attach->u.rail.first_engine;
01150         next_to_attach->u.rail.first_engine = INVALID_ENGINE;
01151 
01152         uint16 callback = GetVehicleCallbackParent(CBID_TRAIN_ALLOW_WAGON_ATTACH, 0, 0, dst_head->engine_type, next_to_attach, dst_head);
01153 
01154         /* Restore original first_engine data */
01155         next_to_attach->u.rail.first_engine = first_engine;
01156 
01157         if (callback != CALLBACK_FAILED) {
01158           StringID error = STR_NULL;
01159 
01160           if (callback == 0xFD) error = STR_INCOMPATIBLE_RAIL_TYPES;
01161           if (callback < 0xFD) error = GetGRFStringID(GetEngineGRFID(dst_head->engine_type), 0xD000 + callback);
01162 
01163           if (error != STR_NULL) {
01164             /*
01165              * The attaching is not allowed. In this case 'next_to_attach'
01166              * can contain some vehicles of the 'source' and the destination
01167              * train can have some too. We 'just' add the to-be added wagons
01168              * to the chain and then split it where it was previously
01169              * separated, i.e. the tail of the original destination train.
01170              * Furthermore the 'previous' link of the original source vehicle needs
01171              * to be restored, otherwise the train goes missing in the depot.
01172              */
01173             dst_tail->SetNext(next_to_attach);
01174             orig_tail->SetNext(NULL);
01175             if (src_previous != NULL) src_previous->SetNext(src);
01176 
01177             return_cmd_error(error);
01178           }
01179         }
01180       }
01181 
01182       /* Only check further wagons if told to move the chain */
01183       if (!HasBit(p2, 0)) break;
01184 
01185       /*
01186        * Adding a next wagon to the chain so we can test the other wagons.
01187        * First 'take' the first wagon from 'next_to_attach' and move it
01188        * to the next wagon. Then add that to the tail of the destination
01189        * train and update the tail with the new vehicle.
01190        */
01191       Vehicle *to_add = next_to_attach;
01192       next_to_attach = next_to_attach->Next();
01193 
01194       to_add->SetNext(NULL);
01195       dst_tail->SetNext(to_add);
01196       dst_tail = dst_tail->Next();
01197     }
01198 
01199     /*
01200      * When we reach this the attaching is allowed. It also means that the
01201      * chain of vehicles to attach is empty, so we do not need to merge that.
01202      * This means only the splitting needs to be done.
01203      * Furthermore the 'previous' link of the original source vehicle needs
01204      * to be restored, otherwise the train goes missing in the depot.
01205      */
01206     orig_tail->SetNext(NULL);
01207     if (src_previous != NULL) src_previous->SetNext(src);
01208   }
01209 
01210   /* do it? */
01211   if (flags & DC_EXEC) {
01212     /* If we move the front Engine and if the second vehicle is not an engine
01213        add the whole vehicle to the DEFAULT_GROUP */
01214     if (IsFrontEngine(src) && !IsDefaultGroupID(src->group_id)) {
01215       Vehicle *v = GetNextVehicle(src);
01216 
01217       if (v != NULL && IsTrainEngine(v)) {
01218         v->group_id   = src->group_id;
01219         src->group_id = DEFAULT_GROUP;
01220       }
01221     }
01222 
01223     if (HasBit(p2, 0)) {
01224       /* unlink ALL wagons */
01225       if (src != src_head) {
01226         Vehicle *v = src_head;
01227         while (GetNextVehicle(v) != src) v = GetNextVehicle(v);
01228         GetLastEnginePart(v)->SetNext(NULL);
01229       } else {
01230         InvalidateWindowData(WC_VEHICLE_DEPOT, src_head->tile); // We removed a line
01231         src_head = NULL;
01232       }
01233     } else {
01234       /* if moving within the same chain, dont use dst_head as it may get invalidated */
01235       if (src_head == dst_head) dst_head = NULL;
01236       /* unlink single wagon from linked list */
01237       src_head = UnlinkWagon(src, src_head);
01238       GetLastEnginePart(src)->SetNext(NULL);
01239     }
01240 
01241     if (dst == NULL) {
01242       /* We make a new line in the depot, so we know already that we invalidate the window data */
01243       InvalidateWindowData(WC_VEHICLE_DEPOT, src->tile);
01244 
01245       /* move the train to an empty line. for locomotives, we set the type to TS_Front. for wagons, 4. */
01246       if (IsTrainEngine(src)) {
01247         if (!IsFrontEngine(src)) {
01248           /* setting the type to 0 also involves setting up the orders field. */
01249           SetFrontEngine(src);
01250           assert(src->orders.list == NULL);
01251 
01252           /* Decrease the engines number of the src engine_type */
01253           if (!IsDefaultGroupID(src->group_id) && IsValidGroupID(src->group_id)) {
01254             GetGroup(src->group_id)->num_engines[src->engine_type]--;
01255           }
01256 
01257           /* If we move an engine to a new line affect it to the DEFAULT_GROUP */
01258           src->group_id = DEFAULT_GROUP;
01259         }
01260       } else {
01261         SetFreeWagon(src);
01262       }
01263       dst_head = src;
01264     } else {
01265       if (IsFrontEngine(src)) {
01266         /* the vehicle was previously a loco. need to free the order list and delete vehicle windows etc. */
01267         DeleteWindowById(WC_VEHICLE_VIEW, src->index);
01268         DeleteWindowById(WC_VEHICLE_ORDERS, src->index);
01269         DeleteWindowById(WC_VEHICLE_REFIT, src->index);
01270         DeleteWindowById(WC_VEHICLE_DETAILS, src->index);
01271         DeleteWindowById(WC_VEHICLE_TIMETABLE, src->index);
01272         DeleteVehicleOrders(src);
01273         RemoveVehicleFromGroup(src);
01274       }
01275 
01276       if (IsFrontEngine(src) || IsFreeWagon(src)) {
01277         InvalidateWindowData(WC_VEHICLE_DEPOT, src->tile);
01278         ClearFrontEngine(src);
01279         ClearFreeWagon(src);
01280         src->unitnumber = 0; // doesn't occupy a unitnumber anymore.
01281       }
01282 
01283       /* link in the wagon(s) in the chain. */
01284       {
01285         Vehicle *v;
01286 
01287         for (v = src; GetNextVehicle(v) != NULL; v = GetNextVehicle(v)) {}
01288         GetLastEnginePart(v)->SetNext(dst->Next());
01289       }
01290       dst->SetNext(src);
01291     }
01292 
01293     if (src->u.rail.other_multiheaded_part != NULL) {
01294       if (src->u.rail.other_multiheaded_part == src_head) {
01295         src_head = src_head->Next();
01296       }
01297       AddWagonToConsist(src->u.rail.other_multiheaded_part, src);
01298     }
01299 
01300     /* If there is an engine behind first_engine we moved away, it should become new first_engine
01301      * To do this, CmdMoveRailVehicle must be called once more
01302      * we can't loop forever here because next time we reach this line we will have a front engine */
01303     if (src_head != NULL && !IsFrontEngine(src_head) && IsTrainEngine(src_head)) {
01304       /* As in CmdMoveRailVehicle src_head->group_id will be equal to DEFAULT_GROUP
01305        * we need to save the group and reaffect it to src_head */
01306       const GroupID tmp_g = src_head->group_id;
01307       CmdMoveRailVehicle(0, flags, src_head->index | (INVALID_VEHICLE << 16), 1, text);
01308       SetTrainGroupID(src_head, tmp_g);
01309       src_head = NULL; // don't do anything more to this train since the new call will do it
01310     }
01311 
01312     if (src_head != NULL) {
01313       NormaliseTrainConsist(src_head);
01314       TrainConsistChanged(src_head, false);
01315       UpdateTrainGroupID(src_head);
01316       if (IsFrontEngine(src_head)) {
01317         /* Update the refit button and window */
01318         InvalidateWindow(WC_VEHICLE_REFIT, src_head->index);
01319         InvalidateWindowWidget(WC_VEHICLE_VIEW, src_head->index, VVW_WIDGET_REFIT_VEH);
01320       }
01321       /* Update the depot window */
01322       InvalidateWindow(WC_VEHICLE_DEPOT, src_head->tile);
01323     }
01324 
01325     if (dst_head != NULL) {
01326       NormaliseTrainConsist(dst_head);
01327       TrainConsistChanged(dst_head, false);
01328       UpdateTrainGroupID(dst_head);
01329       if (IsFrontEngine(dst_head)) {
01330         /* Update the refit button and window */
01331         InvalidateWindowWidget(WC_VEHICLE_VIEW, dst_head->index, VVW_WIDGET_REFIT_VEH);
01332         InvalidateWindow(WC_VEHICLE_REFIT, dst_head->index);
01333       }
01334       /* Update the depot window */
01335       InvalidateWindow(WC_VEHICLE_DEPOT, dst_head->tile);
01336     }
01337 
01338     InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
01339   }
01340 
01341   return CommandCost();
01342 }
01343 
01353 CommandCost CmdSellRailWagon(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01354 {
01355   /* Check if we deleted a vehicle window */
01356   Window *w = NULL;
01357 
01358   if (!IsValidVehicleID(p1) || p2 > 1) return CMD_ERROR;
01359 
01360   Vehicle *v = GetVehicle(p1);
01361 
01362   if (v->type != VEH_TRAIN || !CheckOwnership(v->owner)) return CMD_ERROR;
01363 
01364   if (HASBITS(v->vehstatus, VS_CRASHED)) return_cmd_error(STR_CAN_T_SELL_DESTROYED_VEHICLE);
01365 
01366   while (IsArticulatedPart(v)) v = v->Previous();
01367   Vehicle *first = v->First();
01368 
01369   /* make sure the vehicle is stopped in the depot */
01370   if (CheckTrainStoppedInDepot(first) < 0) {
01371     return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED);
01372   }
01373 
01374   if (IsRearDualheaded(v)) return_cmd_error(STR_REAR_ENGINE_FOLLOW_FRONT_ERROR);
01375 
01376   if (flags & DC_EXEC) {
01377     if (v == first && IsFrontEngine(first)) {
01378       DeleteWindowById(WC_VEHICLE_VIEW, first->index);
01379       DeleteWindowById(WC_VEHICLE_ORDERS, first->index);
01380       DeleteWindowById(WC_VEHICLE_REFIT, first->index);
01381       DeleteWindowById(WC_VEHICLE_DETAILS, first->index);
01382       DeleteWindowById(WC_VEHICLE_TIMETABLE, first->index);
01383     }
01384     InvalidateWindow(WC_VEHICLE_DEPOT, first->tile);
01385     InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
01386   }
01387 
01388   CommandCost cost(EXPENSES_NEW_VEHICLES);
01389   switch (p2) {
01390     case 0: { // Delete given wagon
01391       bool switch_engine = false;    // update second wagon to engine?
01392 
01393       /* 1. Delete the engine, if it is dualheaded also delete the matching
01394        * rear engine of the loco (from the point of deletion onwards) */
01395       Vehicle *rear = (IsMultiheaded(v) &&
01396         IsTrainEngine(v)) ? v->u.rail.other_multiheaded_part : NULL;
01397 
01398       if (rear != NULL) {
01399         cost.AddCost(-rear->value);
01400         if (flags & DC_EXEC) {
01401           UnlinkWagon(rear, first);
01402           delete rear;
01403         }
01404       }
01405 
01406       /* 2. We are selling the front vehicle, some special action might be required
01407        * here, so take attention */
01408       if (v == first) {
01409         Vehicle *new_f = GetNextVehicle(first);
01410 
01411         /* 2.2 If there are wagons present after the deleted front engine, check
01412          * if the second wagon (which will be first) is an engine. If it is one,
01413          * promote it as a new train, retaining the unitnumber, orders */
01414         if (new_f != NULL && IsTrainEngine(new_f)) {
01415           if (IsTrainEngine(first)) {
01416             /* Let the new front engine take over the setup of the old engine */
01417             switch_engine = true;
01418 
01419             if (flags & DC_EXEC) {
01420               /* Make sure the group counts stay correct. */
01421               new_f->group_id        = first->group_id;
01422               first->group_id        = DEFAULT_GROUP;
01423 
01424               /* Copy orders (by sharing) */
01425               new_f->orders.list     = first->orders.list;
01426               new_f->AddToShared(first);
01427               DeleteVehicleOrders(first);
01428 
01429               /* Copy other important data from the front engine */
01430               new_f->CopyVehicleConfigAndStatistics(first);
01431 
01432               /* If we deleted a window then open a new one for the 'new' train */
01433               if (IsLocalCompany() && w != NULL) ShowVehicleViewWindow(new_f);
01434             }
01435           } else {
01436             /* We are selling a free wagon, and construct a new train at the same time.
01437              * This needs lots of extra checks (e.g. train limit), which are done by first moving
01438              * the remaining vehicles to a new row */
01439             cost.AddCost(DoCommand(0, new_f->index | INVALID_VEHICLE << 16, 1, flags, CMD_MOVE_RAIL_VEHICLE));
01440             if (cost.Failed()) return cost;
01441           }
01442         }
01443       }
01444 
01445       /* 3. Delete the requested wagon */
01446       cost.AddCost(-v->value);
01447       if (flags & DC_EXEC) {
01448         first = UnlinkWagon(v, first);
01449         delete v;
01450 
01451         /* 4 If the second wagon was an engine, update it to front_engine
01452          * which UnlinkWagon() has changed to TS_Free_Car */
01453         if (switch_engine) SetFrontEngine(first);
01454 
01455         /* 5. If the train still exists, update its acceleration, window, etc. */
01456         if (first != NULL) {
01457           NormaliseTrainConsist(first);
01458           TrainConsistChanged(first, false);
01459           UpdateTrainGroupID(first);
01460           if (IsFrontEngine(first)) InvalidateWindow(WC_VEHICLE_REFIT, first->index);
01461         }
01462 
01463       }
01464     } break;
01465     case 1: { // Delete wagon and all wagons after it given certain criteria
01466       /* Start deleting every vehicle after the selected one
01467        * If we encounter a matching rear-engine to a front-engine
01468        * earlier in the chain (before deletion), leave it alone */
01469       for (Vehicle *tmp; v != NULL; v = tmp) {
01470         tmp = GetNextVehicle(v);
01471 
01472         if (IsMultiheaded(v)) {
01473           if (IsTrainEngine(v)) {
01474             /* We got a front engine of a multiheaded set. Now we will sell the rear end too */
01475             Vehicle *rear = v->u.rail.other_multiheaded_part;
01476 
01477             if (rear != NULL) {
01478               cost.AddCost(-rear->value);
01479 
01480               /* If this is a multiheaded vehicle with nothing
01481                * between the parts, tmp will be pointing to the
01482                * rear part, which is unlinked from the train and
01483                * deleted here. However, because tmp has already
01484                * been set it needs to be updated now so that the
01485                * loop never sees the rear part. */
01486               if (tmp == rear) tmp = GetNextVehicle(tmp);
01487 
01488               if (flags & DC_EXEC) {
01489                 first = UnlinkWagon(rear, first);
01490                 delete rear;
01491               }
01492             }
01493           } else if (v->u.rail.other_multiheaded_part != NULL) {
01494             /* The front to this engine is earlier in this train. Do nothing */
01495             continue;
01496           }
01497         }
01498 
01499         cost.AddCost(-v->value);
01500         if (flags & DC_EXEC) {
01501           first = UnlinkWagon(v, first);
01502           delete v;
01503         }
01504       }
01505 
01506       /* 3. If it is still a valid train after selling, update its acceleration and cached values */
01507       if (flags & DC_EXEC && first != NULL) {
01508         NormaliseTrainConsist(first);
01509         TrainConsistChanged(first, false);
01510         UpdateTrainGroupID(first);
01511         InvalidateWindow(WC_VEHICLE_REFIT, first->index);
01512       }
01513     } break;
01514   }
01515   return cost;
01516 }
01517 
01518 void Train::UpdateDeltaXY(Direction direction)
01519 {
01520 #define MKIT(a, b, c, d) ((a & 0xFF) << 24) | ((b & 0xFF) << 16) | ((c & 0xFF) << 8) | ((d & 0xFF) << 0)
01521   static const uint32 _delta_xy_table[8] = {
01522     MKIT(3, 3, -1, -1),
01523     MKIT(3, 7, -1, -3),
01524     MKIT(3, 3, -1, -1),
01525     MKIT(7, 3, -3, -1),
01526     MKIT(3, 3, -1, -1),
01527     MKIT(3, 7, -1, -3),
01528     MKIT(3, 3, -1, -1),
01529     MKIT(7, 3, -3, -1),
01530   };
01531 #undef MKIT
01532 
01533   uint32 x = _delta_xy_table[direction];
01534   this->x_offs        = GB(x,  0, 8);
01535   this->y_offs        = GB(x,  8, 8);
01536   this->x_extent      = GB(x, 16, 8);
01537   this->y_extent      = GB(x, 24, 8);
01538   this->z_extent      = 6;
01539 }
01540 
01541 static inline void SetLastSpeed(Vehicle *v, int spd)
01542 {
01543   int old = v->u.rail.last_speed;
01544   if (spd != old) {
01545     v->u.rail.last_speed = spd;
01546     if (_settings_client.gui.vehicle_speed || (old == 0) != (spd == 0)) {
01547       InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
01548     }
01549   }
01550 }
01551 
01553 static void MarkTrainAsStuck(Vehicle *v)
01554 {
01555   if (!HasBit(v->u.rail.flags, VRF_TRAIN_STUCK)) {
01556     /* It is the first time the problem occured, set the "train stuck" flag. */
01557     SetBit(v->u.rail.flags, VRF_TRAIN_STUCK);
01558 
01559     /* When loading the vehicle is already stopped. No need to change that. */
01560     if (v->current_order.IsType(OT_LOADING)) return;
01561 
01562     v->load_unload_time_rem = 0;
01563 
01564     /* Stop train */
01565     v->cur_speed = 0;
01566     v->subspeed = 0;
01567     SetLastSpeed(v, 0);
01568 
01569     InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
01570   }
01571 }
01572 
01573 static void SwapTrainFlags(uint16 *swap_flag1, uint16 *swap_flag2)
01574 {
01575   uint16 flag1 = *swap_flag1;
01576   uint16 flag2 = *swap_flag2;
01577 
01578   /* Clear the flags */
01579   ClrBit(*swap_flag1, VRF_GOINGUP);
01580   ClrBit(*swap_flag1, VRF_GOINGDOWN);
01581   ClrBit(*swap_flag2, VRF_GOINGUP);
01582   ClrBit(*swap_flag2, VRF_GOINGDOWN);
01583 
01584   /* Reverse the rail-flags (if needed) */
01585   if (HasBit(flag1, VRF_GOINGUP)) {
01586     SetBit(*swap_flag2, VRF_GOINGDOWN);
01587   } else if (HasBit(flag1, VRF_GOINGDOWN)) {
01588     SetBit(*swap_flag2, VRF_GOINGUP);
01589   }
01590   if (HasBit(flag2, VRF_GOINGUP)) {
01591     SetBit(*swap_flag1, VRF_GOINGDOWN);
01592   } else if (HasBit(flag2, VRF_GOINGDOWN)) {
01593     SetBit(*swap_flag1, VRF_GOINGUP);
01594   }
01595 }
01596 
01597 static void ReverseTrainSwapVeh(Vehicle *v, int l, int r)
01598 {
01599   Vehicle *a, *b;
01600 
01601   /* locate vehicles to swap */
01602   for (a = v; l != 0; l--) a = a->Next();
01603   for (b = v; r != 0; r--) b = b->Next();
01604 
01605   if (a != b) {
01606     /* swap the hidden bits */
01607     {
01608       uint16 tmp = (a->vehstatus & ~VS_HIDDEN) | (b->vehstatus&VS_HIDDEN);
01609       b->vehstatus = (b->vehstatus & ~VS_HIDDEN) | (a->vehstatus&VS_HIDDEN);
01610       a->vehstatus = tmp;
01611     }
01612 
01613     Swap(a->u.rail.track, b->u.rail.track);
01614     Swap(a->direction,    b->direction);
01615 
01616     /* toggle direction */
01617     if (a->u.rail.track != TRACK_BIT_DEPOT) a->direction = ReverseDir(a->direction);
01618     if (b->u.rail.track != TRACK_BIT_DEPOT) b->direction = ReverseDir(b->direction);
01619 
01620     Swap(a->x_pos, b->x_pos);
01621     Swap(a->y_pos, b->y_pos);
01622     Swap(a->tile,  b->tile);
01623     Swap(a->z_pos, b->z_pos);
01624 
01625     SwapTrainFlags(&a->u.rail.flags, &b->u.rail.flags);
01626 
01627     /* update other vars */
01628     a->UpdateViewport(true, true);
01629     b->UpdateViewport(true, true);
01630 
01631     /* call the proper EnterTile function unless we are in a wormhole */
01632     if (a->u.rail.track != TRACK_BIT_WORMHOLE) VehicleEnterTile(a, a->tile, a->x_pos, a->y_pos);
01633     if (b->u.rail.track != TRACK_BIT_WORMHOLE) VehicleEnterTile(b, b->tile, b->x_pos, b->y_pos);
01634   } else {
01635     if (a->u.rail.track != TRACK_BIT_DEPOT) a->direction = ReverseDir(a->direction);
01636     a->UpdateViewport(true, true);
01637 
01638     if (a->u.rail.track != TRACK_BIT_WORMHOLE) VehicleEnterTile(a, a->tile, a->x_pos, a->y_pos);
01639   }
01640 
01641   /* Update train's power incase tiles were different rail type */
01642   TrainPowerChanged(v);
01643 }
01644 
01645 
01651 static Vehicle *TrainOnTileEnum(Vehicle *v, void *)
01652 {
01653   return (v->type == VEH_TRAIN) ? v : NULL;
01654 }
01655 
01656 
01663 static Vehicle *TrainApproachingCrossingEnum(Vehicle *v, void *data)
01664 {
01665   /* not a train || not front engine || crashed */
01666   if (v->type != VEH_TRAIN || !IsFrontEngine(v) || v->vehstatus & VS_CRASHED) return NULL;
01667 
01668   TileIndex tile = *(TileIndex*)data;
01669 
01670   if (TrainApproachingCrossingTile(v) != tile) return NULL;
01671 
01672   return v;
01673 }
01674 
01675 
01682 static bool TrainApproachingCrossing(TileIndex tile)
01683 {
01684   assert(IsLevelCrossingTile(tile));
01685 
01686   DiagDirection dir = AxisToDiagDir(GetCrossingRailAxis(tile));
01687   TileIndex tile_from = tile + TileOffsByDiagDir(dir);
01688 
01689   if (HasVehicleOnPos(tile_from, &tile, &TrainApproachingCrossingEnum)) return true;
01690 
01691   dir = ReverseDiagDir(dir);
01692   tile_from = tile + TileOffsByDiagDir(dir);
01693 
01694   return HasVehicleOnPos(tile_from, &tile, &TrainApproachingCrossingEnum);
01695 }
01696 
01697 
01704 void UpdateLevelCrossing(TileIndex tile, bool sound)
01705 {
01706   assert(IsLevelCrossingTile(tile));
01707 
01708   /* train on crossing || train approaching crossing || reserved */
01709   bool new_state = HasVehicleOnPos(tile, NULL, &TrainOnTileEnum) || TrainApproachingCrossing(tile) || GetCrossingReservation(tile);
01710 
01711   if (new_state != IsCrossingBarred(tile)) {
01712     if (new_state && sound) {
01713       SndPlayTileFx(SND_0E_LEVEL_CROSSING, tile);
01714     }
01715     SetCrossingBarred(tile, new_state);
01716     MarkTileDirtyByTile(tile);
01717   }
01718 }
01719 
01720 
01726 static inline void MaybeBarCrossingWithSound(TileIndex tile)
01727 {
01728   if (!IsCrossingBarred(tile)) {
01729     BarCrossing(tile);
01730     SndPlayTileFx(SND_0E_LEVEL_CROSSING, tile);
01731     MarkTileDirtyByTile(tile);
01732   }
01733 }
01734 
01735 
01741 static void AdvanceWagonsBeforeSwap(Vehicle *v)
01742 {
01743   Vehicle *base = v;
01744   Vehicle *first = base;                    // first vehicle to move
01745   Vehicle *last = GetLastVehicleInChain(v); // last vehicle to move
01746   uint length = CountVehiclesInChain(v);
01747 
01748   while (length > 2) {
01749     last = last->Previous();
01750     first = first->Next();
01751 
01752     int differential = base->u.rail.cached_veh_length - last->u.rail.cached_veh_length;
01753 
01754     /* do not update images now
01755      * negative differential will be handled in AdvanceWagonsAfterSwap() */
01756     for (int i = 0; i < differential; i++) TrainController(first, last->Next());
01757 
01758     base = first; // == base->Next()
01759     length -= 2;
01760   }
01761 }
01762 
01763 
01769 static void AdvanceWagonsAfterSwap(Vehicle *v)
01770 {
01771   /* first of all, fix the situation when the train was entering a depot */
01772   Vehicle *dep = v; // last vehicle in front of just left depot
01773   while (dep->Next() != NULL && (dep->u.rail.track == TRACK_BIT_DEPOT || dep->Next()->u.rail.track != TRACK_BIT_DEPOT)) {
01774     dep = dep->Next(); // find first vehicle outside of a depot, with next vehicle inside a depot
01775   }
01776 
01777   Vehicle *leave = dep->Next(); // first vehicle in a depot we are leaving now
01778 
01779   if (leave != NULL) {
01780     /* 'pull' next wagon out of the depot, so we won't miss it (it could stay in depot forever) */
01781     int d = TicksToLeaveDepot(dep);
01782 
01783     if (d <= 0) {
01784       leave->vehstatus &= ~VS_HIDDEN; // move it out of the depot
01785       leave->u.rail.track = TrackToTrackBits(GetRailDepotTrack(leave->tile));
01786       for (int i = 0; i >= d; i--) TrainController(leave, NULL); // maybe move it, and maybe let another wagon leave
01787     }
01788   } else {
01789     dep = NULL; // no vehicle in a depot, so no vehicle leaving a depot
01790   }
01791 
01792   Vehicle *base = v;
01793   Vehicle *first = base;                    // first vehicle to move
01794   Vehicle *last = GetLastVehicleInChain(v); // last vehicle to move
01795   uint length = CountVehiclesInChain(v);
01796 
01797   /* we have to make sure all wagons that leave a depot because of train reversing are moved coorectly
01798    * they have already correct spacing, so we have to make sure they are moved how they should */
01799   bool nomove = (dep == NULL); // if there is no vehicle leaving a depot, limit the number of wagons moved immediatelly
01800 
01801   while (length > 2) {
01802     /* we reached vehicle (originally) in front of a depot, stop now
01803      * (we would move wagons that are alredy moved with new wagon length) */
01804     if (base == dep) break;
01805 
01806     /* the last wagon was that one leaving a depot, so do not move it anymore */
01807     if (last == dep) nomove = true;
01808 
01809     last = last->Previous();
01810     first = first->Next();
01811 
01812     int differential = last->u.rail.cached_veh_length - base->u.rail.cached_veh_length;
01813 
01814     /* do not update images now */
01815     for (int i = 0; i < differential; i++) TrainController(first, (nomove ? last->Next() : NULL));
01816 
01817     base = first; // == base->Next()
01818     length -= 2;
01819   }
01820 }
01821 
01822 
01823 static void ReverseTrainDirection(Vehicle *v)
01824 {
01825   if (IsRailDepotTile(v->tile)) {
01826     InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
01827   }
01828 
01829   /* Clear path reservation in front if train is not stuck. */
01830   if (!HasBit(v->u.rail.flags, VRF_TRAIN_STUCK)) FreeTrainTrackReservation(v);
01831 
01832   /* Check if we were approaching a rail/road-crossing */
01833   TileIndex crossing = TrainApproachingCrossingTile(v);
01834 
01835   /* count number of vehicles */
01836   int r = CountVehiclesInChain(v) - 1;  // number of vehicles - 1
01837 
01838   AdvanceWagonsBeforeSwap(v);
01839 
01840   /* swap start<>end, start+1<>end-1, ... */
01841   int l = 0;
01842   do {
01843     ReverseTrainSwapVeh(v, l++, r--);
01844   } while (l <= r);
01845 
01846   AdvanceWagonsAfterSwap(v);
01847 
01848   if (IsRailDepotTile(v->tile)) {
01849     InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
01850   }
01851 
01852   ToggleBit(v->u.rail.flags, VRF_TOGGLE_REVERSE);
01853 
01854   ClrBit(v->u.rail.flags, VRF_REVERSING);
01855 
01856   /* recalculate cached data */
01857   TrainConsistChanged(v, true);
01858 
01859   /* update all images */
01860   for (Vehicle *u = v; u != NULL; u = u->Next()) u->UpdateViewport(false, false);
01861 
01862   /* update crossing we were approaching */
01863   if (crossing != INVALID_TILE) UpdateLevelCrossing(crossing);
01864 
01865   /* maybe we are approaching crossing now, after reversal */
01866   crossing = TrainApproachingCrossingTile(v);
01867   if (crossing != INVALID_TILE) MaybeBarCrossingWithSound(crossing);
01868 
01869   /* If we are inside a depot after reversing, don't bother with path reserving. */
01870   if (v->u.rail.track & TRACK_BIT_DEPOT) {
01871     /* Can't be stuck here as inside a depot is always a safe tile. */
01872     if (HasBit(v->u.rail.flags, VRF_TRAIN_STUCK)) InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
01873     ClrBit(v->u.rail.flags, VRF_TRAIN_STUCK);
01874     return;
01875   }
01876 
01877   /* TrainExitDir does not always produce the desired dir for depots and
01878    * tunnels/bridges that is needed for UpdateSignalsOnSegment. */
01879   DiagDirection dir = TrainExitDir(v->direction, v->u.rail.track);
01880   if (IsRailDepotTile(v->tile) || IsTileType(v->tile, MP_TUNNELBRIDGE)) dir = INVALID_DIAGDIR;
01881 
01882   if (UpdateSignalsOnSegment(v->tile, dir, v->owner) == SIGSEG_PBS || _settings_game.pf.reserve_paths) {
01883     /* If we are currently on a tile with conventional signals, we can't treat the
01884      * current tile as a safe tile or we would enter a PBS block without a reservation. */
01885     bool first_tile_okay = !(IsTileType(v->tile, MP_RAILWAY) &&
01886       HasSignalOnTrackdir(v->tile, GetVehicleTrackdir(v)) &&
01887       !IsPbsSignal(GetSignalType(v->tile, FindFirstTrack(v->u.rail.track))));
01888 
01889     if (IsRailwayStationTile(v->tile)) SetRailwayStationPlatformReservation(v->tile, TrackdirToExitdir(GetVehicleTrackdir(v)), true);
01890     if (TryPathReserve(v, false, first_tile_okay)) {
01891       /* Do a look-ahead now in case our current tile was already a safe tile. */
01892       CheckNextTrainTile(v);
01893     } else if (v->current_order.GetType() != OT_LOADING) {
01894       /* Do not wait for a way out when we're still loading */
01895       MarkTrainAsStuck(v);
01896     }
01897   } else if (HasBit(v->u.rail.flags, VRF_TRAIN_STUCK)) {
01898     /* A train not inside a PBS block can't be stuck. */
01899     ClrBit(v->u.rail.flags, VRF_TRAIN_STUCK);
01900     v->load_unload_time_rem = 0;
01901   }
01902 }
01903 
01910 CommandCost CmdReverseTrainDirection(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01911 {
01912   if (!IsValidVehicleID(p1)) return CMD_ERROR;
01913 
01914   Vehicle *v = GetVehicle(p1);
01915 
01916   if (v->type != VEH_TRAIN || !CheckOwnership(v->owner)) return CMD_ERROR;
01917 
01918   if (p2 != 0) {
01919     /* turn a single unit around */
01920 
01921     if (IsMultiheaded(v) || HasBit(EngInfo(v->engine_type)->callbackmask, CBM_VEHICLE_ARTIC_ENGINE)) {
01922       return_cmd_error(STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE_MULTIPLE_UNITS);
01923     }
01924 
01925     Vehicle *front = v->First();
01926     /* make sure the vehicle is stopped in the depot */
01927     if (CheckTrainStoppedInDepot(front) < 0) {
01928       return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED);
01929     }
01930 
01931     if (flags & DC_EXEC) {
01932       ToggleBit(v->u.rail.flags, VRF_REVERSE_DIRECTION);
01933       InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
01934       InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
01935     }
01936   } else {
01937     /* turn the whole train around */
01938     if (v->vehstatus & VS_CRASHED || v->breakdown_ctr != 0) return CMD_ERROR;
01939 
01940     if (flags & DC_EXEC) {
01941       /* Properly leave the station if we are loading and won't be loading anymore */
01942       if (v->current_order.IsType(OT_LOADING)) {
01943         const Vehicle *last = v;
01944         while (last->Next() != NULL) last = last->Next();
01945 
01946         /* not a station || different station --> leave the station */
01947         if (!IsTileType(last->tile, MP_STATION) || GetStationIndex(last->tile) != GetStationIndex(v->tile)) {
01948           v->LeaveStation();
01949         }
01950       }
01951 
01952       if (_settings_game.vehicle.train_acceleration_model != TAM_ORIGINAL && v->cur_speed != 0) {
01953         ToggleBit(v->u.rail.flags, VRF_REVERSING);
01954       } else {
01955         v->cur_speed = 0;
01956         SetLastSpeed(v, 0);
01957         HideFillingPercent(&v->fill_percent_te_id);
01958         ReverseTrainDirection(v);
01959       }
01960     }
01961   }
01962   return CommandCost();
01963 }
01964 
01971 CommandCost CmdForceTrainProceed(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01972 {
01973   if (!IsValidVehicleID(p1)) return CMD_ERROR;
01974 
01975   Vehicle *v = GetVehicle(p1);
01976 
01977   if (v->type != VEH_TRAIN || !CheckOwnership(v->owner)) return CMD_ERROR;
01978 
01979   if (flags & DC_EXEC) v->u.rail.force_proceed = 0x50;
01980 
01981   return CommandCost();
01982 }
01983 
01994 CommandCost CmdRefitRailVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01995 {
01996   CargoID new_cid = GB(p2, 0, 8);
01997   byte new_subtype = GB(p2, 8, 8);
01998   bool only_this = HasBit(p2, 16);
01999 
02000   if (!IsValidVehicleID(p1)) return CMD_ERROR;
02001 
02002   Vehicle *v = GetVehicle(p1);
02003 
02004   if (v->type != VEH_TRAIN || !CheckOwnership(v->owner)) return CMD_ERROR;
02005   if (CheckTrainStoppedInDepot(v) < 0) return_cmd_error(STR_TRAIN_MUST_BE_STOPPED);
02006   if (v->vehstatus & VS_CRASHED) return_cmd_error(STR_CAN_T_REFIT_DESTROYED_VEHICLE);
02007 
02008   /* Check cargo */
02009   if (new_cid >= NUM_CARGO) return CMD_ERROR;
02010 
02011   CommandCost cost(EXPENSES_TRAIN_RUN);
02012   uint num = 0;
02013 
02014   do {
02015     /* XXX: We also refit all the attached wagons en-masse if they
02016      * can be refitted. This is how TTDPatch does it.  TODO: Have
02017      * some nice [Refit] button near each wagon. --pasky */
02018     if (!CanRefitTo(v->engine_type, new_cid)) continue;
02019 
02020     const Engine *e = GetEngine(v->engine_type);
02021     if (e->CanCarryCargo()) {
02022       uint16 amount = CALLBACK_FAILED;
02023 
02024       if (HasBit(EngInfo(v->engine_type)->callbackmask, CBM_VEHICLE_REFIT_CAPACITY)) {
02025         /* Back up the vehicle's cargo type */
02026         CargoID temp_cid = v->cargo_type;
02027         byte temp_subtype = v->cargo_subtype;
02028         v->cargo_type = new_cid;
02029         v->cargo_subtype = new_subtype;
02030         /* Check the refit capacity callback */
02031         amount = GetVehicleCallback(CBID_VEHICLE_REFIT_CAPACITY, 0, 0, v->engine_type, v);
02032         /* Restore the original cargo type */
02033         v->cargo_type = temp_cid;
02034         v->cargo_subtype = temp_subtype;
02035       }
02036 
02037       if (amount == CALLBACK_FAILED) { // callback failed or not used, use default
02038         CargoID old_cid = e->GetDefaultCargoType();
02039         /* normally, the capacity depends on the cargo type, a rail vehicle can
02040          * carry twice as much mail/goods as normal cargo, and four times as
02041          * many passengers
02042          */
02043         amount = e->u.rail.capacity;
02044         switch (old_cid) {
02045           case CT_PASSENGERS: break;
02046           case CT_MAIL:
02047           case CT_GOODS: amount *= 2; break;
02048           default:       amount *= 4; break;
02049         }
02050         switch (new_cid) {
02051           case CT_PASSENGERS: break;
02052           case CT_MAIL:
02053           case CT_GOODS: amount /= 2; break;
02054           default:       amount /= 4; break;
02055         }
02056       }
02057 
02058       if (new_cid != v->cargo_type) {
02059         cost.AddCost(GetRefitCost(v->engine_type));
02060       }
02061 
02062       num += amount;
02063       if (flags & DC_EXEC) {
02064         v->cargo.Truncate((v->cargo_type == new_cid) ? amount : 0);
02065         v->cargo_type = new_cid;
02066         v->cargo_cap = amount;
02067         v->cargo_subtype = new_subtype;
02068         InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
02069         InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
02070         InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
02071       }
02072     }
02073   } while ((v = v->Next()) != NULL && !only_this);
02074 
02075   _returned_refit_capacity = num;
02076 
02077   /* Update the train's cached variables */
02078   if (flags & DC_EXEC) TrainConsistChanged(GetVehicle(p1)->First(), false);
02079 
02080   return cost;
02081 }
02082 
02083 struct TrainFindDepotData {
02084   uint best_length;
02085   TileIndex tile;
02086   Owner owner;
02091   bool reverse;
02092 };
02093 
02094 static bool NtpCallbFindDepot(TileIndex tile, TrainFindDepotData *tfdd, int track, uint length)
02095 {
02096   if (IsTileType(tile, MP_RAILWAY) &&
02097       IsTileOwner(tile, tfdd->owner) &&
02098       IsRailDepot(tile)) {
02099     /* approximate number of tiles by dividing by DIAG_FACTOR */
02100     tfdd->best_length = length / DIAG_FACTOR;
02101     tfdd->tile = tile;
02102     return true;
02103   }
02104 
02105   return false;
02106 }
02107 
02110 static TrainFindDepotData FindClosestTrainDepot(Vehicle *v, int max_distance)
02111 {
02112   assert(!(v->vehstatus & VS_CRASHED));
02113 
02114   TrainFindDepotData tfdd;
02115   tfdd.owner = v->owner;
02116   tfdd.reverse = false;
02117 
02118   if (IsRailDepotTile(v->tile)) {
02119     tfdd.tile = v->tile;
02120     tfdd.best_length = 0;
02121     return tfdd;
02122   }
02123 
02124   PBSTileInfo origin = FollowTrainReservation(v);
02125   if (IsRailDepotTile(origin.tile)) {
02126     tfdd.tile = origin.tile;
02127     tfdd.best_length = 0;
02128     return tfdd;
02129   }
02130 
02131   tfdd.best_length = UINT_MAX;
02132 
02133   uint8 pathfinder = _settings_game.pf.pathfinder_for_trains;
02134   if ((_settings_game.pf.reserve_paths || HasReservedTracks(v->tile, v->u.rail.track)) && pathfinder == VPF_NTP) pathfinder = VPF_NPF;
02135 
02136   switch (pathfinder) {
02137     case VPF_YAPF: { // YAPF
02138       bool found = YapfFindNearestRailDepotTwoWay(v, max_distance, NPF_INFINITE_PENALTY, &tfdd.tile, &tfdd.reverse);
02139       tfdd.best_length = found ? max_distance / 2 : UINT_MAX; // some fake distance or NOT_FOUND
02140     } break;
02141 
02142     case VPF_NPF: { // NPF
02143       const Vehicle *last = GetLastVehicleInChain(v);
02144       Trackdir trackdir = GetVehicleTrackdir(v);
02145       Trackdir trackdir_rev = ReverseTrackdir(GetVehicleTrackdir(last));
02146 
02147       assert(trackdir != INVALID_TRACKDIR);
02148       NPFFoundTargetData ftd = NPFRouteToDepotBreadthFirstTwoWay(v->tile, trackdir, false, last->tile, trackdir_rev, false, TRANSPORT_RAIL, 0, v->owner, v->u.rail.compatible_railtypes, NPF_INFINITE_PENALTY);
02149       if (ftd.best_bird_dist == 0) {
02150         /* Found target */
02151         tfdd.tile = ftd.node.tile;
02152         /* Our caller expects a number of tiles, so we just approximate that
02153          * number by this. It might not be completely what we want, but it will
02154          * work for now :-) We can possibly change this when the old pathfinder
02155          * is removed. */
02156         tfdd.best_length = ftd.best_path_dist / NPF_TILE_LENGTH;
02157         if (NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE)) tfdd.reverse = true;
02158       }
02159     } break;
02160 
02161     default:
02162     case VPF_NTP: { // NTP
02163       /* search in the forward direction first. */
02164       DiagDirection i = TrainExitDir(v->direction, v->u.rail.track);
02165       NewTrainPathfind(v->tile, 0, v->u.rail.compatible_railtypes, i, (NTPEnumProc*)NtpCallbFindDepot, &tfdd);
02166       if (tfdd.best_length == UINT_MAX){
02167         tfdd.reverse = true;
02168         /* search in backwards direction */
02169         i = TrainExitDir(ReverseDir(v->direction), v->u.rail.track);
02170         NewTrainPathfind(v->tile, 0, v->u.rail.compatible_railtypes, i, (NTPEnumProc*)NtpCallbFindDepot, &tfdd);
02171       }
02172     } break;
02173   }
02174 
02175   return tfdd;
02176 }
02177 
02178 bool Train::FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse)
02179 {
02180   TrainFindDepotData tfdd = FindClosestTrainDepot(this, 0);
02181   if (tfdd.best_length == UINT_MAX) return false;
02182 
02183   if (location    != NULL) *location    = tfdd.tile;
02184   if (destination != NULL) *destination = GetDepotByTile(tfdd.tile)->index;
02185   if (reverse     != NULL) *reverse     = tfdd.reverse;
02186 
02187   return true;
02188 }
02189 
02198 CommandCost CmdSendTrainToDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
02199 {
02200   if (p2 & DEPOT_MASS_SEND) {
02201     /* Mass goto depot requested */
02202     if (!ValidVLWFlags(p2 & VLW_MASK)) return CMD_ERROR;
02203     return SendAllVehiclesToDepot(VEH_TRAIN, flags, p2 & DEPOT_SERVICE, _current_company, (p2 & VLW_MASK), p1);
02204   }
02205 
02206   if (!IsValidVehicleID(p1)) return CMD_ERROR;
02207 
02208   Vehicle *v = GetVehicle(p1);
02209 
02210   if (v->type != VEH_TRAIN) return CMD_ERROR;
02211 
02212   return v->SendToDepot(flags, (DepotCommand)(p2 & DEPOT_COMMAND_MASK));
02213 }
02214 
02215 
02216 void OnTick_Train()
02217 {
02218   _age_cargo_skip_counter = (_age_cargo_skip_counter == 0) ? 184 : (_age_cargo_skip_counter - 1);
02219 }
02220 
02221 static const int8 _vehicle_smoke_pos[8] = {
02222   1, 1, 1, 0, -1, -1, -1, 0
02223 };
02224 
02225 static void HandleLocomotiveSmokeCloud(const Vehicle *v)
02226 {
02227   bool sound = false;
02228 
02229   if (v->vehstatus & VS_TRAIN_SLOWING || v->load_unload_time_rem != 0 || v->cur_speed < 2) {
02230     return;
02231   }
02232 
02233   const Vehicle *u = v;
02234 
02235   do {
02236     const RailVehicleInfo *rvi = RailVehInfo(v->engine_type);
02237     int effect_offset = GB(v->u.rail.cached_vis_effect, 0, 4) - 8;
02238     byte effect_type = GB(v->u.rail.cached_vis_effect, 4, 2);
02239     bool disable_effect = HasBit(v->u.rail.cached_vis_effect, 6);
02240 
02241     /* no smoke? */
02242     if ((rvi->railveh_type == RAILVEH_WAGON && effect_type == 0) ||
02243         disable_effect ||
02244         v->vehstatus & VS_HIDDEN) {
02245       continue;
02246     }
02247 
02248     /* No smoke in depots or tunnels */
02249     if (IsRailDepotTile(v->tile) || IsTunnelTile(v->tile)) continue;
02250 
02251     /* No sparks for electric vehicles on nonelectrified tracks */
02252     if (!HasPowerOnRail(v->u.rail.railtype, GetTileRailType(v->tile))) continue;
02253 
02254     if (effect_type == 0) {
02255       /* Use default effect type for engine class. */
02256       effect_type = rvi->engclass;
02257     } else {
02258       effect_type--;
02259     }
02260 
02261     int x = _vehicle_smoke_pos[v->direction] * effect_offset;
02262     int y = _vehicle_smoke_pos[(v->direction + 2) % 8] * effect_offset;
02263 
02264     if (HasBit(v->u.rail.flags, VRF_REVERSE_DIRECTION)) {
02265       x = -x;
02266       y = -y;
02267     }
02268 
02269     switch (effect_type) {
02270       case 0:
02271         /* steam smoke. */
02272         if (GB(v->tick_counter, 0, 4) == 0) {
02273           CreateEffectVehicleRel(v, x, y, 10, EV_STEAM_SMOKE);
02274           sound = true;
02275         }
02276         break;
02277 
02278       case 1:
02279         /* diesel smoke */
02280         if (u->cur_speed <= 40 && Chance16(15, 128)) {
02281           CreateEffectVehicleRel(v, 0, 0, 10, EV_DIESEL_SMOKE);
02282           sound = true;
02283         }
02284         break;
02285 
02286       case 2:
02287         /* blue spark */
02288         if (GB(v->tick_counter, 0, 2) == 0 && Chance16(1, 45)) {
02289           CreateEffectVehicleRel(v, 0, 0, 10, EV_ELECTRIC_SPARK);
02290           sound = true;
02291         }
02292         break;
02293 
02294       default:
02295         break;
02296     }
02297   } while ((v = v->Next()) != NULL);
02298 
02299   if (sound) PlayVehicleSound(u, VSE_TRAIN_EFFECT);
02300 }
02301 
02302 void Train::PlayLeaveStationSound() const
02303 {
02304   static const SoundFx sfx[] = {
02305     SND_04_TRAIN,
02306     SND_0A_TRAIN_HORN,
02307     SND_0A_TRAIN_HORN,
02308     SND_47_MAGLEV_2,
02309     SND_41_MAGLEV
02310   };
02311 
02312   if (PlayVehicleSound(this, VSE_START)) return;
02313 
02314   EngineID engtype = this->engine_type;
02315   SndPlayVehicleFx(sfx[RailVehInfo(engtype)->engclass], this);
02316 }
02317 
02319 static void CheckNextTrainTile(Vehicle *v)
02320 {
02321   /* Don't do any look-ahead if path_backoff_interval is 255. */
02322   if (_settings_game.pf.path_backoff_interval == 255) return;
02323 
02324   /* Exit if we reached our destination depot or are inside a depot. */
02325   if ((v->tile == v->dest_tile && v->current_order.IsType(OT_GOTO_DEPOT)) || v->u.rail.track & TRACK_BIT_DEPOT) return;
02326   /* Exit if we are on a station tile and are going to stop. */
02327   if (IsRailwayStationTile(v->tile) && v->current_order.ShouldStopAtStation(v, GetStationIndex(v->tile))) return;
02328   /* Exit if the current order doesn't have a destination, but the train has orders. */
02329   if ((v->current_order.IsType(OT_NOTHING) || v->current_order.IsType(OT_LEAVESTATION) || v->current_order.IsType(OT_LOADING)) && v->GetNumOrders() > 0) return;
02330 
02331   Trackdir td = GetVehicleTrackdir(v);
02332 
02333   /* On a tile with a red non-pbs signal, don't look ahead. */
02334   if (IsTileType(v->tile, MP_RAILWAY) && HasSignalOnTrackdir(v->tile, td) &&
02335       !IsPbsSignal(GetSignalType(v->tile, TrackdirToTrack(td))) &&
02336       GetSignalStateByTrackdir(v->tile, td) == SIGNAL_STATE_RED) return;
02337 
02338   CFollowTrackRail ft(v);
02339   if (!ft.Follow(v->tile, td)) return;
02340 
02341   if (!HasReservedTracks(ft.m_new_tile, TrackdirBitsToTrackBits(ft.m_new_td_bits))) {
02342     /* Next tile is not reserved. */
02343     if (KillFirstBit(ft.m_new_td_bits) == TRACKDIR_BIT_NONE) {
02344       if (HasPbsSignalOnTrackdir(ft.m_new_tile, FindFirstTrackdir(ft.m_new_td_bits))) {
02345         /* If the next tile is a PBS signal, try to make a reservation. */
02346         TrackBits tracks = TrackdirBitsToTrackBits(ft.m_new_td_bits);
02347         if (_settings_game.pf.pathfinder_for_trains != VPF_NTP && _settings_game.pf.forbid_90_deg) {
02348           tracks &= ~TrackCrossesTracks(TrackdirToTrack(ft.m_old_td));
02349         }
02350         ChooseTrainTrack(v, ft.m_new_tile, ft.m_exitdir, tracks, false, NULL, false);
02351       }
02352     }
02353   }
02354 }
02355 
02356 static bool CheckTrainStayInDepot(Vehicle *v)
02357 {
02358   /* bail out if not all wagons are in the same depot or not in a depot at all */
02359   for (const Vehicle *u = v; u != NULL; u = u->Next()) {
02360     if (u->u.rail.track != TRACK_BIT_DEPOT || u->tile != v->tile) return false;
02361   }
02362 
02363   /* if the train got no power, then keep it in the depot */
02364   if (v->u.rail.cached_power == 0) {
02365     v->vehstatus |= VS_STOPPED;
02366     InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
02367     return true;
02368   }
02369 
02370   SigSegState seg_state;
02371 
02372   if (v->u.rail.force_proceed == 0) {
02373     /* force proceed was not pressed */
02374     if (++v->load_unload_time_rem < 37) {
02375       InvalidateWindowClasses(WC_TRAINS_LIST);
02376       return true;
02377     }
02378 
02379     v->load_unload_time_rem = 0;
02380 
02381     seg_state = _settings_game.pf.reserve_paths ? SIGSEG_PBS : UpdateSignalsOnSegment(v->tile, INVALID_DIAGDIR, v->owner);
02382     if (seg_state == SIGSEG_FULL || GetDepotWaypointReservation(v->tile)) {
02383       /* Full and no PBS signal in block or depot reserved, can't exit. */
02384       InvalidateWindowClasses(WC_TRAINS_LIST);
02385       return true;
02386     }
02387   } else {
02388     seg_state = _settings_game.pf.reserve_paths ? SIGSEG_PBS : UpdateSignalsOnSegment(v->tile, INVALID_DIAGDIR, v->owner);
02389   }
02390 
02391   /* We are leaving a depot, but have to go to the exact same one; re-enter */
02392   if (v->current_order.IsType(OT_GOTO_DEPOT) && v->tile == v->dest_tile) {
02393     /* We need to have a reservation for this to work. */
02394     if (GetDepotWaypointReservation(v->tile)) return true;
02395     SetDepotWaypointReservation(v->tile, true);
02396     VehicleEnterDepot(v);
02397     return true;
02398   }
02399 
02400   /* Only leave when we can reserve a path to our destination. */
02401   if (seg_state == SIGSEG_PBS && !TryPathReserve(v) && v->u.rail.force_proceed == 0) {
02402     /* No path and no force proceed. */
02403     InvalidateWindowClasses(WC_TRAINS_LIST);
02404     MarkTrainAsStuck(v);
02405     return true;
02406   }
02407 
02408   SetDepotWaypointReservation(v->tile, true);
02409   if (_settings_client.gui.show_track_reservation) MarkTileDirtyByTile(v->tile);
02410 
02411   VehicleServiceInDepot(v);
02412   InvalidateWindowClasses(WC_TRAINS_LIST);
02413   v->PlayLeaveStationSound();
02414 
02415   v->u.rail.track = TRACK_BIT_X;
02416   if (v->direction & 2) v->u.rail.track = TRACK_BIT_Y;
02417 
02418   v->vehstatus &= ~VS_HIDDEN;
02419   v->cur_speed = 0;
02420 
02421   v->UpdateDeltaXY(v->direction);
02422   v->cur_image = v->GetImage(v->direction);
02423   VehicleMove(v, false);
02424   UpdateSignalsOnSegment(v->tile, INVALID_DIAGDIR, v->owner);
02425   UpdateTrainAcceleration(v);
02426   InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
02427 
02428   return false;
02429 }
02430 
02432 static void ClearPathReservation(const Vehicle *v, TileIndex tile, Trackdir track_dir)
02433 {
02434   DiagDirection dir = TrackdirToExitdir(track_dir);
02435 
02436   if (IsTileType(tile, MP_TUNNELBRIDGE)) {
02437     /* Are we just leaving a tunnel/bridge? */
02438     if (GetTunnelBridgeDirection(tile) == ReverseDiagDir(dir)) {
02439       TileIndex end = GetOtherTunnelBridgeEnd(tile);
02440 
02441       if (!HasVehicleOnTunnelBridge(tile, end, v)) {
02442         /* Free the reservation only if no other train is on the tiles. */
02443         SetTunnelBridgeReservation(tile, false);
02444         SetTunnelBridgeReservation(end, false);
02445 
02446         if (_settings_client.gui.show_track_reservation) {
02447           MarkTileDirtyByTile(tile);
02448           MarkTileDirtyByTile(end);
02449         }
02450       }
02451     }
02452   } else if (IsRailwayStationTile(tile)) {
02453     TileIndex new_tile = TileAddByDiagDir(tile, dir);
02454     /* If the new tile is not a further tile of the same station, we
02455      * clear the reservation for the whole platform. */
02456     if (!IsCompatibleTrainStationTile(new_tile, tile)) {
02457       SetRailwayStationPlatformReservation(tile, ReverseDiagDir(dir), false);
02458     }
02459   } else {
02460     /* Any other tile */
02461     UnreserveRailTrack(tile, TrackdirToTrack(track_dir));
02462   }
02463 }
02464 
02466 void FreeTrainTrackReservation(const Vehicle *v, TileIndex origin, Trackdir orig_td)
02467 {
02468   assert(IsFrontEngine(v));
02469 
02470   TileIndex tile = origin != INVALID_TILE ? origin : v->tile;
02471   Trackdir  td = orig_td != INVALID_TRACKDIR ? orig_td : GetVehicleTrackdir(v);
02472   bool      free_tile = tile != v->tile || !(IsRailwayStationTile(v->tile) || IsTileType(v->tile, MP_TUNNELBRIDGE));
02473   StationID station_id = IsRailwayStationTile(v->tile) ? GetStationIndex(v->tile) : INVALID_STATION;
02474 
02475   /* Don't free reservation if it's not ours. */
02476   if (TracksOverlap(GetReservedTrackbits(tile) | TrackToTrackBits(TrackdirToTrack(td)))) return;
02477 
02478   CFollowTrackRail ft(v, GetRailTypeInfo(v->u.rail.railtype)->compatible_railtypes);
02479   while (ft.Follow(tile, td)) {
02480     tile = ft.m_new_tile;
02481     TrackdirBits bits = ft.m_new_td_bits & TrackBitsToTrackdirBits(GetReservedTrackbits(tile));
02482     td = RemoveFirstTrackdir(&bits);
02483     assert(bits == TRACKDIR_BIT_NONE);
02484 
02485     if (!IsValidTrackdir(td)) break;
02486 
02487     if (IsTileType(tile, MP_RAILWAY)) {
02488       if (HasSignalOnTrackdir(tile, td) && !IsPbsSignal(GetSignalType(tile, TrackdirToTrack(td)))) {
02489         /* Conventional signal along trackdir: remove reservation and stop. */
02490         UnreserveRailTrack(tile, TrackdirToTrack(td));
02491         break;
02492       }
02493       if (HasPbsSignalOnTrackdir(tile, td)) {
02494         if (GetSignalStateByTrackdir(tile, td) == SIGNAL_STATE_RED) {
02495           /* Red PBS signal? Can't be our reservation, would be green then. */
02496           break;
02497         } else {
02498           /* Turn the signal back to red. */
02499           SetSignalStateByTrackdir(tile, td, SIGNAL_STATE_RED);
02500           MarkTileDirtyByTile(tile);
02501         }
02502       } else if (HasSignalOnTrackdir(tile, ReverseTrackdir(td)) && IsOnewaySignal(tile, TrackdirToTrack(td))) {
02503         break;
02504       }
02505     }
02506 
02507     /* Don't free first station/bridge/tunnel if we are on it. */
02508     if (free_tile || (!(ft.m_is_station && GetStationIndex(ft.m_new_tile) == station_id) && !ft.m_is_tunnel && !ft.m_is_bridge)) ClearPathReservation(v, tile, td);
02509 
02510     free_tile = true;
02511   }
02512 }
02513 
02515 struct TrainTrackFollowerData {
02516   TileIndex dest_coords;
02517   StationID station_index; 
02518   uint best_bird_dist;
02519   uint best_track_dist;
02520   TrackdirByte best_track;
02521 };
02522 
02523 static bool NtpCallbFindStation(TileIndex tile, TrainTrackFollowerData *ttfd, Trackdir track, uint length)
02524 {
02525   /* heading for nowhere? */
02526   if (ttfd->dest_coords == 0) return false;
02527 
02528   /* did we reach the final station? */
02529   if ((ttfd->station_index == INVALID_STATION && tile == ttfd->dest_coords) || (
02530         IsTileType(tile, MP_STATION) &&
02531         IsRailwayStation(tile) &&
02532         GetStationIndex(tile) == ttfd->station_index
02533       )) {
02534     /* We do not check for dest_coords if we have a station_index,
02535      * because in that case the dest_coords are just an
02536      * approximation of where the station is */
02537 
02538     /* found station */
02539     ttfd->best_track = track;
02540     ttfd->best_bird_dist = 0;
02541     return true;
02542   } else {
02543     /* didn't find station, keep track of the best path so far. */
02544     uint dist = DistanceManhattan(tile, ttfd->dest_coords);
02545     if (dist < ttfd->best_bird_dist) {
02546       ttfd->best_bird_dist = dist;
02547       ttfd->best_track = track;
02548     }
02549     return false;
02550   }
02551 }
02552 
02553 static void FillWithStationData(TrainTrackFollowerData *fd, const Vehicle *v)
02554 {
02555   fd->dest_coords = v->dest_tile;
02556   fd->station_index = v->current_order.IsType(OT_GOTO_STATION) ? v->current_order.GetDestination() : INVALID_STATION;
02557 }
02558 
02559 static const byte _initial_tile_subcoord[6][4][3] = {
02560 {{ 15, 8, 1 }, { 0, 0, 0 }, { 0, 8, 5 }, { 0,  0, 0 }},
02561 {{  0, 0, 0 }, { 8, 0, 3 }, { 0, 0, 0 }, { 8, 15, 7 }},
02562 {{  0, 0, 0 }, { 7, 0, 2 }, { 0, 7, 6 }, { 0,  0, 0 }},
02563 {{ 15, 8, 2 }, { 0, 0, 0 }, { 0, 0, 0 }, { 8, 15, 6 }},
02564 {{ 15, 7, 0 }, { 8, 0, 4 }, { 0, 0, 0 }, { 0,  0, 0 }},
02565 {{  0, 0, 0 }, { 0, 0, 0 }, { 0, 8, 4 }, { 7, 15, 0 }},
02566 };
02567 
02568 static const byte _search_directions[6][4] = {
02569   { 0, 9, 2, 9 }, 
02570   { 9, 1, 9, 3 }, 
02571   { 9, 0, 3, 9 }, 
02572   { 1, 9, 9, 2 }, 
02573   { 3, 2, 9, 9 }, 
02574   { 9, 9, 1, 0 }, 
02575 };
02576 
02577 static const byte _pick_track_table[6] = {1, 3, 2, 2, 0, 0};
02578 
02591 static Track DoTrainPathfind(Vehicle *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool *path_not_found, bool do_track_reservation, PBSTileInfo *dest)
02592 {
02593   Track best_track;
02594 
02595 #ifdef PF_BENCHMARK
02596   TIC()
02597 #endif
02598 
02599   if (path_not_found) *path_not_found = false;
02600 
02601   uint8 pathfinder = _settings_game.pf.pathfinder_for_trains;
02602   if (do_track_reservation && pathfinder == VPF_NTP) pathfinder = VPF_NPF;
02603 
02604   switch (pathfinder) {
02605     case VPF_YAPF: { // YAPF
02606       Trackdir trackdir = YapfChooseRailTrack(v, tile, enterdir, tracks, path_not_found, do_track_reservation, dest);
02607       if (trackdir != INVALID_TRACKDIR) {
02608         best_track = TrackdirToTrack(trackdir);
02609       } else {
02610         best_track = FindFirstTrack(tracks);
02611       }
02612     } break;
02613 
02614     case VPF_NPF: { // NPF
02615       void *perf = NpfBeginInterval();
02616 
02617       NPFFindStationOrTileData fstd;
02618       NPFFillWithOrderData(&fstd, v, do_track_reservation);
02619 
02620       PBSTileInfo origin = FollowTrainReservation(v);
02621       assert(IsValidTrackdir(origin.trackdir));
02622 
02623       NPFFoundTargetData ftd = NPFRouteToStationOrTile(origin.tile, origin.trackdir, true, &fstd, TRANSPORT_RAIL, 0, v->owner, v->u.rail.compatible_railtypes);
02624 
02625       if (dest != NULL) {
02626         dest->tile = ftd.node.tile;
02627         dest->trackdir = (Trackdir)ftd.node.direction;
02628         dest->okay = ftd.res_okay;
02629       }
02630 
02631       if (ftd.best_trackdir == INVALID_TRACKDIR) {
02632         /* We are already at our target. Just do something
02633          * @todo maybe display error?
02634          * @todo: go straight ahead if possible? */
02635         best_track = FindFirstTrack(tracks);
02636       } else {
02637         /* If ftd.best_bird_dist is 0, we found our target and ftd.best_trackdir contains
02638          * the direction we need to take to get there, if ftd.best_bird_dist is not 0,
02639          * we did not find our target, but ftd.best_trackdir contains the direction leading
02640          * to the tile closest to our target. */
02641         if (ftd.best_bird_dist != 0 && path_not_found != NULL) *path_not_found = true;
02642         /* Discard enterdir information, making it a normal track */
02643         best_track = TrackdirToTrack(ftd.best_trackdir);
02644       }
02645 
02646       int time = NpfEndInterval(perf);
02647       DEBUG(yapf, 4, "[NPFT] %d us - %d rounds - %d open - %d closed -- ", time, 0, _aystar_stats_open_size, _aystar_stats_closed_size);
02648     } break;
02649 
02650     default:
02651     case VPF_NTP: { // NTP
02652       void *perf = NpfBeginInterval();
02653 
02654       TrainTrackFollowerData fd;
02655       FillWithStationData(&fd, v);
02656 
02657       /* New train pathfinding */
02658       fd.best_bird_dist = UINT_MAX;
02659       fd.best_track_dist = UINT_MAX;
02660       fd.best_track = INVALID_TRACKDIR;
02661 
02662       NewTrainPathfind(tile - TileOffsByDiagDir(enterdir), v->dest_tile,
02663         v->u.rail.compatible_railtypes, enterdir, (NTPEnumProc*)NtpCallbFindStation, &fd);
02664 
02665       /* check whether the path was found or only 'guessed' */
02666       if (fd.best_bird_dist != 0 && path_not_found != NULL) *path_not_found = true;
02667 
02668       if (fd.best_track == INVALID_TRACKDIR) {
02669         /* blaha */
02670         best_track = FindFirstTrack(tracks);
02671       } else {
02672         best_track = TrackdirToTrack(fd.best_track);
02673       }
02674 
02675       int time = NpfEndInterval(perf);
02676       DEBUG(yapf, 4, "[NTPT] %d us - %d rounds - %d open - %d closed -- ", time, 0, 0, 0);
02677     } break;
02678   }
02679 
02680 #ifdef PF_BENCHMARK
02681   TOC("PF time = ", 1)
02682 #endif
02683 
02684   return best_track;
02685 }
02686 
02692 static PBSTileInfo ExtendTrainReservation(const Vehicle *v, TrackBits *new_tracks, DiagDirection *enterdir)
02693 {
02694   bool no_90deg_turns = _settings_game.pf.pathfinder_for_trains != VPF_NTP && _settings_game.pf.forbid_90_deg;
02695   PBSTileInfo origin = FollowTrainReservation(v);
02696 
02697   CFollowTrackRail ft(v);
02698 
02699   TileIndex tile = origin.tile;
02700   Trackdir  cur_td = origin.trackdir;
02701   while (ft.Follow(tile, cur_td)) {
02702     if (KillFirstBit(ft.m_new_td_bits) == TRACKDIR_BIT_NONE) {
02703       /* Possible signal tile. */
02704       if (HasOnewaySignalBlockingTrackdir(ft.m_new_tile, FindFirstTrackdir(ft.m_new_td_bits))) break;
02705     }
02706 
02707     if (no_90deg_turns) {
02708       ft.m_new_td_bits &= ~TrackdirCrossesTrackdirs(ft.m_old_td);
02709       if (ft.m_new_td_bits == TRACKDIR_BIT_NONE) break;
02710     }
02711 
02712     /* Station, depot or waypoint are a possible target. */
02713     bool target_seen = ft.m_is_station || (IsTileType(ft.m_new_tile, MP_RAILWAY) && !IsPlainRail(ft.m_new_tile));
02714     if (target_seen || KillFirstBit(ft.m_new_td_bits) != TRACKDIR_BIT_NONE) {
02715       /* Choice found or possible target encountered.
02716        * On finding a possible target, we need to stop and let the pathfinder handle the
02717        * remaining path. This is because we don't know if this target is in one of our
02718        * orders, so we might cause pathfinding to fail later on if we find a choice.
02719        * This failure would cause a bogous call to TryReserveSafePath which might reserve
02720        * a wrong path not leading to our next destination. */
02721       if (HasReservedTracks(ft.m_new_tile, TrackdirBitsToTrackBits(TrackdirReachesTrackdirs(ft.m_old_td)))) break;
02722 
02723       /* If we did skip some tiles, backtrack to the first skipped tile so the pathfinder
02724        * actually starts its search at the first unreserved tile. */
02725       if (ft.m_tiles_skipped != 0) ft.m_new_tile -= TileOffsByDiagDir(ft.m_exitdir) * ft.m_tiles_skipped;
02726 
02727       /* Choice found, path valid but not okay. Save info about the choice tile as well. */
02728       if (new_tracks) *new_tracks = TrackdirBitsToTrackBits(ft.m_new_td_bits);
02729       if (enterdir) *enterdir = ft.m_exitdir;
02730       return PBSTileInfo(ft.m_new_tile, ft.m_old_td, false);
02731     }
02732 
02733     tile = ft.m_new_tile;
02734     cur_td = FindFirstTrackdir(ft.m_new_td_bits);
02735 
02736     if (IsSafeWaitingPosition(v, tile, cur_td, true, no_90deg_turns)) {
02737       bool wp_free = IsWaitingPositionFree(v, tile, cur_td, no_90deg_turns);
02738       if (!(wp_free && TryReserveRailTrack(tile, TrackdirToTrack(cur_td)))) break;
02739       /* Safe position is all good, path valid and okay. */
02740       return PBSTileInfo(tile, cur_td, true);
02741     }
02742 
02743     if (!TryReserveRailTrack(tile, TrackdirToTrack(cur_td))) break;
02744   }
02745 
02746   if (ft.m_err == CFollowTrackRail::EC_OWNER || ft.m_err == CFollowTrackRail::EC_NO_WAY) {
02747     /* End of line, path valid and okay. */
02748     return PBSTileInfo(ft.m_old_tile, ft.m_old_td, true);
02749   }
02750 
02751   /* Sorry, can't reserve path, back out. */
02752   tile = origin.tile;
02753   cur_td = origin.trackdir;
02754   TileIndex stopped = ft.m_old_tile;
02755   Trackdir  stopped_td = ft.m_old_td;
02756   while (tile != stopped || cur_td != stopped_td) {
02757     if (!ft.Follow(tile, cur_td)) break;
02758 
02759     if (no_90deg_turns) {
02760       ft.m_new_td_bits &= ~TrackdirCrossesTrackdirs(ft.m_old_td);
02761       assert(ft.m_new_td_bits != TRACKDIR_BIT_NONE);
02762     }
02763     assert(KillFirstBit(ft.m_new_td_bits) == TRACKDIR_BIT_NONE);
02764 
02765     tile = ft.m_new_tile;
02766     cur_td = FindFirstTrackdir(ft.m_new_td_bits);
02767 
02768     UnreserveRailTrack(tile, TrackdirToTrack(cur_td));
02769   }
02770 
02771   /* Path invalid. */
02772   return PBSTileInfo();
02773 }
02774 
02785 static bool TryReserveSafeTrack(const Vehicle *v, TileIndex tile, Trackdir td, bool override_tailtype)
02786 {
02787   if (_settings_game.pf.pathfinder_for_trains == VPF_YAPF) {
02788     return YapfRailFindNearestSafeTile(v, tile, td, override_tailtype);
02789   } else {
02790     return NPFRouteToSafeTile(v, tile, td, override_tailtype).res_okay;
02791   }
02792 }
02793 
02795 class VehicleOrderSaver
02796 {
02797 private:
02798   Vehicle        *v;
02799   Order          old_order;
02800   TileIndex      old_dest_tile;
02801   StationID      old_last_station_visited;
02802   VehicleOrderID index;
02803 
02804 public:
02805   VehicleOrderSaver(Vehicle *_v) :
02806     v(_v),
02807     old_order(_v->current_order),
02808     old_dest_tile(_v->dest_tile),
02809     old_last_station_visited(_v->last_station_visited),
02810     index(_v->cur_order_index)
02811   {
02812   }
02813 
02814   ~VehicleOrderSaver()
02815   {
02816     this->v->current_order = this->old_order;
02817     this->v->dest_tile = this->old_dest_tile;
02818     this->v->last_station_visited = this->old_last_station_visited;
02819   }
02820 
02826   bool SwitchToNextOrder(bool skip_first)
02827   {
02828     if (this->v->GetNumOrders() == 0) return false;
02829 
02830     if (skip_first) ++this->index;
02831 
02832     int conditional_depth = 0;
02833 
02834     do {
02835       /* Wrap around. */
02836       if (this->index >= this->v->GetNumOrders()) this->index = 0;
02837 
02838       Order *order = GetVehicleOrder(this->v, this->index);
02839       assert(order != NULL);
02840 
02841       switch (order->GetType()) {
02842         case OT_GOTO_DEPOT:
02843           /* Skip service in depot orders when the train doesn't need service. */
02844           if ((order->GetDepotOrderType() & ODTFB_SERVICE) && !this->v->NeedsServicing()) break;
02845         case OT_GOTO_STATION:
02846         case OT_GOTO_WAYPOINT:
02847           this->v->current_order = *order;
02848           UpdateOrderDest(this->v, order);
02849           return true;
02850         case OT_CONDITIONAL: {
02851           if (conditional_depth > this->v->GetNumOrders()) return false;
02852           VehicleOrderID next = ProcessConditionalOrder(order, this->v);
02853           if (next != INVALID_VEH_ORDER_ID) {
02854             conditional_depth++;
02855             this->index = next;
02856             /* Don't increment next, so no break here. */
02857             continue;
02858           }
02859           break;
02860         }
02861         default:
02862           break;
02863       }
02864       /* Don't increment inside the while because otherwise conditional
02865        * orders can lead to an infinite loop. */
02866       ++this->index;
02867     } while (this->index != this->v->cur_order_index);
02868 
02869     return false;
02870   }
02871 };
02872 
02873 /* choose a track */
02874 static Track ChooseTrainTrack(Vehicle *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool force_res, bool *got_reservation, bool mark_stuck)
02875 {
02876   Track best_track = INVALID_TRACK;
02877   bool do_track_reservation = _settings_game.pf.reserve_paths || force_res;
02878   bool changed_signal = false;
02879 
02880   assert((tracks & ~TRACK_BIT_MASK) == 0);
02881 
02882   if (got_reservation != NULL) *got_reservation = false;
02883 
02884   /* Don't use tracks here as the setting to forbid 90 deg turns might have been switched between reservation and now. */
02885   TrackBits res_tracks = (TrackBits)(GetReservedTrackbits(tile) & DiagdirReachesTracks(enterdir));
02886   /* Do we have a suitable reserved track? */
02887   if (res_tracks != TRACK_BIT_NONE) return FindFirstTrack(res_tracks);
02888 
02889   /* Quick return in case only one possible track is available */
02890   if (KillFirstBit(tracks) == TRACK_BIT_NONE) {
02891     Track track = FindFirstTrack(tracks);
02892     /* We need to check for signals only here, as a junction tile can't have signals. */
02893     if (track != INVALID_TRACK && HasPbsSignalOnTrackdir(tile, TrackEnterdirToTrackdir(track, enterdir))) {
02894       do_track_reservation = true;
02895       changed_signal = true;
02896       SetSignalStateByTrackdir(tile, TrackEnterdirToTrackdir(track, enterdir), SIGNAL_STATE_GREEN);
02897     } else if (!do_track_reservation) {
02898       return track;
02899     }
02900     best_track = track;
02901   }
02902 
02903   PBSTileInfo   res_dest(tile, INVALID_TRACKDIR, false);
02904   DiagDirection dest_enterdir = enterdir;
02905   if (do_track_reservation) {
02906     /* Check if the train needs service here, so it has a chance to always find a depot.
02907      * Also check if the current order is a service order so we don't reserve a path to
02908      * the destination but instead to the next one if service isn't needed. */
02909     CheckIfTrainNeedsService(v);
02910     if (v->current_order.IsType(OT_DUMMY) || v->current_order.IsType(OT_CONDITIONAL) || v->current_order.IsType(OT_GOTO_DEPOT)) ProcessOrders(v);
02911 
02912     res_dest = ExtendTrainReservation(v, &tracks, &dest_enterdir);
02913     if (res_dest.tile == INVALID_TILE) {
02914       /* Reservation failed? */
02915       if (mark_stuck) MarkTrainAsStuck(v);
02916       if (changed_signal) SetSignalStateByTrackdir(tile, TrackEnterdirToTrackdir(best_track, enterdir), SIGNAL_STATE_RED);
02917       return FindFirstTrack(tracks);
02918     }
02919   }
02920 
02921   /* Save the current train order. The destructor will restore the old order on function exit. */
02922   VehicleOrderSaver orders(v);
02923 
02924   /* If the current tile is the destination of the current order and
02925    * a reservation was requested, advance to the next order.
02926    * Don't advance on a depot order as depots are always safe end points
02927    * for a path and no look-ahead is necessary. This also avoids a
02928    * problem with depot orders not part of the order list when the
02929    * order list itself is empty. */
02930   if (v->current_order.IsType(OT_LEAVESTATION)) {
02931     orders.SwitchToNextOrder(false);
02932   } else if (v->current_order.IsType(OT_LOADING) || (!v->current_order.IsType(OT_GOTO_DEPOT) && (
02933       v->current_order.IsType(OT_GOTO_STATION) ?
02934       IsRailwayStationTile(v->tile) && v->current_order.GetDestination() == GetStationIndex(v->tile) :
02935       v->tile == v->dest_tile))) {
02936     orders.SwitchToNextOrder(true);
02937   }
02938 
02939   if (res_dest.tile != INVALID_TILE && !res_dest.okay) {
02940     /* Pathfinders are able to tell that route was only 'guessed'. */
02941     bool      path_not_found = false;
02942     TileIndex new_tile = res_dest.tile;
02943 
02944     Track next_track = DoTrainPathfind(v, new_tile, dest_enterdir, tracks, &path_not_found, do_track_reservation, &res_dest);
02945     if (new_tile == tile) best_track = next_track;
02946 
02947     /* handle "path not found" state */
02948     if (path_not_found) {
02949       /* PF didn't find the route */
02950       if (!HasBit(v->u.rail.flags, VRF_NO_PATH_TO_DESTINATION)) {
02951         /* it is first time the problem occurred, set the "path not found" flag */
02952         SetBit(v->u.rail.flags, VRF_NO_PATH_TO_DESTINATION);
02953         /* and notify user about the event */
02954         AI::NewEvent(v->owner, new AIEventVehicleLost(v->index));
02955         if (_settings_client.gui.lost_train_warn && v->owner == _local_company) {
02956           SetDParam(0, v->index);
02957           AddNewsItem(
02958             STR_TRAIN_IS_LOST,
02959             NS_ADVICE,
02960             v->index,
02961             0);
02962         }
02963       }
02964     } else {
02965       /* route found, is the train marked with "path not found" flag? */
02966       if (HasBit(v->u.rail.flags, VRF_NO_PATH_TO_DESTINATION)) {
02967         /* clear the flag as the PF's problem was solved */
02968         ClrBit(v->u.rail.flags, VRF_NO_PATH_TO_DESTINATION);
02969         /* can we also delete the "News" item somehow? */
02970       }
02971     }
02972   }
02973 
02974   /* No track reservation requested -> finished. */
02975   if (!do_track_reservation) return best_track;
02976 
02977   /* A path was found, but could not be reserved. */
02978   if (res_dest.tile != INVALID_TILE && !res_dest.okay) {
02979     if (mark_stuck) MarkTrainAsStuck(v);
02980     FreeTrainTrackReservation(v);
02981     return best_track;
02982   }
02983 
02984   /* No possible reservation target found, we are probably lost. */
02985   if (res_dest.tile == INVALID_TILE) {
02986     /* Try to find any safe destination. */
02987     PBSTileInfo origin = FollowTrainReservation(v);
02988     if (TryReserveSafeTrack(v, origin.tile, origin.trackdir, false)) {
02989       TrackBits res = GetReservedTrackbits(tile) & DiagdirReachesTracks(enterdir);
02990       best_track = FindFirstTrack(res);
02991       TryReserveRailTrack(v->tile, TrackdirToTrack(GetVehicleTrackdir(v)));
02992       if (got_reservation != NULL) *got_reservation = true;
02993       if (changed_signal) MarkTileDirtyByTile(tile);
02994     } else {
02995       FreeTrainTrackReservation(v);
02996       if (mark_stuck) MarkTrainAsStuck(v);
02997     }
02998     return best_track;
02999   }
03000 
03001   if (got_reservation != NULL) *got_reservation = true;
03002 
03003   /* Reservation target found and free, check if it is safe. */
03004   while (!IsSafeWaitingPosition(v, res_dest.tile, res_dest.trackdir, true, _settings_game.pf.forbid_90_deg)) {
03005     /* Extend reservation until we have found a safe position. */
03006     DiagDirection exitdir = TrackdirToExitdir(res_dest.trackdir);
03007     TileIndex     next_tile = TileAddByDiagDir(res_dest.tile, exitdir);
03008     TrackBits     reachable = TrackdirBitsToTrackBits((TrackdirBits)(GetTileTrackStatus(next_tile, TRANSPORT_RAIL, 0))) & DiagdirReachesTracks(exitdir);
03009     if (_settings_game.pf.pathfinder_for_trains != VPF_NTP && _settings_game.pf.forbid_90_deg) {
03010       reachable &= ~TrackCrossesTracks(TrackdirToTrack(res_dest.trackdir));
03011     }
03012 
03013     /* Get next order with destination. */
03014     if (orders.SwitchToNextOrder(true)) {
03015       PBSTileInfo cur_dest;
03016       DoTrainPathfind(v, next_tile, exitdir, reachable, NULL, true, &cur_dest);
03017       if (cur_dest.tile != INVALID_TILE) {
03018         res_dest = cur_dest;
03019         if (res_dest.okay) continue;
03020         /* Path found, but could not be reserved. */
03021         FreeTrainTrackReservation(v);
03022         if (mark_stuck) MarkTrainAsStuck(v);
03023         if (got_reservation != NULL) *got_reservation = false;
03024         changed_signal = false;
03025         break;
03026       }
03027     }
03028     /* No order or no safe position found, try any position. */
03029     if (!TryReserveSafeTrack(v, res_dest.tile, res_dest.trackdir, true)) {
03030       FreeTrainTrackReservation(v);
03031       if (mark_stuck) MarkTrainAsStuck(v);
03032       if (got_reservation != NULL) *got_reservation = false;
03033       changed_signal = false;
03034     }
03035     break;
03036   }
03037 
03038   TryReserveRailTrack(v->tile, TrackdirToTrack(GetVehicleTrackdir(v)));
03039 
03040   if (changed_signal) MarkTileDirtyByTile(tile);
03041 
03042   return best_track;
03043 }
03044 
03053 bool TryPathReserve(Vehicle *v, bool mark_as_stuck, bool first_tile_okay)
03054 {
03055   assert(v->type == VEH_TRAIN && IsFrontEngine(v));
03056 
03057   /* We have to handle depots specially as the track follower won't look
03058    * at the depot tile itself but starts from the next tile. If we are still
03059    * inside the depot, a depot reservation can never be ours. */
03060   if (v->u.rail.track & TRACK_BIT_DEPOT) {
03061     if (GetDepotWaypointReservation(v->tile)) {
03062       if (mark_as_stuck) MarkTrainAsStuck(v);
03063       return false;
03064     } else {
03065       /* Depot not reserved, but the next tile might be. */
03066       TileIndex next_tile = TileAddByDiagDir(v->tile, GetRailDepotDirection(v->tile));
03067       if (HasReservedTracks(next_tile, DiagdirReachesTracks(GetRailDepotDirection(v->tile)))) return false;
03068     }
03069   }
03070 
03071   /* Special check if we are in front of a two-sided conventional signal. */
03072   DiagDirection dir = TrainExitDir(v->direction, v->u.rail.track);
03073   TileIndex next_tile = TileAddByDiagDir(v->tile, dir);
03074   if (IsTileType(next_tile, MP_RAILWAY) && HasReservedTracks(next_tile, DiagdirReachesTracks(dir))) {
03075     /* Can have only one reserved trackdir. */
03076     Trackdir td = FindFirstTrackdir(TrackBitsToTrackdirBits(GetReservedTrackbits(next_tile)) & DiagdirReachesTrackdirs(dir));
03077     if (HasSignalOnTrackdir(next_tile, td) && HasSignalOnTrackdir(next_tile, ReverseTrackdir(td)) &&
03078         !IsPbsSignal(GetSignalType(next_tile, TrackdirToTrack(td)))) {
03079       /* Signal already reserved, is not ours. */
03080       if (mark_as_stuck) MarkTrainAsStuck(v);
03081       return false;
03082     }
03083   }
03084 
03085   bool other_train = false;
03086   PBSTileInfo origin = FollowTrainReservation(v, &other_train);
03087   /* The path we are driving on is alread blocked by some other train.
03088    * This can only happen in certain situations when mixing path and
03089    * block signals or when changing tracks and/or signals.
03090    * Exit here as doing any further reservations will probably just
03091    * make matters worse. */
03092   if (other_train && v->tile != origin.tile) {
03093     if (mark_as_stuck) MarkTrainAsStuck(v);
03094     return false;
03095   }
03096   /* If we have a reserved path and the path ends at a safe tile, we are finished already. */
03097   if (origin.okay && (v->tile != origin.tile || first_tile_okay)) {
03098     /* Can't be stuck then. */
03099     if (HasBit(v->u.rail.flags, VRF_TRAIN_STUCK)) InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
03100     ClrBit(v->u.rail.flags, VRF_TRAIN_STUCK);
03101     return true;
03102   }
03103 
03104   /* If we are in a depot, tentativly reserve the depot. */
03105   if (v->u.rail.track & TRACK_BIT_DEPOT) {
03106     SetDepotWaypointReservation(v->tile, true);
03107     if (_settings_client.gui.show_track_reservation) MarkTileDirtyByTile(v->tile);
03108   }
03109 
03110   DiagDirection exitdir = TrackdirToExitdir(origin.trackdir);
03111   TileIndex     new_tile = TileAddByDiagDir(origin.tile, exitdir);
03112   TrackBits     reachable = TrackdirBitsToTrackBits(TrackStatusToTrackdirBits(GetTileTrackStatus(new_tile, TRANSPORT_RAIL, 0)) & DiagdirReachesTrackdirs(exitdir));
03113 
03114   if (_settings_game.pf.pathfinder_for_trains != VPF_NTP && _settings_game.pf.forbid_90_deg) reachable &= ~TrackCrossesTracks(TrackdirToTrack(origin.trackdir));
03115 
03116   bool res_made = false;
03117   ChooseTrainTrack(v, new_tile, exitdir, reachable, true, &res_made, mark_as_stuck);
03118 
03119   if (!res_made) {
03120     /* Free the depot reservation as well. */
03121     if (v->u.rail.track & TRACK_BIT_DEPOT) SetDepotWaypointReservation(v->tile, false);
03122     return false;
03123   }
03124 
03125   if (HasBit(v->u.rail.flags, VRF_TRAIN_STUCK)) {
03126     v->load_unload_time_rem = 0;
03127     InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
03128   }
03129   ClrBit(v->u.rail.flags, VRF_TRAIN_STUCK);
03130   return true;
03131 }
03132 
03133 
03134 static bool CheckReverseTrain(Vehicle *v)
03135 {
03136   if (_settings_game.difficulty.line_reverse_mode != 0 ||
03137       v->u.rail.track == TRACK_BIT_DEPOT || v->u.rail.track == TRACK_BIT_WORMHOLE ||
03138       !(v->direction & 1)) {
03139     return false;
03140   }
03141 
03142   uint reverse_best = 0;
03143 
03144   assert(v->u.rail.track);
03145 
03146   switch (_settings_game.pf.pathfinder_for_trains) {
03147     case VPF_YAPF: // YAPF
03148       reverse_best = YapfCheckReverseTrain(v);
03149       break;
03150 
03151     case VPF_NPF: { // NPF
03152       NPFFindStationOrTileData fstd;
03153       NPFFoundTargetData ftd;
03154       Vehicle *last = GetLastVehicleInChain(v);
03155 
03156       NPFFillWithOrderData(&fstd, v);
03157 
03158       Trackdir trackdir = GetVehicleTrackdir(v);
03159       Trackdir trackdir_rev = ReverseTrackdir(GetVehicleTrackdir(last));
03160       assert(trackdir != INVALID_TRACKDIR);
03161       assert(trackdir_rev != INVALID_TRACKDIR);
03162 
03163       ftd = NPFRouteToStationOrTileTwoWay(v->tile, trackdir, false, last->tile, trackdir_rev, false, &fstd, TRANSPORT_RAIL, 0, v->owner, v->u.rail.compatible_railtypes);
03164       if (ftd.best_bird_dist != 0) {
03165         /* We didn't find anything, just keep on going straight ahead */
03166         reverse_best = false;
03167       } else {
03168         if (NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE)) {
03169           reverse_best = true;
03170         } else {
03171           reverse_best = false;
03172         }
03173       }
03174     } break;
03175 
03176     default:
03177     case VPF_NTP: { // NTP
03178       TrainTrackFollowerData fd;
03179       FillWithStationData(&fd, v);
03180 
03181       int i = _search_directions[FindFirstTrack(v->u.rail.track)][DirToDiagDir(v->direction)];
03182 
03183       int best_track = -1;
03184       uint reverse = 0;
03185       uint best_bird_dist  = 0;
03186       uint best_track_dist = 0;
03187 
03188       for (;;) {
03189         fd.best_bird_dist = UINT_MAX;
03190         fd.best_track_dist = UINT_MAX;
03191 
03192         NewTrainPathfind(v->tile, v->dest_tile, v->u.rail.compatible_railtypes, (DiagDirection)(reverse ^ i), (NTPEnumProc*)NtpCallbFindStation, &fd);
03193 
03194         if (best_track != -1) {
03195           if (best_bird_dist != 0) {
03196             if (fd.best_bird_dist != 0) {
03197               /* neither reached the destination, pick the one with the smallest bird dist */
03198               if (fd.best_bird_dist > best_bird_dist) goto bad;
03199               if (fd.best_bird_dist < best_bird_dist) goto good;
03200             } else {
03201               /* we found the destination for the first time */
03202               goto good;
03203             }
03204           } else {
03205             if (fd.best_bird_dist != 0) {
03206               /* didn't find destination, but we've found the destination previously */
03207               goto bad;
03208             } else {
03209               /* both old & new reached the destination, compare track length */
03210               if (fd.best_track_dist > best_track_dist) goto bad;
03211               if (fd.best_track_dist < best_track_dist) goto good;
03212             }
03213           }
03214 
03215           /* if we reach this position, there's two paths of equal value so far.
03216            * pick one randomly. */
03217           int r = GB(Random(), 0, 8);
03218           if (_pick_track_table[i] == (v->direction & 3)) r += 80;
03219           if (_pick_track_table[best_track] == (v->direction & 3)) r -= 80;
03220           if (r <= 127) goto bad;
03221         }
03222 good:;
03223         best_track = i;
03224         best_bird_dist = fd.best_bird_dist;
03225         best_track_dist = fd.best_track_dist;
03226         reverse_best = reverse;
03227 bad:;
03228         if (reverse != 0) break;
03229         reverse = 2;
03230       }
03231     } break;
03232   }
03233 
03234   return reverse_best != 0;
03235 }
03236 
03237 TileIndex Train::GetOrderStationLocation(StationID station)
03238 {
03239   if (station == this->last_station_visited) this->last_station_visited = INVALID_STATION;
03240 
03241   const Station *st = GetStation(station);
03242   if (!(st->facilities & FACIL_TRAIN)) {
03243     /* The destination station has no trainstation tiles. */
03244     this->cur_order_index++;
03245     return 0;
03246   }
03247 
03248   return st->xy;
03249 }
03250 
03251 void Train::MarkDirty()
03252 {
03253   Vehicle *v = this;
03254   do {
03255     v->UpdateViewport(false, false);
03256   } while ((v = v->Next()) != NULL);
03257 
03258   /* need to update acceleration and cached values since the goods on the train changed. */
03259   TrainCargoChanged(this);
03260   UpdateTrainAcceleration(this);
03261 }
03262 
03273 static int UpdateTrainSpeed(Vehicle *v)
03274 {
03275   uint accel;
03276 
03277   if (v->vehstatus & VS_STOPPED || HasBit(v->u.rail.flags, VRF_REVERSING) || HasBit(v->u.rail.flags, VRF_TRAIN_STUCK)) {
03278     switch (_settings_game.vehicle.train_acceleration_model) {
03279       default: NOT_REACHED();
03280       case TAM_ORIGINAL:  accel = v->acceleration * -4; break;
03281       case TAM_REALISTIC: accel = GetTrainAcceleration(v, AM_BRAKE); break;
03282     }
03283   } else {
03284     switch (_settings_game.vehicle.train_acceleration_model) {
03285       default: NOT_REACHED();
03286       case TAM_ORIGINAL:  accel = v->acceleration * 2; break;
03287       case TAM_REALISTIC: accel = GetTrainAcceleration(v, AM_ACCEL); break;
03288     }
03289   }
03290 
03291   uint spd = v->subspeed + accel;
03292   v->subspeed = (byte)spd;
03293   {
03294     int tempmax = v->max_speed;
03295     if (v->cur_speed > v->max_speed)
03296       tempmax = v->cur_speed - (v->cur_speed / 10) - 1;
03297     v->cur_speed = spd = Clamp(v->cur_speed + ((int)spd >> 8), 0, tempmax);
03298   }
03299 
03300   /* Scale speed by 3/4. Previously this was only done when the train was
03301    * facing diagonally and would apply to however many moves the train made
03302    * regardless the of direction actually moved in. Now it is always scaled,
03303    * 256 spd is used to go straight and 192 is used to go diagonally
03304    * (3/4 of 256). This results in the same effect, but without the error the
03305    * previous method caused.
03306    *
03307    * The scaling is done in this direction and not by multiplying the amount
03308    * to be subtracted by 4/3 so that the leftover speed can be saved in a
03309    * byte in v->progress.
03310    */
03311   int scaled_spd = spd * 3 >> 2;
03312 
03313   scaled_spd += v->progress;
03314   v->progress = 0; // set later in TrainLocoHandler or TrainController
03315   return scaled_spd;
03316 }
03317 
03318 static void TrainEnterStation(Vehicle *v, StationID station)
03319 {
03320   v->last_station_visited = station;
03321 
03322   /* check if a train ever visited this station before */
03323   Station *st = GetStation(station);
03324   if (!(st->had_vehicle_of_type & HVOT_TRAIN)) {
03325     st->had_vehicle_of_type |= HVOT_TRAIN;
03326     SetDParam(0, st->index);
03327     AddNewsItem(
03328       STR_8801_CITIZENS_CELEBRATE_FIRST,
03329       v->owner == _local_company ? NS_ARRIVAL_COMPANY : NS_ARRIVAL_OTHER,
03330       v->index,
03331       st->index
03332     );
03333     AI::NewEvent(v->owner, new AIEventStationFirstVehicle(st->index, v->index));
03334   }
03335 
03336   v->BeginLoading();
03337 
03338   StationAnimationTrigger(st, v->tile, STAT_ANIM_TRAIN_ARRIVES);
03339 }
03340 
03341 static byte AfterSetTrainPos(Vehicle *v, bool new_tile)
03342 {
03343   byte old_z = v->z_pos;
03344   v->z_pos = GetSlopeZ(v->x_pos, v->y_pos);
03345 
03346   if (new_tile) {
03347     ClrBit(v->u.rail.flags, VRF_GOINGUP);
03348     ClrBit(v->u.rail.flags, VRF_GOINGDOWN);
03349 
03350     if (v->u.rail.track == TRACK_BIT_X || v->u.rail.track == TRACK_BIT_Y) {
03351       /* Any track that isn't TRACK_BIT_X or TRACK_BIT_Y cannot be sloped.
03352        * To check whether the current tile is sloped, and in which
03353        * direction it is sloped, we get the 'z' at the center of
03354        * the tile (middle_z) and the edge of the tile (old_z),
03355        * which we then can compare. */
03356       static const int HALF_TILE_SIZE = TILE_SIZE / 2;
03357       static const int INV_TILE_SIZE_MASK = ~(TILE_SIZE - 1);
03358 
03359       byte middle_z = GetSlopeZ((v->x_pos & INV_TILE_SIZE_MASK) | HALF_TILE_SIZE, (v->y_pos & INV_TILE_SIZE_MASK) | HALF_TILE_SIZE);
03360 
03361       /* For some reason tunnel tiles are always given as sloped :(
03362        * But they are not sloped... */
03363       if (middle_z != v->z_pos && !IsTunnelTile(TileVirtXY(v->x_pos, v->y_pos))) {
03364         SetBit(v->u.rail.flags, (middle_z > old_z) ? VRF_GOINGUP : VRF_GOINGDOWN);
03365       }
03366     }
03367   }
03368 
03369   VehicleMove(v, true);
03370   return old_z;
03371 }
03372 
03373 static const Direction _new_vehicle_direction_table[11] = {
03374   DIR_N , DIR_NW, DIR_W , INVALID_DIR,
03375   DIR_NE, DIR_N , DIR_SW, INVALID_DIR,
03376   DIR_E , DIR_SE, DIR_S
03377 };
03378 
03379 static inline Direction GetNewVehicleDirectionByTile(TileIndex new_tile, TileIndex old_tile)
03380 {
03381   uint offs = (TileY(new_tile) - TileY(old_tile) + 1) * 4 +
03382               TileX(new_tile) - TileX(old_tile) + 1;
03383   assert(offs < 11);
03384   return _new_vehicle_direction_table[offs];
03385 }
03386 
03387 static inline int GetDirectionToVehicle(const Vehicle *v, int x, int y)
03388 {
03389   byte offs;
03390 
03391   x -= v->x_pos;
03392   if (x >= 0) {
03393     offs = (x > 2) ? 0 : 1;
03394   } else {
03395     offs = (x < -2) ? 2 : 1;
03396   }
03397 
03398   y -= v->y_pos;
03399   if (y >= 0) {
03400     offs += ((y > 2) ? 0 : 1) * 4;
03401   } else {
03402     offs += ((y < -2) ? 2 : 1) * 4;
03403   }
03404 
03405   assert(offs < 11);
03406   return _new_vehicle_direction_table[offs];
03407 }
03408 
03409 /* Check if the vehicle is compatible with the specified tile */
03410 static inline bool CheckCompatibleRail(const Vehicle *v, TileIndex tile)
03411 {
03412   return
03413     IsTileOwner(tile, v->owner) && (
03414       !IsFrontEngine(v) ||
03415       HasBit(v->u.rail.compatible_railtypes, GetRailType(tile))
03416     );
03417 }
03418 
03419 struct RailtypeSlowdownParams {
03420   byte small_turn, large_turn;
03421   byte z_up; // fraction to remove when moving up
03422   byte z_down; // fraction to remove when moving down
03423 };
03424 
03425 static const RailtypeSlowdownParams _railtype_slowdown[] = {
03426   /* normal accel */
03427   {256 / 4, 256 / 2, 256 / 4, 2}, 
03428   {256 / 4, 256 / 2, 256 / 4, 2}, 
03429   {256 / 4, 256 / 2, 256 / 4, 2}, 
03430   {0,       256 / 2, 256 / 4, 2}, 
03431 };
03432 
03434 static inline void AffectSpeedByDirChange(Vehicle *v, Direction new_dir)
03435 {
03436   if (_settings_game.vehicle.train_acceleration_model != TAM_ORIGINAL) return;
03437 
03438   DirDiff diff = DirDifference(v->direction, new_dir);
03439   if (diff == DIRDIFF_SAME) return;
03440 
03441   const RailtypeSlowdownParams *rsp = &_railtype_slowdown[v->u.rail.railtype];
03442   v->cur_speed -= (diff == DIRDIFF_45RIGHT || diff == DIRDIFF_45LEFT ? rsp->small_turn : rsp->large_turn) * v->cur_speed >> 8;
03443 }
03444 
03446 static inline void AffectSpeedByZChange(Vehicle *v, byte old_z)
03447 {
03448   if (old_z == v->z_pos || _settings_game.vehicle.train_acceleration_model != TAM_ORIGINAL) return;
03449 
03450   const RailtypeSlowdownParams *rsp = &_railtype_slowdown[v->u.rail.railtype];
03451 
03452   if (old_z < v->z_pos) {
03453     v->cur_speed -= (v->cur_speed * rsp->z_up >> 8);
03454   } else {
03455     uint16 spd = v->cur_speed + rsp->z_down;
03456     if (spd <= v->max_speed) v->cur_speed = spd;
03457   }
03458 }
03459 
03460 static bool TrainMovedChangeSignals(TileIndex tile, DiagDirection dir)
03461 {
03462   if (IsTileType(tile, MP_RAILWAY) &&
03463       GetRailTileType(tile) == RAIL_TILE_SIGNALS) {
03464     TrackdirBits tracks = TrackBitsToTrackdirBits(GetTrackBits(tile)) & DiagdirReachesTrackdirs(dir);
03465     Trackdir trackdir = FindFirstTrackdir(tracks);
03466     if (UpdateSignalsOnSegment(tile,  TrackdirToExitdir(trackdir), GetTileOwner(tile)) == SIGSEG_PBS && HasSignalOnTrackdir(tile, trackdir)) {
03467       /* A PBS block with a non-PBS signal facing us? */
03468       if (!IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir)))) return true;
03469     }
03470   }
03471   return false;
03472 }
03473 
03474 
03475 static void SetVehicleCrashed(Vehicle *v)
03476 {
03477   if (v->u.rail.crash_anim_pos != 0) return;
03478 
03479   if (IsFrontEngine(v)) {
03480     /* Remove the reserved path in front of the train if it is not stuck.
03481      * Also clear all reserved tracks the train is currently on. */
03482     if (!HasBit(v->u.rail.flags, VRF_TRAIN_STUCK)) FreeTrainTrackReservation(v);
03483     for (const Vehicle *u = v; u != NULL; u = u->Next()) {
03484       ClearPathReservation(u, u->tile, GetVehicleTrackdir(u));
03485       if (IsTileType(u->tile, MP_TUNNELBRIDGE)) {
03486         /* ClearPathReservation will not free the wormhole exit
03487          * if the train has just entered the wormhole. */
03488         SetTunnelBridgeReservation(GetOtherTunnelBridgeEnd(u->tile), false);
03489       }
03490     }
03491   }
03492 
03493   /* we may need to update crossing we were approaching */
03494   TileIndex crossing = TrainApproachingCrossingTile(v);
03495 
03496   v->u.rail.crash_anim_pos++;
03497 
03498   InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
03499   InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
03500 
03501   if (v->u.rail.track == TRACK_BIT_DEPOT) {
03502     InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
03503   }
03504 
03505   InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
03506 
03507   for (; v != NULL; v = v->Next()) {
03508     v->vehstatus |= VS_CRASHED;
03509     MarkSingleVehicleDirty(v);
03510   }
03511 
03512   /* must be updated after the train has been marked crashed */
03513   if (crossing != INVALID_TILE) UpdateLevelCrossing(crossing);
03514 }
03515 
03516 static uint CountPassengersInTrain(const Vehicle *v)
03517 {
03518   uint num = 0;
03519 
03520   for (; v != NULL; v = v->Next()) {
03521     if (IsCargoInClass(v->cargo_type, CC_PASSENGERS)) num += v->cargo.Count();
03522   }
03523 
03524   return num;
03525 }
03526 
03533 static uint TrainCrashed(Vehicle *v)
03534 {
03535   /* do not crash train twice */
03536   if (v->vehstatus & VS_CRASHED) return 0;
03537 
03538   /* two drivers + passengers */
03539   uint num = 2 + CountPassengersInTrain(v);
03540 
03541   SetVehicleCrashed(v);
03542   AI::NewEvent(v->owner, new AIEventVehicleCrashed(v->index, v->tile, AIEventVehicleCrashed::CRASH_TRAIN));
03543 
03544   return num;
03545 }
03546 
03547 struct TrainCollideChecker {
03548   Vehicle *v;  
03549   uint num;    
03550 };
03551 
03552 static Vehicle *FindTrainCollideEnum(Vehicle *v, void *data)
03553 {
03554   TrainCollideChecker *tcc = (TrainCollideChecker*)data;
03555 
03556   if (v->type != VEH_TRAIN) return NULL;
03557 
03558   /* get first vehicle now to make most usual checks faster */
03559   Vehicle *coll = v->First();
03560 
03561   /* can't collide with own wagons && can't crash in depot && the same height level */
03562   if (coll != tcc->v && v->u.rail.track != TRACK_BIT_DEPOT && abs(v->z_pos - tcc->v->z_pos) < 6) {
03563     int x_diff = v->x_pos - tcc->v->x_pos;
03564     int y_diff = v->y_pos - tcc->v->y_pos;
03565 
03566     /* needed to disable possible crash of competitor train in station by building diagonal track at its end */
03567     if (x_diff * x_diff + y_diff * y_diff > 25) return NULL;
03568 
03569     /* crash both trains */
03570     tcc->num += TrainCrashed(tcc->v);
03571     tcc->num += TrainCrashed(coll);
03572 
03573     /* Try to reserve all tiles directly under the crashed trains.
03574      * As there might be more than two trains involved, we have to do that for all vehicles */
03575     const Vehicle *u;
03576     FOR_ALL_VEHICLES(u) {
03577       if (u->type == VEH_TRAIN && HASBITS(u->vehstatus, VS_CRASHED) && (u->u.rail.track & TRACK_BIT_DEPOT) == TRACK_BIT_NONE) {
03578         TrackBits trackbits = u->u.rail.track;
03579         if ((trackbits & TRACK_BIT_WORMHOLE) == TRACK_BIT_WORMHOLE) {
03580           /* Vehicle is inside a wormhole, v->u.rail.track contains no useful value then. */
03581           trackbits |= DiagDirToDiagTrackBits(GetTunnelBridgeDirection(u->tile));
03582         }
03583         TryReserveRailTrack(u->tile, TrackBitsToTrack(trackbits));
03584       }
03585     }
03586   }
03587 
03588   return NULL;
03589 }
03590 
03597 static bool CheckTrainCollision(Vehicle *v)
03598 {
03599   /* can't collide in depot */
03600   if (v->u.rail.track == TRACK_BIT_DEPOT) return false;
03601 
03602   assert(v->u.rail.track == TRACK_BIT_WORMHOLE || TileVirtXY(v->x_pos, v->y_pos) == v->tile);
03603 
03604   TrainCollideChecker tcc;
03605   tcc.v = v;
03606   tcc.num = 0;
03607 
03608   /* find colliding vehicles */
03609   if (v->u.rail.track == TRACK_BIT_WORMHOLE) {
03610     FindVehicleOnPos(v->tile, &tcc, FindTrainCollideEnum);
03611     FindVehicleOnPos(GetOtherTunnelBridgeEnd(v->tile), &tcc, FindTrainCollideEnum);
03612   } else {
03613     FindVehicleOnPosXY(v->x_pos, v->y_pos, &tcc, FindTrainCollideEnum);
03614   }
03615 
03616   /* any dead -> no crash */
03617   if (tcc.num == 0) return false;
03618 
03619   SetDParam(0, tcc.num);
03620   AddNewsItem(STR_8868_TRAIN_CRASH_DIE_IN_FIREBALL,
03621     NS_ACCIDENT_VEHICLE,
03622     v->index,
03623     0
03624   );
03625 
03626   ModifyStationRatingAround(v->tile, v->owner, -160, 30);
03627   SndPlayVehicleFx(SND_13_BIG_CRASH, v);
03628   return true;
03629 }
03630 
03631 static Vehicle *CheckVehicleAtSignal(Vehicle *v, void *data)
03632 {
03633   DiagDirection exitdir = *(DiagDirection *)data;
03634 
03635   /* front engine of a train, not inside wormhole or depot, not crashed */
03636   if (v->type == VEH_TRAIN && IsFrontEngine(v) && (v->u.rail.track & TRACK_BIT_MASK) != 0 && !(v->vehstatus & VS_CRASHED)) {
03637     if (v->cur_speed <= 5 && TrainExitDir(v->direction, v->u.rail.track) == exitdir) return v;
03638   }
03639 
03640   return NULL;
03641 }
03642 
03643 static void TrainController(Vehicle *v, Vehicle *nomove)
03644 {
03645   Vehicle *prev;
03646 
03647   /* For every vehicle after and including the given vehicle */
03648   for (prev = v->Previous(); v != nomove; prev = v, v = v->Next()) {
03649     DiagDirection enterdir = DIAGDIR_BEGIN;
03650     bool update_signals_crossing = false; // will we update signals or crossing state?
03651 
03652     GetNewVehiclePosResult gp = GetNewVehiclePos(v);
03653     if (v->u.rail.track != TRACK_BIT_WORMHOLE) {
03654       /* Not inside tunnel */
03655       if (gp.old_tile == gp.new_tile) {
03656         /* Staying in the old tile */
03657         if (v->u.rail.track == TRACK_BIT_DEPOT) {
03658           /* Inside depot */
03659           gp.x = v->x_pos;
03660           gp.y = v->y_pos;
03661         } else {
03662           /* Not inside depot */
03663 
03664           /* Reverse when we are at the end of the track already, do not move to the new position */
03665           if (IsFrontEngine(v) && !TrainCheckIfLineEnds(v)) return;
03666 
03667           uint32 r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y);
03668           if (HasBit(r, VETS_CANNOT_ENTER)) {
03669             goto invalid_rail;
03670           }
03671           if (HasBit(r, VETS_ENTERED_STATION)) {
03672             /* The new position is the end of the platform */
03673             TrainEnterStation(v, r >> VETS_STATION_ID_OFFSET);
03674           }
03675         }
03676       } else {
03677         /* A new tile is about to be entered. */
03678 
03679         /* Determine what direction we're entering the new tile from */
03680         Direction dir = GetNewVehicleDirectionByTile(gp.new_tile, gp.old_tile);
03681         enterdir = DirToDiagDir(dir);
03682         assert(IsValidDiagDirection(enterdir));
03683 
03684         /* Get the status of the tracks in the new tile and mask
03685          * away the bits that aren't reachable. */
03686         TrackStatus ts = GetTileTrackStatus(gp.new_tile, TRANSPORT_RAIL, 0, ReverseDiagDir(enterdir));
03687         TrackdirBits reachable_trackdirs = DiagdirReachesTrackdirs(enterdir);
03688 
03689         TrackdirBits trackdirbits = TrackStatusToTrackdirBits(ts) & reachable_trackdirs;
03690         TrackBits red_signals = TrackdirBitsToTrackBits(TrackStatusToRedSignals(ts) & reachable_trackdirs);
03691 
03692         TrackBits bits = TrackdirBitsToTrackBits(trackdirbits);
03693         if (_settings_game.pf.pathfinder_for_trains != VPF_NTP && _settings_game.pf.forbid_90_deg && prev == NULL) {
03694           /* We allow wagons to make 90 deg turns, because forbid_90_deg
03695            * can be switched on halfway a turn */
03696           bits &= ~TrackCrossesTracks(FindFirstTrack(v->u.rail.track));
03697         }
03698 
03699         if (bits == TRACK_BIT_NONE) goto invalid_rail;
03700 
03701         /* Check if the new tile contrains tracks that are compatible
03702          * with the current train, if not, bail out. */
03703         if (!CheckCompatibleRail(v, gp.new_tile)) goto invalid_rail;
03704 
03705         TrackBits chosen_track;
03706         if (prev == NULL) {
03707           /* Currently the locomotive is active. Determine which one of the
03708            * available tracks to choose */
03709           chosen_track = TrackToTrackBits(ChooseTrainTrack(v, gp.new_tile, enterdir, bits, false, NULL, true));
03710           assert(chosen_track & (bits | GetReservedTrackbits(gp.new_tile)));
03711 
03712           /* Check if it's a red signal and that force proceed is not clicked. */
03713           if (red_signals & chosen_track && v->u.rail.force_proceed == 0) {
03714             /* In front of a red signal */
03715             Trackdir i = FindFirstTrackdir(trackdirbits);
03716 
03717             /* Don't handle stuck trains here. */
03718             if (HasBit(v->u.rail.flags, VRF_TRAIN_STUCK)) return;
03719 
03720             if (!HasSignalOnTrackdir(gp.new_tile, ReverseTrackdir(i))) {
03721               v->cur_speed = 0;
03722               v->subspeed = 0;
03723               v->progress = 255 - 100;
03724               if (_settings_game.pf.wait_oneway_signal == 255 || ++v->load_unload_time_rem < _settings_game.pf.wait_oneway_signal * 20) return;
03725             } else if (HasSignalOnTrackdir(gp.new_tile, i)) {
03726               v->cur_speed = 0;
03727               v->subspeed = 0;
03728               v->progress = 255 - 10;
03729               if (_settings_game.pf.wait_twoway_signal == 255 || ++v->load_unload_time_rem < _settings_game.pf.wait_twoway_signal * 73) {
03730                 DiagDirection exitdir = TrackdirToExitdir(i);
03731                 TileIndex o_tile = TileAddByDiagDir(gp.new_tile, exitdir);
03732 
03733                 exitdir = ReverseDiagDir(exitdir);
03734 
03735                 /* check if a train is waiting on the other side */
03736                 if (!HasVehicleOnPos(o_tile, &exitdir, &CheckVehicleAtSignal)) return;
03737               }
03738             }
03739 
03740             /* If we would reverse but are currently in a PBS block and
03741              * reversing of stuck trains is disabled, don't reverse. */
03742             if (_settings_game.pf.wait_for_pbs_path == 255 && UpdateSignalsOnSegment(v->tile, enterdir, v->owner) == SIGSEG_PBS) {
03743               v->load_unload_time_rem = 0;
03744               return;
03745             }
03746             goto reverse_train_direction;
03747           } else {
03748             TryReserveRailTrack(gp.new_tile, TrackBitsToTrack(chosen_track));
03749           }
03750         } else {
03751           static const TrackBits _matching_tracks[8] = {
03752               TRACK_BIT_LEFT  | TRACK_BIT_RIGHT, TRACK_BIT_X,
03753               TRACK_BIT_UPPER | TRACK_BIT_LOWER, TRACK_BIT_Y,
03754               TRACK_BIT_LEFT  | TRACK_BIT_RIGHT, TRACK_BIT_X,
03755               TRACK_BIT_UPPER | TRACK_BIT_LOWER, TRACK_BIT_Y
03756           };
03757 
03758           /* The wagon is active, simply follow the prev vehicle. */
03759           chosen_track = (TrackBits)(byte)(_matching_tracks[GetDirectionToVehicle(prev, gp.x, gp.y)] & bits);
03760         }
03761 
03762         /* Make sure chosen track is a valid track */
03763         assert(
03764             chosen_track == TRACK_BIT_X     || chosen_track == TRACK_BIT_Y ||
03765             chosen_track == TRACK_BIT_UPPER || chosen_track == TRACK_BIT_LOWER ||
03766             chosen_track == TRACK_BIT_LEFT  || chosen_track == TRACK_BIT_RIGHT);
03767 
03768         /* Update XY to reflect the entrance to the new tile, and select the direction to use */
03769         const byte *b = _initial_tile_subcoord[FIND_FIRST_BIT(chosen_track)][enterdir];
03770         gp.x = (gp.x & ~0xF) | b[0];
03771         gp.y = (gp.y & ~0xF) | b[1];
03772         Direction chosen_dir = (Direction)b[2];
03773 
03774         /* Call the landscape function and tell it that the vehicle entered the tile */
03775         uint32 r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y);
03776         if (HasBit(r, VETS_CANNOT_ENTER)) {
03777           goto invalid_rail;
03778         }
03779 
03780         if (!HasBit(r, VETS_ENTERED_WORMHOLE)) {
03781           Track track = FindFirstTrack(chosen_track);
03782           Trackdir tdir = TrackDirectionToTrackdir(track, chosen_dir);
03783           if (IsFrontEngine(v) && HasPbsSignalOnTrackdir(gp.new_tile, tdir)) {
03784             SetSignalStateByTrackdir(gp.new_tile, tdir, SIGNAL_STATE_RED);
03785             MarkTileDirtyByTile(gp.new_tile);
03786           }
03787 
03788           /* Clear any track reservation when the last vehicle leaves the tile */
03789           if (v->Next() == NULL) ClearPathReservation(v, v->tile, GetVehicleTrackdir(v));
03790 
03791           v->tile = gp.new_tile;
03792 
03793           if (GetTileRailType(gp.new_tile) != GetTileRailType(gp.old_tile)) {
03794             TrainPowerChanged(v->First());
03795           }
03796 
03797           v->u.rail.track = chosen_track;
03798           assert(v->u.rail.track);
03799         }
03800 
03801         /* We need to update signal status, but after the vehicle position hash
03802          * has been updated by AfterSetTrainPos() */
03803         update_signals_crossing = true;
03804 
03805         if (prev == NULL) AffectSpeedByDirChange(v, chosen_dir);
03806 
03807         v->direction = chosen_dir;
03808 
03809         if (IsFrontEngine(v)) {
03810           v->load_unload_time_rem = 0;
03811 
03812           /* If we are approching a crossing that is reserved, play the sound now. */
03813           TileIndex crossing = TrainApproachingCrossingTile(v);
03814           if (crossing != INVALID_TILE && GetCrossingReservation(crossing)) SndPlayTileFx(SND_0E_LEVEL_CROSSING, crossing);
03815 
03816           /* Always try to extend the reservation when entering a tile. */
03817           CheckNextTrainTile(v);
03818         }
03819       }
03820     } else {
03821       /* In a tunnel or on a bridge
03822        * - for tunnels, only the part when the vehicle is not visible (part of enter/exit tile too)
03823        * - for bridges, only the middle part - without the bridge heads */
03824       if (!(v->vehstatus & VS_HIDDEN)) {
03825         v->cur_speed =
03826           min(v->cur_speed, GetBridgeSpec(GetBridgeType(v->tile))->speed);
03827       }
03828 
03829       if (IsTileType(gp.new_tile, MP_TUNNELBRIDGE) && HasBit(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y), VETS_ENTERED_WORMHOLE)) {
03830         /* Perform look-ahead on tunnel exit. */
03831         if (IsFrontEngine(v)) {
03832           TryReserveRailTrack(gp.new_tile, DiagDirToDiagTrack(GetTunnelBridgeDirection(gp.new_tile)));
03833           CheckNextTrainTile(v);
03834         }
03835       } else {
03836         v->x_pos = gp.x;
03837         v->y_pos = gp.y;
03838         VehicleMove(v, !(v->vehstatus & VS_HIDDEN));
03839         continue;
03840       }
03841     }
03842 
03843     /* update image of train, as well as delta XY */
03844     v->UpdateDeltaXY(v->direction);
03845 
03846     v->x_pos = gp.x;
03847     v->y_pos = gp.y;
03848 
03849     /* update the Z position of the vehicle */
03850     byte old_z = AfterSetTrainPos(v, (gp.new_tile != gp.old_tile));
03851 
03852     if (prev == NULL) {
03853       /* This is the first vehicle in the train */
03854       AffectSpeedByZChange(v, old_z);
03855     }
03856 
03857     if (update_signals_crossing) {
03858       if (IsFrontEngine(v)) {
03859         if (TrainMovedChangeSignals(gp.new_tile, enterdir)) {
03860           /* We are entering a block with PBS signals right now, but
03861            * not through a PBS signal. This means we don't have a
03862            * reservation right now. As a conventional signal will only
03863            * ever be green if no other train is in the block, getting
03864            * a path should always be possible. If the player built
03865            * such a strange network that it is not possible, the train
03866            * will be marked as stuck and the player has to deal with
03867            * the problem. */
03868           if ((!HasReservedTracks(gp.new_tile, v->u.rail.track) &&
03869               !TryReserveRailTrack(gp.new_tile, FindFirstTrack(v->u.rail.track))) ||
03870               !TryPathReserve(v)) {
03871             MarkTrainAsStuck(v);
03872           }
03873         }
03874       }
03875 
03876       /* Signals can only change when the first
03877        * (above) or the last vehicle moves. */
03878       if (v->Next() == NULL) {
03879         TrainMovedChangeSignals(gp.old_tile, ReverseDiagDir(enterdir));
03880         if (IsLevelCrossingTile(gp.old_tile)) UpdateLevelCrossing(gp.old_tile);
03881       }
03882     }
03883 
03884     /* Do not check on every tick to save some computing time. */
03885     if (IsFrontEngine(v) && v->tick_counter % _settings_game.pf.path_backoff_interval == 0) CheckNextTrainTile(v);
03886   }
03887   return;
03888 
03889 invalid_rail:
03890   /* We've reached end of line?? */
03891   if (prev != NULL) error("Disconnecting train");
03892 
03893 reverse_train_direction:
03894   v->load_unload_time_rem = 0;
03895   v->cur_speed = 0;
03896   v->subspeed = 0;
03897   ReverseTrainDirection(v);
03898 }
03899 
03905 static Vehicle *CollectTrackbitsFromCrashedVehiclesEnum(Vehicle *v, void *data)
03906 {
03907   TrackBits *trackbits = (TrackBits *)data;
03908 
03909   if (v->type == VEH_TRAIN && (v->vehstatus & VS_CRASHED) != 0) {
03910     if ((v->u.rail.track & TRACK_BIT_WORMHOLE) == TRACK_BIT_WORMHOLE) {
03911       /* Vehicle is inside a wormhole, v->u.rail.track contains no useful value then. */
03912       *trackbits |= DiagDirToDiagTrackBits(GetTunnelBridgeDirection(v->tile));
03913     } else {
03914       *trackbits |= v->u.rail.track;
03915     }
03916   }
03917 
03918   return NULL;
03919 }
03920 
03928 static void DeleteLastWagon(Vehicle *v)
03929 {
03930   Vehicle *first = v->First();
03931 
03932   /* Go to the last wagon and delete the link pointing there
03933    * *u is then the one-before-last wagon, and *v the last
03934    * one which will physicially be removed */
03935   Vehicle *u = v;
03936   for (; v->Next() != NULL; v = v->Next()) u = v;
03937   u->SetNext(NULL);
03938 
03939   if (first != v) {
03940     /* Recalculate cached train properties */
03941     TrainConsistChanged(first, false);
03942     /* Update the depot window if the first vehicle is in depot -
03943      * if v == first, then it is updated in PreDestructor() */
03944     if (first->u.rail.track == TRACK_BIT_DEPOT) {
03945       InvalidateWindow(WC_VEHICLE_DEPOT, first->tile);
03946     }
03947   }
03948 
03949   /* 'v' shouldn't be accessed after it has been deleted */
03950   TrackBits trackbits = v->u.rail.track;
03951   TileIndex tile = v->tile;
03952   Owner owner = v->owner;
03953 
03954   delete v;
03955   v = NULL; // make sure nobody will try to read 'v' anymore
03956 
03957   if ((trackbits & TRACK_BIT_WORMHOLE) == TRACK_BIT_WORMHOLE) {
03958     /* Vehicle is inside a wormhole, v->u.rail.track contains no useful value then. */
03959     trackbits |= DiagDirToDiagTrackBits(GetTunnelBridgeDirection(tile));
03960   }
03961 
03962   Track track = TrackBitsToTrack(trackbits);
03963   if (HasReservedTracks(tile, trackbits)) {
03964     UnreserveRailTrack(tile, track);
03965 
03966     /* If there are still crashed vehicles on the tile, give the track reservation to them */
03967     TrackBits remaining_trackbits = TRACK_BIT_NONE;
03968     FindVehicleOnPos(tile, &remaining_trackbits, CollectTrackbitsFromCrashedVehiclesEnum);
03969 
03970     /* It is important that these two are the first in the loop, as reservation cannot deal with every trackbit combination */
03971     assert(TRACK_BEGIN == TRACK_X && TRACK_Y == TRACK_BEGIN + 1);
03972     for (Track t = TRACK_BEGIN; t < TRACK_END; t++) {
03973       if (HasBit(remaining_trackbits, t)) {
03974         TryReserveRailTrack(tile, t);
03975       }
03976     }
03977   }
03978 
03979   /* check if the wagon was on a road/rail-crossing */
03980   if (IsLevelCrossingTile(tile)) UpdateLevelCrossing(tile);
03981 
03982   /* Update signals */
03983   if (IsTileType(tile, MP_TUNNELBRIDGE) || IsRailDepotTile(tile)) {
03984     UpdateSignalsOnSegment(tile, INVALID_DIAGDIR, owner);
03985   } else {
03986     SetSignalsOnBothDir(tile, track, owner);
03987   }
03988 }
03989 
03990 static void ChangeTrainDirRandomly(Vehicle *v)
03991 {
03992   static const DirDiff delta[] = {
03993     DIRDIFF_45LEFT, DIRDIFF_SAME, DIRDIFF_SAME, DIRDIFF_45RIGHT
03994   };
03995 
03996   do {
03997     /* We don't need to twist around vehicles if they're not visible */
03998     if (!(v->vehstatus & VS_HIDDEN)) {
03999       v->direction = ChangeDir(v->direction, delta[GB(Random(), 0, 2)]);
04000       v->UpdateDeltaXY(v->direction);
04001       v->cur_image = v->GetImage(v->direction);
04002       /* Refrain from updating the z position of the vehicle when on
04003        * a bridge, because AfterSetTrainPos will put the vehicle under
04004        * the bridge in that case */
04005       if (v->u.rail.track != TRACK_BIT_WORMHOLE) AfterSetTrainPos(v, false);
04006     }
04007   } while ((v = v->Next()) != NULL);
04008 }
04009 
04010 static void HandleCrashedTrain(Vehicle *v)
04011 {
04012   int state = ++v->u.rail.crash_anim_pos;
04013 
04014   if (state == 4 && !(v->vehstatus & VS_HIDDEN)) {
04015     CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
04016   }
04017 
04018   uint32 r;
04019   if (state <= 200 && Chance16R(1, 7, r)) {
04020     int index = (r * 10 >> 16);
04021 
04022     Vehicle *u = v;
04023     do {
04024       if (--index < 0) {
04025         r = Random();
04026 
04027         CreateEffectVehicleRel(u,
04028           GB(r,  8, 3) + 2,
04029           GB(r, 16, 3) + 2,
04030           GB(r,  0, 3) + 5,
04031           EV_EXPLOSION_SMALL);
04032         break;
04033       }
04034     } while ((u = u->Next()) != NULL);
04035   }
04036 
04037   if (state <= 240 && !(v->tick_counter & 3)) ChangeTrainDirRandomly(v);
04038 
04039   if (state >= 4440 && !(v->tick_counter & 0x1F)) {
04040     DeleteLastWagon(v);
04041     InvalidateWindow(WC_REPLACE_VEHICLE, (v->group_id << 16) | VEH_TRAIN);
04042   }
04043 }
04044 
04045 static void HandleBrokenTrain(Vehicle *v)
04046 {
04047   if (v->breakdown_ctr != 1) {
04048     v->breakdown_ctr = 1;
04049     v->cur_speed = 0;
04050 
04051     if (v->breakdowns_since_last_service != 255)
04052       v->breakdowns_since_last_service++;
04053 
04054     InvalidateWindow(WC_VEHICLE_VIEW, v->index);
04055     InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
04056     v->MarkDirty();
04057 
04058     if (!PlayVehicleSound(v, VSE_BREAKDOWN)) {
04059       SndPlayVehicleFx((_settings_game.game_creation.landscape != LT_TOYLAND) ?
04060         SND_10_TRAIN_BREAKDOWN : SND_3A_COMEDY_BREAKDOWN_2, v);
04061     }
04062 
04063     if (!(v->vehstatus & VS_HIDDEN)) {
04064       Vehicle *u = CreateEffectVehicleRel(v, 4, 4, 5, EV_BREAKDOWN_SMOKE);
04065       if (u != NULL) u->u.effect.animation_state = v->breakdown_delay * 2;
04066     }
04067   }
04068 
04069   if (!(v->tick_counter & 3)) {
04070     if (!--v->breakdown_delay) {
04071       v->breakdown_ctr = 0;
04072       InvalidateWindow(WC_VEHICLE_VIEW, v->index);
04073       v->MarkDirty();
04074     }
04075   }
04076 }
04077 
04079 static const uint16 _breakdown_speeds[16] = {
04080   225, 210, 195, 180, 165, 150, 135, 120, 105, 90, 75, 60, 45, 30, 15, 15
04081 };
04082 
04083 
04091 static bool TrainApproachingLineEnd(Vehicle *v, bool signal)
04092 {
04093   /* Calc position within the current tile */
04094   uint x = v->x_pos & 0xF;
04095   uint y = v->y_pos & 0xF;
04096 
04097   /* for diagonal directions, 'x' will be 0..15 -
04098    * for other directions, it will be 1, 3, 5, ..., 15 */
04099   switch (v->direction) {
04100     case DIR_N : x = ~x + ~y + 25; break;
04101     case DIR_NW: x = y;            // FALLTHROUGH
04102     case DIR_NE: x = ~x + 16;      break;
04103     case DIR_E : x = ~x + y + 9;   break;
04104     case DIR_SE: x = y;            break;
04105     case DIR_S : x = x + y - 7;    break;
04106     case DIR_W : x = ~y + x + 9;   break;
04107     default: break;
04108   }
04109 
04110   /* do not reverse when approaching red signal */
04111   if (!signal && x + (v->u.rail.cached_veh_length + 1) / 2 >= TILE_SIZE) {
04112     /* we are too near the tile end, reverse now */
04113     v->cur_speed = 0;
04114     ReverseTrainDirection(v);
04115     return false;
04116   }
04117 
04118   /* slow down */
04119   v->vehstatus |= VS_TRAIN_SLOWING;
04120   uint16 break_speed = _breakdown_speeds[x & 0xF];
04121   if (break_speed < v->cur_speed) v->cur_speed = break_speed;
04122 
04123   return true;
04124 }
04125 
04126 
04132 static bool TrainCanLeaveTile(const Vehicle *v)
04133 {
04134   /* Exit if inside a tunnel/bridge or a depot */
04135   if (v->u.rail.track == TRACK_BIT_WORMHOLE || v->u.rail.track == TRACK_BIT_DEPOT) return false;
04136 
04137   TileIndex tile = v->tile;
04138 
04139   /* entering a tunnel/bridge? */
04140   if (IsTileType(tile, MP_TUNNELBRIDGE)) {
04141     DiagDirection dir = GetTunnelBridgeDirection(tile);
04142     if (DiagDirToDir(dir) == v->direction) return false;
04143   }
04144 
04145   /* entering a depot? */
04146   if (IsRailDepotTile(tile)) {
04147     DiagDirection dir = ReverseDiagDir(GetRailDepotDirection(tile));
04148     if (DiagDirToDir(dir) == v->direction) return false;
04149   }
04150 
04151   return true;
04152 }
04153 
04154 
04162 static TileIndex TrainApproachingCrossingTile(const Vehicle *v)
04163 {
04164   assert(IsFrontEngine(v));
04165   assert(!(v->vehstatus & VS_CRASHED));
04166 
04167   if (!TrainCanLeaveTile(v)) return INVALID_TILE;
04168 
04169   DiagDirection dir = TrainExitDir(v->direction, v->u.rail.track);
04170   TileIndex tile = v->tile + TileOffsByDiagDir(dir);
04171 
04172   /* not a crossing || wrong axis || unusable rail (wrong type or owner) */
04173   if (!IsLevelCrossingTile(tile) || DiagDirToAxis(dir) == GetCrossingRoadAxis(tile) ||
04174       !CheckCompatibleRail(v, tile)) {
04175     return INVALID_TILE;
04176   }
04177 
04178   return tile;
04179 }
04180 
04181 
04188 static bool TrainCheckIfLineEnds(Vehicle *v)
04189 {
04190   /* First, handle broken down train */
04191 
04192   int t = v->breakdown_ctr;
04193   if (t > 1) {
04194     v->vehstatus |= VS_TRAIN_SLOWING;
04195 
04196     uint16 break_speed = _breakdown_speeds[GB(~t, 4, 4)];
04197     if (break_speed < v->cur_speed) v->cur_speed = break_speed;
04198   } else {
04199     v->vehstatus &= ~VS_TRAIN_SLOWING;
04200   }
04201 
04202   if (!TrainCanLeaveTile(v)) return true;
04203 
04204   /* Determine the non-diagonal direction in which we will exit this tile */
04205   DiagDirection dir = TrainExitDir(v->direction, v->u.rail.track);
04206   /* Calculate next tile */
04207   TileIndex tile = v->tile + TileOffsByDiagDir(dir);
04208 
04209   /* Determine the track status on the next tile */
04210   TrackStatus ts = GetTileTrackStatus(tile, TRANSPORT_RAIL, 0, ReverseDiagDir(dir));
04211   TrackdirBits reachable_trackdirs = DiagdirReachesTrackdirs(dir);
04212 
04213   TrackdirBits trackdirbits = TrackStatusToTrackdirBits(ts) & reachable_trackdirs;
04214   TrackdirBits red_signals = TrackStatusToRedSignals(ts) & reachable_trackdirs;
04215 
04216   /* We are sure the train is not entering a depot, it is detected above */
04217 
04218   /* mask unreachable track bits if we are forbidden to do 90deg turns */
04219   TrackBits bits = TrackdirBitsToTrackBits(trackdirbits);
04220   if (_settings_game.pf.pathfinder_for_trains != VPF_NTP && _settings_game.pf.forbid_90_deg) {
04221     bits &= ~TrackCrossesTracks(FindFirstTrack(v->u.rail.track));
04222   }
04223 
04224   /* no suitable trackbits at all || unusable rail (wrong type or owner) */
04225   if (bits == TRACK_BIT_NONE || !CheckCompatibleRail(v, tile)) {
04226     return TrainApproachingLineEnd(v, false);
04227   }
04228 
04229   /* approaching red signal */
04230   if ((trackdirbits & red_signals) != 0) return TrainApproachingLineEnd(v, true);
04231 
04232   /* approaching a rail/road crossing? then make it red */
04233   if (IsLevelCrossingTile(tile)) MaybeBarCrossingWithSound(tile);
04234 
04235   return true;
04236 }
04237 
04238 
04239 static void TrainLocoHandler(Vehicle *v, bool mode)
04240 {
04241   /* train has crashed? */
04242   if (v->vehstatus & VS_CRASHED) {
04243     if (!mode) HandleCrashedTrain(v);
04244     return;
04245   }
04246 
04247   if (v->u.rail.force_proceed != 0) {
04248     v->u.rail.force_proceed--;
04249     ClrBit(v->u.rail.flags, VRF_TRAIN_STUCK);
04250     InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
04251   }
04252 
04253   /* train is broken down? */
04254   if (v->breakdown_ctr != 0) {
04255     if (v->breakdown_ctr <= 2) {
04256       HandleBrokenTrain(v);
04257       return;
04258     }
04259     if (!v->current_order.IsType(OT_LOADING)) v->breakdown_ctr--;
04260   }
04261 
04262   if (HasBit(v->u.rail.flags, VRF_REVERSING) && v->cur_speed == 0) {
04263     ReverseTrainDirection(v);
04264   }
04265 
04266   /* exit if train is stopped */
04267   if (v->vehstatus & VS_STOPPED && v->cur_speed == 0) return;
04268 
04269   bool valid_order = v->current_order.IsValid() && v->current_order.GetType() != OT_CONDITIONAL;
04270   if (ProcessOrders(v) && CheckReverseTrain(v)) {
04271     v->load_unload_time_rem = 0;
04272     v->cur_speed = 0;
04273     v->subspeed = 0;
04274     ReverseTrainDirection(v);
04275     return;
04276   }
04277 
04278   v->HandleLoading(mode);
04279 
04280   if (v->current_order.IsType(OT_LOADING)) return;
04281 
04282   if (CheckTrainStayInDepot(v)) return;
04283 
04284   if (!mode) HandleLocomotiveSmokeCloud(v);
04285 
04286   /* We had no order but have an order now, do look ahead. */
04287   if (!valid_order && v->current_order.IsValid()) {
04288     CheckNextTrainTile(v);
04289   }
04290 
04291   /* Handle stuck trains. */
04292   if (!mode && HasBit(v->u.rail.flags, VRF_TRAIN_STUCK)) {
04293     ++v->load_unload_time_rem;
04294 
04295     /* Should we try reversing this tick if still stuck? */
04296     bool turn_around = v->load_unload_time_rem % (_settings_game.pf.wait_for_pbs_path * DAY_TICKS) == 0 && _settings_game.pf.wait_for_pbs_path < 255;
04297 
04298     if (!turn_around && v->load_unload_time_rem % _settings_game.pf.path_backoff_interval != 0 && v->u.rail.force_proceed == 0) return;
04299     if (!TryPathReserve(v)) {
04300       /* Still stuck. */
04301       if (turn_around) ReverseTrainDirection(v);
04302 
04303       if (HasBit(v->u.rail.flags, VRF_TRAIN_STUCK) && v->load_unload_time_rem > 2 * _settings_game.pf.wait_for_pbs_path * DAY_TICKS) {
04304         /* Show message to player. */
04305         if (_settings_client.gui.lost_train_warn && v->owner == _local_company) {
04306           SetDParam(0, v->index);
04307           AddNewsItem(
04308             STR_TRAIN_IS_STUCK,
04309             NS_ADVICE,
04310             v->index,
04311             0);
04312         }
04313         v->load_unload_time_rem = 0;
04314       }
04315       /* Exit if force proceed not pressed, else reset stuck flag anyway. */
04316       if (v->u.rail.force_proceed == 0) return;
04317       ClrBit(v->u.rail.flags, VRF_TRAIN_STUCK);
04318       v->load_unload_time_rem = 0;
04319       InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
04320     }
04321   }
04322 
04323   if (v->current_order.IsType(OT_LEAVESTATION)) {
04324     v->current_order.Free();
04325     InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
04326     return;
04327   }
04328 
04329   int j = UpdateTrainSpeed(v);
04330 
04331   /* we need to invalidate the widget if we are stopping from 'Stopping 0 km/h' to 'Stopped' */
04332   if (v->cur_speed == 0 && v->u.rail.last_speed == 0 && v->vehstatus & VS_STOPPED) {
04333     InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
04334   }
04335 
04336   int adv_spd = (v->direction & 1) ? 192 : 256;
04337   if (j < adv_spd) {
04338     /* if the vehicle has speed 0, update the last_speed field. */
04339     if (v->cur_speed == 0) SetLastSpeed(v, v->cur_speed);
04340   } else {
04341     TrainCheckIfLineEnds(v);
04342     /* Loop until the train has finished moving. */
04343     for (;;) {
04344       j -= adv_spd;
04345       TrainController(v, NULL);
04346       /* Don't continue to move if the train crashed. */
04347       if (CheckTrainCollision(v)) break;
04348       /* 192 spd used for going straight, 256 for going diagonally. */
04349       adv_spd = (v->direction & 1) ? 192 : 256;
04350 
04351       /* No more moving this tick */
04352       if (j < adv_spd || v->cur_speed == 0) break;
04353 
04354       OrderType order_type = v->current_order.GetType();
04355       /* Do not skip waypoints (incl. 'via' stations) when passing through at full speed. */
04356       if ((order_type == OT_GOTO_WAYPOINT &&
04357             v->dest_tile == v->tile) ||
04358           (order_type == OT_GOTO_STATION &&
04359             (v->current_order.GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) &&
04360             IsTileType(v->tile, MP_STATION) &&
04361             v->current_order.GetDestination() == GetStationIndex(v->tile))) {
04362         ProcessOrders(v);
04363       }
04364     }
04365     SetLastSpeed(v, v->cur_speed);
04366   }
04367 
04368   for (Vehicle *u = v; u != NULL; u = u->Next()) {
04369     if ((u->vehstatus & VS_HIDDEN) != 0) continue;
04370 
04371     u->UpdateViewport(false, false);
04372   }
04373 
04374   if (v->progress == 0) v->progress = j; // Save unused spd for next time, if TrainController didn't set progress
04375 }
04376 
04377 
04378 
04379 Money Train::GetRunningCost() const
04380 {
04381   Money cost = 0;
04382   const Vehicle *v = this;
04383 
04384   do {
04385     const RailVehicleInfo *rvi = RailVehInfo(v->engine_type);
04386 
04387     byte cost_factor = GetVehicleProperty(v, 0x0D, rvi->running_cost);
04388     if (cost_factor == 0) continue;
04389 
04390     /* Halve running cost for multiheaded parts */
04391     if (IsMultiheaded(v)) cost_factor /= 2;
04392 
04393     cost += cost_factor * GetPriceByIndex(rvi->running_cost_class);
04394   } while ((v = GetNextVehicle(v)) != NULL);
04395 
04396   return cost;
04397 }
04398 
04399 
04400 void Train::Tick()
04401 {
04402   if (_age_cargo_skip_counter == 0) this->cargo.AgeCargo();
04403 
04404   this->tick_counter++;
04405 
04406   if (IsFrontEngine(this)) {
04407     if (!(this->vehstatus & VS_STOPPED)) this->running_ticks++;
04408     this->current_order_time++;
04409 
04410     TrainLocoHandler(this, false);
04411 
04412     /* make sure vehicle wasn't deleted. */
04413     if (this->type == VEH_TRAIN && IsFrontEngine(this))
04414       TrainLocoHandler(this, true);
04415   } else if (IsFreeWagon(this) && HASBITS(this->vehstatus, VS_CRASHED)) {
04416     /* Delete flooded standalone wagon chain */
04417     if (++this->u.rail.crash_anim_pos >= 4400) delete this;
04418   }
04419 }
04420 
04421 static void CheckIfTrainNeedsService(Vehicle *v)
04422 {
04423   static const uint MAX_ACCEPTABLE_DEPOT_DIST = 16;
04424 
04425   if (_settings_game.vehicle.servint_trains == 0 || !v->NeedsAutomaticServicing()) return;
04426   if (v->IsInDepot()) {
04427     VehicleServiceInDepot(v);
04428     return;
04429   }
04430 
04431   TrainFindDepotData tfdd = FindClosestTrainDepot(v, MAX_ACCEPTABLE_DEPOT_DIST);
04432   /* Only go to the depot if it is not too far out of our way. */
04433   if (tfdd.best_length == UINT_MAX || tfdd.best_length > MAX_ACCEPTABLE_DEPOT_DIST) {
04434     if (v->current_order.IsType(OT_GOTO_DEPOT)) {
04435       /* If we were already heading for a depot but it has
04436        * suddenly moved farther away, we continue our normal
04437        * schedule? */
04438       v->current_order.MakeDummy();
04439       InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
04440     }
04441     return;
04442   }
04443 
04444   const Depot *depot = GetDepotByTile(tfdd.tile);
04445 
04446   if (v->current_order.IsType(OT_GOTO_DEPOT) &&
04447       v->current_order.GetDestination() != depot->index &&
04448       !Chance16(3, 16)) {
04449     return;
04450   }
04451 
04452   v->current_order.MakeGoToDepot(depot->index, ODTFB_SERVICE);
04453   v->dest_tile = tfdd.tile;
04454   InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
04455 }
04456 
04457 void Train::OnNewDay()
04458 {
04459   if ((++this->day_counter & 7) == 0) DecreaseVehicleValue(this);
04460 
04461   if (IsFrontEngine(this)) {
04462     CheckVehicleBreakdown(this);
04463     AgeVehicle(this);
04464 
04465     CheckIfTrainNeedsService(this);
04466 
04467     CheckOrders(this);
04468 
04469     /* update destination */
04470     if (this->current_order.IsType(OT_GOTO_STATION)) {
04471       TileIndex tile = GetStation(this->current_order.GetDestination())->train_tile;
04472       if (tile != INVALID_TILE) this->dest_tile = tile;
04473     }
04474 
04475     if (this->running_ticks != 0) {
04476       /* running costs */
04477       CommandCost cost(EXPENSES_TRAIN_RUN, this->GetRunningCost() * this->running_ticks / (DAYS_IN_YEAR  * DAY_TICKS));
04478 
04479       this->profit_this_year -= cost.GetCost();
04480       this->running_ticks = 0;
04481 
04482       SubtractMoneyFromCompanyFract(this->owner, cost);
04483 
04484       InvalidateWindow(WC_VEHICLE_DETAILS, this->index);
04485       InvalidateWindowClasses(WC_TRAINS_LIST);
04486     }
04487   } else if (IsTrainEngine(this)) {
04488     /* Also age engines that aren't front engines */
04489     AgeVehicle(this);
04490   }
04491 }
04492 
04493 void InitializeTrains()
04494 {
04495   _age_cargo_skip_counter = 1;
04496 }

Generated on Mon Dec 14 21:00:04 2009 for OpenTTD by  doxygen 1.5.6