OpenTTD
train_cmd.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of OpenTTD.
3  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6  */
7 
10 #include "stdafx.h"
11 #include "error.h"
12 #include "articulated_vehicles.h"
13 #include "command_func.h"
15 #include "pathfinder/yapf/yapf.hpp"
16 #include "news_func.h"
17 #include "company_func.h"
18 #include "newgrf_sound.h"
19 #include "newgrf_text.h"
20 #include "strings_func.h"
21 #include "viewport_func.h"
22 #include "vehicle_func.h"
23 #include "sound_func.h"
24 #include "ai/ai.hpp"
25 #include "game/game.hpp"
26 #include "newgrf_station.h"
27 #include "effectvehicle_func.h"
28 #include "network/network.h"
29 #include "spritecache.h"
30 #include "core/random_func.hpp"
31 #include "company_base.h"
32 #include "newgrf.h"
33 #include "order_backup.h"
34 #include "zoom_func.h"
35 #include "newgrf_debug.h"
36 #include "framerate_type.h"
37 
38 #include "table/strings.h"
39 #include "table/train_cmd.h"
40 
41 #include "safeguards.h"
42 
43 static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool force_res, bool *got_reservation, bool mark_stuck);
44 static bool TrainCheckIfLineEnds(Train *v, bool reverse = true);
45 bool TrainController(Train *v, Vehicle *nomove, bool reverse = true); // Also used in vehicle_sl.cpp.
47 static void CheckIfTrainNeedsService(Train *v);
48 static void CheckNextTrainTile(Train *v);
49 
50 static const byte _vehicle_initial_x_fract[4] = {10, 8, 4, 8};
51 static const byte _vehicle_initial_y_fract[4] = { 8, 4, 8, 10};
52 
53 template <>
54 bool IsValidImageIndex<VEH_TRAIN>(uint8 image_index)
55 {
56  return image_index < lengthof(_engine_sprite_base);
57 }
58 
59 
66 {
67  if (!CargoSpec::Get(cargo)->is_freight) return 1;
69 }
70 
73 {
74  bool first = true;
75 
76  for (const Train *v : Train::Iterate()) {
77  if (v->First() == v && !(v->vehstatus & VS_CRASHED)) {
78  for (const Train *u = v, *w = v->Next(); w != nullptr; u = w, w = w->Next()) {
79  if (u->track != TRACK_BIT_DEPOT) {
80  if ((w->track != TRACK_BIT_DEPOT &&
81  max(abs(u->x_pos - w->x_pos), abs(u->y_pos - w->y_pos)) != u->CalcNextVehicleOffset()) ||
82  (w->track == TRACK_BIT_DEPOT && TicksToLeaveDepot(u) <= 0)) {
83  SetDParam(0, v->index);
84  SetDParam(1, v->owner);
85  ShowErrorMessage(STR_BROKEN_VEHICLE_LENGTH, INVALID_STRING_ID, WL_CRITICAL);
86 
87  if (!_networking && first) {
88  first = false;
90  }
91  /* Break so we warn only once for each train. */
92  break;
93  }
94  }
95  }
96  }
97  }
98 }
99 
107 {
108  uint16 max_speed = UINT16_MAX;
109 
110  assert(this->IsFrontEngine() || this->IsFreeWagon());
111 
112  const RailVehicleInfo *rvi_v = RailVehInfo(this->engine_type);
113  EngineID first_engine = this->IsFrontEngine() ? this->engine_type : INVALID_ENGINE;
114  this->gcache.cached_total_length = 0;
115  this->compatible_railtypes = RAILTYPES_NONE;
116 
117  bool train_can_tilt = true;
118 
119  for (Train *u = this; u != nullptr; u = u->Next()) {
120  const RailVehicleInfo *rvi_u = RailVehInfo(u->engine_type);
121 
122  /* Check the this->first cache. */
123  assert(u->First() == this);
124 
125  /* update the 'first engine' */
126  u->gcache.first_engine = this == u ? INVALID_ENGINE : first_engine;
127  u->railtype = rvi_u->railtype;
128 
129  if (u->IsEngine()) first_engine = u->engine_type;
130 
131  /* Set user defined data to its default value */
132  u->tcache.user_def_data = rvi_u->user_def_data;
133  this->InvalidateNewGRFCache();
134  u->InvalidateNewGRFCache();
135  }
136 
137  for (Train *u = this; u != nullptr; u = u->Next()) {
138  /* Update user defined data (must be done before other properties) */
139  u->tcache.user_def_data = GetVehicleProperty(u, PROP_TRAIN_USER_DATA, u->tcache.user_def_data);
140  this->InvalidateNewGRFCache();
141  u->InvalidateNewGRFCache();
142  }
143 
144  for (Train *u = this; u != nullptr; u = u->Next()) {
145  const Engine *e_u = u->GetEngine();
146  const RailVehicleInfo *rvi_u = &e_u->u.rail;
147 
148  if (!HasBit(e_u->info.misc_flags, EF_RAIL_TILTS)) train_can_tilt = false;
149 
150  /* Cache wagon override sprite group. nullptr is returned if there is none */
151  u->tcache.cached_override = GetWagonOverrideSpriteSet(u->engine_type, u->cargo_type, u->gcache.first_engine);
152 
153  /* Reset colour map */
154  u->colourmap = PAL_NONE;
155 
156  /* Update powered-wagon-status and visual effect */
157  u->UpdateVisualEffect(true);
158 
159  if (rvi_v->pow_wag_power != 0 && rvi_u->railveh_type == RAILVEH_WAGON &&
160  UsesWagonOverride(u) && !HasBit(u->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER)) {
161  /* wagon is powered */
162  SetBit(u->flags, VRF_POWEREDWAGON); // cache 'powered' status
163  } else {
164  ClrBit(u->flags, VRF_POWEREDWAGON);
165  }
166 
167  if (!u->IsArticulatedPart()) {
168  /* Do not count powered wagons for the compatible railtypes, as wagons always
169  have railtype normal */
170  if (rvi_u->power > 0) {
171  this->compatible_railtypes |= GetRailTypeInfo(u->railtype)->powered_railtypes;
172  }
173 
174  /* Some electric engines can be allowed to run on normal rail. It happens to all
175  * existing electric engines when elrails are disabled and then re-enabled */
176  if (HasBit(u->flags, VRF_EL_ENGINE_ALLOWED_NORMAL_RAIL)) {
177  u->railtype = RAILTYPE_RAIL;
178  u->compatible_railtypes |= RAILTYPES_RAIL;
179  }
180 
181  /* max speed is the minimum of the speed limits of all vehicles in the consist */
182  if ((rvi_u->railveh_type != RAILVEH_WAGON || _settings_game.vehicle.wagon_speed_limits) && !UsesWagonOverride(u)) {
183  uint16 speed = GetVehicleProperty(u, PROP_TRAIN_SPEED, rvi_u->max_speed);
184  if (speed != 0) max_speed = min(speed, max_speed);
185  }
186  }
187 
188  uint16 new_cap = e_u->DetermineCapacity(u);
189  if (allowed_changes & CCF_CAPACITY) {
190  /* Update vehicle capacity. */
191  if (u->cargo_cap > new_cap) u->cargo.Truncate(new_cap);
192  u->refit_cap = min(new_cap, u->refit_cap);
193  u->cargo_cap = new_cap;
194  } else {
195  /* Verify capacity hasn't changed. */
196  if (new_cap != u->cargo_cap) ShowNewGrfVehicleError(u->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_CAPACITY, GBUG_VEH_CAPACITY, true);
197  }
198  u->vcache.cached_cargo_age_period = GetVehicleProperty(u, PROP_TRAIN_CARGO_AGE_PERIOD, e_u->info.cargo_age_period);
199 
200  /* check the vehicle length (callback) */
201  uint16 veh_len = CALLBACK_FAILED;
202  if (e_u->GetGRF() != nullptr && e_u->GetGRF()->grf_version >= 8) {
203  /* Use callback 36 */
204  veh_len = GetVehicleProperty(u, PROP_TRAIN_SHORTEN_FACTOR, CALLBACK_FAILED);
205 
206  if (veh_len != CALLBACK_FAILED && veh_len >= VEHICLE_LENGTH) {
208  }
209  } else if (HasBit(e_u->info.callback_mask, CBM_VEHICLE_LENGTH)) {
210  /* Use callback 11 */
211  veh_len = GetVehicleCallback(CBID_VEHICLE_LENGTH, 0, 0, u->engine_type, u);
212  }
213  if (veh_len == CALLBACK_FAILED) veh_len = rvi_u->shorten_factor;
214  veh_len = VEHICLE_LENGTH - Clamp(veh_len, 0, VEHICLE_LENGTH - 1);
215 
216  if (allowed_changes & CCF_LENGTH) {
217  /* Update vehicle length. */
218  u->gcache.cached_veh_length = veh_len;
219  } else {
220  /* Verify length hasn't changed. */
221  if (veh_len != u->gcache.cached_veh_length) VehicleLengthChanged(u);
222  }
223 
224  this->gcache.cached_total_length += u->gcache.cached_veh_length;
225  this->InvalidateNewGRFCache();
226  u->InvalidateNewGRFCache();
227  }
228 
229  /* store consist weight/max speed in cache */
230  this->vcache.cached_max_speed = max_speed;
231  this->tcache.cached_tilt = train_can_tilt;
232  this->tcache.cached_max_curve_speed = this->GetCurveSpeedLimit();
233 
234  /* 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) */
235  this->CargoChanged();
236 
237  if (this->IsFrontEngine()) {
238  this->UpdateAcceleration();
242  InvalidateNewGRFInspectWindow(GSF_TRAINS, this->index);
243  }
244 }
245 
256 int GetTrainStopLocation(StationID station_id, TileIndex tile, const Train *v, int *station_ahead, int *station_length)
257 {
258  const Station *st = Station::Get(station_id);
259  *station_ahead = st->GetPlatformLength(tile, DirToDiagDir(v->direction)) * TILE_SIZE;
260  *station_length = st->GetPlatformLength(tile) * TILE_SIZE;
261 
262  /* Default to the middle of the station for stations stops that are not in
263  * the order list like intermediate stations when non-stop is disabled */
265  if (v->gcache.cached_total_length >= *station_length) {
266  /* The train is longer than the station, make it stop at the far end of the platform */
267  osl = OSL_PLATFORM_FAR_END;
268  } else if (v->current_order.IsType(OT_GOTO_STATION) && v->current_order.GetDestination() == station_id) {
269  osl = v->current_order.GetStopLocation();
270  }
271 
272  /* The stop location of the FRONT! of the train */
273  int stop;
274  switch (osl) {
275  default: NOT_REACHED();
276 
278  stop = v->gcache.cached_total_length;
279  break;
280 
281  case OSL_PLATFORM_MIDDLE:
282  stop = *station_length - (*station_length - v->gcache.cached_total_length) / 2;
283  break;
284 
286  stop = *station_length;
287  break;
288  }
289 
290  /* Subtract half the front vehicle length of the train so we get the real
291  * stop location of the train. */
292  return stop - (v->gcache.cached_veh_length + 1) / 2;
293 }
294 
295 
301 {
302  assert(this->First() == this);
303 
304  static const int absolute_max_speed = UINT16_MAX;
305  int max_speed = absolute_max_speed;
306 
307  if (_settings_game.vehicle.train_acceleration_model == AM_ORIGINAL) return max_speed;
308 
309  int curvecount[2] = {0, 0};
310 
311  /* first find the curve speed limit */
312  int numcurve = 0;
313  int sum = 0;
314  int pos = 0;
315  int lastpos = -1;
316  for (const Vehicle *u = this; u->Next() != nullptr; u = u->Next(), pos++) {
317  Direction this_dir = u->direction;
318  Direction next_dir = u->Next()->direction;
319 
320  DirDiff dirdiff = DirDifference(this_dir, next_dir);
321  if (dirdiff == DIRDIFF_SAME) continue;
322 
323  if (dirdiff == DIRDIFF_45LEFT) curvecount[0]++;
324  if (dirdiff == DIRDIFF_45RIGHT) curvecount[1]++;
325  if (dirdiff == DIRDIFF_45LEFT || dirdiff == DIRDIFF_45RIGHT) {
326  if (lastpos != -1) {
327  numcurve++;
328  sum += pos - lastpos;
329  if (pos - lastpos == 1 && max_speed > 88) {
330  max_speed = 88;
331  }
332  }
333  lastpos = pos;
334  }
335 
336  /* if we have a 90 degree turn, fix the speed limit to 60 */
337  if (dirdiff == DIRDIFF_90LEFT || dirdiff == DIRDIFF_90RIGHT) {
338  max_speed = 61;
339  }
340  }
341 
342  if (numcurve > 0 && max_speed > 88) {
343  if (curvecount[0] == 1 && curvecount[1] == 1) {
344  max_speed = absolute_max_speed;
345  } else {
346  sum /= numcurve;
347  max_speed = 232 - (13 - Clamp(sum, 1, 12)) * (13 - Clamp(sum, 1, 12));
348  }
349  }
350 
351  if (max_speed != absolute_max_speed) {
352  /* Apply the engine's rail type curve speed advantage, if it slowed by curves */
353  const RailtypeInfo *rti = GetRailTypeInfo(this->railtype);
354  max_speed += (max_speed / 2) * rti->curve_speed;
355 
356  if (this->tcache.cached_tilt) {
357  /* Apply max_speed bonus of 20% for a tilting train */
358  max_speed += max_speed / 5;
359  }
360  }
361 
362  return max_speed;
363 }
364 
370 {
371  int max_speed = _settings_game.vehicle.train_acceleration_model == AM_ORIGINAL ?
373  this->tcache.cached_max_curve_speed;
374 
375  if (_settings_game.vehicle.train_acceleration_model == AM_REALISTIC && IsRailStationTile(this->tile)) {
376  StationID sid = GetStationIndex(this->tile);
377  if (this->current_order.ShouldStopAtStation(this, sid)) {
378  int station_ahead;
379  int station_length;
380  int stop_at = GetTrainStopLocation(sid, this->tile, this, &station_ahead, &station_length);
381 
382  /* The distance to go is whatever is still ahead of the train minus the
383  * distance from the train's stop location to the end of the platform */
384  int distance_to_go = station_ahead / TILE_SIZE - (station_length - stop_at) / TILE_SIZE;
385 
386  if (distance_to_go > 0) {
387  int st_max_speed = 120;
388 
389  int delta_v = this->cur_speed / (distance_to_go + 1);
390  if (max_speed > (this->cur_speed - delta_v)) {
391  st_max_speed = this->cur_speed - (delta_v / 10);
392  }
393 
394  st_max_speed = max(st_max_speed, 25 * distance_to_go);
395  max_speed = min(max_speed, st_max_speed);
396  }
397  }
398  }
399 
400  for (const Train *u = this; u != nullptr; u = u->Next()) {
401  if (_settings_game.vehicle.train_acceleration_model == AM_REALISTIC && u->track == TRACK_BIT_DEPOT) {
402  max_speed = min(max_speed, 61);
403  break;
404  }
405 
406  /* Vehicle is on the middle part of a bridge. */
407  if (u->track == TRACK_BIT_WORMHOLE && !(u->vehstatus & VS_HIDDEN)) {
408  max_speed = min(max_speed, GetBridgeSpec(GetBridgeType(u->tile))->speed);
409  }
410  }
411 
412  max_speed = min(max_speed, this->current_order.GetMaxSpeed());
413  return min(max_speed, this->gcache.cached_max_track_speed);
414 }
415 
418 {
419  assert(this->IsFrontEngine() || this->IsFreeWagon());
420 
421  uint power = this->gcache.cached_power;
422  uint weight = this->gcache.cached_weight;
423  assert(weight != 0);
424  this->acceleration = Clamp(power / weight * 4, 1, 255);
425 }
426 
433 {
434  int reference_width = TRAININFO_DEFAULT_VEHICLE_WIDTH;
435  int vehicle_pitch = 0;
436 
437  const Engine *e = this->GetEngine();
438  if (e->GetGRF() != nullptr && is_custom_sprite(e->u.rail.image_index)) {
439  reference_width = e->GetGRF()->traininfo_vehicle_width;
440  vehicle_pitch = e->GetGRF()->traininfo_vehicle_pitch;
441  }
442 
443  if (offset != nullptr) {
444  offset->x = ScaleGUITrad(reference_width) / 2;
445  offset->y = ScaleGUITrad(vehicle_pitch);
446  }
447  return ScaleGUITrad(this->gcache.cached_veh_length * reference_width / VEHICLE_LENGTH);
448 }
449 
450 static SpriteID GetDefaultTrainSprite(uint8 spritenum, Direction direction)
451 {
452  assert(IsValidImageIndex<VEH_TRAIN>(spritenum));
453  return ((direction + _engine_sprite_add[spritenum]) & _engine_sprite_and[spritenum]) + _engine_sprite_base[spritenum];
454 }
455 
463 {
464  uint8 spritenum = this->spritenum;
465 
466  if (HasBit(this->flags, VRF_REVERSE_DIRECTION)) direction = ReverseDir(direction);
467 
468  if (is_custom_sprite(spritenum)) {
469  GetCustomVehicleSprite(this, (Direction)(direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(spritenum)), image_type, result);
470  if (result->IsValid()) return;
471 
472  spritenum = this->GetEngine()->original_image_index;
473  }
474 
475  assert(IsValidImageIndex<VEH_TRAIN>(spritenum));
476  SpriteID sprite = GetDefaultTrainSprite(spritenum, direction);
477 
478  if (this->cargo.StoredCount() >= this->cargo_cap / 2U) sprite += _wagon_full_adder[spritenum];
479 
480  result->Set(sprite);
481 }
482 
483 static void GetRailIcon(EngineID engine, bool rear_head, int &y, EngineImageType image_type, VehicleSpriteSeq *result)
484 {
485  const Engine *e = Engine::Get(engine);
486  Direction dir = rear_head ? DIR_E : DIR_W;
487  uint8 spritenum = e->u.rail.image_index;
488 
489  if (is_custom_sprite(spritenum)) {
490  GetCustomVehicleIcon(engine, dir, image_type, result);
491  if (result->IsValid()) {
492  if (e->GetGRF() != nullptr) {
494  }
495  return;
496  }
497 
498  spritenum = Engine::Get(engine)->original_image_index;
499  }
500 
501  if (rear_head) spritenum++;
502 
503  result->Set(GetDefaultTrainSprite(spritenum, DIR_W));
504 }
505 
506 void DrawTrainEngine(int left, int right, int preferred_x, int y, EngineID engine, PaletteID pal, EngineImageType image_type)
507 {
508  if (RailVehInfo(engine)->railveh_type == RAILVEH_MULTIHEAD) {
509  int yf = y;
510  int yr = y;
511 
512  VehicleSpriteSeq seqf, seqr;
513  GetRailIcon(engine, false, yf, image_type, &seqf);
514  GetRailIcon(engine, true, yr, image_type, &seqr);
515 
516  Rect rectf, rectr;
517  seqf.GetBounds(&rectf);
518  seqr.GetBounds(&rectr);
519 
520  preferred_x = Clamp(preferred_x,
521  left - UnScaleGUI(rectf.left) + ScaleGUITrad(14),
522  right - UnScaleGUI(rectr.right) - ScaleGUITrad(15));
523 
524  seqf.Draw(preferred_x - ScaleGUITrad(14), yf, pal, pal == PALETTE_CRASH);
525  seqr.Draw(preferred_x + ScaleGUITrad(15), yr, pal, pal == PALETTE_CRASH);
526  } else {
527  VehicleSpriteSeq seq;
528  GetRailIcon(engine, false, y, image_type, &seq);
529 
530  Rect rect;
531  seq.GetBounds(&rect);
532  preferred_x = Clamp(preferred_x,
533  left - UnScaleGUI(rect.left),
534  right - UnScaleGUI(rect.right));
535 
536  seq.Draw(preferred_x, y, pal, pal == PALETTE_CRASH);
537  }
538 }
539 
549 void GetTrainSpriteSize(EngineID engine, uint &width, uint &height, int &xoffs, int &yoffs, EngineImageType image_type)
550 {
551  int y = 0;
552 
553  VehicleSpriteSeq seq;
554  GetRailIcon(engine, false, y, image_type, &seq);
555 
556  Rect rect;
557  seq.GetBounds(&rect);
558 
559  width = UnScaleGUI(rect.right - rect.left + 1);
560  height = UnScaleGUI(rect.bottom - rect.top + 1);
561  xoffs = UnScaleGUI(rect.left);
562  yoffs = UnScaleGUI(rect.top);
563 
564  if (RailVehInfo(engine)->railveh_type == RAILVEH_MULTIHEAD) {
565  GetRailIcon(engine, true, y, image_type, &seq);
566  seq.GetBounds(&rect);
567 
568  /* Calculate values relative to an imaginary center between the two sprites. */
569  width = ScaleGUITrad(TRAININFO_DEFAULT_VEHICLE_WIDTH) + UnScaleGUI(rect.right) - xoffs;
570  height = max<uint>(height, UnScaleGUI(rect.bottom - rect.top + 1));
571  xoffs = xoffs - ScaleGUITrad(TRAININFO_DEFAULT_VEHICLE_WIDTH) / 2;
572  yoffs = min(yoffs, UnScaleGUI(rect.top));
573  }
574 }
575 
585 {
586  const RailVehicleInfo *rvi = &e->u.rail;
587 
588  /* Check that the wagon can drive on the track in question */
589  if (!IsCompatibleRail(rvi->railtype, GetRailType(tile))) return CMD_ERROR;
590 
591  if (flags & DC_EXEC) {
592  Train *v = new Train();
593  *ret = v;
594  v->spritenum = rvi->image_index;
595 
596  v->engine_type = e->index;
597  v->gcache.first_engine = INVALID_ENGINE; // needs to be set before first callback
598 
600 
601  v->direction = DiagDirToDir(dir);
602  v->tile = tile;
603 
604  int x = TileX(tile) * TILE_SIZE | _vehicle_initial_x_fract[dir];
605  int y = TileY(tile) * TILE_SIZE | _vehicle_initial_y_fract[dir];
606 
607  v->x_pos = x;
608  v->y_pos = y;
609  v->z_pos = GetSlopePixelZ(x, y);
610  v->owner = _current_company;
611  v->track = TRACK_BIT_DEPOT;
613 
614  v->SetWagon();
615 
616  v->SetFreeWagon();
618 
620  v->cargo_cap = rvi->capacity;
621  v->refit_cap = 0;
622 
623  v->railtype = rvi->railtype;
624 
626  v->build_year = _cur_year;
627  v->sprite_seq.Set(SPR_IMG_QUERY);
629 
630  v->group_id = DEFAULT_GROUP;
631 
633 
634  _new_vehicle_id = v->index;
635 
636  v->UpdatePosition();
639 
641 
642  /* Try to connect the vehicle to one of free chains of wagons. */
643  for (Train *w : Train::Iterate()) {
644  if (w->tile == tile &&
645  w->IsFreeWagon() &&
646  w->engine_type == e->index &&
647  w->First() != v &&
648  !(w->vehstatus & VS_CRASHED)) {
649  DoCommand(0, v->index | 1 << 20, w->Last()->index, DC_EXEC, CMD_MOVE_RAIL_VEHICLE);
650  break;
651  }
652  }
653  }
654 
655  return CommandCost();
656 }
657 
659 static void NormalizeTrainVehInDepot(const Train *u)
660 {
661  for (const Train *v : Train::Iterate()) {
662  if (v->IsFreeWagon() && v->tile == u->tile &&
663  v->track == TRACK_BIT_DEPOT) {
664  if (DoCommand(0, v->index | 1 << 20, u->index, DC_EXEC,
666  break;
667  }
668  }
669 }
670 
671 static void AddRearEngineToMultiheadedTrain(Train *v)
672 {
673  Train *u = new Train();
674  v->value >>= 1;
675  u->value = v->value;
676  u->direction = v->direction;
677  u->owner = v->owner;
678  u->tile = v->tile;
679  u->x_pos = v->x_pos;
680  u->y_pos = v->y_pos;
681  u->z_pos = v->z_pos;
682  u->track = TRACK_BIT_DEPOT;
683  u->vehstatus = v->vehstatus & ~VS_STOPPED;
684  u->spritenum = v->spritenum + 1;
685  u->cargo_type = v->cargo_type;
687  u->cargo_cap = v->cargo_cap;
688  u->refit_cap = v->refit_cap;
689  u->railtype = v->railtype;
690  u->engine_type = v->engine_type;
692  u->build_year = v->build_year;
693  u->sprite_seq.Set(SPR_IMG_QUERY);
695  v->SetMultiheaded();
696  u->SetMultiheaded();
697  v->SetNext(u);
698  u->UpdatePosition();
699 
700  /* Now we need to link the front and rear engines together */
701  v->other_multiheaded_part = u;
702  u->other_multiheaded_part = v;
703 }
704 
715 {
716  const RailVehicleInfo *rvi = &e->u.rail;
717 
718  if (rvi->railveh_type == RAILVEH_WAGON) return CmdBuildRailWagon(tile, flags, e, ret);
719 
720  /* Check if depot and new engine uses the same kind of tracks *
721  * We need to see if the engine got power on the tile to avoid electric engines in non-electric depots */
722  if (!HasPowerOnRail(rvi->railtype, GetRailType(tile))) return CMD_ERROR;
723 
724  if (flags & DC_EXEC) {
726  int x = TileX(tile) * TILE_SIZE + _vehicle_initial_x_fract[dir];
727  int y = TileY(tile) * TILE_SIZE + _vehicle_initial_y_fract[dir];
728 
729  Train *v = new Train();
730  *ret = v;
731  v->direction = DiagDirToDir(dir);
732  v->tile = tile;
733  v->owner = _current_company;
734  v->x_pos = x;
735  v->y_pos = y;
736  v->z_pos = GetSlopePixelZ(x, y);
737  v->track = TRACK_BIT_DEPOT;
739  v->spritenum = rvi->image_index;
741  v->cargo_cap = rvi->capacity;
742  v->refit_cap = 0;
743  v->last_station_visited = INVALID_STATION;
744  v->last_loading_station = INVALID_STATION;
745 
746  v->engine_type = e->index;
747  v->gcache.first_engine = INVALID_ENGINE; // needs to be set before first callback
748 
749  v->reliability = e->reliability;
751  v->max_age = e->GetLifeLengthInDays();
752 
753  v->railtype = rvi->railtype;
754  _new_vehicle_id = v->index;
755 
756  v->SetServiceInterval(Company::Get(_current_company)->settings.vehicle.servint_trains);
758  v->build_year = _cur_year;
759  v->sprite_seq.Set(SPR_IMG_QUERY);
761 
763  v->SetServiceIntervalIsPercent(Company::Get(_current_company)->settings.vehicle.servint_ispercent);
764 
765  v->group_id = DEFAULT_GROUP;
766 
767  v->SetFrontEngine();
768  v->SetEngine();
769 
770  v->UpdatePosition();
771 
772  if (rvi->railveh_type == RAILVEH_MULTIHEAD) {
773  AddRearEngineToMultiheadedTrain(v);
774  } else {
776  }
777 
780 
781  if (!HasBit(data, 0) && !(flags & DC_AUTOREPLACE)) { // check if the cars should be added to the new vehicle
783  }
784 
786  }
787 
788  return CommandCost();
789 }
790 
791 static Train *FindGoodVehiclePos(const Train *src)
792 {
793  EngineID eng = src->engine_type;
794  TileIndex tile = src->tile;
795 
796  for (Train *dst : Train::Iterate()) {
797  if (dst->IsFreeWagon() && dst->tile == tile && !(dst->vehstatus & VS_CRASHED)) {
798  /* check so all vehicles in the line have the same engine. */
799  Train *t = dst;
800  while (t->engine_type == eng) {
801  t = t->Next();
802  if (t == nullptr) return dst;
803  }
804  }
805  }
806 
807  return nullptr;
808 }
809 
811 typedef std::vector<Train *> TrainList;
812 
819 {
820  for (; t != nullptr; t = t->Next()) list.push_back(t);
821 }
822 
828 {
829  /* No train, nothing to do. */
830  if (list.size() == 0) return;
831 
832  Train *prev = nullptr;
833  /* Iterate over the list and rebuild it. */
834  for (Train *t : list) {
835  if (prev != nullptr) {
836  prev->SetNext(t);
837  } else if (t->Previous() != nullptr) {
838  /* Make sure the head of the train is always the first in the chain. */
839  t->Previous()->SetNext(nullptr);
840  }
841  prev = t;
842  }
843 }
844 
850 static void RemoveFromConsist(Train *part, bool chain = false)
851 {
852  Train *tail = chain ? part->Last() : part->GetLastEnginePart();
853 
854  /* Unlink at the front, but make it point to the next
855  * vehicle after the to be remove part. */
856  if (part->Previous() != nullptr) part->Previous()->SetNext(tail->Next());
857 
858  /* Unlink at the back */
859  tail->SetNext(nullptr);
860 }
861 
867 static void InsertInConsist(Train *dst, Train *chain)
868 {
869  /* We do not want to add something in the middle of an articulated part. */
870  assert(dst != nullptr && (dst->Next() == nullptr || !dst->Next()->IsArticulatedPart()));
871 
872  chain->Last()->SetNext(dst->Next());
873  dst->SetNext(chain);
874 }
875 
881 static void NormaliseDualHeads(Train *t)
882 {
883  for (; t != nullptr; t = t->GetNextVehicle()) {
884  if (!t->IsMultiheaded() || !t->IsEngine()) continue;
885 
886  /* Make sure that there are no free cars before next engine */
887  Train *u;
888  for (u = t; u->Next() != nullptr && !u->Next()->IsEngine(); u = u->Next()) {}
889 
890  if (u == t->other_multiheaded_part) continue;
891 
892  /* Remove the part from the 'wrong' train */
893  RemoveFromConsist(t->other_multiheaded_part);
894  /* And add it to the 'right' train */
895  InsertInConsist(u, t->other_multiheaded_part);
896  }
897 }
898 
903 static void NormaliseSubtypes(Train *chain)
904 {
905  /* Nothing to do */
906  if (chain == nullptr) return;
907 
908  /* We must be the first in the chain. */
909  assert(chain->Previous() == nullptr);
910 
911  /* Set the appropriate bits for the first in the chain. */
912  if (chain->IsWagon()) {
913  chain->SetFreeWagon();
914  } else {
915  assert(chain->IsEngine());
916  chain->SetFrontEngine();
917  }
918 
919  /* Now clear the bits for the rest of the chain */
920  for (Train *t = chain->Next(); t != nullptr; t = t->Next()) {
921  t->ClearFreeWagon();
922  t->ClearFrontEngine();
923  }
924 }
925 
935 static CommandCost CheckNewTrain(Train *original_dst, Train *dst, Train *original_src, Train *src)
936 {
937  /* Just add 'new' engines and subtract the original ones.
938  * If that's less than or equal to 0 we can be sure we did
939  * not add any engines (read: trains) along the way. */
940  if ((src != nullptr && src->IsEngine() ? 1 : 0) +
941  (dst != nullptr && dst->IsEngine() ? 1 : 0) -
942  (original_src != nullptr && original_src->IsEngine() ? 1 : 0) -
943  (original_dst != nullptr && original_dst->IsEngine() ? 1 : 0) <= 0) {
944  return CommandCost();
945  }
946 
947  /* Get a free unit number and check whether it's within the bounds.
948  * There will always be a maximum of one new train. */
950 
951  return_cmd_error(STR_ERROR_TOO_MANY_VEHICLES_IN_GAME);
952 }
953 
960 {
961  /* No multi-part train, no need to check. */
962  if (t == nullptr || t->Next() == nullptr || !t->IsEngine()) return CommandCost();
963 
964  /* The maximum length for a train. For each part we decrease this by one
965  * and if the result is negative the train is simply too long. */
967 
968  Train *head = t;
969  Train *prev = t;
970 
971  /* Break the prev -> t link so it always holds within the loop. */
972  t = t->Next();
973  prev->SetNext(nullptr);
974 
975  /* Make sure the cache is cleared. */
976  head->InvalidateNewGRFCache();
977 
978  while (t != nullptr) {
979  allowed_len -= t->gcache.cached_veh_length;
980 
981  Train *next = t->Next();
982 
983  /* Unlink the to-be-added piece; it is already unlinked from the previous
984  * part due to the fact that the prev -> t link is broken. */
985  t->SetNext(nullptr);
986 
987  /* Don't check callback for articulated or rear dual headed parts */
988  if (!t->IsArticulatedPart() && !t->IsRearDualheaded()) {
989  /* Back up and clear the first_engine data to avoid using wagon override group */
990  EngineID first_engine = t->gcache.first_engine;
992 
993  /* We don't want the cache to interfere. head's cache is cleared before
994  * the loop and after each callback does not need to be cleared here. */
996 
997  uint16 callback = GetVehicleCallbackParent(CBID_TRAIN_ALLOW_WAGON_ATTACH, 0, 0, head->engine_type, t, head);
998 
999  /* Restore original first_engine data */
1000  t->gcache.first_engine = first_engine;
1001 
1002  /* We do not want to remember any cached variables from the test run */
1003  t->InvalidateNewGRFCache();
1004  head->InvalidateNewGRFCache();
1005 
1006  if (callback != CALLBACK_FAILED) {
1007  /* A failing callback means everything is okay */
1008  StringID error = STR_NULL;
1009 
1010  if (head->GetGRF()->grf_version < 8) {
1011  if (callback == 0xFD) error = STR_ERROR_INCOMPATIBLE_RAIL_TYPES;
1012  if (callback < 0xFD) error = GetGRFStringID(head->GetGRFID(), 0xD000 + callback);
1013  if (callback >= 0x100) ErrorUnknownCallbackResult(head->GetGRFID(), CBID_TRAIN_ALLOW_WAGON_ATTACH, callback);
1014  } else {
1015  if (callback < 0x400) {
1016  error = GetGRFStringID(head->GetGRFID(), 0xD000 + callback);
1017  } else {
1018  switch (callback) {
1019  case 0x400: // allow if railtypes match (always the case for OpenTTD)
1020  case 0x401: // allow
1021  break;
1022 
1023  default: // unknown reason -> disallow
1024  case 0x402: // disallow attaching
1025  error = STR_ERROR_INCOMPATIBLE_RAIL_TYPES;
1026  break;
1027  }
1028  }
1029  }
1030 
1031  if (error != STR_NULL) return_cmd_error(error);
1032  }
1033  }
1034 
1035  /* And link it to the new part. */
1036  prev->SetNext(t);
1037  prev = t;
1038  t = next;
1039  }
1040 
1041  if (allowed_len < 0) return_cmd_error(STR_ERROR_TRAIN_TOO_LONG);
1042  return CommandCost();
1043 }
1044 
1055 static CommandCost ValidateTrains(Train *original_dst, Train *dst, Train *original_src, Train *src, bool check_limit)
1056 {
1057  /* Check whether we may actually construct the trains. */
1058  CommandCost ret = CheckTrainAttachment(src);
1059  if (ret.Failed()) return ret;
1060  ret = CheckTrainAttachment(dst);
1061  if (ret.Failed()) return ret;
1062 
1063  /* Check whether we need to build a new train. */
1064  return check_limit ? CheckNewTrain(original_dst, dst, original_src, src) : CommandCost();
1065 }
1066 
1075 static void ArrangeTrains(Train **dst_head, Train *dst, Train **src_head, Train *src, bool move_chain)
1076 {
1077  /* First determine the front of the two resulting trains */
1078  if (*src_head == *dst_head) {
1079  /* If we aren't moving part(s) to a new train, we are just moving the
1080  * front back and there is not destination head. */
1081  *dst_head = nullptr;
1082  } else if (*dst_head == nullptr) {
1083  /* If we are moving to a new train the head of the move train would become
1084  * the head of the new vehicle. */
1085  *dst_head = src;
1086  }
1087 
1088  if (src == *src_head) {
1089  /* If we are moving the front of a train then we are, in effect, creating
1090  * a new head for the train. Point to that. Unless we are moving the whole
1091  * train in which case there is not 'source' train anymore.
1092  * In case we are a multiheaded part we want the complete thing to come
1093  * with us, so src->GetNextUnit(), however... when we are e.g. a wagon
1094  * that is followed by a rear multihead we do not want to include that. */
1095  *src_head = move_chain ? nullptr :
1096  (src->IsMultiheaded() ? src->GetNextUnit() : src->GetNextVehicle());
1097  }
1098 
1099  /* Now it's just simply removing the part that we are going to move from the
1100  * source train and *if* the destination is a not a new train add the chain
1101  * at the destination location. */
1102  RemoveFromConsist(src, move_chain);
1103  if (*dst_head != src) InsertInConsist(dst, src);
1104 
1105  /* Now normalise the dual heads, that is move the dual heads around in such
1106  * a way that the head and rear of a dual head are in the same train */
1107  NormaliseDualHeads(*src_head);
1108  NormaliseDualHeads(*dst_head);
1109 }
1110 
1116 static void NormaliseTrainHead(Train *head)
1117 {
1118  /* Not much to do! */
1119  if (head == nullptr) return;
1120 
1121  /* Tell the 'world' the train changed. */
1122  head->ConsistChanged(CCF_ARRANGE);
1123  UpdateTrainGroupID(head);
1124 
1125  /* Not a front engine, i.e. a free wagon chain. No need to do more. */
1126  if (!head->IsFrontEngine()) return;
1127 
1128  /* Update the refit button and window */
1131 
1132  /* If we don't have a unit number yet, set one. */
1133  if (head->unitnumber != 0) return;
1135 }
1136 
1149 CommandCost CmdMoveRailVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
1150 {
1151  VehicleID s = GB(p1, 0, 20);
1152  VehicleID d = GB(p2, 0, 20);
1153  bool move_chain = HasBit(p1, 20);
1154 
1155  Train *src = Train::GetIfValid(s);
1156  if (src == nullptr) return CMD_ERROR;
1157 
1158  CommandCost ret = CheckOwnership(src->owner);
1159  if (ret.Failed()) return ret;
1160 
1161  /* Do not allow moving crashed vehicles inside the depot, it is likely to cause asserts later */
1162  if (src->vehstatus & VS_CRASHED) return CMD_ERROR;
1163 
1164  /* if nothing is selected as destination, try and find a matching vehicle to drag to. */
1165  Train *dst;
1166  if (d == INVALID_VEHICLE) {
1167  dst = src->IsEngine() ? nullptr : FindGoodVehiclePos(src);
1168  } else {
1169  dst = Train::GetIfValid(d);
1170  if (dst == nullptr) return CMD_ERROR;
1171 
1172  CommandCost ret = CheckOwnership(dst->owner);
1173  if (ret.Failed()) return ret;
1174 
1175  /* Do not allow appending to crashed vehicles, too */
1176  if (dst->vehstatus & VS_CRASHED) return CMD_ERROR;
1177  }
1178 
1179  /* if an articulated part is being handled, deal with its parent vehicle */
1180  src = src->GetFirstEnginePart();
1181  if (dst != nullptr) {
1182  dst = dst->GetFirstEnginePart();
1183  }
1184 
1185  /* don't move the same vehicle.. */
1186  if (src == dst) return CommandCost();
1187 
1188  /* locate the head of the two chains */
1189  Train *src_head = src->First();
1190  Train *dst_head;
1191  if (dst != nullptr) {
1192  dst_head = dst->First();
1193  if (dst_head->tile != src_head->tile) return CMD_ERROR;
1194  /* Now deal with articulated part of destination wagon */
1195  dst = dst->GetLastEnginePart();
1196  } else {
1197  dst_head = nullptr;
1198  }
1199 
1200  if (src->IsRearDualheaded()) return_cmd_error(STR_ERROR_REAR_ENGINE_FOLLOW_FRONT);
1201 
1202  /* When moving all wagons, we can't have the same src_head and dst_head */
1203  if (move_chain && src_head == dst_head) return CommandCost();
1204 
1205  /* When moving a multiheaded part to be place after itself, bail out. */
1206  if (!move_chain && dst != nullptr && dst->IsRearDualheaded() && src == dst->other_multiheaded_part) return CommandCost();
1207 
1208  /* Check if all vehicles in the source train are stopped inside a depot. */
1209  if (!src_head->IsStoppedInDepot()) return_cmd_error(STR_ERROR_TRAINS_CAN_ONLY_BE_ALTERED_INSIDE_A_DEPOT);
1210 
1211  /* Check if all vehicles in the destination train are stopped inside a depot. */
1212  if (dst_head != nullptr && !dst_head->IsStoppedInDepot()) return_cmd_error(STR_ERROR_TRAINS_CAN_ONLY_BE_ALTERED_INSIDE_A_DEPOT);
1213 
1214  /* First make a backup of the order of the trains. That way we can do
1215  * whatever we want with the order and later on easily revert. */
1216  TrainList original_src;
1217  TrainList original_dst;
1218 
1219  MakeTrainBackup(original_src, src_head);
1220  MakeTrainBackup(original_dst, dst_head);
1221 
1222  /* Also make backup of the original heads as ArrangeTrains can change them.
1223  * For the destination head we do not care if it is the same as the source
1224  * head because in that case it's just a copy. */
1225  Train *original_src_head = src_head;
1226  Train *original_dst_head = (dst_head == src_head ? nullptr : dst_head);
1227 
1228  /* We want this information from before the rearrangement, but execute this after the validation.
1229  * original_src_head can't be nullptr; src is by definition != nullptr, so src_head can't be nullptr as
1230  * src->GetFirst() always yields non-nullptr, so eventually original_src_head != nullptr as well. */
1231  bool original_src_head_front_engine = original_src_head->IsFrontEngine();
1232  bool original_dst_head_front_engine = original_dst_head != nullptr && original_dst_head->IsFrontEngine();
1233 
1234  /* (Re)arrange the trains in the wanted arrangement. */
1235  ArrangeTrains(&dst_head, dst, &src_head, src, move_chain);
1236 
1237  if ((flags & DC_AUTOREPLACE) == 0) {
1238  /* If the autoreplace flag is set we do not need to test for the validity
1239  * because we are going to revert the train to its original state. As we
1240  * assume the original state was correct autoreplace can skip this. */
1241  CommandCost ret = ValidateTrains(original_dst_head, dst_head, original_src_head, src_head, true);
1242  if (ret.Failed()) {
1243  /* Restore the train we had. */
1244  RestoreTrainBackup(original_src);
1245  RestoreTrainBackup(original_dst);
1246  return ret;
1247  }
1248  }
1249 
1250  /* do it? */
1251  if (flags & DC_EXEC) {
1252  /* Remove old heads from the statistics */
1253  if (original_src_head_front_engine) GroupStatistics::CountVehicle(original_src_head, -1);
1254  if (original_dst_head_front_engine) GroupStatistics::CountVehicle(original_dst_head, -1);
1255 
1256  /* First normalise the sub types of the chains. */
1257  NormaliseSubtypes(src_head);
1258  NormaliseSubtypes(dst_head);
1259 
1260  /* There are 14 different cases:
1261  * 1) front engine gets moved to a new train, it stays a front engine.
1262  * a) the 'next' part is a wagon that becomes a free wagon chain.
1263  * b) the 'next' part is an engine that becomes a front engine.
1264  * c) there is no 'next' part, nothing else happens
1265  * 2) front engine gets moved to another train, it is not a front engine anymore
1266  * a) the 'next' part is a wagon that becomes a free wagon chain.
1267  * b) the 'next' part is an engine that becomes a front engine.
1268  * c) there is no 'next' part, nothing else happens
1269  * 3) front engine gets moved to later in the current train, it is not a front engine anymore.
1270  * a) the 'next' part is a wagon that becomes a free wagon chain.
1271  * b) the 'next' part is an engine that becomes a front engine.
1272  * 4) free wagon gets moved
1273  * a) the 'next' part is a wagon that becomes a free wagon chain.
1274  * b) the 'next' part is an engine that becomes a front engine.
1275  * c) there is no 'next' part, nothing else happens
1276  * 5) non front engine gets moved and becomes a new train, nothing else happens
1277  * 6) non front engine gets moved within a train / to another train, nothing happens
1278  * 7) wagon gets moved, nothing happens
1279  */
1280  if (src == original_src_head && src->IsEngine() && !src->IsFrontEngine()) {
1281  /* Cases #2 and #3: the front engine gets trashed. */
1287  DeleteNewGRFInspectWindow(GSF_TRAINS, src->index);
1289 
1290  /* Delete orders, group stuff and the unit number as we're not the
1291  * front of any vehicle anymore. */
1292  DeleteVehicleOrders(src);
1294  src->unitnumber = 0;
1295  }
1296 
1297  /* We weren't a front engine but are becoming one. So
1298  * we should be put in the default group. */
1299  if (original_src_head != src && dst_head == src) {
1302  }
1303 
1304  /* Add new heads to statistics */
1305  if (src_head != nullptr && src_head->IsFrontEngine()) GroupStatistics::CountVehicle(src_head, 1);
1306  if (dst_head != nullptr && dst_head->IsFrontEngine()) GroupStatistics::CountVehicle(dst_head, 1);
1307 
1308  /* Handle 'new engine' part of cases #1b, #2b, #3b, #4b and #5 in NormaliseTrainHead. */
1309  NormaliseTrainHead(src_head);
1310  NormaliseTrainHead(dst_head);
1311 
1312  if ((flags & DC_NO_CARGO_CAP_CHECK) == 0) {
1313  CheckCargoCapacity(src_head);
1314  CheckCargoCapacity(dst_head);
1315  }
1316 
1317  if (src_head != nullptr) src_head->First()->MarkDirty();
1318  if (dst_head != nullptr) dst_head->First()->MarkDirty();
1319 
1320  /* We are undoubtedly changing something in the depot and train list. */
1323  } else {
1324  /* We don't want to execute what we're just tried. */
1325  RestoreTrainBackup(original_src);
1326  RestoreTrainBackup(original_dst);
1327  }
1328 
1329  return CommandCost();
1330 }
1331 
1343 CommandCost CmdSellRailWagon(DoCommandFlag flags, Vehicle *t, uint16 data, uint32 user)
1344 {
1345  /* Sell a chain of vehicles or not? */
1346  bool sell_chain = HasBit(data, 0);
1347 
1349  Train *first = v->First();
1350 
1351  if (v->IsRearDualheaded()) return_cmd_error(STR_ERROR_REAR_ENGINE_FOLLOW_FRONT);
1352 
1353  /* First make a backup of the order of the train. That way we can do
1354  * whatever we want with the order and later on easily revert. */
1355  TrainList original;
1356  MakeTrainBackup(original, first);
1357 
1358  /* We need to keep track of the new head and the head of what we're going to sell. */
1359  Train *new_head = first;
1360  Train *sell_head = nullptr;
1361 
1362  /* Split the train in the wanted way. */
1363  ArrangeTrains(&sell_head, nullptr, &new_head, v, sell_chain);
1364 
1365  /* We don't need to validate the second train; it's going to be sold. */
1366  CommandCost ret = ValidateTrains(nullptr, nullptr, first, new_head, (flags & DC_AUTOREPLACE) == 0);
1367  if (ret.Failed()) {
1368  /* Restore the train we had. */
1369  RestoreTrainBackup(original);
1370  return ret;
1371  }
1372 
1373  if (first->orders.list == nullptr && !OrderList::CanAllocateItem()) {
1374  /* Restore the train we had. */
1375  RestoreTrainBackup(original);
1376  return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
1377  }
1378 
1380  for (Train *t = sell_head; t != nullptr; t = t->Next()) cost.AddCost(-t->value);
1381 
1382  /* do it? */
1383  if (flags & DC_EXEC) {
1384  /* First normalise the sub types of the chain. */
1385  NormaliseSubtypes(new_head);
1386 
1387  if (v == first && v->IsEngine() && !sell_chain && new_head != nullptr && new_head->IsFrontEngine()) {
1388  /* We are selling the front engine. In this case we want to
1389  * 'give' the order, unit number and such to the new head. */
1390  new_head->orders.list = first->orders.list;
1391  new_head->AddToShared(first);
1392  DeleteVehicleOrders(first);
1393 
1394  /* Copy other important data from the front engine */
1395  new_head->CopyVehicleConfigAndStatistics(first);
1396  GroupStatistics::CountVehicle(new_head, 1); // after copying over the profit
1397  } else if (v->IsPrimaryVehicle() && data & (MAKE_ORDER_BACKUP_FLAG >> 20)) {
1398  OrderBackup::Backup(v, user);
1399  }
1400 
1401  /* We need to update the information about the train. */
1402  NormaliseTrainHead(new_head);
1403 
1404  /* We are undoubtedly changing something in the depot and train list. */
1407 
1408  /* Actually delete the sold 'goods' */
1409  delete sell_head;
1410  } else {
1411  /* We don't want to execute what we're just tried. */
1412  RestoreTrainBackup(original);
1413  }
1414 
1415  return cost;
1416 }
1417 
1419 {
1420  /* Set common defaults. */
1421  this->x_offs = -1;
1422  this->y_offs = -1;
1423  this->x_extent = 3;
1424  this->y_extent = 3;
1425  this->z_extent = 6;
1426  this->x_bb_offs = 0;
1427  this->y_bb_offs = 0;
1428 
1429  if (!IsDiagonalDirection(this->direction)) {
1430  static const int _sign_table[] =
1431  {
1432  /* x, y */
1433  -1, -1, // DIR_N
1434  -1, 1, // DIR_E
1435  1, 1, // DIR_S
1436  1, -1, // DIR_W
1437  };
1438 
1439  int half_shorten = (VEHICLE_LENGTH - this->gcache.cached_veh_length) / 2;
1440 
1441  /* For all straight directions, move the bound box to the centre of the vehicle, but keep the size. */
1442  this->x_offs -= half_shorten * _sign_table[this->direction];
1443  this->y_offs -= half_shorten * _sign_table[this->direction + 1];
1444  this->x_extent += this->x_bb_offs = half_shorten * _sign_table[direction];
1445  this->y_extent += this->y_bb_offs = half_shorten * _sign_table[direction + 1];
1446  } else {
1447  switch (this->direction) {
1448  /* Shorten southern corner of the bounding box according the vehicle length
1449  * and center the bounding box on the vehicle. */
1450  case DIR_NE:
1451  this->x_offs = 1 - (this->gcache.cached_veh_length + 1) / 2;
1452  this->x_extent = this->gcache.cached_veh_length - 1;
1453  this->x_bb_offs = -1;
1454  break;
1455 
1456  case DIR_NW:
1457  this->y_offs = 1 - (this->gcache.cached_veh_length + 1) / 2;
1458  this->y_extent = this->gcache.cached_veh_length - 1;
1459  this->y_bb_offs = -1;
1460  break;
1461 
1462  /* Move northern corner of the bounding box down according to vehicle length
1463  * and center the bounding box on the vehicle. */
1464  case DIR_SW:
1465  this->x_offs = 1 + (this->gcache.cached_veh_length + 1) / 2 - VEHICLE_LENGTH;
1466  this->x_extent = VEHICLE_LENGTH - 1;
1467  this->x_bb_offs = VEHICLE_LENGTH - this->gcache.cached_veh_length - 1;
1468  break;
1469 
1470  case DIR_SE:
1471  this->y_offs = 1 + (this->gcache.cached_veh_length + 1) / 2 - VEHICLE_LENGTH;
1472  this->y_extent = VEHICLE_LENGTH - 1;
1473  this->y_bb_offs = VEHICLE_LENGTH - this->gcache.cached_veh_length - 1;
1474  break;
1475 
1476  default:
1477  NOT_REACHED();
1478  }
1479  }
1480 }
1481 
1486 static void MarkTrainAsStuck(Train *v)
1487 {
1488  if (!HasBit(v->flags, VRF_TRAIN_STUCK)) {
1489  /* It is the first time the problem occurred, set the "train stuck" flag. */
1490  SetBit(v->flags, VRF_TRAIN_STUCK);
1491 
1492  v->wait_counter = 0;
1493 
1494  /* Stop train */
1495  v->cur_speed = 0;
1496  v->subspeed = 0;
1497  v->SetLastSpeed();
1498 
1500  }
1501 }
1502 
1510 static void SwapTrainFlags(uint16 *swap_flag1, uint16 *swap_flag2)
1511 {
1512  uint16 flag1 = *swap_flag1;
1513  uint16 flag2 = *swap_flag2;
1514 
1515  /* Clear the flags */
1516  ClrBit(*swap_flag1, GVF_GOINGUP_BIT);
1517  ClrBit(*swap_flag1, GVF_GOINGDOWN_BIT);
1518  ClrBit(*swap_flag2, GVF_GOINGUP_BIT);
1519  ClrBit(*swap_flag2, GVF_GOINGDOWN_BIT);
1520 
1521  /* Reverse the rail-flags (if needed) */
1522  if (HasBit(flag1, GVF_GOINGUP_BIT)) {
1523  SetBit(*swap_flag2, GVF_GOINGDOWN_BIT);
1524  } else if (HasBit(flag1, GVF_GOINGDOWN_BIT)) {
1525  SetBit(*swap_flag2, GVF_GOINGUP_BIT);
1526  }
1527  if (HasBit(flag2, GVF_GOINGUP_BIT)) {
1528  SetBit(*swap_flag1, GVF_GOINGDOWN_BIT);
1529  } else if (HasBit(flag2, GVF_GOINGDOWN_BIT)) {
1530  SetBit(*swap_flag1, GVF_GOINGUP_BIT);
1531  }
1532 }
1533 
1539 {
1540  /* Reverse the direction. */
1541  if (v->track != TRACK_BIT_DEPOT) v->direction = ReverseDir(v->direction);
1542 
1543  /* Call the proper EnterTile function unless we are in a wormhole. */
1544  if (v->track != TRACK_BIT_WORMHOLE) {
1545  VehicleEnterTile(v, v->tile, v->x_pos, v->y_pos);
1546  } else {
1547  /* VehicleEnter_TunnelBridge() sets TRACK_BIT_WORMHOLE when the vehicle
1548  * is on the last bit of the bridge head (frame == TILE_SIZE - 1).
1549  * If we were swapped with such a vehicle, we have set TRACK_BIT_WORMHOLE,
1550  * when we shouldn't have. Check if this is the case. */
1551  TileIndex vt = TileVirtXY(v->x_pos, v->y_pos);
1552  if (IsTileType(vt, MP_TUNNELBRIDGE)) {
1553  VehicleEnterTile(v, vt, v->x_pos, v->y_pos);
1554  if (v->track != TRACK_BIT_WORMHOLE && IsBridgeTile(v->tile)) {
1555  /* We have just left the wormhole, possibly set the
1556  * "goingdown" bit. UpdateInclination() can be used
1557  * because we are at the border of the tile. */
1558  v->UpdatePosition();
1559  v->UpdateInclination(true, true);
1560  return;
1561  }
1562  }
1563  }
1564 
1565  v->UpdatePosition();
1566  v->UpdateViewport(true, true);
1567 }
1568 
1575 void ReverseTrainSwapVeh(Train *v, int l, int r)
1576 {
1577  Train *a, *b;
1578 
1579  /* locate vehicles to swap */
1580  for (a = v; l != 0; l--) a = a->Next();
1581  for (b = v; r != 0; r--) b = b->Next();
1582 
1583  if (a != b) {
1584  /* swap the hidden bits */
1585  {
1586  uint16 tmp = (a->vehstatus & ~VS_HIDDEN) | (b->vehstatus & VS_HIDDEN);
1587  b->vehstatus = (b->vehstatus & ~VS_HIDDEN) | (a->vehstatus & VS_HIDDEN);
1588  a->vehstatus = tmp;
1589  }
1590 
1591  Swap(a->track, b->track);
1592  Swap(a->direction, b->direction);
1593  Swap(a->x_pos, b->x_pos);
1594  Swap(a->y_pos, b->y_pos);
1595  Swap(a->tile, b->tile);
1596  Swap(a->z_pos, b->z_pos);
1597 
1598  SwapTrainFlags(&a->gv_flags, &b->gv_flags);
1599 
1602  } else {
1603  /* Swap GVF_GOINGUP_BIT/GVF_GOINGDOWN_BIT.
1604  * This is a little bit redundant way, a->gv_flags will
1605  * be (re)set twice, but it reduces code duplication */
1606  SwapTrainFlags(&a->gv_flags, &a->gv_flags);
1608  }
1609 }
1610 
1611 
1617 static Vehicle *TrainOnTileEnum(Vehicle *v, void *)
1618 {
1619  return (v->type == VEH_TRAIN) ? v : nullptr;
1620 }
1621 
1622 
1630 {
1631  if (v->type != VEH_TRAIN || (v->vehstatus & VS_CRASHED)) return nullptr;
1632 
1633  Train *t = Train::From(v);
1634  if (!t->IsFrontEngine()) return nullptr;
1635 
1636  TileIndex tile = *(TileIndex *)data;
1637 
1638  if (TrainApproachingCrossingTile(t) != tile) return nullptr;
1639 
1640  return t;
1641 }
1642 
1643 
1651 {
1652  assert(IsLevelCrossingTile(tile));
1653 
1655  TileIndex tile_from = tile + TileOffsByDiagDir(dir);
1656 
1657  if (HasVehicleOnPos(tile_from, &tile, &TrainApproachingCrossingEnum)) return true;
1658 
1659  dir = ReverseDiagDir(dir);
1660  tile_from = tile + TileOffsByDiagDir(dir);
1661 
1662  return HasVehicleOnPos(tile_from, &tile, &TrainApproachingCrossingEnum);
1663 }
1664 
1665 
1673 {
1674  assert(IsLevelCrossingTile(tile));
1675 
1676  /* reserved || train on crossing || train approaching crossing */
1677  bool new_state = HasCrossingReservation(tile) || HasVehicleOnPos(tile, nullptr, &TrainOnTileEnum) || TrainApproachingCrossing(tile);
1678 
1679  if (new_state != IsCrossingBarred(tile)) {
1680  if (new_state && sound) {
1681  if (_settings_client.sound.ambient) SndPlayTileFx(SND_0E_LEVEL_CROSSING, tile);
1682  }
1683  SetCrossingBarred(tile, new_state);
1684  MarkTileDirtyByTile(tile);
1685  }
1686 }
1687 
1688 
1695 {
1696  if (!IsCrossingBarred(tile)) {
1697  BarCrossing(tile);
1698  if (_settings_client.sound.ambient) SndPlayTileFx(SND_0E_LEVEL_CROSSING, tile);
1699  MarkTileDirtyByTile(tile);
1700  }
1701 }
1702 
1703 
1710 {
1711  Train *base = v;
1712  Train *first = base; // first vehicle to move
1713  Train *last = v->Last(); // last vehicle to move
1714  uint length = CountVehiclesInChain(v);
1715 
1716  while (length > 2) {
1717  last = last->Previous();
1718  first = first->Next();
1719 
1720  int differential = base->CalcNextVehicleOffset() - last->CalcNextVehicleOffset();
1721 
1722  /* do not update images now
1723  * negative differential will be handled in AdvanceWagonsAfterSwap() */
1724  for (int i = 0; i < differential; i++) TrainController(first, last->Next());
1725 
1726  base = first; // == base->Next()
1727  length -= 2;
1728  }
1729 }
1730 
1731 
1738 {
1739  /* first of all, fix the situation when the train was entering a depot */
1740  Train *dep = v; // last vehicle in front of just left depot
1741  while (dep->Next() != nullptr && (dep->track == TRACK_BIT_DEPOT || dep->Next()->track != TRACK_BIT_DEPOT)) {
1742  dep = dep->Next(); // find first vehicle outside of a depot, with next vehicle inside a depot
1743  }
1744 
1745  Train *leave = dep->Next(); // first vehicle in a depot we are leaving now
1746 
1747  if (leave != nullptr) {
1748  /* 'pull' next wagon out of the depot, so we won't miss it (it could stay in depot forever) */
1749  int d = TicksToLeaveDepot(dep);
1750 
1751  if (d <= 0) {
1752  leave->vehstatus &= ~VS_HIDDEN; // move it out of the depot
1753  leave->track = TrackToTrackBits(GetRailDepotTrack(leave->tile));
1754  for (int i = 0; i >= d; i--) TrainController(leave, nullptr); // maybe move it, and maybe let another wagon leave
1755  }
1756  } else {
1757  dep = nullptr; // no vehicle in a depot, so no vehicle leaving a depot
1758  }
1759 
1760  Train *base = v;
1761  Train *first = base; // first vehicle to move
1762  Train *last = v->Last(); // last vehicle to move
1763  uint length = CountVehiclesInChain(v);
1764 
1765  /* We have to make sure all wagons that leave a depot because of train reversing are moved correctly
1766  * they have already correct spacing, so we have to make sure they are moved how they should */
1767  bool nomove = (dep == nullptr); // If there is no vehicle leaving a depot, limit the number of wagons moved immediately.
1768 
1769  while (length > 2) {
1770  /* we reached vehicle (originally) in front of a depot, stop now
1771  * (we would move wagons that are already moved with new wagon length). */
1772  if (base == dep) break;
1773 
1774  /* the last wagon was that one leaving a depot, so do not move it anymore */
1775  if (last == dep) nomove = true;
1776 
1777  last = last->Previous();
1778  first = first->Next();
1779 
1780  int differential = last->CalcNextVehicleOffset() - base->CalcNextVehicleOffset();
1781 
1782  /* do not update images now */
1783  for (int i = 0; i < differential; i++) TrainController(first, (nomove ? last->Next() : nullptr));
1784 
1785  base = first; // == base->Next()
1786  length -= 2;
1787  }
1788 }
1789 
1795 {
1796  if (IsRailDepotTile(v->tile)) {
1798  }
1799 
1800  /* Clear path reservation in front if train is not stuck. */
1801  if (!HasBit(v->flags, VRF_TRAIN_STUCK)) FreeTrainTrackReservation(v);
1802 
1803  /* Check if we were approaching a rail/road-crossing */
1805 
1806  /* count number of vehicles */
1807  int r = CountVehiclesInChain(v) - 1; // number of vehicles - 1
1808 
1810 
1811  /* swap start<>end, start+1<>end-1, ... */
1812  int l = 0;
1813  do {
1814  ReverseTrainSwapVeh(v, l++, r--);
1815  } while (l <= r);
1816 
1818 
1819  if (IsRailDepotTile(v->tile)) {
1821  }
1822 
1823  ToggleBit(v->flags, VRF_TOGGLE_REVERSE);
1824 
1825  ClrBit(v->flags, VRF_REVERSING);
1826 
1827  /* recalculate cached data */
1829 
1830  /* update all images */
1831  for (Train *u = v; u != nullptr; u = u->Next()) u->UpdateViewport(false, false);
1832 
1833  /* update crossing we were approaching */
1834  if (crossing != INVALID_TILE) UpdateLevelCrossing(crossing);
1835 
1836  /* maybe we are approaching crossing now, after reversal */
1837  crossing = TrainApproachingCrossingTile(v);
1838  if (crossing != INVALID_TILE) MaybeBarCrossingWithSound(crossing);
1839 
1840  /* If we are inside a depot after reversing, don't bother with path reserving. */
1841  if (v->track == TRACK_BIT_DEPOT) {
1842  /* Can't be stuck here as inside a depot is always a safe tile. */
1844  ClrBit(v->flags, VRF_TRAIN_STUCK);
1845  return;
1846  }
1847 
1848  /* VehicleExitDir does not always produce the desired dir for depots and
1849  * tunnels/bridges that is needed for UpdateSignalsOnSegment. */
1850  DiagDirection dir = VehicleExitDir(v->direction, v->track);
1852 
1854  /* If we are currently on a tile with conventional signals, we can't treat the
1855  * current tile as a safe tile or we would enter a PBS block without a reservation. */
1856  bool first_tile_okay = !(IsTileType(v->tile, MP_RAILWAY) &&
1858  !IsPbsSignal(GetSignalType(v->tile, FindFirstTrack(v->track))));
1859 
1860  /* If we are on a depot tile facing outwards, do not treat the current tile as safe. */
1861  if (IsRailDepotTile(v->tile) && TrackdirToExitdir(v->GetVehicleTrackdir()) == GetRailDepotDirection(v->tile)) first_tile_okay = false;
1862 
1864  if (TryPathReserve(v, false, first_tile_okay)) {
1865  /* Do a look-ahead now in case our current tile was already a safe tile. */
1866  CheckNextTrainTile(v);
1867  } else if (v->current_order.GetType() != OT_LOADING) {
1868  /* Do not wait for a way out when we're still loading */
1869  MarkTrainAsStuck(v);
1870  }
1871  } else if (HasBit(v->flags, VRF_TRAIN_STUCK)) {
1872  /* A train not inside a PBS block can't be stuck. */
1873  ClrBit(v->flags, VRF_TRAIN_STUCK);
1874  v->wait_counter = 0;
1875  }
1876 }
1877 
1887 CommandCost CmdReverseTrainDirection(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
1888 {
1889  Train *v = Train::GetIfValid(p1);
1890  if (v == nullptr) return CMD_ERROR;
1891 
1892  CommandCost ret = CheckOwnership(v->owner);
1893  if (ret.Failed()) return ret;
1894 
1895  if (p2 != 0) {
1896  /* turn a single unit around */
1897 
1898  if (v->IsMultiheaded() || HasBit(EngInfo(v->engine_type)->callback_mask, CBM_VEHICLE_ARTIC_ENGINE)) {
1899  return_cmd_error(STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE_MULTIPLE_UNITS);
1900  }
1901  if (!HasBit(EngInfo(v->engine_type)->misc_flags, EF_RAIL_FLIPS)) return CMD_ERROR;
1902 
1903  Train *front = v->First();
1904  /* make sure the vehicle is stopped in the depot */
1905  if (!front->IsStoppedInDepot()) {
1906  return_cmd_error(STR_ERROR_TRAINS_CAN_ONLY_BE_ALTERED_INSIDE_A_DEPOT);
1907  }
1908 
1909  if (flags & DC_EXEC) {
1910  ToggleBit(v->flags, VRF_REVERSE_DIRECTION);
1911 
1912  front->ConsistChanged(CCF_ARRANGE);
1917  }
1918  } else {
1919  /* turn the whole train around */
1920  if ((v->vehstatus & VS_CRASHED) || v->breakdown_ctr != 0) return CMD_ERROR;
1921 
1922  if (flags & DC_EXEC) {
1923  /* Properly leave the station if we are loading and won't be loading anymore */
1924  if (v->current_order.IsType(OT_LOADING)) {
1925  const Vehicle *last = v;
1926  while (last->Next() != nullptr) last = last->Next();
1927 
1928  /* not a station || different station --> leave the station */
1929  if (!IsTileType(last->tile, MP_STATION) || GetStationIndex(last->tile) != GetStationIndex(v->tile)) {
1930  v->LeaveStation();
1931  }
1932  }
1933 
1934  /* We cancel any 'skip signal at dangers' here */
1935  v->force_proceed = TFP_NONE;
1937 
1938  if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL && v->cur_speed != 0) {
1939  ToggleBit(v->flags, VRF_REVERSING);
1940  } else {
1941  v->cur_speed = 0;
1942  v->SetLastSpeed();
1945  }
1946  }
1947  }
1948  return CommandCost();
1949 }
1950 
1960 CommandCost CmdForceTrainProceed(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
1961 {
1962  Train *t = Train::GetIfValid(p1);
1963  if (t == nullptr) return CMD_ERROR;
1964 
1965  if (!t->IsPrimaryVehicle()) return CMD_ERROR;
1966 
1967  CommandCost ret = CheckOwnership(t->owner);
1968  if (ret.Failed()) return ret;
1969 
1970 
1971  if (flags & DC_EXEC) {
1972  /* If we are forced to proceed, cancel that order.
1973  * If we are marked stuck we would want to force the train
1974  * to proceed to the next signal. In the other cases we
1975  * would like to pass the signal at danger and run till the
1976  * next signal we encounter. */
1977  t->force_proceed = t->force_proceed == TFP_SIGNAL ? TFP_NONE : HasBit(t->flags, VRF_TRAIN_STUCK) || t->IsChainInDepot() ? TFP_STUCK : TFP_SIGNAL;
1979  }
1980 
1981  return CommandCost();
1982 }
1983 
1991 static FindDepotData FindClosestTrainDepot(Train *v, int max_distance)
1992 {
1993  assert(!(v->vehstatus & VS_CRASHED));
1994 
1995  if (IsRailDepotTile(v->tile)) return FindDepotData(v->tile, 0);
1996 
1997  PBSTileInfo origin = FollowTrainReservation(v);
1998  if (IsRailDepotTile(origin.tile)) return FindDepotData(origin.tile, 0);
1999 
2001  case VPF_NPF: return NPFTrainFindNearestDepot(v, max_distance);
2002  case VPF_YAPF: return YapfTrainFindNearestDepot(v, max_distance);
2003 
2004  default: NOT_REACHED();
2005  }
2006 }
2007 
2015 bool Train::FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse)
2016 {
2017  FindDepotData tfdd = FindClosestTrainDepot(this, 0);
2018  if (tfdd.best_length == UINT_MAX) return false;
2019 
2020  if (location != nullptr) *location = tfdd.tile;
2021  if (destination != nullptr) *destination = GetDepotIndex(tfdd.tile);
2022  if (reverse != nullptr) *reverse = tfdd.reverse;
2023 
2024  return true;
2025 }
2026 
2029 {
2030  static const SoundFx sfx[] = {
2031  SND_04_TRAIN,
2032  SND_0A_TRAIN_HORN,
2033  SND_0A_TRAIN_HORN,
2034  SND_47_MAGLEV_2,
2035  SND_41_MAGLEV
2036  };
2037 
2038  if (PlayVehicleSound(this, VSE_START)) return;
2039 
2040  EngineID engtype = this->engine_type;
2041  SndPlayVehicleFx(sfx[RailVehInfo(engtype)->engclass], this);
2042 }
2043 
2048 static void CheckNextTrainTile(Train *v)
2049 {
2050  /* Don't do any look-ahead if path_backoff_interval is 255. */
2051  if (_settings_game.pf.path_backoff_interval == 255) return;
2052 
2053  /* Exit if we are inside a depot. */
2054  if (v->track == TRACK_BIT_DEPOT) return;
2055 
2056  switch (v->current_order.GetType()) {
2057  /* Exit if we reached our destination depot. */
2058  case OT_GOTO_DEPOT:
2059  if (v->tile == v->dest_tile) return;
2060  break;
2061 
2062  case OT_GOTO_WAYPOINT:
2063  /* If we reached our waypoint, make sure we see that. */
2065  break;
2066 
2067  case OT_NOTHING:
2068  case OT_LEAVESTATION:
2069  case OT_LOADING:
2070  /* Exit if the current order doesn't have a destination, but the train has orders. */
2071  if (v->GetNumOrders() > 0) return;
2072  break;
2073 
2074  default:
2075  break;
2076  }
2077  /* Exit if we are on a station tile and are going to stop. */
2079 
2080  Trackdir td = v->GetVehicleTrackdir();
2081 
2082  /* On a tile with a red non-pbs signal, don't look ahead. */
2083  if (IsTileType(v->tile, MP_RAILWAY) && HasSignalOnTrackdir(v->tile, td) &&
2084  !IsPbsSignal(GetSignalType(v->tile, TrackdirToTrack(td))) &&
2085  GetSignalStateByTrackdir(v->tile, td) == SIGNAL_STATE_RED) return;
2086 
2087  CFollowTrackRail ft(v);
2088  if (!ft.Follow(v->tile, td)) return;
2089 
2091  /* Next tile is not reserved. */
2094  /* If the next tile is a PBS signal, try to make a reservation. */
2098  }
2099  ChooseTrainTrack(v, ft.m_new_tile, ft.m_exitdir, tracks, false, nullptr, false);
2100  }
2101  }
2102  }
2103 }
2104 
2111 {
2112  /* bail out if not all wagons are in the same depot or not in a depot at all */
2113  for (const Train *u = v; u != nullptr; u = u->Next()) {
2114  if (u->track != TRACK_BIT_DEPOT || u->tile != v->tile) return false;
2115  }
2116 
2117  /* if the train got no power, then keep it in the depot */
2118  if (v->gcache.cached_power == 0) {
2119  v->vehstatus |= VS_STOPPED;
2121  return true;
2122  }
2123 
2124  SigSegState seg_state;
2125 
2126  if (v->force_proceed == TFP_NONE) {
2127  /* force proceed was not pressed */
2128  if (++v->wait_counter < 37) {
2130  return true;
2131  }
2132 
2133  v->wait_counter = 0;
2134 
2136  if (seg_state == SIGSEG_FULL || HasDepotReservation(v->tile)) {
2137  /* Full and no PBS signal in block or depot reserved, can't exit. */
2139  return true;
2140  }
2141  } else {
2143  }
2144 
2145  /* We are leaving a depot, but have to go to the exact same one; re-enter. */
2146  if (v->current_order.IsType(OT_GOTO_DEPOT) && v->tile == v->dest_tile) {
2147  /* Service when depot has no reservation. */
2149  return true;
2150  }
2151 
2152  /* Only leave when we can reserve a path to our destination. */
2153  if (seg_state == SIGSEG_PBS && !TryPathReserve(v) && v->force_proceed == TFP_NONE) {
2154  /* No path and no force proceed. */
2156  MarkTrainAsStuck(v);
2157  return true;
2158  }
2159 
2160  SetDepotReservation(v->tile, true);
2162 
2165  v->PlayLeaveStationSound();
2166 
2167  v->track = TRACK_BIT_X;
2168  if (v->direction & 2) v->track = TRACK_BIT_Y;
2169 
2170  v->vehstatus &= ~VS_HIDDEN;
2171  v->cur_speed = 0;
2172 
2173  v->UpdateViewport(true, true);
2174  v->UpdatePosition();
2176  v->UpdateAcceleration();
2178 
2179  return false;
2180 }
2181 
2188 static void ClearPathReservation(const Train *v, TileIndex tile, Trackdir track_dir)
2189 {
2190  DiagDirection dir = TrackdirToExitdir(track_dir);
2191 
2192  if (IsTileType(tile, MP_TUNNELBRIDGE)) {
2193  /* Are we just leaving a tunnel/bridge? */
2194  if (GetTunnelBridgeDirection(tile) == ReverseDiagDir(dir)) {
2195  TileIndex end = GetOtherTunnelBridgeEnd(tile);
2196 
2197  if (TunnelBridgeIsFree(tile, end, v).Succeeded()) {
2198  /* Free the reservation only if no other train is on the tiles. */
2199  SetTunnelBridgeReservation(tile, false);
2200  SetTunnelBridgeReservation(end, false);
2201 
2203  if (IsBridge(tile)) {
2204  MarkBridgeDirty(tile);
2205  } else {
2206  MarkTileDirtyByTile(tile);
2207  MarkTileDirtyByTile(end);
2208  }
2209  }
2210  }
2211  }
2212  } else if (IsRailStationTile(tile)) {
2213  TileIndex new_tile = TileAddByDiagDir(tile, dir);
2214  /* If the new tile is not a further tile of the same station, we
2215  * clear the reservation for the whole platform. */
2216  if (!IsCompatibleTrainStationTile(new_tile, tile)) {
2218  }
2219  } else {
2220  /* Any other tile */
2221  UnreserveRailTrack(tile, TrackdirToTrack(track_dir));
2222  }
2223 }
2224 
2230 {
2231  assert(v->IsFrontEngine());
2232 
2233  TileIndex tile = v->tile;
2234  Trackdir td = v->GetVehicleTrackdir();
2235  bool free_tile = !(IsRailStationTile(v->tile) || IsTileType(v->tile, MP_TUNNELBRIDGE));
2236  StationID station_id = IsRailStationTile(v->tile) ? GetStationIndex(v->tile) : INVALID_STATION;
2237 
2238  /* Can't be holding a reservation if we enter a depot. */
2239  if (IsRailDepotTile(tile) && TrackdirToExitdir(td) != GetRailDepotDirection(tile)) return;
2240  if (v->track == TRACK_BIT_DEPOT) {
2241  /* Front engine is in a depot. We enter if some part is not in the depot. */
2242  for (const Train *u = v; u != nullptr; u = u->Next()) {
2243  if (u->track != TRACK_BIT_DEPOT || u->tile != v->tile) return;
2244  }
2245  }
2246  /* Don't free reservation if it's not ours. */
2248 
2250  while (ft.Follow(tile, td)) {
2251  tile = ft.m_new_tile;
2253  td = RemoveFirstTrackdir(&bits);
2254  assert(bits == TRACKDIR_BIT_NONE);
2255 
2256  if (!IsValidTrackdir(td)) break;
2257 
2258  if (IsTileType(tile, MP_RAILWAY)) {
2259  if (HasSignalOnTrackdir(tile, td) && !IsPbsSignal(GetSignalType(tile, TrackdirToTrack(td)))) {
2260  /* Conventional signal along trackdir: remove reservation and stop. */
2262  break;
2263  }
2264  if (HasPbsSignalOnTrackdir(tile, td)) {
2265  if (GetSignalStateByTrackdir(tile, td) == SIGNAL_STATE_RED) {
2266  /* Red PBS signal? Can't be our reservation, would be green then. */
2267  break;
2268  } else {
2269  /* Turn the signal back to red. */
2271  MarkTileDirtyByTile(tile);
2272  }
2273  } else if (HasSignalOnTrackdir(tile, ReverseTrackdir(td)) && IsOnewaySignal(tile, TrackdirToTrack(td))) {
2274  break;
2275  }
2276  }
2277 
2278  /* Don't free first station/bridge/tunnel if we are on it. */
2279  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);
2280 
2281  free_tile = true;
2282  }
2283 }
2284 
2285 static const byte _initial_tile_subcoord[6][4][3] = {
2286 {{ 15, 8, 1 }, { 0, 0, 0 }, { 0, 8, 5 }, { 0, 0, 0 }},
2287 {{ 0, 0, 0 }, { 8, 0, 3 }, { 0, 0, 0 }, { 8, 15, 7 }},
2288 {{ 0, 0, 0 }, { 7, 0, 2 }, { 0, 7, 6 }, { 0, 0, 0 }},
2289 {{ 15, 8, 2 }, { 0, 0, 0 }, { 0, 0, 0 }, { 8, 15, 6 }},
2290 {{ 15, 7, 0 }, { 8, 0, 4 }, { 0, 0, 0 }, { 0, 0, 0 }},
2291 {{ 0, 0, 0 }, { 0, 0, 0 }, { 0, 8, 4 }, { 7, 15, 0 }},
2292 };
2293 
2306 static Track DoTrainPathfind(const Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found, bool do_track_reservation, PBSTileInfo *dest)
2307 {
2309  case VPF_NPF: return NPFTrainChooseTrack(v, path_found, do_track_reservation, dest);
2310  case VPF_YAPF: return YapfTrainChooseTrack(v, tile, enterdir, tracks, path_found, do_track_reservation, dest);
2311 
2312  default: NOT_REACHED();
2313  }
2314 }
2315 
2321 static PBSTileInfo ExtendTrainReservation(const Train *v, TrackBits *new_tracks, DiagDirection *enterdir)
2322 {
2323  PBSTileInfo origin = FollowTrainReservation(v);
2324 
2325  CFollowTrackRail ft(v);
2326 
2327  TileIndex tile = origin.tile;
2328  Trackdir cur_td = origin.trackdir;
2329  while (ft.Follow(tile, cur_td)) {
2331  /* Possible signal tile. */
2333  }
2334 
2337  if (ft.m_new_td_bits == TRACKDIR_BIT_NONE) break;
2338  }
2339 
2340  /* Station, depot or waypoint are a possible target. */
2341  bool target_seen = ft.m_is_station || (IsTileType(ft.m_new_tile, MP_RAILWAY) && !IsPlainRail(ft.m_new_tile));
2342  if (target_seen || KillFirstBit(ft.m_new_td_bits) != TRACKDIR_BIT_NONE) {
2343  /* Choice found or possible target encountered.
2344  * On finding a possible target, we need to stop and let the pathfinder handle the
2345  * remaining path. This is because we don't know if this target is in one of our
2346  * orders, so we might cause pathfinding to fail later on if we find a choice.
2347  * This failure would cause a bogous call to TryReserveSafePath which might reserve
2348  * a wrong path not leading to our next destination. */
2350 
2351  /* If we did skip some tiles, backtrack to the first skipped tile so the pathfinder
2352  * actually starts its search at the first unreserved tile. */
2354 
2355  /* Choice found, path valid but not okay. Save info about the choice tile as well. */
2356  if (new_tracks != nullptr) *new_tracks = TrackdirBitsToTrackBits(ft.m_new_td_bits);
2357  if (enterdir != nullptr) *enterdir = ft.m_exitdir;
2358  return PBSTileInfo(ft.m_new_tile, ft.m_old_td, false);
2359  }
2360 
2361  tile = ft.m_new_tile;
2362  cur_td = FindFirstTrackdir(ft.m_new_td_bits);
2363 
2364  if (IsSafeWaitingPosition(v, tile, cur_td, true, _settings_game.pf.forbid_90_deg)) {
2365  bool wp_free = IsWaitingPositionFree(v, tile, cur_td, _settings_game.pf.forbid_90_deg);
2366  if (!(wp_free && TryReserveRailTrack(tile, TrackdirToTrack(cur_td)))) break;
2367  /* Safe position is all good, path valid and okay. */
2368  return PBSTileInfo(tile, cur_td, true);
2369  }
2370 
2371  if (!TryReserveRailTrack(tile, TrackdirToTrack(cur_td))) break;
2372  }
2373 
2374  if (ft.m_err == CFollowTrackRail::EC_OWNER || ft.m_err == CFollowTrackRail::EC_NO_WAY) {
2375  /* End of line, path valid and okay. */
2376  return PBSTileInfo(ft.m_old_tile, ft.m_old_td, true);
2377  }
2378 
2379  /* Sorry, can't reserve path, back out. */
2380  tile = origin.tile;
2381  cur_td = origin.trackdir;
2382  TileIndex stopped = ft.m_old_tile;
2383  Trackdir stopped_td = ft.m_old_td;
2384  while (tile != stopped || cur_td != stopped_td) {
2385  if (!ft.Follow(tile, cur_td)) break;
2386 
2389  assert(ft.m_new_td_bits != TRACKDIR_BIT_NONE);
2390  }
2392 
2393  tile = ft.m_new_tile;
2394  cur_td = FindFirstTrackdir(ft.m_new_td_bits);
2395 
2396  UnreserveRailTrack(tile, TrackdirToTrack(cur_td));
2397  }
2398 
2399  /* Path invalid. */
2400  return PBSTileInfo();
2401 }
2402 
2413 static bool TryReserveSafeTrack(const Train *v, TileIndex tile, Trackdir td, bool override_railtype)
2414 {
2416  case VPF_NPF: return NPFTrainFindNearestSafeTile(v, tile, td, override_railtype);
2417  case VPF_YAPF: return YapfTrainFindNearestSafeTile(v, tile, td, override_railtype);
2418 
2419  default: NOT_REACHED();
2420  }
2421 }
2422 
2425 private:
2426  Train *v;
2427  Order old_order;
2428  TileIndex old_dest_tile;
2429  StationID old_last_station_visited;
2431  bool suppress_implicit_orders;
2432 
2433 public:
2434  VehicleOrderSaver(Train *_v) :
2435  v(_v),
2436  old_order(_v->current_order),
2437  old_dest_tile(_v->dest_tile),
2438  old_last_station_visited(_v->last_station_visited),
2440  suppress_implicit_orders(HasBit(_v->gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS))
2441  {
2442  }
2443 
2445  {
2446  this->v->current_order = this->old_order;
2447  this->v->dest_tile = this->old_dest_tile;
2448  this->v->last_station_visited = this->old_last_station_visited;
2449  SB(this->v->gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS, 1, suppress_implicit_orders ? 1: 0);
2450  }
2451 
2457  bool SwitchToNextOrder(bool skip_first)
2458  {
2459  if (this->v->GetNumOrders() == 0) return false;
2460 
2461  if (skip_first) ++this->index;
2462 
2463  int depth = 0;
2464 
2465  do {
2466  /* Wrap around. */
2467  if (this->index >= this->v->GetNumOrders()) this->index = 0;
2468 
2469  Order *order = this->v->GetOrder(this->index);
2470  assert(order != nullptr);
2471 
2472  switch (order->GetType()) {
2473  case OT_GOTO_DEPOT:
2474  /* Skip service in depot orders when the train doesn't need service. */
2475  if ((order->GetDepotOrderType() & ODTFB_SERVICE) && !this->v->NeedsServicing()) break;
2476  FALLTHROUGH;
2477  case OT_GOTO_STATION:
2478  case OT_GOTO_WAYPOINT:
2479  this->v->current_order = *order;
2480  return UpdateOrderDest(this->v, order, 0, true);
2481  case OT_CONDITIONAL: {
2482  VehicleOrderID next = ProcessConditionalOrder(order, this->v);
2483  if (next != INVALID_VEH_ORDER_ID) {
2484  depth++;
2485  this->index = next;
2486  /* Don't increment next, so no break here. */
2487  continue;
2488  }
2489  break;
2490  }
2491  default:
2492  break;
2493  }
2494  /* Don't increment inside the while because otherwise conditional
2495  * orders can lead to an infinite loop. */
2496  ++this->index;
2497  depth++;
2498  } while (this->index != this->v->cur_real_order_index && depth < this->v->GetNumOrders());
2499 
2500  return false;
2501  }
2502 };
2503 
2504 /* choose a track */
2505 static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool force_res, bool *got_reservation, bool mark_stuck)
2506 {
2507  Track best_track = INVALID_TRACK;
2508  bool do_track_reservation = _settings_game.pf.reserve_paths || force_res;
2509  bool changed_signal = false;
2510 
2511  assert((tracks & ~TRACK_BIT_MASK) == 0);
2512 
2513  if (got_reservation != nullptr) *got_reservation = false;
2514 
2515  /* Don't use tracks here as the setting to forbid 90 deg turns might have been switched between reservation and now. */
2516  TrackBits res_tracks = (TrackBits)(GetReservedTrackbits(tile) & DiagdirReachesTracks(enterdir));
2517  /* Do we have a suitable reserved track? */
2518  if (res_tracks != TRACK_BIT_NONE) return FindFirstTrack(res_tracks);
2519 
2520  /* Quick return in case only one possible track is available */
2521  if (KillFirstBit(tracks) == TRACK_BIT_NONE) {
2522  Track track = FindFirstTrack(tracks);
2523  /* We need to check for signals only here, as a junction tile can't have signals. */
2524  if (track != INVALID_TRACK && HasPbsSignalOnTrackdir(tile, TrackEnterdirToTrackdir(track, enterdir))) {
2525  do_track_reservation = true;
2526  changed_signal = true;
2528  } else if (!do_track_reservation) {
2529  return track;
2530  }
2531  best_track = track;
2532  }
2533 
2534  PBSTileInfo res_dest(tile, INVALID_TRACKDIR, false);
2535  DiagDirection dest_enterdir = enterdir;
2536  if (do_track_reservation) {
2537  res_dest = ExtendTrainReservation(v, &tracks, &dest_enterdir);
2538  if (res_dest.tile == INVALID_TILE) {
2539  /* Reservation failed? */
2540  if (mark_stuck) MarkTrainAsStuck(v);
2541  if (changed_signal) SetSignalStateByTrackdir(tile, TrackEnterdirToTrackdir(best_track, enterdir), SIGNAL_STATE_RED);
2542  return FindFirstTrack(tracks);
2543  }
2544  if (res_dest.okay) {
2545  /* Got a valid reservation that ends at a safe target, quick exit. */
2546  if (got_reservation != nullptr) *got_reservation = true;
2547  if (changed_signal) MarkTileDirtyByTile(tile);
2549  return best_track;
2550  }
2551 
2552  /* Check if the train needs service here, so it has a chance to always find a depot.
2553  * Also check if the current order is a service order so we don't reserve a path to
2554  * the destination but instead to the next one if service isn't needed. */
2556  if (v->current_order.IsType(OT_DUMMY) || v->current_order.IsType(OT_CONDITIONAL) || v->current_order.IsType(OT_GOTO_DEPOT)) ProcessOrders(v);
2557  }
2558 
2559  /* Save the current train order. The destructor will restore the old order on function exit. */
2561 
2562  /* If the current tile is the destination of the current order and
2563  * a reservation was requested, advance to the next order.
2564  * Don't advance on a depot order as depots are always safe end points
2565  * for a path and no look-ahead is necessary. This also avoids a
2566  * problem with depot orders not part of the order list when the
2567  * order list itself is empty. */
2568  if (v->current_order.IsType(OT_LEAVESTATION)) {
2569  orders.SwitchToNextOrder(false);
2570  } else if (v->current_order.IsType(OT_LOADING) || (!v->current_order.IsType(OT_GOTO_DEPOT) && (
2571  v->current_order.IsType(OT_GOTO_STATION) ?
2573  v->tile == v->dest_tile))) {
2574  orders.SwitchToNextOrder(true);
2575  }
2576 
2577  if (res_dest.tile != INVALID_TILE && !res_dest.okay) {
2578  /* Pathfinders are able to tell that route was only 'guessed'. */
2579  bool path_found = true;
2580  TileIndex new_tile = res_dest.tile;
2581 
2582  Track next_track = DoTrainPathfind(v, new_tile, dest_enterdir, tracks, path_found, do_track_reservation, &res_dest);
2583  if (new_tile == tile) best_track = next_track;
2584  v->HandlePathfindingResult(path_found);
2585  }
2586 
2587  /* No track reservation requested -> finished. */
2588  if (!do_track_reservation) return best_track;
2589 
2590  /* A path was found, but could not be reserved. */
2591  if (res_dest.tile != INVALID_TILE && !res_dest.okay) {
2592  if (mark_stuck) MarkTrainAsStuck(v);
2594  return best_track;
2595  }
2596 
2597  /* No possible reservation target found, we are probably lost. */
2598  if (res_dest.tile == INVALID_TILE) {
2599  /* Try to find any safe destination. */
2600  PBSTileInfo origin = FollowTrainReservation(v);
2601  if (TryReserveSafeTrack(v, origin.tile, origin.trackdir, false)) {
2603  best_track = FindFirstTrack(res);
2605  if (got_reservation != nullptr) *got_reservation = true;
2606  if (changed_signal) MarkTileDirtyByTile(tile);
2607  } else {
2609  if (mark_stuck) MarkTrainAsStuck(v);
2610  }
2611  return best_track;
2612  }
2613 
2614  if (got_reservation != nullptr) *got_reservation = true;
2615 
2616  /* Reservation target found and free, check if it is safe. */
2617  while (!IsSafeWaitingPosition(v, res_dest.tile, res_dest.trackdir, true, _settings_game.pf.forbid_90_deg)) {
2618  /* Extend reservation until we have found a safe position. */
2619  DiagDirection exitdir = TrackdirToExitdir(res_dest.trackdir);
2620  TileIndex next_tile = TileAddByDiagDir(res_dest.tile, exitdir);
2622  if (Rail90DegTurnDisallowed(GetTileRailType(res_dest.tile), GetTileRailType(next_tile))) {
2623  reachable &= ~TrackCrossesTracks(TrackdirToTrack(res_dest.trackdir));
2624  }
2625 
2626  /* Get next order with destination. */
2627  if (orders.SwitchToNextOrder(true)) {
2628  PBSTileInfo cur_dest;
2629  bool path_found;
2630  DoTrainPathfind(v, next_tile, exitdir, reachable, path_found, true, &cur_dest);
2631  if (cur_dest.tile != INVALID_TILE) {
2632  res_dest = cur_dest;
2633  if (res_dest.okay) continue;
2634  /* Path found, but could not be reserved. */
2636  if (mark_stuck) MarkTrainAsStuck(v);
2637  if (got_reservation != nullptr) *got_reservation = false;
2638  changed_signal = false;
2639  break;
2640  }
2641  }
2642  /* No order or no safe position found, try any position. */
2643  if (!TryReserveSafeTrack(v, res_dest.tile, res_dest.trackdir, true)) {
2645  if (mark_stuck) MarkTrainAsStuck(v);
2646  if (got_reservation != nullptr) *got_reservation = false;
2647  changed_signal = false;
2648  }
2649  break;
2650  }
2651 
2653 
2654  if (changed_signal) MarkTileDirtyByTile(tile);
2655 
2656  return best_track;
2657 }
2658 
2667 bool TryPathReserve(Train *v, bool mark_as_stuck, bool first_tile_okay)
2668 {
2669  assert(v->IsFrontEngine());
2670 
2671  /* We have to handle depots specially as the track follower won't look
2672  * at the depot tile itself but starts from the next tile. If we are still
2673  * inside the depot, a depot reservation can never be ours. */
2674  if (v->track == TRACK_BIT_DEPOT) {
2675  if (HasDepotReservation(v->tile)) {
2676  if (mark_as_stuck) MarkTrainAsStuck(v);
2677  return false;
2678  } else {
2679  /* Depot not reserved, but the next tile might be. */
2681  if (HasReservedTracks(next_tile, DiagdirReachesTracks(GetRailDepotDirection(v->tile)))) return false;
2682  }
2683  }
2684 
2685  Vehicle *other_train = nullptr;
2686  PBSTileInfo origin = FollowTrainReservation(v, &other_train);
2687  /* The path we are driving on is already blocked by some other train.
2688  * This can only happen in certain situations when mixing path and
2689  * block signals or when changing tracks and/or signals.
2690  * Exit here as doing any further reservations will probably just
2691  * make matters worse. */
2692  if (other_train != nullptr && other_train->index != v->index) {
2693  if (mark_as_stuck) MarkTrainAsStuck(v);
2694  return false;
2695  }
2696  /* If we have a reserved path and the path ends at a safe tile, we are finished already. */
2697  if (origin.okay && (v->tile != origin.tile || first_tile_okay)) {
2698  /* Can't be stuck then. */
2700  ClrBit(v->flags, VRF_TRAIN_STUCK);
2701  return true;
2702  }
2703 
2704  /* If we are in a depot, tentatively reserve the depot. */
2705  if (v->track == TRACK_BIT_DEPOT) {
2706  SetDepotReservation(v->tile, true);
2708  }
2709 
2710  DiagDirection exitdir = TrackdirToExitdir(origin.trackdir);
2711  TileIndex new_tile = TileAddByDiagDir(origin.tile, exitdir);
2713 
2715 
2716  bool res_made = false;
2717  ChooseTrainTrack(v, new_tile, exitdir, reachable, true, &res_made, mark_as_stuck);
2718 
2719  if (!res_made) {
2720  /* Free the depot reservation as well. */
2721  if (v->track == TRACK_BIT_DEPOT) SetDepotReservation(v->tile, false);
2722  return false;
2723  }
2724 
2725  if (HasBit(v->flags, VRF_TRAIN_STUCK)) {
2726  v->wait_counter = 0;
2728  }
2729  ClrBit(v->flags, VRF_TRAIN_STUCK);
2730  return true;
2731 }
2732 
2733 
2734 static bool CheckReverseTrain(const Train *v)
2735 {
2737  v->track == TRACK_BIT_DEPOT || v->track == TRACK_BIT_WORMHOLE ||
2738  !(v->direction & 1)) {
2739  return false;
2740  }
2741 
2742  assert(v->track != TRACK_BIT_NONE);
2743 
2745  case VPF_NPF: return NPFTrainCheckReverse(v);
2746  case VPF_YAPF: return YapfTrainCheckReverse(v);
2747 
2748  default: NOT_REACHED();
2749  }
2750 }
2751 
2758 {
2759  if (station == this->last_station_visited) this->last_station_visited = INVALID_STATION;
2760 
2761  const Station *st = Station::Get(station);
2762  if (!(st->facilities & FACIL_TRAIN)) {
2763  /* The destination station has no trainstation tiles. */
2764  this->IncrementRealOrderIndex();
2765  return 0;
2766  }
2767 
2768  return st->xy;
2769 }
2770 
2773 {
2774  Train *v = this;
2775  do {
2776  v->colourmap = PAL_NONE;
2777  v->UpdateViewport(true, false);
2778  } while ((v = v->Next()) != nullptr);
2779 
2780  /* need to update acceleration and cached values since the goods on the train changed. */
2781  this->CargoChanged();
2782  this->UpdateAcceleration();
2783 }
2784 
2793 {
2795  default: NOT_REACHED();
2796  case AM_ORIGINAL:
2797  return this->DoUpdateSpeed(this->acceleration * (this->GetAccelerationStatus() == AS_BRAKE ? -4 : 2), 0, this->GetCurrentMaxSpeed());
2798 
2799  case AM_REALISTIC:
2800  return this->DoUpdateSpeed(this->GetAcceleration(), this->GetAccelerationStatus() == AS_BRAKE ? 0 : 2, this->GetCurrentMaxSpeed());
2801  }
2802 }
2803 
2809 static void TrainEnterStation(Train *v, StationID station)
2810 {
2811  v->last_station_visited = station;
2812 
2813  /* check if a train ever visited this station before */
2814  Station *st = Station::Get(station);
2815  if (!(st->had_vehicle_of_type & HVOT_TRAIN)) {
2816  st->had_vehicle_of_type |= HVOT_TRAIN;
2817  SetDParam(0, st->index);
2819  STR_NEWS_FIRST_TRAIN_ARRIVAL,
2821  v->index,
2822  st->index
2823  );
2824  AI::NewEvent(v->owner, new ScriptEventStationFirstVehicle(st->index, v->index));
2825  Game::NewEvent(new ScriptEventStationFirstVehicle(st->index, v->index));
2826  }
2827 
2828  v->force_proceed = TFP_NONE;
2830 
2831  v->BeginLoading();
2832 
2834  TriggerStationAnimation(st, v->tile, SAT_TRAIN_ARRIVES);
2835 }
2836 
2837 /* Check if the vehicle is compatible with the specified tile */
2838 static inline bool CheckCompatibleRail(const Train *v, TileIndex tile)
2839 {
2840  return IsTileOwner(tile, v->owner) &&
2841  (!v->IsFrontEngine() || HasBit(v->compatible_railtypes, GetRailType(tile)));
2842 }
2843 
2846  byte small_turn;
2847  byte large_turn;
2848  byte z_up;
2849  byte z_down;
2850 };
2851 
2854  /* normal accel */
2855  {256 / 4, 256 / 2, 256 / 4, 2},
2856  {256 / 4, 256 / 2, 256 / 4, 2},
2857  {0, 256 / 2, 256 / 4, 2},
2858 };
2859 
2865 static inline void AffectSpeedByZChange(Train *v, int old_z)
2866 {
2867  if (old_z == v->z_pos || _settings_game.vehicle.train_acceleration_model != AM_ORIGINAL) return;
2868 
2869  const AccelerationSlowdownParams *asp = &_accel_slowdown[GetRailTypeInfo(v->railtype)->acceleration_type];
2870 
2871  if (old_z < v->z_pos) {
2872  v->cur_speed -= (v->cur_speed * asp->z_up >> 8);
2873  } else {
2874  uint16 spd = v->cur_speed + asp->z_down;
2875  if (spd <= v->gcache.cached_max_track_speed) v->cur_speed = spd;
2876  }
2877 }
2878 
2879 static bool TrainMovedChangeSignals(TileIndex tile, DiagDirection dir)
2880 {
2881  if (IsTileType(tile, MP_RAILWAY) &&
2884  Trackdir trackdir = FindFirstTrackdir(tracks);
2886  /* A PBS block with a non-PBS signal facing us? */
2887  if (!IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir)))) return true;
2888  }
2889  }
2890  return false;
2891 }
2892 
2895 {
2896  for (const Train *u = this; u != nullptr; u = u->Next()) {
2897  switch (u->track) {
2898  case TRACK_BIT_WORMHOLE:
2900  break;
2901  case TRACK_BIT_DEPOT:
2902  break;
2903  default:
2904  TryReserveRailTrack(u->tile, TrackBitsToTrack(u->track));
2905  break;
2906  }
2907  }
2908 }
2909 
2916 uint Train::Crash(bool flooded)
2917 {
2918  uint pass = 0;
2919  if (this->IsFrontEngine()) {
2920  pass += 2; // driver
2921 
2922  /* Remove the reserved path in front of the train if it is not stuck.
2923  * Also clear all reserved tracks the train is currently on. */
2924  if (!HasBit(this->flags, VRF_TRAIN_STUCK)) FreeTrainTrackReservation(this);
2925  for (const Train *v = this; v != nullptr; v = v->Next()) {
2927  if (IsTileType(v->tile, MP_TUNNELBRIDGE)) {
2928  /* ClearPathReservation will not free the wormhole exit
2929  * if the train has just entered the wormhole. */
2931  }
2932  }
2933 
2934  /* we may need to update crossing we were approaching,
2935  * but must be updated after the train has been marked crashed */
2936  TileIndex crossing = TrainApproachingCrossingTile(this);
2937  if (crossing != INVALID_TILE) UpdateLevelCrossing(crossing);
2938 
2939  /* Remove the loading indicators (if any) */
2941  }
2942 
2943  pass += this->GroundVehicleBase::Crash(flooded);
2944 
2945  this->crash_anim_pos = flooded ? 4000 : 1; // max 4440, disappear pretty fast when flooded
2946  return pass;
2947 }
2948 
2955 static uint TrainCrashed(Train *v)
2956 {
2957  uint num = 0;
2958 
2959  /* do not crash train twice */
2960  if (!(v->vehstatus & VS_CRASHED)) {
2961  num = v->Crash();
2962  AI::NewEvent(v->owner, new ScriptEventVehicleCrashed(v->index, v->tile, ScriptEventVehicleCrashed::CRASH_TRAIN));
2963  Game::NewEvent(new ScriptEventVehicleCrashed(v->index, v->tile, ScriptEventVehicleCrashed::CRASH_TRAIN));
2964  }
2965 
2966  /* Try to re-reserve track under already crashed train too.
2967  * Crash() clears the reservation! */
2969 
2970  return num;
2971 }
2972 
2976  uint num;
2977 };
2978 
2985 static Vehicle *FindTrainCollideEnum(Vehicle *v, void *data)
2986 {
2988 
2989  /* not a train or in depot */
2990  if (v->type != VEH_TRAIN || Train::From(v)->track == TRACK_BIT_DEPOT) return nullptr;
2991 
2992  /* do not crash into trains of another company. */
2993  if (v->owner != tcc->v->owner) return nullptr;
2994 
2995  /* get first vehicle now to make most usual checks faster */
2996  Train *coll = Train::From(v)->First();
2997 
2998  /* can't collide with own wagons */
2999  if (coll == tcc->v) return nullptr;
3000 
3001  int x_diff = v->x_pos - tcc->v->x_pos;
3002  int y_diff = v->y_pos - tcc->v->y_pos;
3003 
3004  /* Do fast calculation to check whether trains are not in close vicinity
3005  * and quickly reject trains distant enough for any collision.
3006  * Differences are shifted by 7, mapping range [-7 .. 8] into [0 .. 15]
3007  * Differences are then ORed and then we check for any higher bits */
3008  uint hash = (y_diff + 7) | (x_diff + 7);
3009  if (hash & ~15) return nullptr;
3010 
3011  /* Slower check using multiplication */
3012  int min_diff = (Train::From(v)->gcache.cached_veh_length + 1) / 2 + (tcc->v->gcache.cached_veh_length + 1) / 2 - 1;
3013  if (x_diff * x_diff + y_diff * y_diff > min_diff * min_diff) return nullptr;
3014 
3015  /* Happens when there is a train under bridge next to bridge head */
3016  if (abs(v->z_pos - tcc->v->z_pos) > 5) return nullptr;
3017 
3018  /* crash both trains */
3019  tcc->num += TrainCrashed(tcc->v);
3020  tcc->num += TrainCrashed(coll);
3021 
3022  return nullptr; // continue searching
3023 }
3024 
3033 {
3034  /* can't collide in depot */
3035  if (v->track == TRACK_BIT_DEPOT) return false;
3036 
3037  assert(v->track == TRACK_BIT_WORMHOLE || TileVirtXY(v->x_pos, v->y_pos) == v->tile);
3038 
3039  TrainCollideChecker tcc;
3040  tcc.v = v;
3041  tcc.num = 0;
3042 
3043  /* find colliding vehicles */
3044  if (v->track == TRACK_BIT_WORMHOLE) {
3047  } else {
3049  }
3050 
3051  /* any dead -> no crash */
3052  if (tcc.num == 0) return false;
3053 
3054  SetDParam(0, tcc.num);
3055  AddVehicleNewsItem(STR_NEWS_TRAIN_CRASH, NT_ACCIDENT, v->index);
3056 
3057  ModifyStationRatingAround(v->tile, v->owner, -160, 30);
3058  if (_settings_client.sound.disaster) SndPlayVehicleFx(SND_13_BIG_CRASH, v);
3059  return true;
3060 }
3061 
3062 static Vehicle *CheckTrainAtSignal(Vehicle *v, void *data)
3063 {
3064  if (v->type != VEH_TRAIN || (v->vehstatus & VS_CRASHED)) return nullptr;
3065 
3066  Train *t = Train::From(v);
3067  DiagDirection exitdir = *(DiagDirection *)data;
3068 
3069  /* not front engine of a train, inside wormhole or depot, crashed */
3070  if (!t->IsFrontEngine() || !(t->track & TRACK_BIT_MASK)) return nullptr;
3071 
3072  if (t->cur_speed > 5 || VehicleExitDir(t->direction, t->track) != exitdir) return nullptr;
3073 
3074  return t;
3075 }
3076 
3084 bool TrainController(Train *v, Vehicle *nomove, bool reverse)
3085 {
3086  Train *first = v->First();
3087  Train *prev;
3088  bool direction_changed = false; // has direction of any part changed?
3089 
3090  /* For every vehicle after and including the given vehicle */
3091  for (prev = v->Previous(); v != nomove; prev = v, v = v->Next()) {
3092  DiagDirection enterdir = DIAGDIR_BEGIN;
3093  bool update_signals_crossing = false; // will we update signals or crossing state?
3094 
3096  if (v->track != TRACK_BIT_WORMHOLE) {
3097  /* Not inside tunnel */
3098  if (gp.old_tile == gp.new_tile) {
3099  /* Staying in the old tile */
3100  if (v->track == TRACK_BIT_DEPOT) {
3101  /* Inside depot */
3102  gp.x = v->x_pos;
3103  gp.y = v->y_pos;
3104  } else {
3105  /* Not inside depot */
3106 
3107  /* Reverse when we are at the end of the track already, do not move to the new position */
3108  if (v->IsFrontEngine() && !TrainCheckIfLineEnds(v, reverse)) return false;
3109 
3110  uint32 r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y);
3111  if (HasBit(r, VETS_CANNOT_ENTER)) {
3112  goto invalid_rail;
3113  }
3114  if (HasBit(r, VETS_ENTERED_STATION)) {
3115  /* The new position is the end of the platform */
3117  }
3118  }
3119  } else {
3120  /* A new tile is about to be entered. */
3121 
3122  /* Determine what direction we're entering the new tile from */
3123  enterdir = DiagdirBetweenTiles(gp.old_tile, gp.new_tile);
3124  assert(IsValidDiagDirection(enterdir));
3125 
3126  /* Get the status of the tracks in the new tile and mask
3127  * away the bits that aren't reachable. */
3128  TrackStatus ts = GetTileTrackStatus(gp.new_tile, TRANSPORT_RAIL, 0, ReverseDiagDir(enterdir));
3129  TrackdirBits reachable_trackdirs = DiagdirReachesTrackdirs(enterdir);
3130 
3131  TrackdirBits trackdirbits = TrackStatusToTrackdirBits(ts) & reachable_trackdirs;
3132  TrackBits red_signals = TrackdirBitsToTrackBits(TrackStatusToRedSignals(ts) & reachable_trackdirs);
3133 
3134  TrackBits bits = TrackdirBitsToTrackBits(trackdirbits);
3135  if (Rail90DegTurnDisallowed(GetTileRailType(gp.old_tile), GetTileRailType(gp.new_tile)) && prev == nullptr) {
3136  /* We allow wagons to make 90 deg turns, because forbid_90_deg
3137  * can be switched on halfway a turn */
3138  bits &= ~TrackCrossesTracks(FindFirstTrack(v->track));
3139  }
3140 
3141  if (bits == TRACK_BIT_NONE) goto invalid_rail;
3142 
3143  /* Check if the new tile constrains tracks that are compatible
3144  * with the current train, if not, bail out. */
3145  if (!CheckCompatibleRail(v, gp.new_tile)) goto invalid_rail;
3146 
3147  TrackBits chosen_track;
3148  if (prev == nullptr) {
3149  /* Currently the locomotive is active. Determine which one of the
3150  * available tracks to choose */
3151  chosen_track = TrackToTrackBits(ChooseTrainTrack(v, gp.new_tile, enterdir, bits, false, nullptr, true));
3152  assert(chosen_track & (bits | GetReservedTrackbits(gp.new_tile)));
3153 
3154  if (v->force_proceed != TFP_NONE && IsPlainRailTile(gp.new_tile) && HasSignals(gp.new_tile)) {
3155  /* For each signal we find decrease the counter by one.
3156  * We start at two, so the first signal we pass decreases
3157  * this to one, then if we reach the next signal it is
3158  * decreased to zero and we won't pass that new signal. */
3159  Trackdir dir = FindFirstTrackdir(trackdirbits);
3160  if (HasSignalOnTrackdir(gp.new_tile, dir) ||
3162  GetSignalType(gp.new_tile, TrackdirToTrack(dir)) != SIGTYPE_PBS)) {
3163  /* However, we do not want to be stopped by PBS signals
3164  * entered via the back. */
3165  v->force_proceed = (v->force_proceed == TFP_SIGNAL) ? TFP_STUCK : TFP_NONE;
3166  SetWindowDirty(WC_VEHICLE_VIEW, v->index);
3167  }
3168  }
3169 
3170  /* Check if it's a red signal and that force proceed is not clicked. */
3171  if ((red_signals & chosen_track) && v->force_proceed == TFP_NONE) {
3172  /* In front of a red signal */
3173  Trackdir i = FindFirstTrackdir(trackdirbits);
3174 
3175  /* Don't handle stuck trains here. */
3176  if (HasBit(v->flags, VRF_TRAIN_STUCK)) return false;
3177 
3179  v->cur_speed = 0;
3180  v->subspeed = 0;
3181  v->progress = 255; // make sure that every bit of acceleration will hit the signal again, so speed stays 0.
3182  if (!_settings_game.pf.reverse_at_signals || ++v->wait_counter < _settings_game.pf.wait_oneway_signal * DAY_TICKS * 2) return false;
3183  } else if (HasSignalOnTrackdir(gp.new_tile, i)) {
3184  v->cur_speed = 0;
3185  v->subspeed = 0;
3186  v->progress = 255; // make sure that every bit of acceleration will hit the signal again, so speed stays 0.
3188  DiagDirection exitdir = TrackdirToExitdir(i);
3189  TileIndex o_tile = TileAddByDiagDir(gp.new_tile, exitdir);
3190 
3191  exitdir = ReverseDiagDir(exitdir);
3192 
3193  /* check if a train is waiting on the other side */
3194  if (!HasVehicleOnPos(o_tile, &exitdir, &CheckTrainAtSignal)) return false;
3195  }
3196  }
3197 
3198  /* If we would reverse but are currently in a PBS block and
3199  * reversing of stuck trains is disabled, don't reverse.
3200  * This does not apply if the reason for reversing is a one-way
3201  * signal blocking us, because a train would then be stuck forever. */
3203  UpdateSignalsOnSegment(v->tile, enterdir, v->owner) == SIGSEG_PBS) {
3204  v->wait_counter = 0;
3205  return false;
3206  }
3207  goto reverse_train_direction;
3208  } else {
3209  TryReserveRailTrack(gp.new_tile, TrackBitsToTrack(chosen_track), false);
3210  }
3211  } else {
3212  /* The wagon is active, simply follow the prev vehicle. */
3213  if (prev->tile == gp.new_tile) {
3214  /* Choose the same track as prev */
3215  if (prev->track == TRACK_BIT_WORMHOLE) {
3216  /* Vehicles entering tunnels enter the wormhole earlier than for bridges.
3217  * However, just choose the track into the wormhole. */
3218  assert(IsTunnel(prev->tile));
3219  chosen_track = bits;
3220  } else {
3221  chosen_track = prev->track;
3222  }
3223  } else {
3224  /* Choose the track that leads to the tile where prev is.
3225  * This case is active if 'prev' is already on the second next tile, when 'v' just enters the next tile.
3226  * I.e. when the tile between them has only space for a single vehicle like
3227  * 1) horizontal/vertical track tiles and
3228  * 2) some orientations of tunnel entries, where the vehicle is already inside the wormhole at 8/16 from the tile edge.
3229  * Is also the train just reversing, the wagon inside the tunnel is 'on' the tile of the opposite tunnel entry.
3230  */
3231  static const TrackBits _connecting_track[DIAGDIR_END][DIAGDIR_END] = {
3236  };
3237  DiagDirection exitdir = DiagdirBetweenTiles(gp.new_tile, prev->tile);
3238  assert(IsValidDiagDirection(exitdir));
3239  chosen_track = _connecting_track[enterdir][exitdir];
3240  }
3241  chosen_track &= bits;
3242  }
3243 
3244  /* Make sure chosen track is a valid track */
3245  assert(
3246  chosen_track == TRACK_BIT_X || chosen_track == TRACK_BIT_Y ||
3247  chosen_track == TRACK_BIT_UPPER || chosen_track == TRACK_BIT_LOWER ||
3248  chosen_track == TRACK_BIT_LEFT || chosen_track == TRACK_BIT_RIGHT);
3249 
3250  /* Update XY to reflect the entrance to the new tile, and select the direction to use */
3251  const byte *b = _initial_tile_subcoord[FIND_FIRST_BIT(chosen_track)][enterdir];
3252  gp.x = (gp.x & ~0xF) | b[0];
3253  gp.y = (gp.y & ~0xF) | b[1];
3254  Direction chosen_dir = (Direction)b[2];
3255 
3256  /* Call the landscape function and tell it that the vehicle entered the tile */
3257  uint32 r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y);
3258  if (HasBit(r, VETS_CANNOT_ENTER)) {
3259  goto invalid_rail;
3260  }
3261 
3262  if (!HasBit(r, VETS_ENTERED_WORMHOLE)) {
3263  Track track = FindFirstTrack(chosen_track);
3264  Trackdir tdir = TrackDirectionToTrackdir(track, chosen_dir);
3265  if (v->IsFrontEngine() && HasPbsSignalOnTrackdir(gp.new_tile, tdir)) {
3268  }
3269 
3270  /* Clear any track reservation when the last vehicle leaves the tile */
3271  if (v->Next() == nullptr) ClearPathReservation(v, v->tile, v->GetVehicleTrackdir());
3272 
3273  v->tile = gp.new_tile;
3274 
3276  v->First()->ConsistChanged(CCF_TRACK);
3277  }
3278 
3279  v->track = chosen_track;
3280  assert(v->track);
3281  }
3282 
3283  /* We need to update signal status, but after the vehicle position hash
3284  * has been updated by UpdateInclination() */
3285  update_signals_crossing = true;
3286 
3287  if (chosen_dir != v->direction) {
3288  if (prev == nullptr && _settings_game.vehicle.train_acceleration_model == AM_ORIGINAL) {
3289  const AccelerationSlowdownParams *asp = &_accel_slowdown[GetRailTypeInfo(v->railtype)->acceleration_type];
3290  DirDiff diff = DirDifference(v->direction, chosen_dir);
3291  v->cur_speed -= (diff == DIRDIFF_45RIGHT || diff == DIRDIFF_45LEFT ? asp->small_turn : asp->large_turn) * v->cur_speed >> 8;
3292  }
3293  direction_changed = true;
3294  v->direction = chosen_dir;
3295  }
3296 
3297  if (v->IsFrontEngine()) {
3298  v->wait_counter = 0;
3299 
3300  /* If we are approaching a crossing that is reserved, play the sound now. */
3302  if (crossing != INVALID_TILE && HasCrossingReservation(crossing) && _settings_client.sound.ambient) SndPlayTileFx(SND_0E_LEVEL_CROSSING, crossing);
3303 
3304  /* Always try to extend the reservation when entering a tile. */
3305  CheckNextTrainTile(v);
3306  }
3307 
3308  if (HasBit(r, VETS_ENTERED_STATION)) {
3309  /* The new position is the location where we want to stop */
3311  }
3312  }
3313  } else {
3315  /* Perform look-ahead on tunnel exit. */
3316  if (v->IsFrontEngine()) {
3318  CheckNextTrainTile(v);
3319  }
3320  /* Prevent v->UpdateInclination() being called with wrong parameters.
3321  * This could happen if the train was reversed inside the tunnel/bridge. */
3322  if (gp.old_tile == gp.new_tile) {
3324  }
3325  } else {
3326  v->x_pos = gp.x;
3327  v->y_pos = gp.y;
3328  v->UpdatePosition();
3329  if ((v->vehstatus & VS_HIDDEN) == 0) v->Vehicle::UpdateViewport(true);
3330  continue;
3331  }
3332  }
3333 
3334  /* update image of train, as well as delta XY */
3335  v->UpdateDeltaXY();
3336 
3337  v->x_pos = gp.x;
3338  v->y_pos = gp.y;
3339  v->UpdatePosition();
3340 
3341  /* update the Z position of the vehicle */
3342  int old_z = v->UpdateInclination(gp.new_tile != gp.old_tile, false);
3343 
3344  if (prev == nullptr) {
3345  /* This is the first vehicle in the train */
3346  AffectSpeedByZChange(v, old_z);
3347  }
3348 
3349  if (update_signals_crossing) {
3350  if (v->IsFrontEngine()) {
3351  if (TrainMovedChangeSignals(gp.new_tile, enterdir)) {
3352  /* We are entering a block with PBS signals right now, but
3353  * not through a PBS signal. This means we don't have a
3354  * reservation right now. As a conventional signal will only
3355  * ever be green if no other train is in the block, getting
3356  * a path should always be possible. If the player built
3357  * such a strange network that it is not possible, the train
3358  * will be marked as stuck and the player has to deal with
3359  * the problem. */
3360  if ((!HasReservedTracks(gp.new_tile, v->track) &&
3361  !TryReserveRailTrack(gp.new_tile, FindFirstTrack(v->track))) ||
3362  !TryPathReserve(v)) {
3363  MarkTrainAsStuck(v);
3364  }
3365  }
3366  }
3367 
3368  /* Signals can only change when the first
3369  * (above) or the last vehicle moves. */
3370  if (v->Next() == nullptr) {
3371  TrainMovedChangeSignals(gp.old_tile, ReverseDiagDir(enterdir));
3373  }
3374  }
3375 
3376  /* Do not check on every tick to save some computing time. */
3377  if (v->IsFrontEngine() && v->tick_counter % _settings_game.pf.path_backoff_interval == 0) CheckNextTrainTile(v);
3378  }
3379 
3380  if (direction_changed) first->tcache.cached_max_curve_speed = first->GetCurveSpeedLimit();
3381 
3382  return true;
3383 
3384 invalid_rail:
3385  /* We've reached end of line?? */
3386  if (prev != nullptr) error("Disconnecting train");
3387 
3388 reverse_train_direction:
3389  if (reverse) {
3390  v->wait_counter = 0;
3391  v->cur_speed = 0;
3392  v->subspeed = 0;
3394  }
3395 
3396  return false;
3397 }
3398 
3406 {
3407  TrackBits *trackbits = (TrackBits *)data;
3408 
3409  if (v->type == VEH_TRAIN && (v->vehstatus & VS_CRASHED) != 0) {
3410  TrackBits train_tbits = Train::From(v)->track;
3411  if (train_tbits == TRACK_BIT_WORMHOLE) {
3412  /* Vehicle is inside a wormhole, v->track contains no useful value then. */
3414  } else if (train_tbits != TRACK_BIT_DEPOT) {
3415  *trackbits |= train_tbits;
3416  }
3417  }
3418 
3419  return nullptr;
3420 }
3421 
3429 static void DeleteLastWagon(Train *v)
3430 {
3431  Train *first = v->First();
3432 
3433  /* Go to the last wagon and delete the link pointing there
3434  * *u is then the one-before-last wagon, and *v the last
3435  * one which will physically be removed */
3436  Train *u = v;
3437  for (; v->Next() != nullptr; v = v->Next()) u = v;
3438  u->SetNext(nullptr);
3439 
3440  if (first != v) {
3441  /* Recalculate cached train properties */
3442  first->ConsistChanged(CCF_ARRANGE);
3443  /* Update the depot window if the first vehicle is in depot -
3444  * if v == first, then it is updated in PreDestructor() */
3445  if (first->track == TRACK_BIT_DEPOT) {
3447  }
3448  v->last_station_visited = first->last_station_visited; // for PreDestructor
3449  }
3450 
3451  /* 'v' shouldn't be accessed after it has been deleted */
3452  TrackBits trackbits = v->track;
3453  TileIndex tile = v->tile;
3454  Owner owner = v->owner;
3455 
3456  delete v;
3457  v = nullptr; // make sure nobody will try to read 'v' anymore
3458 
3459  if (trackbits == TRACK_BIT_WORMHOLE) {
3460  /* Vehicle is inside a wormhole, v->track contains no useful value then. */
3462  }
3463 
3464  Track track = TrackBitsToTrack(trackbits);
3465  if (HasReservedTracks(tile, trackbits)) {
3466  UnreserveRailTrack(tile, track);
3467 
3468  /* If there are still crashed vehicles on the tile, give the track reservation to them */
3469  TrackBits remaining_trackbits = TRACK_BIT_NONE;
3470  FindVehicleOnPos(tile, &remaining_trackbits, CollectTrackbitsFromCrashedVehiclesEnum);
3471 
3472  /* It is important that these two are the first in the loop, as reservation cannot deal with every trackbit combination */
3473  assert(TRACK_BEGIN == TRACK_X && TRACK_Y == TRACK_BEGIN + 1);
3474  Track t;
3475  FOR_EACH_SET_TRACK(t, remaining_trackbits) TryReserveRailTrack(tile, t);
3476  }
3477 
3478  /* check if the wagon was on a road/rail-crossing */
3479  if (IsLevelCrossingTile(tile)) UpdateLevelCrossing(tile);
3480 
3481  /* Update signals */
3482  if (IsTileType(tile, MP_TUNNELBRIDGE) || IsRailDepotTile(tile)) {
3484  } else {
3485  SetSignalsOnBothDir(tile, track, owner);
3486  }
3487 }
3488 
3494 {
3495  static const DirDiff delta[] = {
3497  };
3498 
3499  do {
3500  /* We don't need to twist around vehicles if they're not visible */
3501  if (!(v->vehstatus & VS_HIDDEN)) {
3502  v->direction = ChangeDir(v->direction, delta[GB(Random(), 0, 2)]);
3503  /* Refrain from updating the z position of the vehicle when on
3504  * a bridge, because UpdateInclination() will put the vehicle under
3505  * the bridge in that case */
3506  if (v->track != TRACK_BIT_WORMHOLE) {
3507  v->UpdatePosition();
3508  v->UpdateInclination(false, true);
3509  } else {
3510  v->UpdateViewport(false, true);
3511  }
3512  }
3513  } while ((v = v->Next()) != nullptr);
3514 }
3515 
3521 static bool HandleCrashedTrain(Train *v)
3522 {
3523  int state = ++v->crash_anim_pos;
3524 
3525  if (state == 4 && !(v->vehstatus & VS_HIDDEN)) {
3527  }
3528 
3529  uint32 r;
3530  if (state <= 200 && Chance16R(1, 7, r)) {
3531  int index = (r * 10 >> 16);
3532 
3533  Vehicle *u = v;
3534  do {
3535  if (--index < 0) {
3536  r = Random();
3537 
3539  GB(r, 8, 3) + 2,
3540  GB(r, 16, 3) + 2,
3541  GB(r, 0, 3) + 5,
3543  break;
3544  }
3545  } while ((u = u->Next()) != nullptr);
3546  }
3547 
3548  if (state <= 240 && !(v->tick_counter & 3)) ChangeTrainDirRandomly(v);
3549 
3550  if (state >= 4440 && !(v->tick_counter & 0x1F)) {
3551  bool ret = v->Next() != nullptr;
3552  DeleteLastWagon(v);
3553  return ret;
3554  }
3555 
3556  return true;
3557 }
3558 
3560 static const uint16 _breakdown_speeds[16] = {
3561  225, 210, 195, 180, 165, 150, 135, 120, 105, 90, 75, 60, 45, 30, 15, 15
3562 };
3563 
3564 
3573 static bool TrainApproachingLineEnd(Train *v, bool signal, bool reverse)
3574 {
3575  /* Calc position within the current tile */
3576  uint x = v->x_pos & 0xF;
3577  uint y = v->y_pos & 0xF;
3578 
3579  /* for diagonal directions, 'x' will be 0..15 -
3580  * for other directions, it will be 1, 3, 5, ..., 15 */
3581  switch (v->direction) {
3582  case DIR_N : x = ~x + ~y + 25; break;
3583  case DIR_NW: x = y; FALLTHROUGH;
3584  case DIR_NE: x = ~x + 16; break;
3585  case DIR_E : x = ~x + y + 9; break;
3586  case DIR_SE: x = y; break;
3587  case DIR_S : x = x + y - 7; break;
3588  case DIR_W : x = ~y + x + 9; break;
3589  default: break;
3590  }
3591 
3592  /* Do not reverse when approaching red signal. Make sure the vehicle's front
3593  * does not cross the tile boundary when we do reverse, but as the vehicle's
3594  * location is based on their center, use half a vehicle's length as offset.
3595  * Multiply the half-length by two for straight directions to compensate that
3596  * we only get odd x offsets there. */
3597  if (!signal && x + (v->gcache.cached_veh_length + 1) / 2 * (IsDiagonalDirection(v->direction) ? 1 : 2) >= TILE_SIZE) {
3598  /* we are too near the tile end, reverse now */
3599  v->cur_speed = 0;
3600  if (reverse) ReverseTrainDirection(v);
3601  return false;
3602  }
3603 
3604  /* slow down */
3606  uint16 break_speed = _breakdown_speeds[x & 0xF];
3607  if (break_speed < v->cur_speed) v->cur_speed = break_speed;
3608 
3609  return true;
3610 }
3611 
3612 
3618 static bool TrainCanLeaveTile(const Train *v)
3619 {
3620  /* Exit if inside a tunnel/bridge or a depot */
3621  if (v->track == TRACK_BIT_WORMHOLE || v->track == TRACK_BIT_DEPOT) return false;
3622 
3623  TileIndex tile = v->tile;
3624 
3625  /* entering a tunnel/bridge? */
3626  if (IsTileType(tile, MP_TUNNELBRIDGE)) {
3628  if (DiagDirToDir(dir) == v->direction) return false;
3629  }
3630 
3631  /* entering a depot? */
3632  if (IsRailDepotTile(tile)) {
3634  if (DiagDirToDir(dir) == v->direction) return false;
3635  }
3636 
3637  return true;
3638 }
3639 
3640 
3649 {
3650  assert(v->IsFrontEngine());
3651  assert(!(v->vehstatus & VS_CRASHED));
3652 
3653  if (!TrainCanLeaveTile(v)) return INVALID_TILE;
3654 
3655  DiagDirection dir = VehicleExitDir(v->direction, v->track);
3656  TileIndex tile = v->tile + TileOffsByDiagDir(dir);
3657 
3658  /* not a crossing || wrong axis || unusable rail (wrong type or owner) */
3659  if (!IsLevelCrossingTile(tile) || DiagDirToAxis(dir) == GetCrossingRoadAxis(tile) ||
3660  !CheckCompatibleRail(v, tile)) {
3661  return INVALID_TILE;
3662  }
3663 
3664  return tile;
3665 }
3666 
3667 
3675 static bool TrainCheckIfLineEnds(Train *v, bool reverse)
3676 {
3677  /* First, handle broken down train */
3678 
3679  int t = v->breakdown_ctr;
3680  if (t > 1) {
3682 
3683  uint16 break_speed = _breakdown_speeds[GB(~t, 4, 4)];
3684  if (break_speed < v->cur_speed) v->cur_speed = break_speed;
3685  } else {
3686  v->vehstatus &= ~VS_TRAIN_SLOWING;
3687  }
3688 
3689  if (!TrainCanLeaveTile(v)) return true;
3690 
3691  /* Determine the non-diagonal direction in which we will exit this tile */
3692  DiagDirection dir = VehicleExitDir(v->direction, v->track);
3693  /* Calculate next tile */
3694  TileIndex tile = v->tile + TileOffsByDiagDir(dir);
3695 
3696  /* Determine the track status on the next tile */
3697  TrackStatus ts = GetTileTrackStatus(tile, TRANSPORT_RAIL, 0, ReverseDiagDir(dir));
3698  TrackdirBits reachable_trackdirs = DiagdirReachesTrackdirs(dir);
3699 
3700  TrackdirBits trackdirbits = TrackStatusToTrackdirBits(ts) & reachable_trackdirs;
3701  TrackdirBits red_signals = TrackStatusToRedSignals(ts) & reachable_trackdirs;
3702 
3703  /* We are sure the train is not entering a depot, it is detected above */
3704 
3705  /* mask unreachable track bits if we are forbidden to do 90deg turns */
3706  TrackBits bits = TrackdirBitsToTrackBits(trackdirbits);
3708  bits &= ~TrackCrossesTracks(FindFirstTrack(v->track));
3709  }
3710 
3711  /* no suitable trackbits at all || unusable rail (wrong type or owner) */
3712  if (bits == TRACK_BIT_NONE || !CheckCompatibleRail(v, tile)) {
3713  return TrainApproachingLineEnd(v, false, reverse);
3714  }
3715 
3716  /* approaching red signal */
3717  if ((trackdirbits & red_signals) != 0) return TrainApproachingLineEnd(v, true, reverse);
3718 
3719  /* approaching a rail/road crossing? then make it red */
3721 
3722  return true;
3723 }
3724 
3725 
3726 static bool TrainLocoHandler(Train *v, bool mode)
3727 {
3728  /* train has crashed? */
3729  if (v->vehstatus & VS_CRASHED) {
3730  return mode ? true : HandleCrashedTrain(v); // 'this' can be deleted here
3731  }
3732 
3733  if (v->force_proceed != TFP_NONE) {
3734  ClrBit(v->flags, VRF_TRAIN_STUCK);
3736  }
3737 
3738  /* train is broken down? */
3739  if (v->HandleBreakdown()) return true;
3740 
3741  if (HasBit(v->flags, VRF_REVERSING) && v->cur_speed == 0) {
3743  }
3744 
3745  /* exit if train is stopped */
3746  if ((v->vehstatus & VS_STOPPED) && v->cur_speed == 0) return true;
3747 
3748  bool valid_order = !v->current_order.IsType(OT_NOTHING) && v->current_order.GetType() != OT_CONDITIONAL;
3749  if (ProcessOrders(v) && CheckReverseTrain(v)) {
3750  v->wait_counter = 0;
3751  v->cur_speed = 0;
3752  v->subspeed = 0;
3753  ClrBit(v->flags, VRF_LEAVING_STATION);
3755  return true;
3756  } else if (HasBit(v->flags, VRF_LEAVING_STATION)) {
3757  /* Try to reserve a path when leaving the station as we
3758  * might not be marked as wanting a reservation, e.g.
3759  * when an overlength train gets turned around in a station. */
3760  DiagDirection dir = VehicleExitDir(v->direction, v->track);
3762 
3764  TryPathReserve(v, true, true);
3765  }
3766  ClrBit(v->flags, VRF_LEAVING_STATION);
3767  }
3768 
3769  v->HandleLoading(mode);
3770 
3771  if (v->current_order.IsType(OT_LOADING)) return true;
3772 
3773  if (CheckTrainStayInDepot(v)) return true;
3774 
3775  if (!mode) v->ShowVisualEffect();
3776 
3777  /* We had no order but have an order now, do look ahead. */
3778  if (!valid_order && !v->current_order.IsType(OT_NOTHING)) {
3779  CheckNextTrainTile(v);
3780  }
3781 
3782  /* Handle stuck trains. */
3783  if (!mode && HasBit(v->flags, VRF_TRAIN_STUCK)) {
3784  ++v->wait_counter;
3785 
3786  /* Should we try reversing this tick if still stuck? */
3788 
3789  if (!turn_around && v->wait_counter % _settings_game.pf.path_backoff_interval != 0 && v->force_proceed == TFP_NONE) return true;
3790  if (!TryPathReserve(v)) {
3791  /* Still stuck. */
3792  if (turn_around) ReverseTrainDirection(v);
3793 
3795  /* Show message to player. */
3797  SetDParam(0, v->index);
3798  AddVehicleAdviceNewsItem(STR_NEWS_TRAIN_IS_STUCK, v->index);
3799  }
3800  v->wait_counter = 0;
3801  }
3802  /* Exit if force proceed not pressed, else reset stuck flag anyway. */
3803  if (v->force_proceed == TFP_NONE) return true;
3804  ClrBit(v->flags, VRF_TRAIN_STUCK);
3805  v->wait_counter = 0;
3807  }
3808  }
3809 
3810  if (v->current_order.IsType(OT_LEAVESTATION)) {
3811  v->current_order.Free();
3813  return true;
3814  }
3815 
3816  int j = v->UpdateSpeed();
3817 
3818  /* we need to invalidate the widget if we are stopping from 'Stopping 0 km/h' to 'Stopped' */
3819  if (v->cur_speed == 0 && (v->vehstatus & VS_STOPPED)) {
3820  /* If we manually stopped, we're not force-proceeding anymore. */
3821  v->force_proceed = TFP_NONE;
3823  }
3824 
3825  int adv_spd = v->GetAdvanceDistance();
3826  if (j < adv_spd) {
3827  /* if the vehicle has speed 0, update the last_speed field. */
3828  if (v->cur_speed == 0) v->SetLastSpeed();
3829  } else {
3831  /* Loop until the train has finished moving. */
3832  for (;;) {
3833  j -= adv_spd;
3834  TrainController(v, nullptr);
3835  /* Don't continue to move if the train crashed. */
3836  if (CheckTrainCollision(v)) break;
3837  /* Determine distance to next map position */
3838  adv_spd = v->GetAdvanceDistance();
3839 
3840  /* No more moving this tick */
3841  if (j < adv_spd || v->cur_speed == 0) break;
3842 
3843  OrderType order_type = v->current_order.GetType();
3844  /* Do not skip waypoints (incl. 'via' stations) when passing through at full speed. */
3845  if ((order_type == OT_GOTO_WAYPOINT || order_type == OT_GOTO_STATION) &&
3847  IsTileType(v->tile, MP_STATION) &&
3849  ProcessOrders(v);
3850  }
3851  }
3852  v->SetLastSpeed();
3853  }
3854 
3855  for (Train *u = v; u != nullptr; u = u->Next()) {
3856  if ((u->vehstatus & VS_HIDDEN) != 0) continue;
3857 
3858  u->UpdateViewport(false, false);
3859  }
3860 
3861  if (v->progress == 0) v->progress = j; // Save unused spd for next time, if TrainController didn't set progress
3862 
3863  return true;
3864 }
3865 
3871 {
3872  Money cost = 0;
3873  const Train *v = this;
3874 
3875  do {
3876  const Engine *e = v->GetEngine();
3877  if (e->u.rail.running_cost_class == INVALID_PRICE) continue;
3878 
3879  uint cost_factor = GetVehicleProperty(v, PROP_TRAIN_RUNNING_COST_FACTOR, e->u.rail.running_cost);
3880  if (cost_factor == 0) continue;
3881 
3882  /* Halve running cost for multiheaded parts */
3883  if (v->IsMultiheaded()) cost_factor /= 2;
3884 
3885  cost += GetPrice(e->u.rail.running_cost_class, cost_factor, e->GetGRF());
3886  } while ((v = v->GetNextVehicle()) != nullptr);
3887 
3888  return cost;
3889 }
3890 
3896 {
3898 
3899  this->tick_counter++;
3900 
3901  if (this->IsFrontEngine()) {
3902  if (!(this->vehstatus & VS_STOPPED) || this->cur_speed > 0) this->running_ticks++;
3903 
3904  this->current_order_time++;
3905 
3906  if (!TrainLocoHandler(this, false)) return false;
3907 
3908  return TrainLocoHandler(this, true);
3909  } else if (this->IsFreeWagon() && (this->vehstatus & VS_CRASHED)) {
3910  /* Delete flooded standalone wagon chain */
3911  if (++this->crash_anim_pos >= 4400) {
3912  delete this;
3913  return false;
3914  }
3915  }
3916 
3917  return true;
3918 }
3919 
3925 {
3926  if (Company::Get(v->owner)->settings.vehicle.servint_trains == 0 || !v->NeedsAutomaticServicing()) return;
3927  if (v->IsChainInDepot()) {
3929  return;
3930  }
3931 
3932  uint max_penalty;
3934  case VPF_NPF: max_penalty = _settings_game.pf.npf.maximum_go_to_depot_penalty; break;
3935  case VPF_YAPF: max_penalty = _settings_game.pf.yapf.maximum_go_to_depot_penalty; break;
3936  default: NOT_REACHED();
3937  }
3938 
3939  FindDepotData tfdd = FindClosestTrainDepot(v, max_penalty);
3940  /* Only go to the depot if it is not too far out of our way. */
3941  if (tfdd.best_length == UINT_MAX || tfdd.best_length > max_penalty) {
3942  if (v->current_order.IsType(OT_GOTO_DEPOT)) {
3943  /* If we were already heading for a depot but it has
3944  * suddenly moved farther away, we continue our normal
3945  * schedule? */
3946  v->current_order.MakeDummy();
3948  }
3949  return;
3950  }
3951 
3952  DepotID depot = GetDepotIndex(tfdd.tile);
3953 
3954  if (v->current_order.IsType(OT_GOTO_DEPOT) &&
3955  v->current_order.GetDestination() != depot &&
3956  !Chance16(3, 16)) {
3957  return;
3958  }
3959 
3962  v->dest_tile = tfdd.tile;
3964 }
3965 
3968 {
3969  AgeVehicle(this);
3970 
3971  if ((++this->day_counter & 7) == 0) DecreaseVehicleValue(this);
3972 
3973  if (this->IsFrontEngine()) {
3974  CheckVehicleBreakdown(this);
3975 
3977 
3978  CheckOrders(this);
3979 
3980  /* update destination */
3981  if (this->current_order.IsType(OT_GOTO_STATION)) {
3982  TileIndex tile = Station::Get(this->current_order.GetDestination())->train_station.tile;
3983  if (tile != INVALID_TILE) this->dest_tile = tile;
3984  }
3985 
3986  if (this->running_ticks != 0) {
3987  /* running costs */
3989 
3990  this->profit_this_year -= cost.GetCost();
3991  this->running_ticks = 0;
3992 
3993  SubtractMoneyFromCompanyFract(this->owner, cost);
3994 
3997  }
3998  }
3999 }
4000 
4006 {
4007  if (this->vehstatus & VS_CRASHED) return INVALID_TRACKDIR;
4008 
4009  if (this->track == TRACK_BIT_DEPOT) {
4010  /* We'll assume the train is facing outwards */
4011  return DiagDirToDiagTrackdir(GetRailDepotDirection(this->tile)); // Train in depot
4012  }
4013 
4014  if (this->track == TRACK_BIT_WORMHOLE) {
4015  /* train in tunnel or on bridge, so just use his direction and assume a diagonal track */
4017  }
4018 
4019  return TrackDirectionToTrackdir(FindFirstTrack(this->track), this->direction);
4020 }
T * GetLastEnginePart()
Get the last part of an articulated engine.
bool TryPathReserve(Train *v, bool mark_as_stuck, bool first_tile_okay)
Try to reserve a path to a safe position.
Definition: train_cmd.cpp:2667
Functions related to OTTD&#39;s strings.
void TriggerStationRandomisation(Station *st, TileIndex tile, StationRandomTrigger trigger, CargoID cargo_type)
Trigger station randomisation.
void ReverseTrainSwapVeh(Train *v, int l, int r)
Swap vehicles l and r in consist v, and reverse their direction.
Definition: train_cmd.cpp:1575
Owner
Enum for all companies/owners.
Definition: company_type.h:18
static Vehicle * TrainApproachingCrossingEnum(Vehicle *v, void *data)
Checks if a train is approaching a rail-road crossing.
Definition: train_cmd.cpp:1629
Normal operation.
Definition: train.h:38
bool HasVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
Checks whether a vehicle is on a specific location.
Definition: vehicle.cpp:511
VehicleSettings vehicle
options for vehicles
This vehicle is in the exclusive preview stage, either being used or being offered to a company...
Definition: engine_type.h:169
static bool HasPowerOnRail(RailType enginetype, RailType tiletype)
Checks if an engine of the given RailType got power on a tile with a given RailType.
Definition: rail.h:332
Functions/types related to NewGRF debugging.
static void Swap(T &a, T &b)
Type safe swap operation.
Definition: math_func.hpp:275
uint16 reliability
Current reliability of the engine.
Definition: engine_base.h:25
Date max_age
Maximum age.
Definition: vehicle_base.h:257
uint32 PaletteID
The number of the palette.
Definition: gfx_type.h:18
StationFacility facilities
The facilities that this station has.
static bool HasSignalOnTrackdir(TileIndex tile, Trackdir trackdir)
Checks for the presence of signals along the given trackdir on the given rail tile.
Definition: rail_map.h:426
Vehicle is stopped by the player.
Definition: vehicle_base.h:31
First vehicle arrived for competitor.
Definition: news_type.h:23
bool cached_tilt
train can tilt; feature provides a bonus in curves
Definition: train.h:74
VehicleCargoList cargo
The cargo this vehicle is carrying.
Definition: vehicle_base.h:307
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition: settings.cpp:79
static void NewEvent(class ScriptEvent *event)
Queue a new event for a Game Script.
Definition: game_core.cpp:141
Definition of stuff that is very close to a company, like the company struct itself.
static PBSTileInfo ExtendTrainReservation(const Train *v, TrackBits *new_tracks, DiagDirection *enterdir)
Extend a train path as far as possible.
Definition: train_cmd.cpp:2321
static bool IsDiagonalDirection(Direction dir)
Checks if a given Direction is diagonal.
Money value
Value of the vehicle.
Definition: vehicle_base.h:239
int CalcNextVehicleOffset() const
Calculate the offset from this vehicle&#39;s center to the following center taking the vehicle lengths in...
Definition: train.h:167
bool _networking
are we in networking mode?
Definition: network.cpp:52
uint16 DepotID
Type for the unique identifier of depots.
Definition: depot_type.h:13
int GetAcceleration() const
Calculates the acceleration of the vehicle under its current conditions.
static const RailtypeInfo * GetRailTypeInfo(RailType railtype)
Returns a pointer to the Railtype information for a given railtype.
Definition: rail.h:304
void DecreaseVehicleValue(Vehicle *v)
Decrease the value of a vehicle.
Definition: vehicle.cpp:1199
static const int DAYS_IN_YEAR
days per year
Definition: date_type.h:29
TrackdirBits
Enumeration of bitmasks for the TrackDirs.
Definition: track_type.h:101
static const uint CALLBACK_FAILED
Different values for Callback result evaluations.
No track build.
Definition: track_type.h:102
Direction direction
facing
Definition: vehicle_base.h:269
static void SetTunnelBridgeReservation(TileIndex t, bool b)
Set the reservation state of the rail tunnel/bridge.
void ShowVisualEffect() const
Draw visual effects (smoke and/or sparks) for a vehicle chain.
Definition: vehicle.cpp:2509
Occupied by a train.
Definition: signal_func.h:51
bool UsesWagonOverride(const Vehicle *v)
Check if a wagon is currently using a wagon override.
Flag for an invalid track.
Definition: track_type.h:28
bool Follow(TileIndex old_tile, Trackdir old_td)
main follower routine.
bool NPFTrainFindNearestSafeTile(const Train *v, TileIndex tile, Trackdir trackdir, bool override_railtype)
Try to extend the reserved path of a train to the nearest safe tile using NPF.
Definition: npf.cpp:1260
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting)
Definition: window.cpp:3215
static DiagDirection DirToDiagDir(Direction dir)
Convert a Direction to a DiagDirection.
void InvalidateNewGRFInspectWindow(GrfSpecFeature feature, uint index)
Invalidate the inspect window for a given feature and index.
static int UnScaleGUI(int value)
Short-hand to apply GUI zoom level.
Definition: zoom_func.h:66
Yet Another PathFinder.
Definition: vehicle_type.h:61
Track along the x-axis (north-east to south-west)
Definition: track_type.h:21
TrackdirBits m_new_td_bits
the new set of available trackdirs
uint32 maximum_go_to_depot_penalty
What is the maximum penalty that may be endured for going to a depot.
bool m_is_tunnel
last turn passed tunnel
Train is just leaving a station.
Definition: train.h:33
void CheckOrders(const Vehicle *v)
Check the orders of a vehicle, to see if there are invalid orders and stuff.
Definition: order_cmd.cpp:1724
void SetFrontEngine()
Set front engine state.
bool TrainController(Train *v, Vehicle *nomove, bool reverse=true)
Move a vehicle chain one movement stop forwards.
Definition: train_cmd.cpp:3084
void MarkBridgeDirty(TileIndex begin, TileIndex end, DiagDirection direction, uint bridge_height)
Mark bridge tiles dirty.
static FindDepotData FindClosestTrainDepot(Train *v, int max_distance)
Try to find a depot nearby.
Definition: train_cmd.cpp:1991
int TicksToLeaveDepot(const Train *v)
Compute number of ticks when next wagon will leave a depot.
Definition: rail_cmd.cpp:2930
ConsistChangeFlags
Flags for Train::ConsistChanged.
Definition: train.h:44
byte curve_speed
Multiplier for curve maximum speed advantage.
Definition: rail.h:203
Train vehicle type.
Definition: vehicle_type.h:24
union Vehicle::@49 orders
The orders currently assigned to the vehicle.
Max. speed: 1 unit = 1/1.6 mph = 1 km-ish/h.
static Titem * Get(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:291
static bool TrainCheckIfLineEnds(Train *v, bool reverse=true)
Checks for line end.
Definition: train_cmd.cpp:3675
static bool IsBridgeTile(TileIndex t)
checks if there is a bridge on this tile
Definition: bridge_map.h:35
Capacity of vehicle changes when not refitting or arranging.
Definition: newgrf_config.h:47
void PlayLeaveStationSound() const
Play a sound for a train leaving the station.
Definition: train_cmd.cpp:2028
Angle of 45 degrees left.
static T ToggleBit(T &x, const uint8 y)
Toggles a bit in a variable.
uint DoUpdateSpeed(uint accel, int min_speed, int max_speed)
Update the speed of the vehicle.
static Track TrackdirToTrack(Trackdir trackdir)
Returns the Track that a given Trackdir represents.
Definition: track_func.h:270
Vehicle composition was changed.
Definition: vehicle_gui.h:34
Trigger platform when train arrives.
static bool TrainApproachingCrossing(TileIndex tile)
Finds a vehicle approaching rail-road crossing.
Definition: train_cmd.cpp:1650
Bitmask for the first 6 bits.
Definition: track_type.h:54
Various explosions.
static CommandCost CheckTrainAttachment(Train *t)
Check whether the train parts can be attached.
Definition: train_cmd.cpp:959
Use default vehicle palette.
Definition: vehicle_base.h:33
Angle of 90 degrees right.
West.
static bool HasCrossingReservation(TileIndex t)
Get the reservation state of the rail crossing.
Definition: road_map.h:380
uint16 GetVehicleCallbackParent(CallbackID callback, uint32 param1, uint32 param2, EngineID engine, const Vehicle *v, const Vehicle *parent)
Evaluate a newgrf callback for vehicles with a different vehicle for parent scope.
static const VehicleOrderID INVALID_VEH_ORDER_ID
Invalid vehicle order index (sentinel)
Definition: order_type.h:21
static void NormaliseTrainHead(Train *head)
Normalise the head of the train again, i.e.
Definition: train_cmd.cpp:1116
Left track.
Definition: track_type.h:44
void AddArticulatedParts(Vehicle *first)
Add the remaining articulated parts to the given vehicle.
bool reverse
True if reversing is necessary for the train to get to this depot.
Used for iterations.
static T SetBit(T &x, const uint8 y)
Set a bit in a variable.
Trackdir
Enumeration for tracks and directions.
Definition: track_type.h:70
Sprites to use for trains.
uint16 cur_speed
current speed
Definition: vehicle_base.h:291
Temporary data storage for testing collisions.
Definition: train_cmd.cpp:2974
static void AddVehicleAdviceNewsItem(StringID string, VehicleID vehicle)
Adds a vehicle-advice news item.
Definition: news_func.h:40
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
Definition: command_func.h:23
void ReserveTrackUnderConsist() const
Tries to reserve track under whole train consist.
Definition: train_cmd.cpp:2894
static int ScaleGUITrad(int value)
Scale traditional pixel dimensions to GUI zoom level.
Definition: zoom_func.h:76
Depot view; Window numbers:
Definition: window_type.h:344
static void ClearPathReservation(const Train *v, TileIndex tile, Trackdir track_dir)
Clear the reservation of tile that was just left by a wagon on track_dir.
Definition: train_cmd.cpp:2188
Rail vehicle can be flipped in the depot.
Definition: engine_type.h:157
Types for recording game performance data.
byte spritenum
currently displayed sprite index 0xfd == custom sprite, 0xfe == custom second head sprite 0xff == res...
Definition: vehicle_base.h:277
CommandCost CmdBuildRailVehicle(TileIndex tile, DoCommandFlag flags, const Engine *e, uint16 data, Vehicle **ret)
Build a railroad vehicle.
Definition: train_cmd.cpp:714
bool IsStoppedInDepot() const
Check whether the vehicle is in the depot and stopped.
Definition: vehicle_base.h:514
Both directions faces to the same direction.
fluid_settings_t * settings
FluidSynth settings handle.
Definition: fluidsynth.cpp:20
OrderList * list
Pointer to the order list for this vehicle.
Definition: vehicle_base.h:319
Train * GetNextUnit() const
Get the next real (non-articulated part and non rear part of dualheaded engine) vehicle in the consis...
Definition: train.h:143
StationID last_loading_station
Last station the vehicle has stopped at and could possibly leave from with any cargo loaded...
Definition: vehicle_base.h:301
Yearly runningcost (if dualheaded: sum of both vehicles)
TileIndex dest_tile
Heading for this tile.
Definition: vehicle_base.h:235
uint16 wait_counter
Ticks waiting in front of a signal, ticks being stuck or a counter for forced proceeding through sign...
Definition: train.h:100
static bool IsOnewaySignal(TileIndex t, Track track)
One-way signals can&#39;t be passed the &#39;wrong&#39; way.
Definition: rail_map.h:319
NPFSettings npf
pathfinder settings for the new pathfinder
X-axis track.
Definition: track_type.h:40
Proceed till next signal, but ignore being stuck till then. This includes force leaving depots...
Definition: train.h:39
Functions related to vehicles.
static TrackBits DiagDirToDiagTrackBits(DiagDirection diagdir)
Maps a (4-way) direction to the diagonal track bits incidating with that diagdir. ...
Definition: track_func.h:532
Stop at the middle of the platform.
Definition: order_type.h:85
static void NormaliseDualHeads(Train *t)
Normalise the dual heads in the train, i.e.
Definition: train_cmd.cpp:881
bool lost_vehicle_warn
if a vehicle can&#39;t find its destination, show a warning
Definition: settings_type.h:84
void IncrementRealOrderIndex()
Advanced cur_real_order_index to the next real order, keeps care of the wrap-around and invalidates t...
Definition: vehicle_base.h:822
uint32 current_order_time
How many ticks have passed since this order started.
Definition: base_consist.h:21
static uint TileX(TileIndex tile)
Get the X component of a tile.
Definition: map_func.h:205
void VehicleEnterDepot(Vehicle *v)
Vehicle entirely entered the depot, update its status, orders, vehicle windows, service it...
Definition: vehicle.cpp:1436
void GetImage(Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) const
Get the sprite to display the train.
Definition: train_cmd.cpp:462
void Draw(int x, int y, PaletteID default_pal, bool force_pal) const
Draw the sprite sequence.
Definition: vehicle.cpp:126
PathfinderSettings pf
settings for all pathfinders
VehicleOrderID ProcessConditionalOrder(const Order *order, const Vehicle *v)
Process a conditional order and determine the next order.
Definition: order_cmd.cpp:1972
static TileIndex TileAddByDiagDir(TileIndex tile, DiagDirection dir)
Adds a DiagDir to a tile.
Definition: map_func.h:382
Vehicle data structure.
Definition: vehicle_base.h:210
int UpdateSpeed()
This function looks at the vehicle and updates its speed (cur_speed and subspeed) variables...
Definition: train_cmd.cpp:2792
Station has seen a train.
Definition: station_type.h:64
static Trackdir TrackEnterdirToTrackdir(Track track, DiagDirection diagdir)
Maps a track and an (4-way) dir to the trackdir that represents the track with the entry in the given...
Definition: track_func.h:494
void LeaveStation()
Perform all actions when leaving a station.
Definition: vehicle.cpp:2180
void Set(SpriteID sprite)
Assign a single sprite to the sequence.
Definition: vehicle_base.h:161
DifficultySettings difficulty
settings related to the difficulty
Start or stop this vehicle, and show information about the current state.
bool ambient
Play ambient, industry and town sounds.
Tindex index
Index of this pool item.
Definition: pool_type.hpp:189
void ShowErrorMessage(StringID summary_msg, StringID detailed_msg, WarningLevel wl, int x=0, int y=0, const GRFFile *textref_stack_grffile=nullptr, uint textref_stack_size=0, const uint32 *textref_stack=nullptr)
Display an error message in a window.
Definition: error_gui.cpp:380
static CommandCost CheckNewTrain(Train *original_dst, Train *dst, Train *original_src, Train *src)
Check/validate whether we may actually build a new train.
Definition: train_cmd.cpp:935
CommandCost CmdReverseTrainDirection(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
Reverse train.
Definition: train_cmd.cpp:1887
static const int DAY_TICKS
1 day is 74 ticks; _date_fract used to be uint16 and incremented by 885.
Definition: date_type.h:28
uint16 speed
maximum travel speed (1 unit = 1/1.6 mph = 1 km-ish/h)
Definition: bridge.h:46
void SetNext(Vehicle *next)
Set the next vehicle of this vehicle.
Definition: vehicle.cpp:2659
Train * First() const
Get the first vehicle in the chain.
Definition: vehicle_base.h:996
bool forbid_90_deg
forbid trains to make 90 deg turns
void UpdateViewport(bool force_update, bool update_delta)
Update vehicle sprite- and position caches.
bool IsMultiheaded() const
Check if the vehicle is a multiheaded engine.
static bool IsRailWaypointTile(TileIndex t)
Is this tile a station tile and a rail waypoint?
Definition: station_map.h:123
StationID last_station_visited
The last station we stopped at.
Definition: vehicle_base.h:300
Rail vehicle tilts in curves.
Definition: engine_type.h:153
uint16 reliability_spd_dec
Reliability decrease speed.
Definition: vehicle_base.h:260
static Track DiagDirToDiagTrack(DiagDirection diagdir)
Maps a (4-way) direction to the diagonal track incidating with that diagdir.
Definition: track_func.h:520
void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist, bool reset_order_indices)
Delete all orders from a vehicle.
Definition: order_cmd.cpp:1888
Determine whether a wagon can be attached to an already existing train.
TileIndex m_old_tile
the origin (vehicle moved from) before move
StringID GetGRFStringID(uint32 grfid, StringID stringid)
Returns the index for this stringid associated with its grfID.
A railway.
Definition: tile_type.h:42
Money GetCost() const
The costs as made up to this moment.
Definition: command_type.h:82
RailTypes compatible_railtypes
bitmask to the OTHER railtypes on which an engine of THIS railtype can physically travel ...
Definition: rail.h:188
void HandlePathfindingResult(bool path_found)
Handle the pathfinding result, especially the lost status.
Definition: vehicle.cpp:773
Number of ticks before carried cargo is aged.
static void InsertInConsist(Train *dst, Train *chain)
Inserts a chain into the train at dst.
Definition: train_cmd.cpp:867
T * GetFirstEnginePart()
Get the first part of an articulated engine.
bool IsChainInDepot() const override
Check whether the whole vehicle chain is in the depot.
Flag for an invalid DiagDirection.
void CargoChanged()
Recalculates the cached weight of a vehicle and its parts.
Common return value for all commands.
Definition: command_type.h:23
static TrackdirBits DiagdirReachesTrackdirs(DiagDirection diagdir)
Returns all trackdirs that can be reached when entering a tile from a given (diagonal) direction...
Definition: track_func.h:563
uint32 cached_power
Total power of the consist (valid only for the first engine).
static const VehicleID INVALID_VEHICLE
Constant representing a non-existing vehicle.
Definition: vehicle_type.h:55
bool m_is_station
last turn passed station
static CommandCost ValidateTrains(Train *original_dst, Train *dst, Train *original_src, Train *src, bool check_limit)
Validate whether we are going to create valid trains.
Definition: train_cmd.cpp:1055
static T max(const T a, const T b)
Returns the maximum of two values.
Definition: math_func.hpp:24
PBSTileInfo FollowTrainReservation(const Train *v, Vehicle **train_on_res)
Follow a train reservation to the last tile.
Definition: pbs.cpp:289
byte vehstatus
Status.
Definition: vehicle_base.h:315
static void SwapTrainFlags(uint16 *swap_flag1, uint16 *swap_flag2)
Swap the two up/down flags in two ways:
Definition: train_cmd.cpp:1510
EngineImageType
Visualisation contexts of vehicles and engines.
Definition: vehicle_type.h:85
byte flags
Flags of the engine.
Definition: engine_base.h:33
static DiagDirection TrackdirToExitdir(Trackdir trackdir)
Maps a trackdir to the (4-way) direction the tile is exited when following that trackdir.
Definition: track_func.h:447
UnitID GetFreeUnitNumber(VehicleType type)
Get an unused unit number for a vehicle (if allowed).
Definition: vehicle.cpp:1725
Year _cur_year
Current year, starting at 0.
Definition: date.cpp:24
uint StoredCount() const
Returns sum of cargo on board the vehicle (ie not only reserved).
Definition: cargopacket.h:351
void CheckTrainsLengths()
Checks if lengths of all rail vehicles are valid.
Definition: train_cmd.cpp:72
static void SetSignalStateByTrackdir(TileIndex tile, Trackdir trackdir, SignalState state)
Sets the state of the signal along the given trackdir.
Definition: rail_map.h:449
bool m_is_bridge
last turn passed bridge ramp
static Train * From(Vehicle *v)
Converts a Vehicle to SpecializedVehicle with type checking.
static void RestoreTrainBackup(TrainList &list)
Restore the train from the backup list.
Definition: train_cmd.cpp:827
bool TryReserveRailTrack(TileIndex tile, Track t, bool trigger_stations)
Try to reserve a specific track on a tile.
Definition: pbs.cpp:80
uint16 cached_max_speed
Maximum speed of the consist (minimum of the max speed of all vehicles in the consist).
Definition: vehicle_base.h:121
Money GetRunningCost() const
Get running cost for the train consist.
Definition: train_cmd.cpp:3870
bool NeedsAutomaticServicing() const
Checks if the current order should be interrupted for a service-in-depot order.
Definition: vehicle.cpp:251
const Engine * GetEngine() const
Retrieves the engine of the vehicle.
Definition: vehicle.cpp:741
Ignore next signal, after the signal ignore being stuck.
Definition: train.h:40
CargoID GetDefaultCargoType() const
Determines the default cargo type of an engine.
Definition: engine_base.h:79
static const uint TILE_SIZE
Tile size in world coordinates.
Definition: tile_type.h:13
byte VehicleRandomBits()
Get a value for a vehicle&#39;s random_bits.
Definition: vehicle.cpp:361
Money GetPrice(Price index, uint cost_factor, const GRFFile *grf_file, int shift)
Determine a certain price.
Definition: economy.cpp:942
Southwest.
Non-electrified rails.
Definition: rail_type.h:48
void AddCost(const Money &cost)
Adds the given cost to the cost of the command.
Definition: command_type.h:62
VehicleSpriteSeq sprite_seq
Vehicle appearance.
Definition: vehicle_base.h:278
static T SB(T &x, const uint8 s, const uint8 n, const U d)
Set n bits in x starting at bit s to d.
static void ArrangeTrains(Train **dst_head, Train *dst, Train **src_head, Train *src, bool move_chain)
Arrange the trains in the wanted way.
Definition: train_cmd.cpp:1075
North.
Various explosions.
The vehicle will stop at any station it passes except the destination.
Definition: order_type.h:75
int8 x_bb_offs
x offset of vehicle bounding box
Definition: vehicle_base.h:282
static Vehicle * FindTrainCollideEnum(Vehicle *v, void *data)
Collision test function.
Definition: train_cmd.cpp:2985
uint32 GetGRFID() const
Retrieve the GRF ID of the NewGRF the engine is tied to.
Definition: engine.cpp:160
when autoreplace/autorenew is in progress, this shall prevent truncating the amount of cargo in the v...
Definition: command_type.h:352
This struct contains all the info that is needed to draw and construct tracks.
Definition: rail.h:124
bool SwitchToNextOrder(bool skip_first)
Set the current vehicle order to the next order in the order list.
Definition: train_cmd.cpp:2457
Stop at the near end of the platform.
Definition: order_type.h:84
No rail types.
Definition: rail_type.h:47
EngineID first_engine
Cached EngineID of the front vehicle. INVALID_ENGINE for the front vehicle itself.
Right track.
Definition: track_type.h:45
static void SetCrossingBarred(TileIndex t, bool barred)
Set the bar state of a level crossing.
Definition: road_map.h:428
Functions related to (drawing on) viewports.
Normal rail tile with signals.
Definition: rail_map.h:25
Pseudo random number generator.
uint Crash(bool flooded=false)
The train vehicle crashed! Update its status and other parts around it.
Definition: train_cmd.cpp:2916
int GetTrainStopLocation(StationID station_id, TileIndex tile, const Train *v, int *station_ahead, int *station_length)
Get the stop location of (the center) of the front vehicle of a train at a platform of a station...
Definition: train_cmd.cpp:256
int8 y_bb_offs
y offset of vehicle bounding box
Definition: vehicle_base.h:283
Angle of 45 degrees right.
byte breakdown_ctr
Counter for managing breakdown events.
Definition: vehicle_base.h:261
Stop at the far end of the platform.
Definition: order_type.h:86
static Track TrackBitsToTrack(TrackBits tracks)
Converts TrackBits to Track.
Definition: track_func.h:201
static bool CheckTrainCollision(Train *v)
Checks whether the specified train has a collision with another vehicle.
Definition: train_cmd.cpp:3032
static void MakeTrainBackup(TrainList &list, Train *t)
Make a backup of a train into a train list.
Definition: train_cmd.cpp:818
static const AccelerationSlowdownParams _accel_slowdown[]
Speed update fractions for each acceleration type.
Definition: train_cmd.cpp:2853
Train()
We don&#39;t want GCC to zero our struct! It already is zeroed and has an index!
Definition: train.h:103
TextEffectID fill_percent_te_id
a text-effect id to a loading indicator object
Definition: vehicle_base.h:288
void InvalidateWindowClassesData(WindowClass cls, int data, bool gui_scope)
Mark window data of all windows of a given class as invalid (in need of re-computing) Note that by de...
Definition: window.cpp:3334
static bool IsCompatibleTrainStationTile(TileIndex test_tile, TileIndex station_tile)
Check if a tile is a valid continuation to a railstation tile.
Definition: station_map.h:378
bool reverse_at_signals
whether to reverse at signals at all
Critical errors, the MessageBox is shown in all cases.
Definition: error.h:24
bool ShouldStopAtStation(const Vehicle *v, StationID station) const
Check whether the given vehicle should stop at the given station based on this order and the non-stop...
Definition: order_cmd.cpp:2229
static void MaybeBarCrossingWithSound(TileIndex tile)
Bars crossing and plays ding-ding sound if not barred already.
Definition: train_cmd.cpp:1694
uint16 cargo_cap
total capacity
Definition: vehicle_base.h:305
void VehicleLengthChanged(const Vehicle *u)
Logs a bug in GRF and shows a warning message if this is for the first time this happened.
Definition: vehicle.cpp:329
static bool IsTileOwner(TileIndex tile, Owner owner)
Checks if a tile belongs to the given owner.
Definition: tile_map.h:214
Header of Action 04 "universal holder" structure and functions.
OrderDepotTypeFlags GetDepotOrderType() const
What caused us going to the depot?
Definition: order_base.h:135
byte z_up
Fraction to remove when moving up.
Definition: train_cmd.cpp:2848
Vehicle orders; Window numbers:
Definition: window_type.h:205
User defined data for vehicle variable 0x42.
void GetTrainSpriteSize(EngineID engine, uint &width, uint &height, int &xoffs, int &yoffs, EngineImageType image_type)
Get the size of the sprite of a train sprite heading west, or both heads (used for lists)...
Definition: train_cmd.cpp:549
static const uint32 MAKE_ORDER_BACKUP_FLAG
Flag to pass to the vehicle construction command when an order should be preserved.
Definition: order_backup.h:29
uint8 freight_trains
value to multiply the weight of cargo by
Vehicle is crashed.
Definition: vehicle_base.h:37
Vehicle is a prototype (accepted as exclusive preview).
Definition: vehicle_base.h:44
static DiagDirection DiagdirBetweenTiles(TileIndex tile_from, TileIndex tile_to)
Determines the DiagDirection to get from one tile to another.
Definition: map_func.h:394
byte acceleration
used by train & aircraft
Definition: vehicle_base.h:293
bool YapfTrainFindNearestSafeTile(const Train *v, TileIndex tile, Trackdir td, bool override_railtype)
Try to extend the reserved path of a train to the nearest safe tile using YAPF.
Definition: yapf_rail.cpp:626
static TileIndexDiff TileOffsByDiagDir(DiagDirection dir)
Convert a DiagDirection to a TileIndexDiff.
Definition: map_func.h:341
uint16 reliability_spd_dec
Speed of reliability decay between services (per day).
Definition: engine_base.h:26
int traininfo_vehicle_pitch
Vertical offset for drawing train images in depot GUI and vehicle details.
Definition: newgrf.h:142
static bool IsValidTrackdir(Trackdir trackdir)
Checks if a Trackdir is valid for non-road vehicles.
Definition: track_func.h:60
bool Tick()
Update train vehicle data for a tick.
Definition: train_cmd.cpp:3895
void SubtractMoneyFromCompanyFract(CompanyID company, CommandCost cst)
Subtract money from a company, including the money fraction.
Track NPFTrainChooseTrack(const Train *v, bool &path_found, bool reserve_track, struct PBSTileInfo *target)
Finds the best path for given train using NPF.
Definition: npf.cpp:1300
static bool IsTileType(TileIndex tile, TileType type)
Checks if a tile is a given tiletype.
Definition: tile_map.h:150
bool IsWagon() const
Check if a vehicle is a wagon.
static void DeleteLastWagon(Train *v)
Deletes/Clears the last wagon of a crashed train.
Definition: train_cmd.cpp:3429
Functions related to errors.
static Vehicle * TrainOnTileEnum(Vehicle *v, void *)
Check if the vehicle is a train.
Definition: train_cmd.cpp:1617
UnitID unitnumber
unit number, for display purposes only
Definition: vehicle_base.h:289
int y
x and y position of the vehicle after moving
Definition: vehicle_func.h:76
CommandCost DoCommand(const CommandContainer *container, DoCommandFlag flags)
Shorthand for calling the long DoCommand with a container.
Definition: command.cpp:441
byte cargo_subtype
Used for livery refits (NewGRF variations)
Definition: vehicle_base.h:304
void AgeVehicle(Vehicle *v)
Update age of a vehicle.
Definition: vehicle.cpp:1327
void SetEngine()
Set engine status.
FindDepotData NPFTrainFindNearestDepot(const Train *v, int max_penalty)
Used when user sends train to the nearest depot or if train needs servicing using NPF...
Definition: npf.cpp:1238
uint16 crash_anim_pos
Crash animation counter.
Definition: train.h:91
bool IsValid() const
Check whether the sequence contains any sprites.
Definition: vehicle_base.h:145
static void UpdateStatusAfterSwap(Train *v)
Updates some variables after swapping the vehicle.
Definition: train_cmd.cpp:1538
SoundSettings sound
sound effect settings
static bool IsRailStationTile(TileIndex t)
Is this tile a station tile and a rail station?
Definition: station_map.h:102
void ConsistChanged(ConsistChangeFlags allowed_changes)
Recalculates the cached stuff of a train.
Definition: train_cmd.cpp:106
Segment is a PBS segment.
Definition: signal_func.h:52
YAPFSettings yapf
pathfinder settings for the yet another pathfinder
#define FIND_FIRST_BIT(x)
Returns the first non-zero bit in a 6-bit value (from right).
bool NeedsServicing() const
Check if the vehicle needs to go to a depot in near future (if a opportunity presents itself) for ser...
Definition: vehicle.cpp:183
void MakeDummy()
Makes this order a Dummy order.
Definition: order_cmd.cpp:132
int8 y_offs
y offset for vehicle sprite
Definition: vehicle_base.h:285
East.
void HideFillingPercent(TextEffectID *te_id)
Hide vehicle loading indicators.
Definition: misc_gui.cpp:651
We want to stop.
uint32 VehicleID
The type all our vehicle IDs have.
Definition: vehicle_type.h:16
CommandCost CmdForceTrainProceed(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
Force a train through a red signal.
Definition: train_cmd.cpp:1960
uint16 pow_wag_power
Extra power applied to consist if wagon should be powered.
Definition: engine_type.h:55
bool IsType(OrderType type) const
Check whether this order is of the given type.
Definition: order_base.h:61
uint16 max_speed
Maximum speed (1 unit = 1/1.6 mph = 1 km-ish/h)
Definition: engine_type.h:47
CommandCost TunnelBridgeIsFree(TileIndex tile, TileIndex endtile, const Vehicle *ignore)
Finds vehicle in tunnel / bridge.
Definition: vehicle.cpp:566
static Owner GetTileOwner(TileIndex tile)
Returns the owner of a tile.
Definition: tile_map.h:178
Southeast.
static DiagDirection GetRailDepotDirection(TileIndex t)
Returns the direction the depot is facing to.
Definition: rail_map.h:171
static DiagDirection ReverseDiagDir(DiagDirection d)
Returns the reverse direction of the given DiagDirection.
DoCommandFlag
List of flags for a command.
Definition: command_type.h:342
T * Next() const
Get next vehicle in the chain.
byte callback_mask
Bitmask of vehicle callbacks that have to be called.
Definition: engine_type.h:143
simple wagon, not motorized
Definition: engine_type.h:29
ClientSettings _settings_client
The current settings for this game.
Definition: settings.cpp:78
Standard non-electric rails.
Definition: rail_type.h:29
bool IsSafeWaitingPosition(const Train *v, TileIndex tile, Trackdir trackdir, bool include_line_end, bool forbid_90deg)
Determine whether a certain track on a tile is a safe position to end a path.
Definition: pbs.cpp:381
The vehicle either entered a bridge, tunnel or depot tile (this includes the last tile of the bridge/...
Definition: tile_cmd.h:22
Definition of base types and functions in a cross-platform compatible way.
Shift the VehicleEnterTileStatus this many bits to the right to get the station ID when VETS_ENTERED_...
Definition: tile_cmd.h:30
bool IsWaitingPositionFree(const Train *v, TileIndex tile, Trackdir trackdir, bool forbid_90deg)
Check if a safe position is free.
Definition: pbs.cpp:427
static const BridgeSpec * GetBridgeSpec(BridgeType i)
Get the specification of a bridge type.
Definition: bridge.h:65
static const uint VEHICLE_LENGTH
The length of a vehicle in tile units.
Definition: vehicle_type.h:76
bool IsArticulatedPart() const
Check if the vehicle is an articulated part of an engine.
Definition: vehicle_base.h:890
A number of safeguards to prevent using unsafe methods.
AccelStatus GetAccelerationStatus() const
Checks the current acceleration status of this vehicle.
Definition: train.h:262
byte x_extent
x-extent of vehicle bounding box
Definition: vehicle_base.h:279
#define FOR_EACH_SET_TRACK(var, track_bits)
Iterate through each set Track in a TrackBits value.
Definition: track_func.h:27
uint best_length
The distance towards the depot in penalty, or UINT_MAX if not found.
uint8 acceleration_type
Acceleration type of this rail type.
Definition: rail.h:223
bool ProcessOrders(Vehicle *v)
Handle the orders of a vehicle and determine the next place to go to if needed.
Definition: order_cmd.cpp:2130
Direction
Defines the 8 directions on the map.
Flag for an invalid trackdir.
Definition: track_type.h:89
std::vector< Train * > TrainList
Helper type for lists/vectors of trains.
Definition: train_cmd.cpp:811
void SetTrainGroupID(Train *v, GroupID grp)
Affect the groupID of a train to new_g.
Definition: group_cmd.cpp:729
static Trackdir RemoveFirstTrackdir(TrackdirBits *trackdirs)
Removes first Trackdir from TrackdirBits and returns it.
Definition: track_func.h:164
Vehicle refit; Window numbers:
Definition: window_type.h:199
Vehicle length (trains and road vehicles)
This class will save the current order of a vehicle and restore it on destruction.
Definition: train_cmd.cpp:2424
DirDiff
Enumeration for the difference between two directions.
byte z_extent
z-extent of vehicle bounding box
Definition: vehicle_base.h:281
Vehicle starting, i.e. leaving, the station.
Definition: newgrf_sound.h:19
Valid changes for arranging the consist in a depot.
Definition: train.h:52
static Axis GetCrossingRailAxis(TileIndex t)
Get the rail axis of a level crossing.
Definition: road_map.h:337
static TrackdirBits TrackStatusToRedSignals(TrackStatus ts)
Returns the red-signal-information of a TrackStatus.
Definition: track_func.h:384
static bool HasPbsSignalOnTrackdir(TileIndex tile, Trackdir td)
Is a pbs signal present along the trackdir?
Definition: rail_map.h:463
static void NormaliseSubtypes(Train *chain)
Normalise the sub types of the parts in this chain.
Definition: train_cmd.cpp:903
CargoID cargo_type
type of cargo this vehicle is carrying
Definition: vehicle_base.h:303
static Axis GetCrossingRoadAxis(TileIndex t)
Get the road axis of a level crossing.
Definition: road_map.h:325
static bool IsValidDiagDirection(DiagDirection d)
Checks if an integer value is a valid DiagDirection.
void AddToShared(Vehicle *shared_chain)
Adds this vehicle to a shared vehicle chain.
Definition: vehicle.cpp:2688
byte capacity
Cargo capacity of vehicle; For multiheaded engines the capacity of each single engine.
Definition: engine_type.h:53
Vehicle view; Window numbers:
Definition: window_type.h:332
byte large_turn
Speed change due to a large turn.
Definition: train_cmd.cpp:2847
uint traininfo_vehicle_width
Width (in pixels) of a 8/8 train vehicle in depot GUI and vehicle details.
Definition: newgrf.h:143
TrackBits
Bitfield corresponding to Track.
Definition: track_type.h:38
Functions related to order backups.
bool IsFrontEngine() const
Check if the vehicle is a front engine.
Definition: vehicle_base.h:881
byte misc_flags
Miscellaneous flags.
Definition: engine_type.h:142
void FindVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
Find a vehicle from a specific location.
Definition: vehicle.cpp:496
TileIndex tile
Current tile index.
Definition: vehicle_base.h:228
South.
New PathFinder.
Definition: vehicle_type.h:60
CommandCost CheckOwnership(Owner owner, TileIndex tile)
Check whether the current owner owns something.
byte shorten_factor
length on main map for this type is 8 - shorten_factor
Definition: engine_type.h:58
static Track DoTrainPathfind(const Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found, bool do_track_reservation, PBSTileInfo *dest)
Perform pathfinding for a train.
Definition: train_cmd.cpp:2306
byte FreightWagonMult(CargoID cargo)
Return the cargo weight multiplier to use for a rail vehicle.
Definition: train_cmd.cpp:65
Functions to access the new pathfinder.
static void CountVehicle(const Vehicle *v, int delta)
Update num_vehicle when adding or removing a vehicle.
Definition: group_cmd.cpp:133
static Trackdir TrackDirectionToTrackdir(Track track, Direction dir)
Maps a track and a full (8-way) direction to the trackdir that represents the track running in the gi...
Definition: track_func.h:506
void MarkTileDirtyByTile(TileIndex tile, int bridge_level_offset, int tile_height_override)
Mark a tile given by its index dirty for repaint.
Definition: viewport.cpp:1938
Vehicle timetable; Window numbers:
Definition: window_type.h:217
static void CheckIfTrainNeedsService(Train *v)
Check whether a train needs service, and if so, find a depot or service it.
Definition: train_cmd.cpp:3924
static Trackdir DiagDirToDiagTrackdir(DiagDirection diagdir)
Maps a (4-way) direction to the diagonal trackdir that runs in that direction.
Definition: track_func.h:545
VehicleEnterTileStatus VehicleEnterTile(Vehicle *v, TileIndex tile, int x, int y)
Call the tile callback function for a vehicle entering a tile.
Definition: vehicle.cpp:1674
void UpdateDeltaXY()
Updates the x and y offsets and the size of the sprite used for this vehicle.
Definition: train_cmd.cpp:1418
Basic functions/variables used all over the place.
static DirDiff DirDifference(Direction d0, Direction d1)
Calculate the difference between two directions.
bool IsRearDualheaded() const
Tell if we are dealing with the rear end of a multiheaded engine.
static Direction ChangeDir(Direction d, DirDiff delta)
Change a direction by a given difference.
bool okay
True if tile is a safe waiting position, false otherwise.
Definition: pbs.h:29
int8 x_offs
x offset for vehicle sprite
Definition: vehicle_base.h:284
static void RemoveFromConsist(Train *part, bool chain=false)
Remove the given wagon from its consist.
Definition: train_cmd.cpp:850
Owner owner
Which company owns the vehicle?
Definition: vehicle_base.h:271
Sprite sequence for a vehicle part.
Definition: vehicle_base.h:128
static Track GetRailDepotTrack(TileIndex t)
Returns the track of a depot, ignoring direction.
Definition: rail_map.h:182
void UpdateTrainGroupID(Train *v)
Recalculates the groupID of a train.
Definition: group_cmd.cpp:757
bool DoCommandP(const CommandContainer *container, bool my_cmd)
Shortcut for the long DoCommandP when having a container with the data.
Definition: command.cpp:532
static uint TrainCrashed(Train *v)
Marks train as crashed and creates an AI event.
Definition: train_cmd.cpp:2955
#define lengthof(x)
Return the length of an fixed size array.
Definition: depend.cpp:40
static TrackdirBits TrackdirReachesTrackdirs(Trackdir trackdir)
Maps a trackdir to the trackdirs that can be reached from it (ie, when entering the next tile...
Definition: track_func.h:592
static T min(const T a, const T b)
Returns the minimum of two values.
Definition: math_func.hpp:40
bool NPFTrainCheckReverse(const Train *v)
Returns true if it is better to reverse the train before leaving station using NPF.
Definition: npf.cpp:1281
uint16 refit_cap
Capacity left over from before last refit.
Definition: vehicle_base.h:306
byte random_bits
Bits used for determining which randomized variational spritegroups to use when drawing.
Definition: vehicle_base.h:297
Functions related to sound.
Add articulated engines (trains and road vehicles)
uint16 reliability
Reliability.
Definition: vehicle_base.h:259
Data structure for storing engine speed changes of an acceleration type.
Definition: train_cmd.cpp:2845
static void CheckNextTrainTile(Train *v)
Check if the train is on the last reserved tile and try to extend the path then.
Definition: train_cmd.cpp:2048
static DiagDirection GetTunnelBridgeDirection(TileIndex t)
Get the direction pointing to the other end.
static bool IsPlainRailTile(TileIndex t)
Checks whether the tile is a rail tile or rail tile with signals.
Definition: rail_map.h:60
Vehicle is currently going uphill. (Cached track information for acceleration)
Track follower helper template class (can serve pathfinders and vehicle controllers).
Functions to cache sprites in memory.
uint32 StringID
Numeric value that represents a string, independent of the selected language.
Definition: strings_type.h:16
bool Failed() const
Did this command fail?
Definition: command_type.h:159
uint16 power
Power of engine (hp); For multiheaded engines the sum of both engine powers.
Definition: engine_type.h:48
byte tick_counter
Increased by one for each tick.
Definition: vehicle_base.h:312
EffectVehicle * CreateEffectVehicleRel(const Vehicle *v, int x, int y, int z, EffectVehicleType type)
Create an effect vehicle above a particular vehicle.
void CheckCargoCapacity(Vehicle *v)
Check the capacity of all vehicles in a chain and spread cargo if needed.
bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth, bool pbs_look_ahead)
Update the vehicle&#39;s destination tile from an order.
Definition: order_cmd.cpp:2002
CommandCost CmdSellRailWagon(DoCommandFlag flags, Vehicle *t, uint16 data, uint32 user)
Sell a (single) train wagon/engine.
Definition: train_cmd.cpp:1343
static bool Chance16R(const uint a, const uint b, uint32 &r)
Flips a coin with a given probability and saves the randomize-number in a variable.
byte small_turn
Speed change due to a small turn.
Definition: train_cmd.cpp:2846
static void BarCrossing(TileIndex t)
Bar a level crossing.
Definition: road_map.h:447
Bitflag for a wormhole (used for tunnels)
Definition: track_type.h:55
static DepotID GetDepotIndex(TileIndex t)
Get the index of which depot is attached to the tile.
Definition: depot_map.h:52
Year build_year
Year the vehicle has been built.
Definition: vehicle_base.h:255
bool PlayVehicleSound(const Vehicle *v, VehicleSoundEvent event)
Checks whether a NewGRF wants to play a different vehicle sound effect.
static Trackdir ReverseTrackdir(Trackdir trackdir)
Maps a trackdir to the reverse trackdir.
Definition: track_func.h:255
TileIndex tile
Tile the path ends, INVALID_TILE if no valid path was found.
Definition: pbs.h:27
#define return_cmd_error(errcode)
Returns from a function with a specific StringID as error.
Definition: command_func.h:33
Information about a rail vehicle.
Definition: engine_type.h:42
static const uint16 _breakdown_speeds[16]
Maximum speeds for train that is broken down or approaching line end.
Definition: train_cmd.cpp:3560
TrackStatus GetTileTrackStatus(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
Returns information about trackdirs and signal states.
Definition: landscape.cpp:589
bool IsPrimaryVehicle() const
Whether this is the primary vehicle in the chain.
Definition: train.h:113
static void NewEvent(CompanyID company, ScriptEvent *event)
Queue a new event for an AI.
Definition: ai_core.cpp:234
void OnNewDay()
Update day counters of the train vehicle.
Definition: train_cmd.cpp:3967
static bool HasSignals(TileIndex t)
Checks if a rail tile has signals.
Definition: rail_map.h:72
static T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition: math_func.hpp:137
static bool TryReserveSafeTrack(const Train *v, TileIndex tile, Trackdir td, bool override_railtype)
Try to reserve any path to a safe tile, ignoring the vehicle&#39;s destination.
Definition: train_cmd.cpp:2413
autoreplace/autorenew is in progress, this shall disable vehicle limits when building, and ignore certain restrictions when undoing things (like vehicle attach callback)
Definition: command_type.h:351
static TrackBits DiagdirReachesTracks(DiagDirection diagdir)
Returns all tracks that can be reached when entering a tile from a given (diagonal) direction...
Definition: track_func.h:581
&#39;Train&#39; is either a loco or a wagon.
Definition: train.h:85
static bool Chance16(const uint a, const uint b)
Flips a coin with given probability.
TileIndex tile
The tile of the depot.
This struct contains information about the end of a reserved path.
Definition: pbs.h:26
static RailTileType GetRailTileType(TileIndex t)
Returns the RailTileType (normal with or without signals, waypoint or depot).
Definition: rail_map.h:36
TileIndex old_tile
Current tile of the vehicle.
Definition: vehicle_func.h:77
static BridgeType GetBridgeType(TileIndex t)
Determines the type of bridge on a tile.
Definition: bridge_map.h:56
static bool CheckTrainStayInDepot(Train *v)
Will the train stay in the depot the next tick?
Definition: train_cmd.cpp:2110
FindDepotData YapfTrainFindNearestDepot(const Train *v, int max_distance)
Used when user sends train to the nearest depot or if train needs servicing using YAPF...
Definition: yapf_rail.cpp:607
static bool TrainApproachingLineEnd(Train *v, bool signal, bool reverse)
Train is approaching line end, slow down and possibly reverse.
Definition: train_cmd.cpp:3573
static TrackBits GetTrackBits(TileIndex tile)
Gets the track bits of the given tile.
Definition: rail_map.h:136
CommandCost CmdMoveRailVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
Move a rail vehicle around inside the depot.
Definition: train_cmd.cpp:1149
void DeleteWindowById(WindowClass cls, WindowNumber number, bool force)
Delete a window by its class and window number (if it is open).
Definition: window.cpp:1162
Wagon is powered.
Definition: train.h:27
Bitflag for a depot.
Definition: track_type.h:56
static Axis DiagDirToAxis(DiagDirection d)
Convert a DiagDirection to the axis.
uint Crash(bool flooded) override
Common code executed for crashed ground vehicles.
Lower track.
Definition: track_type.h:43
static TileIndex GetOtherTunnelBridgeEnd(TileIndex t)
Determines type of the wormhole and returns its other end.
Angle of 90 degrees left.
Transport by train.
execute the given command
Definition: command_type.h:344
bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse)
Locate the closest depot for this consist, and return the information to the caller.
Definition: train_cmd.cpp:2015
static const EngineID INVALID_ENGINE
Constant denoting an invalid engine.
Definition: engine_type.h:174
static TrackBits TrackToTrackBits(Track track)
Maps a Track to the corresponding TrackBits value.
Definition: track_func.h:85
Open the refit window.
static const GroupID DEFAULT_GROUP
Ungrouped vehicles are in this group.
Definition: group_type.h:17
static void AdvanceWagonsAfterSwap(Train *v)
Advances wagons for train reversing, needed for variable length wagons.
Definition: train_cmd.cpp:1737
Functions related to companies.
int GetDisplayImageWidth(Point *offset=nullptr) const
Get the width of a train vehicle image in the GUI.
Definition: train_cmd.cpp:432
byte path_backoff_interval
ticks between checks for a free path.
RailType GetTileRailType(TileIndex tile)
Return the rail type of tile, or INVALID_RAILTYPE if this is no rail tile.
Definition: rail.cpp:155
GetNewVehiclePosResult GetNewVehiclePos(const Vehicle *v)
Get position information of a vehicle when moving one pixel in the direction it is facing...
Definition: vehicle.cpp:1620
void UpdatePosition()
Update the position of the vehicle.
Definition: vehicle.cpp:1559
static StationID GetStationIndex(TileIndex t)
Get StationID from a tile.
Definition: station_map.h:28
static TileIndex TileVirtXY(uint x, uint y)
Get a tile from the virtual XY-coordinate.
Definition: map_func.h:194
void CheckConsistencyOfArticulatedVehicle(const Vehicle *v)
Checks whether the specs of freshly build articulated vehicles are consistent with the information sp...
OrderStopLocation
Where to stop the trains.
Definition: order_type.h:83
Vehicle is currently going downhill. (Cached track information for acceleration)
Allow vehicles to change length.
Definition: train.h:45
Electric train engine is allowed to run on normal rail. */.
Definition: train.h:30
No track.
Definition: track_type.h:39
static T KillFirstBit(T value)
Clear the first bit in an integer.
Functions related to articulated vehicles.
void ErrorUnknownCallbackResult(uint32 grfid, uint16 cbid, uint16 cb_res)
Record that a NewGRF returned an unknown/invalid callback result.
Trigger platform when train arrives.
Header file for NewGRF stations.
Track along the y-axis (north-west to south-east)
Definition: track_type.h:22
static T ClrBit(T &x, const uint8 y)
Clears a bit in a variable.
Train can&#39;t get a path reservation.
Definition: train.h:32
Trackdir GetVehicleTrackdir() const
Get the tracks of the train vehicle.
Definition: train_cmd.cpp:4005
static bool TrainCanLeaveTile(const Train *v)
Determines whether train would like to leave the tile.
Definition: train_cmd.cpp:3618
T * Previous() const
Get previous vehicle in the chain.
GUISettings gui
settings related to the GUI
Tunnel entry/exit and bridge heads.
Definition: tile_type.h:50
DestinationID GetDestination() const
Gets the destination of this order.
Definition: order_base.h:94
const GRFFile * GetGRF() const
Retrieve the NewGRF the engine is tied to.
Definition: engine_base.h:138
void VehicleServiceInDepot(Vehicle *v)
Service a vehicle and all subsequent vehicles in the consist.
Definition: vehicle.cpp:162
Running costs trains.
Definition: economy_type.h:151
void SetWindowWidgetDirty(WindowClass cls, WindowNumber number, byte widget_index)
Mark a particular widget in a particular window as dirty (in need of repainting)
Definition: window.cpp:3229
byte subspeed
fractional speed
Definition: vehicle_base.h:292
static bool IsRailDepotTile(TileIndex t)
Is this tile rail tile and a rail depot?
Definition: rail_map.h:105
void MakeGoToDepot(DepotID destination, OrderDepotTypeFlags order, OrderNonStopFlags non_stop_type=ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS, OrderDepotActionFlags action=ODATF_SERVICE_ONLY, CargoID cargo=CT_NO_REFIT)
Makes this order a Go To Depot order.
Definition: order_cmd.cpp:89
bool HandleBreakdown()
Handle all of the aspects of a vehicle breakdown This includes adding smoke and sounds, and ending the breakdown when appropriate.
Definition: vehicle.cpp:1261
int cached_max_curve_speed
max consist speed limited by curves
Definition: train.h:79
uint32 SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition: gfx_type.h:17
OrderStopLocation GetStopLocation() const
Where must we stop at the platform?
Definition: order_base.h:133
Used for vehicle var 0xFE bit 8 (toggled each time the train is reversed, accurate for first vehicle ...
Definition: train.h:31
uint16 EngineID
Unique identification number of an engine.
Definition: engine_type.h:21
Upper track.
Definition: track_type.h:42
bool line_reverse_mode
reversing at stations or not
Definition: settings_type.h:67
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo ID.
Definition: cargotype.h:117
T * Last()
Get the last vehicle in the chain.
uint32 TileIndex
The index/ID of a Tile.
Definition: tile_type.h:78
static const PaletteID PALETTE_CRASH
Recolour sprite greying of crashed vehicles.
Definition: sprites.h:1587
The vehicle entered a station.
Definition: tile_cmd.h:21
uint GetAdvanceDistance()
Determines the vehicle "progress" needed for moving a step.
Definition: vehicle_base.h:412
Used for iterations.
Helper container to find a depot.
void BeginLoading()
Prepare everything to begin the loading when arriving at a station.
Definition: vehicle.cpp:2033
Vehicle * Next() const
Get the next vehicle of this vehicle.
Definition: vehicle_base.h:579
Date date_of_last_service
Last date the vehicle had a service at a depot.
Definition: vehicle_base.h:258
void ShowNewGrfVehicleError(EngineID engine, StringID part1, StringID part2, GRFBugs bug_type, bool critical)
Displays a "NewGrf Bug" error message for a engine, and pauses the game if not networking.
Definition: vehicle.cpp:296
byte z_down
Fraction to add when moving down.
Definition: train_cmd.cpp:2849
Position information of a vehicle after it moved.
Definition: vehicle_func.h:75
Base includes/functions for YAPF.
static bool IsLevelCrossingTile(TileIndex t)
Return whether a tile is a level crossing tile.
Definition: road_map.h:94
First vehicle arrived for company.
Definition: news_type.h:22
Track
These are used to specify a single track.
Definition: track_type.h:19
void FindVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc)
Find a vehicle from a specific location.
Definition: vehicle.cpp:436
static bool HandleCrashedTrain(Train *v)
Handle a crashed train.
Definition: train_cmd.cpp:3521
bool wagon_speed_limits
enable wagon speed limits
static uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition: map_func.h:215
Train * v
Vehicle we are testing for collision.
Definition: train_cmd.cpp:2975
void Free()
&#39;Free&#39; the order
Definition: order_cmd.cpp:62
void CDECL error(const char *s,...)
Error handling for fatal non-user errors.
Definition: openttd.cpp:112
uint8 pathfinder_for_trains
the pathfinder to use for trains
SigSegState UpdateSignalsOnSegment(TileIndex tile, DiagDirection side, Owner owner)
Update signals, starting at one side of a tile Will check tile next to this at opposite side too...
Definition: signal.cpp:638
static T abs(const T a)
Returns the absolute value of (scalar) variable.
Definition: math_func.hpp:81
indicates a combination of two locomotives
Definition: engine_type.h:28
TrackBits GetReservedTrackbits(TileIndex t)
Get the reserved trackbits for any tile, regardless of type.
Definition: pbs.cpp:24
TileIndex m_new_tile
the new tile (the vehicle has entered)
TileIndex xy
Base tile of the station.
static uint GB(const T x, const uint8 s, const uint8 n)
Fetch n bits from x, started at bit s.
uint16 cached_total_length
Length of the whole vehicle (valid only for the first engine).
byte wait_twoway_signal
waitingtime in days before a twoway signal
Trains list; Window numbers:
Definition: window_type.h:301
Functions related to zooming.
VehicleType type
Type of vehicle.
Definition: vehicle_type.h:52
Vehicle * next
pointer to the next vehicle in the chain
Definition: vehicle_base.h:215
A tile of a station.
Definition: tile_type.h:46
static Track FindFirstTrack(TrackBits tracks)
Returns first Track from TrackBits or INVALID_TRACK.
Definition: track_func.h:185
RAII class for measuring multi-step elements of performance.
OrderType
Order types.
Definition: order_type.h:35
Reverse the visible direction of the vehicle.
Definition: train.h:28
bool show_track_reservation
highlight reserved tracks.
void SetRailStationPlatformReservation(TileIndex start, DiagDirection dir, bool b)
Set the reservation for a complete station platform.
Definition: pbs.cpp:57
Northwest.
void CopyVehicleConfigAndStatistics(const Vehicle *src)
Copy certain configurations and statistics of a vehicle after successful autoreplace/renew The functi...
Definition: vehicle_base.h:710
int GetCurveSpeedLimit() const
Computes train speed limit caused by curves.
Definition: train_cmd.cpp:300
T * GetNextVehicle() const
Get the next real (non-articulated part) vehicle in the consist.
bool disaster
Play disaster and accident sounds.
SigSegState
State of the signal segment.
Definition: signal_func.h:49
uint16 cached_max_track_speed
Maximum consist speed (in internal units) limited by track type (valid only for the first engine)...
static bool CanAllocateItem(size_t n=1)
Helper functions so we can use PoolItem::Function() instead of _poolitem_pool.Function() ...
Definition: pool_type.hpp:261
static bool IsCompatibleRail(RailType enginetype, RailType tiletype)
Checks if an engine of the given RailType can drive on a tile with a given RailType.
Definition: rail.h:319
RailTypes powered_railtypes
bitmask to the OTHER railtypes on which an engine of THIS railtype generates power ...
Definition: rail.h:185
int32 z_pos
z coordinate.
Definition: vehicle_base.h:268
Vehicle is not visible.
Definition: vehicle_base.h:30
Vehicle details; Window numbers:
Definition: window_type.h:193
void UpdateLevelCrossing(TileIndex tile, bool sound)
Sets correct crossing state.
Definition: train_cmd.cpp:1672
static DiagDirection VehicleExitDir(Direction direction, TrackBits track)
Determine the side in which the vehicle will leave the tile.
Definition: track_func.h:722
Used for iterations.
Definition: track_type.h:20
Base functions for all Games.
The signal is red.
Definition: signal_type.h:45
Functions related to commands.
static void AdvanceWagonsBeforeSwap(Train *v)
Advances wagons for train reversing, needed for variable length wagons.
Definition: train_cmd.cpp:1709
Coordinates of a point in 2D.
An accident or disaster has occurred.
Definition: news_type.h:24
Northeast.
CompanyID _current_company
Company currently doing an action.
Definition: company_cmd.cpp:45
static void AffectSpeedByZChange(Train *v, int old_z)
Modify the speed of the vehicle due to a change in altitude.
Definition: train_cmd.cpp:2865
uint32 GetGRFID() const
Retrieve the GRF ID of the NewGRF the vehicle is tied to.
Definition: vehicle.cpp:761
uint8 train_acceleration_model
realistic acceleration for trains
uint32 maximum_go_to_depot_penalty
What is the maximum penalty that may be endured for going to a depot.
UnitID max_trains
max trains in game per company
static void ChangeTrainDirRandomly(Train *v)
Rotate all vehicles of a (crashed) train chain randomly to animate the crash.
Definition: train_cmd.cpp:3493
Order * GetOrder(int index) const
Returns order &#39;index&#39; of a vehicle or nullptr when it doesn&#39;t exists.
Definition: vehicle_base.h:858
static const StringID INVALID_STRING_ID
Constant representing an invalid string (16bit in case it is used in savegames)
Definition: strings_type.h:17
VehicleOrderID GetNumOrders() const
Get the number of orders this vehicle has.
Definition: vehicle_base.h:685
uint16 GetVehicleCallback(CallbackID callback, uint32 param1, uint32 param2, EngineID engine, const Vehicle *v)
Evaluate a newgrf callback for vehicles.
uint num
Total number of victims if train collided.
Definition: train_cmd.cpp:2976
void MarkDirty()
Goods at the consist have changed, update the graphics, cargo, and acceleration.
Definition: train_cmd.cpp:2772
DiagDirection m_exitdir
exit direction (leaving the old tile)
static Pool::IterateWrapper< Train > Iterate(size_t from=0)
Returns an iterable ensemble of all valid vehicles of type T.
static void TrainEnterStation(Train *v, StationID station)
Trains enters a station, send out a news item if it is the first train, and start loading...
Definition: train_cmd.cpp:2809
void SetSignalsOnBothDir(TileIndex tile, Track track, Owner owner)
Update signals at segments that are at both ends of given (existent or non-existent) track...
Definition: signal.cpp:656
void SetLastSpeed()
Update the GUI variant of the current speed of the vehicle.
uint8 cached_veh_length
Length of this vehicle in units of 1/VEHICLE_LENGTH of normal length. It is cached because this can b...
bool IsFreeWagon() const
Check if the vehicle is a free wagon (got no engine in front of it).
uint8 original_image_index
Original vehicle image index, thus the image index of the overridden vehicle.
Definition: engine_base.h:39
byte running_ticks
Number of ticks this vehicle was not stopped this day.
Definition: vehicle_base.h:313
byte y_extent
y-extent of vehicle bounding box
Definition: vehicle_base.h:280
Flag to disable wagon power.
Definition: vehicle_base.h:90
EngineID engine_type
The type of engine used for this vehicle.
Definition: vehicle_base.h:286
Trackdir m_old_td
the trackdir (the vehicle was on) before move
static TrackBits TrackCrossesTracks(Track track)
Maps a track to all tracks that make 90 deg turns with it.
Definition: track_func.h:428
void RemoveVehicleFromGroup(const Vehicle *v)
Decrease the num_vehicle variable before delete an front engine from a group.
Definition: group_cmd.cpp:715
int GetCurrentMaxSpeed() const
Calculates the maximum speed of the vehicle under its current conditions.
Definition: train_cmd.cpp:369
int32 x_pos
x coordinate.
Definition: vehicle_base.h:266
Trackdir trackdir
The reserved trackdir on the tile.
Definition: pbs.h:28
byte VehicleOrderID
The index of an order within its current vehicle (not pool related)
Definition: order_type.h:15
uint16 vehicle_flags
Used for gradual loading and other miscellaneous things (.
Definition: base_consist.h:30
static bool HasReservedTracks(TileIndex tile, TrackBits tracks)
Check whether some of tracks is reserved on a tile.
Definition: pbs.h:58
static bool HasBit(const T x, const uint8 y)
Checks if a bit in a value is set.
Functions related to NewGRF provided sounds.
DiagDirection
Enumeration for diagonal directions.
Base functions for all AIs.
static TrackdirBits TrackBitsToTrackdirBits(TrackBits bits)
Converts TrackBits to TrackdirBits while allowing both directions.
Definition: track_func.h:327
static const TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition: tile_type.h:83
bool reserve_paths
always reserve paths regardless of signal type.
void SetFreeWagon()
Set a vehicle as a free wagon.
static bool IsCrossingBarred(TileIndex t)
Check if the level crossing is barred.
Definition: road_map.h:416
const GRFFile * GetGRF() const
Retrieve the NewGRF the vehicle is tied to.
Definition: vehicle.cpp:751
static void NormalizeTrainVehInDepot(const Train *u)
Move all free vehicles in the depot to the train.
Definition: train_cmd.cpp:659
byte progress
The percentage (if divided by 256) this vehicle already crossed the tile unit.
Definition: vehicle_base.h:295
The vehicle cannot enter the tile.
Definition: tile_cmd.h:23
static bool IsPlainRail(TileIndex t)
Returns whether this is plain rails, with or without signals.
Definition: rail_map.h:49
OrderType GetType() const
Get the type of order of this order.
Definition: order_base.h:67
Specification of a rectangle with absolute coordinates of all edges.
byte CargoID
Cargo slots to indicate a cargo type within a game.
Definition: cargo_type.h:20
int32 y_pos
y coordinate.
Definition: vehicle_base.h:267
uint16 GetMaxSpeed() const
Get the maxmimum speed in km-ish/h a vehicle is allowed to reach on the way to the destination...
Definition: order_base.h:192
uint16 cargo_age_period
Number of ticks before carried cargo is aged.
Definition: engine_type.h:146
New vehicles.
Definition: economy_type.h:150
static Vehicle * CollectTrackbitsFromCrashedVehiclesEnum(Vehicle *v, void *data)
Collect trackbits of all crashed train vehicles on a tile.
Definition: train_cmd.cpp:3405
byte wait_for_pbs_path
how long to wait for a path reservation.
static TrackBits TrackdirBitsToTrackBits(TrackdirBits bits)
Discards all directional information from a TrackdirBits value.
Definition: track_func.h:316
Track YapfTrainChooseTrack(const Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found, bool reserve_track, struct PBSTileInfo *target)
Finds the best path for given train using YAPF.
Definition: yapf_rail.cpp:533
std::vector< Train * > TrainList
Helper type for lists/vectors of trains.
Definition: rail_cmd.cpp:42
static bool HasDepotReservation(TileIndex t)
Get the reservation state of the depot.
Definition: rail_map.h:258
static CommandCost CmdBuildRailWagon(TileIndex tile, DoCommandFlag flags, const Engine *e, Vehicle **ret)
Build a railroad wagon.
Definition: train_cmd.cpp:584
Station with train station.
Definition: station_type.h:52
static bool HasOnewaySignalBlockingTrackdir(TileIndex tile, Trackdir td)
Is a one-way signal blocking the trackdir? A one-way signal on the trackdir against will block...
Definition: rail_map.h:475
static void Backup(const Vehicle *v, uint32 user)
Create an order backup for the given vehicle.
static DiagDirection AxisToDiagDir(Axis a)
Converts an Axis to a DiagDirection.
Vehicle length, returns the amount of 1/8&#39;s the vehicle is shorter for trains and RVs...
bool YapfTrainCheckReverse(const Train *v)
Returns true if it is better to reverse the train before leaving station using YAPF.
Definition: yapf_rail.cpp:548
static SignalState GetSignalStateByTrackdir(TileIndex tile, Trackdir trackdir)
Gets the state of the signal along the given trackdir.
Definition: rail_map.h:438
static TileIndex TrainApproachingCrossingTile(const Train *v)
Determines whether train is approaching a rail-road crossing (thus making it barred) ...
Definition: train_cmd.cpp:3648
int UpdateInclination(bool new_tile, bool update_delta)
Checks if the vehicle is in a slope and sets the required flags in that case.
move a rail vehicle (in the depot)
Definition: command_type.h:220
Money profit_this_year
Profit this year << 8, low 8 bits are fract.
Definition: vehicle_base.h:237
void SetMultiheaded()
Set a vehicle as a multiheaded engine.
byte running_cost
Running cost of engine; For multiheaded engines the sum of both running costs.
Definition: engine_type.h:50
void SetWindowClassesDirty(WindowClass cls)
Mark all windows of a particular class as dirty (in need of repainting)
Definition: window.cpp:3243
uint DetermineCapacity(const Vehicle *v, uint16 *mail_capacity=nullptr) const
Determines capacity of a given vehicle from scratch.
Definition: engine.cpp:204
Functions related to news.
normal pbs signal
Definition: signal_type.h:28
TileIndex GetOrderStationLocation(StationID station)
Get the location of the next station to visit.
Definition: train_cmd.cpp:2757
VehicleCache vcache
Cache of often used vehicle values.
Definition: vehicle_base.h:328
static Station * Get(size_t index)
Gets station with given index.
int m_tiles_skipped
number of skipped tunnel or station tiles
Date _date
Current date in days (day counter)
Definition: date.cpp:26
void SetWagon()
Set a vehicle to be a wagon.
static Direction ReverseDir(Direction d)
Return the reverse of a direction.
byte wait_oneway_signal
waitingtime in days before a oneway signal
Company view; Window numbers:
Definition: window_type.h:362
static TrackdirBits TrackdirCrossesTrackdirs(Trackdir trackdir)
Maps a trackdir to all trackdirs that make 90 deg turns with it.
Definition: track_func.h:614
TileIndex new_tile
Tile of the vehicle after moving.
Definition: vehicle_func.h:78
static bool Rail90DegTurnDisallowed(RailType rt1, RailType rt2, bool def=_settings_game.pf.forbid_90_deg)
Test if 90 degree turns are disallowed between two railtypes.
Definition: rail.h:354
Vehicle * first
NOSAVE: pointer to the first vehicle in the chain.
Definition: vehicle_base.h:217
uint GetPlatformLength(TileIndex tile, DiagDirection dir) const override
Determines the REMAINING length of a platform, starting at (and including) the given tile...
Definition: station.cpp:267
Allow vehicles to change capacity.
Definition: train.h:46
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
Definition: company_cmd.cpp:44
Y-axis track.
Definition: track_type.h:41
void DeleteNewGRFInspectWindow(GrfSpecFeature feature, uint index)
Delete inspect window for a given feature and index.
This depot order is because of the servicing limit.
Definition: order_type.h:95
VehicleOrderID cur_real_order_index
The index to the current real (non-implicit) order.
Definition: base_consist.h:27
static bool IsTunnel(TileIndex t)
Is this a tunnel (entrance)?
Definition: tunnel_map.h:22
byte user_def_data
Property 0x25: "User-defined bit mask" Used only for (very few) NewGRF vehicles.
Definition: engine_type.h:61
void HandleLoading(bool mode=false)
Handle the loading of the vehicle; when not it skips through dummy orders and does nothing in all oth...
Definition: vehicle.cpp:2242
Valid changes while vehicle is driving, and possibly changing tracks.
Definition: train.h:48
static TrackdirBits TrackStatusToTrackdirBits(TrackStatus ts)
Returns the present-trackdir-information of a TrackStatus.
Definition: track_func.h:360
SoundFx
Sound effects from baseset.
Definition: sound_type.h:37
void ReverseTrainDirection(Train *v)
Turn a train around.
Definition: train_cmd.cpp:1794
Station data structure.
Definition: station_base.h:450
Functions related to effect vehicles.
OrderNonStopFlags GetNonStopType() const
At which stations must we stop?
Definition: order_base.h:131
Time spent processing trains.
void FreeTrainTrackReservation(const Train *v)
Free the reserved path in front of a vehicle.
Definition: train_cmd.cpp:2229
uint32 cached_weight
Total weight of the consist (valid only for the first engine).
void InvalidateNewGRFCache()
Invalidates cached NewGRF variables.
Definition: vehicle_base.h:449
Disable insertion and removal of automatic orders until the vehicle completes the real order...
A game paused because a (critical) error.
Definition: openttd.h:60
void GetBounds(Rect *bounds) const
Determine shared bounds of all sprites.
Definition: vehicle.cpp:98
Date GetLifeLengthInDays() const
Returns the vehicle&#39;s (not model&#39;s!) life length in days.
Definition: engine.cpp:444
Train is slowing down.
Definition: vehicle_base.h:34
static void MarkTrainAsStuck(Train *v)
Mark a train as stuck and stop it if it isn&#39;t stopped right now.
Definition: train_cmd.cpp:1486
byte day_counter
Increased by one for each day.
Definition: vehicle_base.h:311
static RailType GetRailType(TileIndex t)
Gets the rail type of the given tile.
Definition: rail_map.h:115
static bool TracksOverlap(TrackBits bits)
Checks if the given tracks overlap, ie form a crossing.
Definition: track_func.h:653
Order current_order
The current order (+ status, like: loading)
Definition: vehicle_base.h:316
static bool IsBridge(TileIndex t)
Checks if this is a bridge, instead of a tunnel.
Definition: bridge_map.h:24
static Direction DiagDirToDir(DiagDirection dir)
Convert a DiagDirection to a Direction.
GroupID group_id
Index of group Pool array.
Definition: vehicle_base.h:324
void InvalidateWindowData(WindowClass cls, WindowNumber number, int data, bool gui_scope)
Mark window data of the window of a given class and specific window number as invalid (in need of re-...
Definition: window.cpp:3316
bool IsEngine() const
Check if a vehicle is an engine (can be first in a consist).
void UpdateAcceleration()
Update acceleration of the train from the cached power and weight.
Definition: train_cmd.cpp:417
GroundVehicleCache gcache
Cache of often calculated values.
The signal is green.
Definition: signal_type.h:46
void UnreserveRailTrack(TileIndex tile, Track t)
Lift the reservation of a specific track on a tile.
Definition: pbs.cpp:141
static Trackdir FindFirstTrackdir(TrackdirBits trackdirs)
Returns first Trackdir from TrackdirBits or INVALID_TRACKDIR.
Definition: track_func.h:219
SpriteID colourmap
NOSAVE: cached colour mapping.
Definition: vehicle_base.h:252
static Train * GetIfValid(size_t index)
Returns vehicle if the index is a valid index for this vehicle type.
static void SetDParam(uint n, uint64 v)
Set a string parameter v at index n in the global string parameter array.
Definition: strings_func.h:199
uint8 max_train_length
maximum length for trains
static void SetDepotReservation(TileIndex t, bool b)
Set the reservation state of the depot.
Definition: rail_map.h:270
static void AddVehicleNewsItem(StringID string, NewsType type, VehicleID vehicle, StationID station=INVALID_STATION)
Adds a newsitem referencing a vehicle.
Definition: news_func.h:30
Base for the NewGRF implementation.
pause the game
Definition: command_type.h:254