OpenTTD Source  20241108-master-g80f628063a
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"
14 #include "error_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 #include "train_cmd.h"
38 #include "misc_cmd.h"
41 
42 #include "table/strings.h"
43 #include "table/train_sprites.h"
44 
45 #include "safeguards.h"
46 
47 static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool force_res, bool *got_reservation, bool mark_stuck);
48 static bool TrainCheckIfLineEnds(Train *v, bool reverse = true);
49 bool TrainController(Train *v, Vehicle *nomove, bool reverse = true); // Also used in vehicle_sl.cpp.
51 static void CheckIfTrainNeedsService(Train *v);
52 static void CheckNextTrainTile(Train *v);
53 
54 static const uint8_t _vehicle_initial_x_fract[4] = {10, 8, 4, 8};
55 static const uint8_t _vehicle_initial_y_fract[4] = { 8, 4, 8, 10};
56 
57 template <>
58 bool IsValidImageIndex<VEH_TRAIN>(uint8_t image_index)
59 {
60  return image_index < lengthof(_engine_sprite_base);
61 }
62 
63 
69 uint8_t FreightWagonMult(CargoID cargo)
70 {
71  if (!CargoSpec::Get(cargo)->is_freight) return 1;
73 }
74 
77 {
78  bool first = true;
79 
80  for (const Train *v : Train::Iterate()) {
81  if (v->First() == v && !(v->vehstatus & VS_CRASHED)) {
82  for (const Train *u = v, *w = v->Next(); w != nullptr; u = w, w = w->Next()) {
83  if (u->track != TRACK_BIT_DEPOT) {
84  if ((w->track != TRACK_BIT_DEPOT &&
85  std::max(abs(u->x_pos - w->x_pos), abs(u->y_pos - w->y_pos)) != u->CalcNextVehicleOffset()) ||
86  (w->track == TRACK_BIT_DEPOT && TicksToLeaveDepot(u) <= 0)) {
87  SetDParam(0, v->index);
88  SetDParam(1, v->owner);
89  ShowErrorMessage(STR_BROKEN_VEHICLE_LENGTH, INVALID_STRING_ID, WL_CRITICAL);
90 
91  if (!_networking && first) {
92  first = false;
94  }
95  /* Break so we warn only once for each train. */
96  break;
97  }
98  }
99  }
100  }
101  }
102 }
103 
111 {
112  uint16_t max_speed = UINT16_MAX;
113 
114  assert(this->IsFrontEngine() || this->IsFreeWagon());
115 
116  const RailVehicleInfo *rvi_v = RailVehInfo(this->engine_type);
117  EngineID first_engine = this->IsFrontEngine() ? this->engine_type : INVALID_ENGINE;
118  this->gcache.cached_total_length = 0;
119  this->compatible_railtypes = RAILTYPES_NONE;
120 
121  bool train_can_tilt = true;
122  int16_t min_curve_speed_mod = INT16_MAX;
123 
124  for (Train *u = this; u != nullptr; u = u->Next()) {
125  const RailVehicleInfo *rvi_u = RailVehInfo(u->engine_type);
126 
127  /* Check the this->first cache. */
128  assert(u->First() == this);
129 
130  /* update the 'first engine' */
131  u->gcache.first_engine = this == u ? INVALID_ENGINE : first_engine;
132  u->railtype = rvi_u->railtype;
133 
134  if (u->IsEngine()) first_engine = u->engine_type;
135 
136  /* Set user defined data to its default value */
137  u->tcache.user_def_data = rvi_u->user_def_data;
138  this->InvalidateNewGRFCache();
139  u->InvalidateNewGRFCache();
140  }
141 
142  for (Train *u = this; u != nullptr; u = u->Next()) {
143  /* Update user defined data (must be done before other properties) */
144  u->tcache.user_def_data = GetVehicleProperty(u, PROP_TRAIN_USER_DATA, u->tcache.user_def_data);
145  this->InvalidateNewGRFCache();
146  u->InvalidateNewGRFCache();
147  }
148 
149  for (Train *u = this; u != nullptr; u = u->Next()) {
150  const Engine *e_u = u->GetEngine();
151  const RailVehicleInfo *rvi_u = &e_u->u.rail;
152 
153  if (!HasBit(e_u->info.misc_flags, EF_RAIL_TILTS)) train_can_tilt = false;
154  min_curve_speed_mod = std::min(min_curve_speed_mod, u->GetCurveSpeedModifier());
155 
156  /* Cache wagon override sprite group. nullptr is returned if there is none */
157  u->tcache.cached_override = GetWagonOverrideSpriteSet(u->engine_type, u->cargo_type, u->gcache.first_engine);
158 
159  /* Reset colour map */
160  u->colourmap = PAL_NONE;
161 
162  /* Update powered-wagon-status and visual effect */
163  u->UpdateVisualEffect(true);
164 
165  if (rvi_v->pow_wag_power != 0 && rvi_u->railveh_type == RAILVEH_WAGON &&
166  UsesWagonOverride(u) && !HasBit(u->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER)) {
167  /* wagon is powered */
168  SetBit(u->flags, VRF_POWEREDWAGON); // cache 'powered' status
169  } else {
170  ClrBit(u->flags, VRF_POWEREDWAGON);
171  }
172 
173  if (!u->IsArticulatedPart()) {
174  /* Do not count powered wagons for the compatible railtypes, as wagons always
175  have railtype normal */
176  if (rvi_u->power > 0) {
177  this->compatible_railtypes |= GetRailTypeInfo(u->railtype)->powered_railtypes;
178  }
179 
180  /* Some electric engines can be allowed to run on normal rail. It happens to all
181  * existing electric engines when elrails are disabled and then re-enabled */
182  if (HasBit(u->flags, VRF_EL_ENGINE_ALLOWED_NORMAL_RAIL)) {
183  u->railtype = RAILTYPE_RAIL;
184  u->compatible_railtypes |= RAILTYPES_RAIL;
185  }
186 
187  /* max speed is the minimum of the speed limits of all vehicles in the consist */
188  if ((rvi_u->railveh_type != RAILVEH_WAGON || _settings_game.vehicle.wagon_speed_limits) && !UsesWagonOverride(u)) {
189  uint16_t speed = GetVehicleProperty(u, PROP_TRAIN_SPEED, rvi_u->max_speed);
190  if (speed != 0) max_speed = std::min(speed, max_speed);
191  }
192  }
193 
194  uint16_t new_cap = e_u->DetermineCapacity(u);
195  if (allowed_changes & CCF_CAPACITY) {
196  /* Update vehicle capacity. */
197  if (u->cargo_cap > new_cap) u->cargo.Truncate(new_cap);
198  u->refit_cap = std::min(new_cap, u->refit_cap);
199  u->cargo_cap = new_cap;
200  } else {
201  /* Verify capacity hasn't changed. */
202  if (new_cap != u->cargo_cap) ShowNewGrfVehicleError(u->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_CAPACITY, GBUG_VEH_CAPACITY, true);
203  }
204  u->vcache.cached_cargo_age_period = GetVehicleProperty(u, PROP_TRAIN_CARGO_AGE_PERIOD, e_u->info.cargo_age_period);
205 
206  /* check the vehicle length (callback) */
207  uint16_t veh_len = CALLBACK_FAILED;
208  if (e_u->GetGRF() != nullptr && e_u->GetGRF()->grf_version >= 8) {
209  /* Use callback 36 */
210  veh_len = GetVehicleProperty(u, PROP_TRAIN_SHORTEN_FACTOR, CALLBACK_FAILED);
211 
212  if (veh_len != CALLBACK_FAILED && veh_len >= VEHICLE_LENGTH) {
214  }
215  } else if (HasBit(e_u->info.callback_mask, CBM_VEHICLE_LENGTH)) {
216  /* Use callback 11 */
217  veh_len = GetVehicleCallback(CBID_VEHICLE_LENGTH, 0, 0, u->engine_type, u);
218  }
219  if (veh_len == CALLBACK_FAILED) veh_len = rvi_u->shorten_factor;
220  veh_len = VEHICLE_LENGTH - Clamp(veh_len, 0, VEHICLE_LENGTH - 1);
221 
222  if (allowed_changes & CCF_LENGTH) {
223  /* Update vehicle length. */
224  u->gcache.cached_veh_length = veh_len;
225  } else {
226  /* Verify length hasn't changed. */
227  if (veh_len != u->gcache.cached_veh_length) VehicleLengthChanged(u);
228  }
229 
230  this->gcache.cached_total_length += u->gcache.cached_veh_length;
231  this->InvalidateNewGRFCache();
232  u->InvalidateNewGRFCache();
233  }
234 
235  /* store consist weight/max speed in cache */
236  this->vcache.cached_max_speed = max_speed;
237  this->tcache.cached_tilt = train_can_tilt;
238  this->tcache.cached_curve_speed_mod = min_curve_speed_mod;
239  this->tcache.cached_max_curve_speed = this->GetCurveSpeedLimit();
240 
241  /* 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) */
242  this->CargoChanged();
243 
244  if (this->IsFrontEngine()) {
245  this->UpdateAcceleration();
249  InvalidateNewGRFInspectWindow(GSF_TRAINS, this->index);
250  }
251 }
252 
263 int GetTrainStopLocation(StationID station_id, TileIndex tile, const Train *v, int *station_ahead, int *station_length)
264 {
265  const Station *st = Station::Get(station_id);
266  *station_ahead = st->GetPlatformLength(tile, DirToDiagDir(v->direction)) * TILE_SIZE;
267  *station_length = st->GetPlatformLength(tile) * TILE_SIZE;
268 
269  /* Default to the middle of the station for stations stops that are not in
270  * the order list like intermediate stations when non-stop is disabled */
272  if (v->gcache.cached_total_length >= *station_length) {
273  /* The train is longer than the station, make it stop at the far end of the platform */
274  osl = OSL_PLATFORM_FAR_END;
275  } else if (v->current_order.IsType(OT_GOTO_STATION) && v->current_order.GetDestination() == station_id) {
276  osl = v->current_order.GetStopLocation();
277  }
278 
279  /* The stop location of the FRONT! of the train */
280  int stop;
281  switch (osl) {
282  default: NOT_REACHED();
283 
285  stop = v->gcache.cached_total_length;
286  break;
287 
288  case OSL_PLATFORM_MIDDLE:
289  stop = *station_length - (*station_length - v->gcache.cached_total_length) / 2;
290  break;
291 
293  stop = *station_length;
294  break;
295  }
296 
297  /* Subtract half the front vehicle length of the train so we get the real
298  * stop location of the train. */
299  return stop - (v->gcache.cached_veh_length + 1) / 2;
300 }
301 
302 
308 {
309  assert(this->First() == this);
310 
311  static const int absolute_max_speed = UINT16_MAX;
312  int max_speed = absolute_max_speed;
313 
314  if (_settings_game.vehicle.train_acceleration_model == AM_ORIGINAL) return max_speed;
315 
316  int curvecount[2] = {0, 0};
317 
318  /* first find the curve speed limit */
319  int numcurve = 0;
320  int sum = 0;
321  int pos = 0;
322  int lastpos = -1;
323  for (const Train *u = this; u->Next() != nullptr; u = u->Next(), pos += u->gcache.cached_veh_length) {
324  Direction this_dir = u->direction;
325  Direction next_dir = u->Next()->direction;
326 
327  DirDiff dirdiff = DirDifference(this_dir, next_dir);
328  if (dirdiff == DIRDIFF_SAME) continue;
329 
330  if (dirdiff == DIRDIFF_45LEFT) curvecount[0]++;
331  if (dirdiff == DIRDIFF_45RIGHT) curvecount[1]++;
332  if (dirdiff == DIRDIFF_45LEFT || dirdiff == DIRDIFF_45RIGHT) {
333  if (lastpos != -1) {
334  numcurve++;
335  sum += pos - lastpos;
336  if (pos - lastpos <= static_cast<int>(VEHICLE_LENGTH) && max_speed > 88) {
337  max_speed = 88;
338  }
339  }
340  lastpos = pos;
341  }
342 
343  /* if we have a 90 degree turn, fix the speed limit to 60 */
344  if (dirdiff == DIRDIFF_90LEFT || dirdiff == DIRDIFF_90RIGHT) {
345  max_speed = 61;
346  }
347  }
348 
349  if (numcurve > 0 && max_speed > 88) {
350  if (curvecount[0] == 1 && curvecount[1] == 1) {
351  max_speed = absolute_max_speed;
352  } else {
353  sum = CeilDiv(sum, VEHICLE_LENGTH);
354  sum /= numcurve;
355  max_speed = 232 - (13 - Clamp(sum, 1, 12)) * (13 - Clamp(sum, 1, 12));
356  }
357  }
358 
359  if (max_speed != absolute_max_speed) {
360  /* Apply the current railtype's curve speed advantage */
361  const RailTypeInfo *rti = GetRailTypeInfo(GetRailType(this->tile));
362  max_speed += (max_speed / 2) * rti->curve_speed;
363 
364  if (this->tcache.cached_tilt) {
365  /* Apply max_speed bonus of 20% for a tilting train */
366  max_speed += max_speed / 5;
367  }
368 
369  /* Apply max_speed modifier (cached value is fixed-point binary with 8 fractional bits)
370  * and clamp the result to an acceptable range. */
371  max_speed += (max_speed * this->tcache.cached_curve_speed_mod) / 256;
372  max_speed = Clamp(max_speed, 2, absolute_max_speed);
373  }
374 
375  return static_cast<uint16_t>(max_speed);
376 }
377 
383 {
384  int max_speed = _settings_game.vehicle.train_acceleration_model == AM_ORIGINAL ?
386  this->tcache.cached_max_curve_speed;
387 
388  if (_settings_game.vehicle.train_acceleration_model == AM_REALISTIC && IsRailStationTile(this->tile)) {
389  StationID sid = GetStationIndex(this->tile);
390  if (this->current_order.ShouldStopAtStation(this, sid)) {
391  int station_ahead;
392  int station_length;
393  int stop_at = GetTrainStopLocation(sid, this->tile, this, &station_ahead, &station_length);
394 
395  /* The distance to go is whatever is still ahead of the train minus the
396  * distance from the train's stop location to the end of the platform */
397  int distance_to_go = station_ahead / TILE_SIZE - (station_length - stop_at) / TILE_SIZE;
398 
399  if (distance_to_go > 0) {
400  int st_max_speed = 120;
401 
402  int delta_v = this->cur_speed / (distance_to_go + 1);
403  if (max_speed > (this->cur_speed - delta_v)) {
404  st_max_speed = this->cur_speed - (delta_v / 10);
405  }
406 
407  st_max_speed = std::max(st_max_speed, 25 * distance_to_go);
408  max_speed = std::min(max_speed, st_max_speed);
409  }
410  }
411  }
412 
413  for (const Train *u = this; u != nullptr; u = u->Next()) {
414  if (_settings_game.vehicle.train_acceleration_model == AM_REALISTIC && u->track == TRACK_BIT_DEPOT) {
415  max_speed = std::min(max_speed, 61);
416  break;
417  }
418 
419  /* Vehicle is on the middle part of a bridge. */
420  if (u->track == TRACK_BIT_WORMHOLE && !(u->vehstatus & VS_HIDDEN)) {
421  max_speed = std::min<int>(max_speed, GetBridgeSpec(GetBridgeType(u->tile))->speed);
422  }
423  }
424 
425  max_speed = std::min<int>(max_speed, this->current_order.GetMaxSpeed());
426  return std::min<int>(max_speed, this->gcache.cached_max_track_speed);
427 }
428 
431 {
432  assert(this->IsFrontEngine() || this->IsFreeWagon());
433 
434  uint power = this->gcache.cached_power;
435  uint weight = this->gcache.cached_weight;
436  assert(weight != 0);
437  this->acceleration = Clamp(power / weight * 4, 1, 255);
438 }
439 
440 int Train::GetCursorImageOffset() const
441 {
442  if (this->gcache.cached_veh_length != 8 && HasBit(this->flags, VRF_REVERSE_DIRECTION) && !HasBit(EngInfo(this->engine_type)->misc_flags, EF_RAIL_FLIPS)) {
443  int reference_width = TRAININFO_DEFAULT_VEHICLE_WIDTH;
444 
445  const Engine *e = this->GetEngine();
446  if (e->GetGRF() != nullptr && is_custom_sprite(e->u.rail.image_index)) {
447  reference_width = e->GetGRF()->traininfo_vehicle_width;
448  }
449 
450  return ScaleSpriteTrad((this->gcache.cached_veh_length - (int)VEHICLE_LENGTH) * reference_width / (int)VEHICLE_LENGTH);
451  }
452  return 0;
453 }
454 
461 {
462  int reference_width = TRAININFO_DEFAULT_VEHICLE_WIDTH;
463  int vehicle_pitch = 0;
464 
465  const Engine *e = this->GetEngine();
466  if (e->GetGRF() != nullptr && is_custom_sprite(e->u.rail.image_index)) {
467  reference_width = e->GetGRF()->traininfo_vehicle_width;
468  vehicle_pitch = e->GetGRF()->traininfo_vehicle_pitch;
469  }
470 
471  if (offset != nullptr) {
472  if (HasBit(this->flags, VRF_REVERSE_DIRECTION) && !HasBit(EngInfo(this->engine_type)->misc_flags, EF_RAIL_FLIPS)) {
473  offset->x = ScaleSpriteTrad(((int)this->gcache.cached_veh_length - (int)VEHICLE_LENGTH / 2) * reference_width / (int)VEHICLE_LENGTH);
474  } else {
475  offset->x = ScaleSpriteTrad(reference_width) / 2;
476  }
477  offset->y = ScaleSpriteTrad(vehicle_pitch);
478  }
479  return ScaleSpriteTrad(this->gcache.cached_veh_length * reference_width / VEHICLE_LENGTH);
480 }
481 
482 static SpriteID GetDefaultTrainSprite(uint8_t spritenum, Direction direction)
483 {
484  assert(IsValidImageIndex<VEH_TRAIN>(spritenum));
485  return ((direction + _engine_sprite_add[spritenum]) & _engine_sprite_and[spritenum]) + _engine_sprite_base[spritenum];
486 }
487 
494 void Train::GetImage(Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) const
495 {
496  uint8_t spritenum = this->spritenum;
497 
499 
500  if (is_custom_sprite(spritenum)) {
501  GetCustomVehicleSprite(this, (Direction)(direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(spritenum)), image_type, result);
502  if (result->IsValid()) return;
503 
505  }
506 
507  assert(IsValidImageIndex<VEH_TRAIN>(spritenum));
508  SpriteID sprite = GetDefaultTrainSprite(spritenum, direction);
509 
510  if (this->cargo.StoredCount() >= this->cargo_cap / 2U) sprite += _wagon_full_adder[spritenum];
511 
512  result->Set(sprite);
513 }
514 
515 static void GetRailIcon(EngineID engine, bool rear_head, int &y, EngineImageType image_type, VehicleSpriteSeq *result)
516 {
517  const Engine *e = Engine::Get(engine);
518  Direction dir = rear_head ? DIR_E : DIR_W;
519  uint8_t spritenum = e->u.rail.image_index;
520 
521  if (is_custom_sprite(spritenum)) {
522  GetCustomVehicleIcon(engine, dir, image_type, result);
523  if (result->IsValid()) {
524  if (e->GetGRF() != nullptr) {
526  }
527  return;
528  }
529 
530  spritenum = Engine::Get(engine)->original_image_index;
531  }
532 
533  if (rear_head) spritenum++;
534 
535  result->Set(GetDefaultTrainSprite(spritenum, DIR_W));
536 }
537 
538 void DrawTrainEngine(int left, int right, int preferred_x, int y, EngineID engine, PaletteID pal, EngineImageType image_type)
539 {
540  if (RailVehInfo(engine)->railveh_type == RAILVEH_MULTIHEAD) {
541  int yf = y;
542  int yr = y;
543 
544  VehicleSpriteSeq seqf, seqr;
545  GetRailIcon(engine, false, yf, image_type, &seqf);
546  GetRailIcon(engine, true, yr, image_type, &seqr);
547 
548  Rect rectf, rectr;
549  seqf.GetBounds(&rectf);
550  seqr.GetBounds(&rectr);
551 
552  preferred_x = Clamp(preferred_x,
553  left - UnScaleGUI(rectf.left) + ScaleSpriteTrad(14),
554  right - UnScaleGUI(rectr.right) - ScaleSpriteTrad(15));
555 
556  seqf.Draw(preferred_x - ScaleSpriteTrad(14), yf, pal, pal == PALETTE_CRASH);
557  seqr.Draw(preferred_x + ScaleSpriteTrad(15), yr, pal, pal == PALETTE_CRASH);
558  } else {
559  VehicleSpriteSeq seq;
560  GetRailIcon(engine, false, y, image_type, &seq);
561 
562  Rect rect;
563  seq.GetBounds(&rect);
564  preferred_x = Clamp(preferred_x,
565  left - UnScaleGUI(rect.left),
566  right - UnScaleGUI(rect.right));
567 
568  seq.Draw(preferred_x, y, pal, pal == PALETTE_CRASH);
569  }
570 }
571 
581 void GetTrainSpriteSize(EngineID engine, uint &width, uint &height, int &xoffs, int &yoffs, EngineImageType image_type)
582 {
583  int y = 0;
584 
585  VehicleSpriteSeq seq;
586  GetRailIcon(engine, false, y, image_type, &seq);
587 
588  Rect rect;
589  seq.GetBounds(&rect);
590 
591  width = UnScaleGUI(rect.Width());
592  height = UnScaleGUI(rect.Height());
593  xoffs = UnScaleGUI(rect.left);
594  yoffs = UnScaleGUI(rect.top);
595 
596  if (RailVehInfo(engine)->railveh_type == RAILVEH_MULTIHEAD) {
597  GetRailIcon(engine, true, y, image_type, &seq);
598  seq.GetBounds(&rect);
599 
600  /* Calculate values relative to an imaginary center between the two sprites. */
601  width = ScaleSpriteTrad(TRAININFO_DEFAULT_VEHICLE_WIDTH) + UnScaleGUI(rect.right) - xoffs;
602  height = std::max<uint>(height, UnScaleGUI(rect.Height()));
603  xoffs = xoffs - ScaleSpriteTrad(TRAININFO_DEFAULT_VEHICLE_WIDTH) / 2;
604  yoffs = std::min(yoffs, UnScaleGUI(rect.top));
605  }
606 }
607 
617 {
618  const RailVehicleInfo *rvi = &e->u.rail;
619 
620  /* Check that the wagon can drive on the track in question */
621  if (!IsCompatibleRail(rvi->railtype, GetRailType(tile))) return CMD_ERROR;
622 
623  if (flags & DC_EXEC) {
624  Train *v = new Train();
625  *ret = v;
626  v->spritenum = rvi->image_index;
627 
628  v->engine_type = e->index;
629  v->gcache.first_engine = INVALID_ENGINE; // needs to be set before first callback
630 
632 
633  v->direction = DiagDirToDir(dir);
634  v->tile = tile;
635 
636  int x = TileX(tile) * TILE_SIZE | _vehicle_initial_x_fract[dir];
637  int y = TileY(tile) * TILE_SIZE | _vehicle_initial_y_fract[dir];
638 
639  v->x_pos = x;
640  v->y_pos = y;
641  v->z_pos = GetSlopePixelZ(x, y, true);
642  v->owner = _current_company;
643  v->track = TRACK_BIT_DEPOT;
645 
646  v->SetWagon();
647 
648  v->SetFreeWagon();
650 
652  assert(IsValidCargoID(v->cargo_type));
653  v->cargo_cap = rvi->capacity;
654  v->refit_cap = 0;
655 
656  v->railtype = rvi->railtype;
657 
661  v->sprite_cache.sprite_seq.Set(SPR_IMG_QUERY);
662  v->random_bits = Random();
663 
664  v->group_id = DEFAULT_GROUP;
665 
666  if (TestVehicleBuildProbability(v, v->engine_type, BuildProbabilityType::Reversed)) SetBit(v->flags, VRF_REVERSE_DIRECTION);
668 
669  v->UpdatePosition();
670  v->First()->ConsistChanged(CCF_ARRANGE);
672 
674 
675  /* Try to connect the vehicle to one of free chains of wagons. */
676  for (Train *w : Train::Iterate()) {
677  if (w->tile == tile &&
678  w->IsFreeWagon() &&
679  w->engine_type == e->index &&
680  w->First() != v &&
681  !(w->vehstatus & VS_CRASHED)) {
682  if (Command<CMD_MOVE_RAIL_VEHICLE>::Do(DC_EXEC, v->index, w->Last()->index, true).Succeeded()) {
683  break;
684  }
685  }
686  }
687  }
688 
689  return CommandCost();
690 }
691 
694 {
695  assert(u->IsEngine());
696  for (const Train *v : Train::Iterate()) {
697  if (v->IsFreeWagon() && v->tile == u->tile &&
698  v->track == TRACK_BIT_DEPOT) {
699  if (Command<CMD_MOVE_RAIL_VEHICLE>::Do(DC_EXEC, v->index, u->index, true).Failed()) {
700  break;
701  }
702  }
703  }
704 }
705 
706 static void AddRearEngineToMultiheadedTrain(Train *v)
707 {
708  Train *u = new Train();
709  v->value >>= 1;
710  u->value = v->value;
711  u->direction = v->direction;
712  u->owner = v->owner;
713  u->tile = v->tile;
714  u->x_pos = v->x_pos;
715  u->y_pos = v->y_pos;
716  u->z_pos = v->z_pos;
717  u->track = TRACK_BIT_DEPOT;
718  u->vehstatus = v->vehstatus & ~VS_STOPPED;
719  u->spritenum = v->spritenum + 1;
720  u->cargo_type = v->cargo_type;
722  u->cargo_cap = v->cargo_cap;
723  u->refit_cap = v->refit_cap;
724  u->railtype = v->railtype;
725  u->engine_type = v->engine_type;
728  u->build_year = v->build_year;
729  u->sprite_cache.sprite_seq.Set(SPR_IMG_QUERY);
730  u->random_bits = Random();
731  v->SetMultiheaded();
732  u->SetMultiheaded();
733  v->SetNext(u);
734  if (TestVehicleBuildProbability(u, u->engine_type, BuildProbabilityType::Reversed)) SetBit(u->flags, VRF_REVERSE_DIRECTION);
735  u->UpdatePosition();
736 
737  /* Now we need to link the front and rear engines together */
738  v->other_multiheaded_part = u;
739  u->other_multiheaded_part = v;
740 }
741 
751 {
752  const RailVehicleInfo *rvi = &e->u.rail;
753 
754  if (rvi->railveh_type == RAILVEH_WAGON) return CmdBuildRailWagon(flags, tile, e, ret);
755 
756  /* Check if depot and new engine uses the same kind of tracks *
757  * We need to see if the engine got power on the tile to avoid electric engines in non-electric depots */
758  if (!HasPowerOnRail(rvi->railtype, GetRailType(tile))) return CMD_ERROR;
759 
760  if (flags & DC_EXEC) {
762  int x = TileX(tile) * TILE_SIZE + _vehicle_initial_x_fract[dir];
763  int y = TileY(tile) * TILE_SIZE + _vehicle_initial_y_fract[dir];
764 
765  Train *v = new Train();
766  *ret = v;
767  v->direction = DiagDirToDir(dir);
768  v->tile = tile;
769  v->owner = _current_company;
770  v->x_pos = x;
771  v->y_pos = y;
772  v->z_pos = GetSlopePixelZ(x, y, true);
773  v->track = TRACK_BIT_DEPOT;
775  v->spritenum = rvi->image_index;
777  assert(IsValidCargoID(v->cargo_type));
778  v->cargo_cap = rvi->capacity;
779  v->refit_cap = 0;
780  v->last_station_visited = INVALID_STATION;
781  v->last_loading_station = INVALID_STATION;
782 
783  v->engine_type = e->index;
784  v->gcache.first_engine = INVALID_ENGINE; // needs to be set before first callback
785 
786  v->reliability = e->reliability;
788  v->max_age = e->GetLifeLengthInDays();
789 
790  v->railtype = rvi->railtype;
791 
792  v->SetServiceInterval(Company::Get(_current_company)->settings.vehicle.servint_trains);
796  v->sprite_cache.sprite_seq.Set(SPR_IMG_QUERY);
797  v->random_bits = Random();
798 
800  v->SetServiceIntervalIsPercent(Company::Get(_current_company)->settings.vehicle.servint_ispercent);
801 
802  v->group_id = DEFAULT_GROUP;
803 
804  v->SetFrontEngine();
805  v->SetEngine();
806 
807  if (TestVehicleBuildProbability(v, v->engine_type, BuildProbabilityType::Reversed)) SetBit(v->flags, VRF_REVERSE_DIRECTION);
808  v->UpdatePosition();
809 
810  if (rvi->railveh_type == RAILVEH_MULTIHEAD) {
811  AddRearEngineToMultiheadedTrain(v);
812  } else {
814  }
815 
818 
820  }
821 
822  return CommandCost();
823 }
824 
825 static Train *FindGoodVehiclePos(const Train *src)
826 {
827  EngineID eng = src->engine_type;
828  TileIndex tile = src->tile;
829 
830  for (Train *dst : Train::Iterate()) {
831  if (dst->IsFreeWagon() && dst->tile == tile && !(dst->vehstatus & VS_CRASHED)) {
832  /* check so all vehicles in the line have the same engine. */
833  Train *t = dst;
834  while (t->engine_type == eng) {
835  t = t->Next();
836  if (t == nullptr) return dst;
837  }
838  }
839  }
840 
841  return nullptr;
842 }
843 
845 typedef std::vector<Train *> TrainList;
846 
852 static void MakeTrainBackup(TrainList &list, Train *t)
853 {
854  for (; t != nullptr; t = t->Next()) list.push_back(t);
855 }
856 
861 static void RestoreTrainBackup(TrainList &list)
862 {
863  /* No train, nothing to do. */
864  if (list.empty()) return;
865 
866  Train *prev = nullptr;
867  /* Iterate over the list and rebuild it. */
868  for (Train *t : list) {
869  if (prev != nullptr) {
870  prev->SetNext(t);
871  } else if (t->Previous() != nullptr) {
872  /* Make sure the head of the train is always the first in the chain. */
873  t->Previous()->SetNext(nullptr);
874  }
875  prev = t;
876  }
877 }
878 
884 static void RemoveFromConsist(Train *part, bool chain = false)
885 {
886  Train *tail = chain ? part->Last() : part->GetLastEnginePart();
887 
888  /* Unlink at the front, but make it point to the next
889  * vehicle after the to be remove part. */
890  if (part->Previous() != nullptr) part->Previous()->SetNext(tail->Next());
891 
892  /* Unlink at the back */
893  tail->SetNext(nullptr);
894 }
895 
901 static void InsertInConsist(Train *dst, Train *chain)
902 {
903  /* We do not want to add something in the middle of an articulated part. */
904  assert(dst != nullptr && (dst->Next() == nullptr || !dst->Next()->IsArticulatedPart()));
905 
906  chain->Last()->SetNext(dst->Next());
907  dst->SetNext(chain);
908 }
909 
915 static void NormaliseDualHeads(Train *t)
916 {
917  for (; t != nullptr; t = t->GetNextVehicle()) {
918  if (!t->IsMultiheaded() || !t->IsEngine()) continue;
919 
920  /* Make sure that there are no free cars before next engine */
921  Train *u;
922  for (u = t; u->Next() != nullptr && !u->Next()->IsEngine(); u = u->Next()) {}
923 
924  if (u == t->other_multiheaded_part) continue;
925 
926  /* Remove the part from the 'wrong' train */
927  RemoveFromConsist(t->other_multiheaded_part);
928  /* And add it to the 'right' train */
929  InsertInConsist(u, t->other_multiheaded_part);
930  }
931 }
932 
937 static void NormaliseSubtypes(Train *chain)
938 {
939  /* Nothing to do */
940  if (chain == nullptr) return;
941 
942  /* We must be the first in the chain. */
943  assert(chain->Previous() == nullptr);
944 
945  /* Set the appropriate bits for the first in the chain. */
946  if (chain->IsWagon()) {
947  chain->SetFreeWagon();
948  } else {
949  assert(chain->IsEngine());
950  chain->SetFrontEngine();
951  }
952 
953  /* Now clear the bits for the rest of the chain */
954  for (Train *t = chain->Next(); t != nullptr; t = t->Next()) {
955  t->ClearFreeWagon();
956  t->ClearFrontEngine();
957  }
958 }
959 
969 static CommandCost CheckNewTrain(Train *original_dst, Train *dst, Train *original_src, Train *src)
970 {
971  /* Just add 'new' engines and subtract the original ones.
972  * If that's less than or equal to 0 we can be sure we did
973  * not add any engines (read: trains) along the way. */
974  if ((src != nullptr && src->IsEngine() ? 1 : 0) +
975  (dst != nullptr && dst->IsEngine() ? 1 : 0) -
976  (original_src != nullptr && original_src->IsEngine() ? 1 : 0) -
977  (original_dst != nullptr && original_dst->IsEngine() ? 1 : 0) <= 0) {
978  return CommandCost();
979  }
980 
981  /* Get a free unit number and check whether it's within the bounds.
982  * There will always be a maximum of one new train. */
984 
985  return_cmd_error(STR_ERROR_TOO_MANY_VEHICLES_IN_GAME);
986 }
987 
994 {
995  /* No multi-part train, no need to check. */
996  if (t == nullptr || t->Next() == nullptr) return CommandCost();
997 
998  /* The maximum length for a train. For each part we decrease this by one
999  * and if the result is negative the train is simply too long. */
1001 
1002  /* For free-wagon chains, check if they are within the max_train_length limit. */
1003  if (!t->IsEngine()) {
1004  t = t->Next();
1005  while (t != nullptr) {
1006  allowed_len -= t->gcache.cached_veh_length;
1007 
1008  t = t->Next();
1009  }
1010 
1011  if (allowed_len < 0) return_cmd_error(STR_ERROR_TRAIN_TOO_LONG);
1012  return CommandCost();
1013  }
1014 
1015  Train *head = t;
1016  Train *prev = t;
1017 
1018  /* Break the prev -> t link so it always holds within the loop. */
1019  t = t->Next();
1020  prev->SetNext(nullptr);
1021 
1022  /* Make sure the cache is cleared. */
1023  head->InvalidateNewGRFCache();
1024 
1025  while (t != nullptr) {
1026  allowed_len -= t->gcache.cached_veh_length;
1027 
1028  Train *next = t->Next();
1029 
1030  /* Unlink the to-be-added piece; it is already unlinked from the previous
1031  * part due to the fact that the prev -> t link is broken. */
1032  t->SetNext(nullptr);
1033 
1034  /* Don't check callback for articulated or rear dual headed parts */
1035  if (!t->IsArticulatedPart() && !t->IsRearDualheaded()) {
1036  /* Back up and clear the first_engine data to avoid using wagon override group */
1037  EngineID first_engine = t->gcache.first_engine;
1039 
1040  /* We don't want the cache to interfere. head's cache is cleared before
1041  * the loop and after each callback does not need to be cleared here. */
1042  t->InvalidateNewGRFCache();
1043 
1044  uint16_t callback = GetVehicleCallbackParent(CBID_TRAIN_ALLOW_WAGON_ATTACH, 0, 0, head->engine_type, t, head);
1045 
1046  /* Restore original first_engine data */
1047  t->gcache.first_engine = first_engine;
1048 
1049  /* We do not want to remember any cached variables from the test run */
1050  t->InvalidateNewGRFCache();
1051  head->InvalidateNewGRFCache();
1052 
1053  if (callback != CALLBACK_FAILED) {
1054  /* A failing callback means everything is okay */
1055  StringID error = STR_NULL;
1056 
1057  if (head->GetGRF()->grf_version < 8) {
1058  if (callback == 0xFD) error = STR_ERROR_INCOMPATIBLE_RAIL_TYPES;
1059  if (callback < 0xFD) error = GetGRFStringID(head->GetGRFID(), 0xD000 + callback);
1060  if (callback >= 0x100) ErrorUnknownCallbackResult(head->GetGRFID(), CBID_TRAIN_ALLOW_WAGON_ATTACH, callback);
1061  } else {
1062  if (callback < 0x400) {
1063  error = GetGRFStringID(head->GetGRFID(), 0xD000 + callback);
1064  } else {
1065  switch (callback) {
1066  case 0x400: // allow if railtypes match (always the case for OpenTTD)
1067  case 0x401: // allow
1068  break;
1069 
1070  default: // unknown reason -> disallow
1071  case 0x402: // disallow attaching
1072  error = STR_ERROR_INCOMPATIBLE_RAIL_TYPES;
1073  break;
1074  }
1075  }
1076  }
1077 
1078  if (error != STR_NULL) return_cmd_error(error);
1079  }
1080  }
1081 
1082  /* And link it to the new part. */
1083  prev->SetNext(t);
1084  prev = t;
1085  t = next;
1086  }
1087 
1088  if (allowed_len < 0) return_cmd_error(STR_ERROR_TRAIN_TOO_LONG);
1089  return CommandCost();
1090 }
1091 
1102 static CommandCost ValidateTrains(Train *original_dst, Train *dst, Train *original_src, Train *src, bool check_limit)
1103 {
1104  /* Check whether we may actually construct the trains. */
1105  CommandCost ret = CheckTrainAttachment(src);
1106  if (ret.Failed()) return ret;
1107  ret = CheckTrainAttachment(dst);
1108  if (ret.Failed()) return ret;
1109 
1110  /* Check whether we need to build a new train. */
1111  return check_limit ? CheckNewTrain(original_dst, dst, original_src, src) : CommandCost();
1112 }
1113 
1122 static void ArrangeTrains(Train **dst_head, Train *dst, Train **src_head, Train *src, bool move_chain)
1123 {
1124  /* First determine the front of the two resulting trains */
1125  if (*src_head == *dst_head) {
1126  /* If we aren't moving part(s) to a new train, we are just moving the
1127  * front back and there is not destination head. */
1128  *dst_head = nullptr;
1129  } else if (*dst_head == nullptr) {
1130  /* If we are moving to a new train the head of the move train would become
1131  * the head of the new vehicle. */
1132  *dst_head = src;
1133  }
1134 
1135  if (src == *src_head) {
1136  /* If we are moving the front of a train then we are, in effect, creating
1137  * a new head for the train. Point to that. Unless we are moving the whole
1138  * train in which case there is not 'source' train anymore.
1139  * In case we are a multiheaded part we want the complete thing to come
1140  * with us, so src->GetNextUnit(), however... when we are e.g. a wagon
1141  * that is followed by a rear multihead we do not want to include that. */
1142  *src_head = move_chain ? nullptr :
1143  (src->IsMultiheaded() ? src->GetNextUnit() : src->GetNextVehicle());
1144  }
1145 
1146  /* Now it's just simply removing the part that we are going to move from the
1147  * source train and *if* the destination is a not a new train add the chain
1148  * at the destination location. */
1149  RemoveFromConsist(src, move_chain);
1150  if (*dst_head != src) InsertInConsist(dst, src);
1151 
1152  /* Now normalise the dual heads, that is move the dual heads around in such
1153  * a way that the head and rear of a dual head are in the same train */
1154  NormaliseDualHeads(*src_head);
1155  NormaliseDualHeads(*dst_head);
1156 }
1157 
1163 static void NormaliseTrainHead(Train *head)
1164 {
1165  /* Not much to do! */
1166  if (head == nullptr) return;
1167 
1168  /* Tell the 'world' the train changed. */
1169  head->ConsistChanged(CCF_ARRANGE);
1170  UpdateTrainGroupID(head);
1171 
1172  /* Not a front engine, i.e. a free wagon chain. No need to do more. */
1173  if (!head->IsFrontEngine()) return;
1174 
1175  /* Update the refit button and window */
1178 
1179  /* If we don't have a unit number yet, set one. */
1180  if (head->unitnumber != 0) return;
1181  head->unitnumber = Company::Get(head->owner)->freeunits[head->type].UseID(GetFreeUnitNumber(VEH_TRAIN));
1182 }
1183 
1193 CommandCost CmdMoveRailVehicle(DoCommandFlag flags, VehicleID src_veh, VehicleID dest_veh, bool move_chain)
1194 {
1195  Train *src = Train::GetIfValid(src_veh);
1196  if (src == nullptr) return CMD_ERROR;
1197 
1198  CommandCost ret = CheckOwnership(src->owner);
1199  if (ret.Failed()) return ret;
1200 
1201  /* Do not allow moving crashed vehicles inside the depot, it is likely to cause asserts later */
1202  if (src->vehstatus & VS_CRASHED) return CMD_ERROR;
1203 
1204  /* if nothing is selected as destination, try and find a matching vehicle to drag to. */
1205  Train *dst;
1206  if (dest_veh == INVALID_VEHICLE) {
1207  dst = (src->IsEngine() || (flags & DC_AUTOREPLACE)) ? nullptr : FindGoodVehiclePos(src);
1208  } else {
1209  dst = Train::GetIfValid(dest_veh);
1210  if (dst == nullptr) return CMD_ERROR;
1211 
1212  ret = CheckOwnership(dst->owner);
1213  if (ret.Failed()) return ret;
1214 
1215  /* Do not allow appending to crashed vehicles, too */
1216  if (dst->vehstatus & VS_CRASHED) return CMD_ERROR;
1217  }
1218 
1219  /* if an articulated part is being handled, deal with its parent vehicle */
1220  src = src->GetFirstEnginePart();
1221  if (dst != nullptr) {
1222  dst = dst->GetFirstEnginePart();
1223  }
1224 
1225  /* don't move the same vehicle.. */
1226  if (src == dst) return CommandCost();
1227 
1228  /* locate the head of the two chains */
1229  Train *src_head = src->First();
1230  Train *dst_head;
1231  if (dst != nullptr) {
1232  dst_head = dst->First();
1233  if (dst_head->tile != src_head->tile) return CMD_ERROR;
1234  /* Now deal with articulated part of destination wagon */
1235  dst = dst->GetLastEnginePart();
1236  } else {
1237  dst_head = nullptr;
1238  }
1239 
1240  if (src->IsRearDualheaded()) return_cmd_error(STR_ERROR_REAR_ENGINE_FOLLOW_FRONT);
1241 
1242  /* When moving all wagons, we can't have the same src_head and dst_head */
1243  if (move_chain && src_head == dst_head) return CommandCost();
1244 
1245  /* When moving a multiheaded part to be place after itself, bail out. */
1246  if (!move_chain && dst != nullptr && dst->IsRearDualheaded() && src == dst->other_multiheaded_part) return CommandCost();
1247 
1248  /* Check if all vehicles in the source train are stopped inside a depot. */
1249  if (!src_head->IsStoppedInDepot()) return_cmd_error(STR_ERROR_TRAINS_CAN_ONLY_BE_ALTERED_INSIDE_A_DEPOT);
1250 
1251  /* Check if all vehicles in the destination train are stopped inside a depot. */
1252  if (dst_head != nullptr && !dst_head->IsStoppedInDepot()) return_cmd_error(STR_ERROR_TRAINS_CAN_ONLY_BE_ALTERED_INSIDE_A_DEPOT);
1253 
1254  /* First make a backup of the order of the trains. That way we can do
1255  * whatever we want with the order and later on easily revert. */
1256  TrainList original_src;
1257  TrainList original_dst;
1258 
1259  MakeTrainBackup(original_src, src_head);
1260  MakeTrainBackup(original_dst, dst_head);
1261 
1262  /* Also make backup of the original heads as ArrangeTrains can change them.
1263  * For the destination head we do not care if it is the same as the source
1264  * head because in that case it's just a copy. */
1265  Train *original_src_head = src_head;
1266  Train *original_dst_head = (dst_head == src_head ? nullptr : dst_head);
1267 
1268  /* We want this information from before the rearrangement, but execute this after the validation.
1269  * original_src_head can't be nullptr; src is by definition != nullptr, so src_head can't be nullptr as
1270  * src->GetFirst() always yields non-nullptr, so eventually original_src_head != nullptr as well. */
1271  bool original_src_head_front_engine = original_src_head->IsFrontEngine();
1272  bool original_dst_head_front_engine = original_dst_head != nullptr && original_dst_head->IsFrontEngine();
1273 
1274  /* (Re)arrange the trains in the wanted arrangement. */
1275  ArrangeTrains(&dst_head, dst, &src_head, src, move_chain);
1276 
1277  if ((flags & DC_AUTOREPLACE) == 0) {
1278  /* If the autoreplace flag is set we do not need to test for the validity
1279  * because we are going to revert the train to its original state. As we
1280  * assume the original state was correct autoreplace can skip this. */
1281  ret = ValidateTrains(original_dst_head, dst_head, original_src_head, src_head, true);
1282  if (ret.Failed()) {
1283  /* Restore the train we had. */
1284  RestoreTrainBackup(original_src);
1285  RestoreTrainBackup(original_dst);
1286  return ret;
1287  }
1288  }
1289 
1290  /* do it? */
1291  if (flags & DC_EXEC) {
1292  /* Remove old heads from the statistics */
1293  if (original_src_head_front_engine) GroupStatistics::CountVehicle(original_src_head, -1);
1294  if (original_dst_head_front_engine) GroupStatistics::CountVehicle(original_dst_head, -1);
1295 
1296  /* First normalise the sub types of the chains. */
1297  NormaliseSubtypes(src_head);
1298  NormaliseSubtypes(dst_head);
1299 
1300  /* There are 14 different cases:
1301  * 1) front engine gets moved to a new train, it stays a front engine.
1302  * a) the 'next' part is a wagon that becomes a free wagon chain.
1303  * b) the 'next' part is an engine that becomes a front engine.
1304  * c) there is no 'next' part, nothing else happens
1305  * 2) front engine gets moved to another train, it is not a front engine anymore
1306  * a) the 'next' part is a wagon that becomes a free wagon chain.
1307  * b) the 'next' part is an engine that becomes a front engine.
1308  * c) there is no 'next' part, nothing else happens
1309  * 3) front engine gets moved to later in the current train, it is not a front engine anymore.
1310  * a) the 'next' part is a wagon that becomes a free wagon chain.
1311  * b) the 'next' part is an engine that becomes a front engine.
1312  * 4) free wagon gets moved
1313  * a) the 'next' part is a wagon that becomes a free wagon chain.
1314  * b) the 'next' part is an engine that becomes a front engine.
1315  * c) there is no 'next' part, nothing else happens
1316  * 5) non front engine gets moved and becomes a new train, nothing else happens
1317  * 6) non front engine gets moved within a train / to another train, nothing happens
1318  * 7) wagon gets moved, nothing happens
1319  */
1320  if (src == original_src_head && src->IsEngine() && !src->IsFrontEngine()) {
1321  /* Cases #2 and #3: the front engine gets trashed. */
1327  DeleteNewGRFInspectWindow(GSF_TRAINS, src->index);
1329 
1330  if (src_head != nullptr && src_head->IsFrontEngine()) {
1331  /* Cases #?b: Transfer order, unit number and other stuff
1332  * to the new front engine. */
1333  src_head->orders = src->orders;
1334  if (src_head->orders != nullptr) src_head->AddToShared(src);
1335  src_head->CopyVehicleConfigAndStatistics(src);
1336  }
1337  /* Remove stuff not valid anymore for non-front engines. */
1338  DeleteVehicleOrders(src);
1339  src->ReleaseUnitNumber();
1340  src->name.clear();
1341  }
1342 
1343  /* We weren't a front engine but are becoming one. So
1344  * we should be put in the default group. */
1345  if (original_src_head != src && dst_head == src) {
1348  }
1349 
1350  /* Handle 'new engine' part of cases #1b, #2b, #3b, #4b and #5 in NormaliseTrainHead. */
1351  NormaliseTrainHead(src_head);
1352  NormaliseTrainHead(dst_head);
1353 
1354  /* Add new heads to statistics.
1355  * This should be done after NormaliseTrainHead due to engine total limit checks in GetFreeUnitNumber. */
1356  if (src_head != nullptr && src_head->IsFrontEngine()) GroupStatistics::CountVehicle(src_head, 1);
1357  if (dst_head != nullptr && dst_head->IsFrontEngine()) GroupStatistics::CountVehicle(dst_head, 1);
1358 
1359  if ((flags & DC_NO_CARGO_CAP_CHECK) == 0) {
1360  CheckCargoCapacity(src_head);
1361  CheckCargoCapacity(dst_head);
1362  }
1363 
1364  if (src_head != nullptr) src_head->First()->MarkDirty();
1365  if (dst_head != nullptr) dst_head->First()->MarkDirty();
1366 
1367  /* We are undoubtedly changing something in the depot and train list. */
1370  } else {
1371  /* We don't want to execute what we're just tried. */
1372  RestoreTrainBackup(original_src);
1373  RestoreTrainBackup(original_dst);
1374  }
1375 
1376  return CommandCost();
1377 }
1378 
1391 CommandCost CmdSellRailWagon(DoCommandFlag flags, Vehicle *t, bool sell_chain, bool backup_order, ClientID user)
1392 {
1393  Train *v = Train::From(t)->GetFirstEnginePart();
1394  Train *first = v->First();
1395 
1396  if (v->IsRearDualheaded()) return_cmd_error(STR_ERROR_REAR_ENGINE_FOLLOW_FRONT);
1397 
1398  /* First make a backup of the order of the train. That way we can do
1399  * whatever we want with the order and later on easily revert. */
1400  TrainList original;
1401  MakeTrainBackup(original, first);
1402 
1403  /* We need to keep track of the new head and the head of what we're going to sell. */
1404  Train *new_head = first;
1405  Train *sell_head = nullptr;
1406 
1407  /* Split the train in the wanted way. */
1408  ArrangeTrains(&sell_head, nullptr, &new_head, v, sell_chain);
1409 
1410  /* We don't need to validate the second train; it's going to be sold. */
1411  CommandCost ret = ValidateTrains(nullptr, nullptr, first, new_head, (flags & DC_AUTOREPLACE) == 0);
1412  if (ret.Failed()) {
1413  /* Restore the train we had. */
1414  RestoreTrainBackup(original);
1415  return ret;
1416  }
1417 
1418  if (first->orders == nullptr && !OrderList::CanAllocateItem()) {
1419  /* Restore the train we had. */
1420  RestoreTrainBackup(original);
1421  return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
1422  }
1423 
1425  for (Train *part = sell_head; part != nullptr; part = part->Next()) cost.AddCost(-part->value);
1426 
1427  /* do it? */
1428  if (flags & DC_EXEC) {
1429  /* First normalise the sub types of the chain. */
1430  NormaliseSubtypes(new_head);
1431 
1432  if (v == first && !sell_chain && new_head != nullptr && new_head->IsFrontEngine()) {
1433  if (v->IsEngine()) {
1434  /* We are selling the front engine. In this case we want to
1435  * 'give' the order, unit number and such to the new head. */
1436  new_head->orders = first->orders;
1437  new_head->AddToShared(first);
1438  DeleteVehicleOrders(first);
1439 
1440  /* Copy other important data from the front engine */
1441  new_head->CopyVehicleConfigAndStatistics(first);
1442  }
1443  GroupStatistics::CountVehicle(new_head, 1); // after copying over the profit, if required
1444  } else if (v->IsPrimaryVehicle() && backup_order) {
1445  OrderBackup::Backup(v, user);
1446  }
1447 
1448  /* We need to update the information about the train. */
1449  NormaliseTrainHead(new_head);
1450 
1451  /* We are undoubtedly changing something in the depot and train list. */
1454 
1455  /* Actually delete the sold 'goods' */
1456  delete sell_head;
1457  } else {
1458  /* We don't want to execute what we're just tried. */
1459  RestoreTrainBackup(original);
1460  }
1461 
1462  return cost;
1463 }
1464 
1466 {
1467  /* Set common defaults. */
1468  this->x_offs = -1;
1469  this->y_offs = -1;
1470  this->x_extent = 3;
1471  this->y_extent = 3;
1472  this->z_extent = 6;
1473  this->x_bb_offs = 0;
1474  this->y_bb_offs = 0;
1475 
1476  /* Set if flipped and engine is NOT flagged with custom flip handling. */
1477  int flipped = HasBit(this->flags, VRF_REVERSE_DIRECTION) && !HasBit(EngInfo(this->engine_type)->misc_flags, EF_RAIL_FLIPS);
1478  /* If flipped and vehicle length is odd, we need to adjust the bounding box offset slightly. */
1479  int flip_offs = flipped && (this->gcache.cached_veh_length & 1);
1480 
1481  Direction dir = this->direction;
1482  if (flipped) dir = ReverseDir(dir);
1483 
1484  if (!IsDiagonalDirection(dir)) {
1485  static const int _sign_table[] =
1486  {
1487  /* x, y */
1488  -1, -1, // DIR_N
1489  -1, 1, // DIR_E
1490  1, 1, // DIR_S
1491  1, -1, // DIR_W
1492  };
1493 
1494  int half_shorten = (VEHICLE_LENGTH - this->gcache.cached_veh_length + flipped) / 2;
1495 
1496  /* For all straight directions, move the bound box to the centre of the vehicle, but keep the size. */
1497  this->x_offs -= half_shorten * _sign_table[dir];
1498  this->y_offs -= half_shorten * _sign_table[dir + 1];
1499  this->x_extent += this->x_bb_offs = half_shorten * _sign_table[dir];
1500  this->y_extent += this->y_bb_offs = half_shorten * _sign_table[dir + 1];
1501  } else {
1502  switch (dir) {
1503  /* Shorten southern corner of the bounding box according the vehicle length
1504  * and center the bounding box on the vehicle. */
1505  case DIR_NE:
1506  this->x_offs = 1 - (this->gcache.cached_veh_length + 1) / 2 + flip_offs;
1507  this->x_extent = this->gcache.cached_veh_length - 1;
1508  this->x_bb_offs = -1;
1509  break;
1510 
1511  case DIR_NW:
1512  this->y_offs = 1 - (this->gcache.cached_veh_length + 1) / 2 + flip_offs;
1513  this->y_extent = this->gcache.cached_veh_length - 1;
1514  this->y_bb_offs = -1;
1515  break;
1516 
1517  /* Move northern corner of the bounding box down according to vehicle length
1518  * and center the bounding box on the vehicle. */
1519  case DIR_SW:
1520  this->x_offs = 1 + (this->gcache.cached_veh_length + 1) / 2 - VEHICLE_LENGTH - flip_offs;
1521  this->x_extent = VEHICLE_LENGTH - 1;
1522  this->x_bb_offs = VEHICLE_LENGTH - this->gcache.cached_veh_length - 1;
1523  break;
1524 
1525  case DIR_SE:
1526  this->y_offs = 1 + (this->gcache.cached_veh_length + 1) / 2 - VEHICLE_LENGTH - flip_offs;
1527  this->y_extent = VEHICLE_LENGTH - 1;
1528  this->y_bb_offs = VEHICLE_LENGTH - this->gcache.cached_veh_length - 1;
1529  break;
1530 
1531  default:
1532  NOT_REACHED();
1533  }
1534  }
1535 }
1536 
1541 static void MarkTrainAsStuck(Train *v)
1542 {
1543  if (!HasBit(v->flags, VRF_TRAIN_STUCK)) {
1544  /* It is the first time the problem occurred, set the "train stuck" flag. */
1545  SetBit(v->flags, VRF_TRAIN_STUCK);
1546 
1547  v->wait_counter = 0;
1548 
1549  /* Stop train */
1550  v->cur_speed = 0;
1551  v->subspeed = 0;
1552  v->SetLastSpeed();
1553 
1555  }
1556 }
1557 
1565 static void SwapTrainFlags(uint16_t *swap_flag1, uint16_t *swap_flag2)
1566 {
1567  uint16_t flag1 = *swap_flag1;
1568  uint16_t flag2 = *swap_flag2;
1569 
1570  /* Clear the flags */
1571  ClrBit(*swap_flag1, GVF_GOINGUP_BIT);
1572  ClrBit(*swap_flag1, GVF_GOINGDOWN_BIT);
1573  ClrBit(*swap_flag2, GVF_GOINGUP_BIT);
1574  ClrBit(*swap_flag2, GVF_GOINGDOWN_BIT);
1575 
1576  /* Reverse the rail-flags (if needed) */
1577  if (HasBit(flag1, GVF_GOINGUP_BIT)) {
1578  SetBit(*swap_flag2, GVF_GOINGDOWN_BIT);
1579  } else if (HasBit(flag1, GVF_GOINGDOWN_BIT)) {
1580  SetBit(*swap_flag2, GVF_GOINGUP_BIT);
1581  }
1582  if (HasBit(flag2, GVF_GOINGUP_BIT)) {
1583  SetBit(*swap_flag1, GVF_GOINGDOWN_BIT);
1584  } else if (HasBit(flag2, GVF_GOINGDOWN_BIT)) {
1585  SetBit(*swap_flag1, GVF_GOINGUP_BIT);
1586  }
1587 }
1588 
1594 {
1595  /* Reverse the direction. */
1596  if (v->track != TRACK_BIT_DEPOT) v->direction = ReverseDir(v->direction);
1597 
1598  /* Call the proper EnterTile function unless we are in a wormhole. */
1599  if (v->track != TRACK_BIT_WORMHOLE) {
1600  VehicleEnterTile(v, v->tile, v->x_pos, v->y_pos);
1601  } else {
1602  /* VehicleEnter_TunnelBridge() sets TRACK_BIT_WORMHOLE when the vehicle
1603  * is on the last bit of the bridge head (frame == TILE_SIZE - 1).
1604  * If we were swapped with such a vehicle, we have set TRACK_BIT_WORMHOLE,
1605  * when we shouldn't have. Check if this is the case. */
1606  TileIndex vt = TileVirtXY(v->x_pos, v->y_pos);
1607  if (IsTileType(vt, MP_TUNNELBRIDGE)) {
1608  VehicleEnterTile(v, vt, v->x_pos, v->y_pos);
1609  if (v->track != TRACK_BIT_WORMHOLE && IsBridgeTile(v->tile)) {
1610  /* We have just left the wormhole, possibly set the
1611  * "goingdown" bit. UpdateInclination() can be used
1612  * because we are at the border of the tile. */
1613  v->UpdatePosition();
1614  v->UpdateInclination(true, true);
1615  return;
1616  }
1617  }
1618  }
1619 
1620  v->UpdatePosition();
1621  v->UpdateViewport(true, true);
1622 }
1623 
1630 void ReverseTrainSwapVeh(Train *v, int l, int r)
1631 {
1632  Train *a, *b;
1633 
1634  /* locate vehicles to swap */
1635  for (a = v; l != 0; l--) a = a->Next();
1636  for (b = v; r != 0; r--) b = b->Next();
1637 
1638  if (a != b) {
1639  /* swap the hidden bits */
1640  {
1641  uint16_t tmp = (a->vehstatus & ~VS_HIDDEN) | (b->vehstatus & VS_HIDDEN);
1642  b->vehstatus = (b->vehstatus & ~VS_HIDDEN) | (a->vehstatus & VS_HIDDEN);
1643  a->vehstatus = tmp;
1644  }
1645 
1646  Swap(a->track, b->track);
1647  Swap(a->direction, b->direction);
1648  Swap(a->x_pos, b->x_pos);
1649  Swap(a->y_pos, b->y_pos);
1650  Swap(a->tile, b->tile);
1651  Swap(a->z_pos, b->z_pos);
1652 
1653  SwapTrainFlags(&a->gv_flags, &b->gv_flags);
1654 
1657  } else {
1658  /* Swap GVF_GOINGUP_BIT/GVF_GOINGDOWN_BIT.
1659  * This is a little bit redundant way, a->gv_flags will
1660  * be (re)set twice, but it reduces code duplication */
1661  SwapTrainFlags(&a->gv_flags, &a->gv_flags);
1663  }
1664 }
1665 
1666 
1672 static Vehicle *TrainOnTileEnum(Vehicle *v, void *)
1673 {
1674  return (v->type == VEH_TRAIN) ? v : nullptr;
1675 }
1676 
1684 {
1685  assert(IsLevelCrossingTile(tile));
1686 
1687  return HasVehicleOnPos(tile, nullptr, &TrainOnTileEnum);
1688 }
1689 
1690 
1698 {
1699  if (v->type != VEH_TRAIN || (v->vehstatus & VS_CRASHED)) return nullptr;
1700 
1701  Train *t = Train::From(v);
1702  if (!t->IsFrontEngine()) return nullptr;
1703 
1704  TileIndex tile = *(TileIndex *)data;
1705 
1706  if (TrainApproachingCrossingTile(t) != tile) return nullptr;
1707 
1708  return t;
1709 }
1710 
1711 
1719 {
1720  assert(IsLevelCrossingTile(tile));
1721 
1723  TileIndex tile_from = tile + TileOffsByDiagDir(dir);
1724 
1725  if (HasVehicleOnPos(tile_from, &tile, &TrainApproachingCrossingEnum)) return true;
1726 
1727  dir = ReverseDiagDir(dir);
1728  tile_from = tile + TileOffsByDiagDir(dir);
1729 
1730  return HasVehicleOnPos(tile_from, &tile, &TrainApproachingCrossingEnum);
1731 }
1732 
1738 static inline bool CheckLevelCrossing(TileIndex tile)
1739 {
1740  /* reserved || train on crossing || train approaching crossing */
1741  return HasCrossingReservation(tile) || TrainOnCrossing(tile) || TrainApproachingCrossing(tile);
1742 }
1743 
1751 static void UpdateLevelCrossingTile(TileIndex tile, bool sound, bool force_barred)
1752 {
1753  assert(IsLevelCrossingTile(tile));
1754  bool set_barred;
1755 
1756  /* We force the crossing to be barred when an adjacent crossing is barred, otherwise let it decide for itself. */
1757  set_barred = force_barred || CheckLevelCrossing(tile);
1758 
1759  /* The state has changed */
1760  if (set_barred != IsCrossingBarred(tile)) {
1761  if (set_barred && sound && _settings_client.sound.ambient) SndPlayTileFx(SND_0E_LEVEL_CROSSING, tile);
1762  SetCrossingBarred(tile, set_barred);
1763  MarkTileDirtyByTile(tile);
1764  }
1765 }
1766 
1773 void UpdateLevelCrossing(TileIndex tile, bool sound, bool force_bar)
1774 {
1775  if (!IsLevelCrossingTile(tile)) return;
1776 
1777  bool forced_state = force_bar;
1778 
1779  const Axis axis = GetCrossingRoadAxis(tile);
1780  const DiagDirection dir1 = AxisToDiagDir(axis);
1781  const DiagDirection dir2 = ReverseDiagDir(dir1);
1782 
1783  /* Check if an adjacent crossing is barred. */
1784  for (DiagDirection dir : { dir1, dir2 }) {
1785  for (TileIndex t = tile; !forced_state && t < Map::Size() && IsLevelCrossingTile(t) && GetCrossingRoadAxis(t) == axis; t = TileAddByDiagDir(t, dir)) {
1786  forced_state |= CheckLevelCrossing(t);
1787  }
1788  }
1789 
1790  /* Now that we know whether all tiles in this crossing should be barred or open,
1791  * we need to update those tiles. We start with the tile itself, then look along the road axis. */
1792  UpdateLevelCrossingTile(tile, sound, forced_state);
1793  for (DiagDirection dir : { dir1, dir2 }) {
1794  for (TileIndex t = TileAddByDiagDir(tile, dir); t < Map::Size() && IsLevelCrossingTile(t) && GetCrossingRoadAxis(t) == axis; t = TileAddByDiagDir(t, dir)) {
1795  UpdateLevelCrossingTile(t, sound, forced_state);
1796  }
1797  }
1798 }
1799 
1806 {
1807  const DiagDirection dir1 = AxisToDiagDir(road_axis);
1808  const DiagDirection dir2 = ReverseDiagDir(dir1);
1809  for (DiagDirection dir : { dir1, dir2 }) {
1810  const TileIndex t = TileAddByDiagDir(tile, dir);
1811  if (t < Map::Size() && IsLevelCrossingTile(t) && GetCrossingRoadAxis(t) == road_axis) {
1813  }
1814  }
1815 }
1816 
1823 {
1824  const DiagDirection dir1 = AxisToDiagDir(road_axis);
1825  const DiagDirection dir2 = ReverseDiagDir(dir1);
1826  for (DiagDirection dir : { dir1, dir2 }) {
1827  const TileIndexDiff diff = TileOffsByDiagDir(dir);
1828  bool occupied = false;
1829  for (TileIndex t = tile + diff; t < Map::Size() && IsLevelCrossingTile(t) && GetCrossingRoadAxis(t) == road_axis; t += diff) {
1830  occupied |= CheckLevelCrossing(t);
1831  }
1832  if (occupied) {
1833  /* Mark the immediately adjacent tile dirty */
1834  const TileIndex t = tile + diff;
1835  if (t < Map::Size() && IsLevelCrossingTile(t) && GetCrossingRoadAxis(t) == road_axis) {
1837  }
1838  } else {
1839  /* Unbar the crossing tiles in this direction as necessary */
1840  for (TileIndex t = tile + diff; t < Map::Size() && IsLevelCrossingTile(t) && GetCrossingRoadAxis(t) == road_axis; t += diff) {
1841  if (IsCrossingBarred(t)) {
1842  /* The crossing tile is barred, unbar it and continue to check the next tile */
1843  SetCrossingBarred(t, false);
1845  } else {
1846  /* The crossing tile is already unbarred, mark the tile dirty and stop checking */
1848  break;
1849  }
1850  }
1851  }
1852  }
1853 }
1854 
1860 static inline void MaybeBarCrossingWithSound(TileIndex tile)
1861 {
1862  if (!IsCrossingBarred(tile)) {
1863  SetCrossingReservation(tile, true);
1864  UpdateLevelCrossing(tile, true);
1865  }
1866 }
1867 
1868 
1875 {
1876  Train *base = v;
1877  Train *first = base; // first vehicle to move
1878  Train *last = v->Last(); // last vehicle to move
1879  uint length = CountVehiclesInChain(v);
1880 
1881  while (length > 2) {
1882  last = last->Previous();
1883  first = first->Next();
1884 
1885  int differential = base->CalcNextVehicleOffset() - last->CalcNextVehicleOffset();
1886 
1887  /* do not update images now
1888  * negative differential will be handled in AdvanceWagonsAfterSwap() */
1889  for (int i = 0; i < differential; i++) TrainController(first, last->Next());
1890 
1891  base = first; // == base->Next()
1892  length -= 2;
1893  }
1894 }
1895 
1896 
1903 {
1904  /* first of all, fix the situation when the train was entering a depot */
1905  Train *dep = v; // last vehicle in front of just left depot
1906  while (dep->Next() != nullptr && (dep->track == TRACK_BIT_DEPOT || dep->Next()->track != TRACK_BIT_DEPOT)) {
1907  dep = dep->Next(); // find first vehicle outside of a depot, with next vehicle inside a depot
1908  }
1909 
1910  Train *leave = dep->Next(); // first vehicle in a depot we are leaving now
1911 
1912  if (leave != nullptr) {
1913  /* 'pull' next wagon out of the depot, so we won't miss it (it could stay in depot forever) */
1914  int d = TicksToLeaveDepot(dep);
1915 
1916  if (d <= 0) {
1917  leave->vehstatus &= ~VS_HIDDEN; // move it out of the depot
1918  leave->track = TrackToTrackBits(GetRailDepotTrack(leave->tile));
1919  for (int i = 0; i >= d; i--) TrainController(leave, nullptr); // maybe move it, and maybe let another wagon leave
1920  }
1921  } else {
1922  dep = nullptr; // no vehicle in a depot, so no vehicle leaving a depot
1923  }
1924 
1925  Train *base = v;
1926  Train *first = base; // first vehicle to move
1927  Train *last = v->Last(); // last vehicle to move
1928  uint length = CountVehiclesInChain(v);
1929 
1930  /* We have to make sure all wagons that leave a depot because of train reversing are moved correctly
1931  * they have already correct spacing, so we have to make sure they are moved how they should */
1932  bool nomove = (dep == nullptr); // If there is no vehicle leaving a depot, limit the number of wagons moved immediately.
1933 
1934  while (length > 2) {
1935  /* we reached vehicle (originally) in front of a depot, stop now
1936  * (we would move wagons that are already moved with new wagon length). */
1937  if (base == dep) break;
1938 
1939  /* the last wagon was that one leaving a depot, so do not move it anymore */
1940  if (last == dep) nomove = true;
1941 
1942  last = last->Previous();
1943  first = first->Next();
1944 
1945  int differential = last->CalcNextVehicleOffset() - base->CalcNextVehicleOffset();
1946 
1947  /* do not update images now */
1948  for (int i = 0; i < differential; i++) TrainController(first, (nomove ? last->Next() : nullptr));
1949 
1950  base = first; // == base->Next()
1951  length -= 2;
1952  }
1953 }
1954 
1955 static bool IsWholeTrainInsideDepot(const Train *v)
1956 {
1957  for (const Train *u = v; u != nullptr; u = u->Next()) {
1958  if (u->track != TRACK_BIT_DEPOT || u->tile != v->tile) return false;
1959  }
1960  return true;
1961 }
1962 
1968 {
1969  if (IsRailDepotTile(v->tile)) {
1970  if (IsWholeTrainInsideDepot(v)) return;
1972  }
1973 
1974  /* Clear path reservation in front if train is not stuck. */
1975  if (!HasBit(v->flags, VRF_TRAIN_STUCK)) FreeTrainTrackReservation(v);
1976 
1977  /* Check if we were approaching a rail/road-crossing */
1979 
1980  /* count number of vehicles */
1981  int r = CountVehiclesInChain(v) - 1; // number of vehicles - 1
1982 
1984 
1985  /* swap start<>end, start+1<>end-1, ... */
1986  int l = 0;
1987  do {
1988  ReverseTrainSwapVeh(v, l++, r--);
1989  } while (l <= r);
1990 
1992 
1993  if (IsRailDepotTile(v->tile)) {
1995  }
1996 
1997  ToggleBit(v->flags, VRF_TOGGLE_REVERSE);
1998 
1999  ClrBit(v->flags, VRF_REVERSING);
2000 
2001  /* recalculate cached data */
2003 
2004  /* update all images */
2005  for (Train *u = v; u != nullptr; u = u->Next()) u->UpdateViewport(false, false);
2006 
2007  /* update crossing we were approaching */
2008  if (crossing != INVALID_TILE) UpdateLevelCrossing(crossing);
2009 
2010  /* maybe we are approaching crossing now, after reversal */
2011  crossing = TrainApproachingCrossingTile(v);
2012  if (crossing != INVALID_TILE) MaybeBarCrossingWithSound(crossing);
2013 
2014  /* If we are inside a depot after reversing, don't bother with path reserving. */
2015  if (v->track == TRACK_BIT_DEPOT) {
2016  /* Can't be stuck here as inside a depot is always a safe tile. */
2018  ClrBit(v->flags, VRF_TRAIN_STUCK);
2019  return;
2020  }
2021 
2022  /* VehicleExitDir does not always produce the desired dir for depots and
2023  * tunnels/bridges that is needed for UpdateSignalsOnSegment. */
2024  DiagDirection dir = VehicleExitDir(v->direction, v->track);
2026 
2028  /* If we are currently on a tile with conventional signals, we can't treat the
2029  * current tile as a safe tile or we would enter a PBS block without a reservation. */
2030  bool first_tile_okay = !(IsTileType(v->tile, MP_RAILWAY) &&
2032  !IsPbsSignal(GetSignalType(v->tile, FindFirstTrack(v->track))));
2033 
2034  /* If we are on a depot tile facing outwards, do not treat the current tile as safe. */
2035  if (IsRailDepotTile(v->tile) && TrackdirToExitdir(v->GetVehicleTrackdir()) == GetRailDepotDirection(v->tile)) first_tile_okay = false;
2036 
2038  if (TryPathReserve(v, false, first_tile_okay)) {
2039  /* Do a look-ahead now in case our current tile was already a safe tile. */
2040  CheckNextTrainTile(v);
2041  } else if (v->current_order.GetType() != OT_LOADING) {
2042  /* Do not wait for a way out when we're still loading */
2043  MarkTrainAsStuck(v);
2044  }
2045  } else if (HasBit(v->flags, VRF_TRAIN_STUCK)) {
2046  /* A train not inside a PBS block can't be stuck. */
2047  ClrBit(v->flags, VRF_TRAIN_STUCK);
2048  v->wait_counter = 0;
2049  }
2050 }
2051 
2059 CommandCost CmdReverseTrainDirection(DoCommandFlag flags, VehicleID veh_id, bool reverse_single_veh)
2060 {
2061  Train *v = Train::GetIfValid(veh_id);
2062  if (v == nullptr) return CMD_ERROR;
2063 
2064  CommandCost ret = CheckOwnership(v->owner);
2065  if (ret.Failed()) return ret;
2066 
2067  if (reverse_single_veh) {
2068  /* turn a single unit around */
2069 
2071  return_cmd_error(STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE_MULTIPLE_UNITS);
2072  }
2073 
2074  Train *front = v->First();
2075  /* make sure the vehicle is stopped in the depot */
2076  if (!front->IsStoppedInDepot()) {
2077  return_cmd_error(STR_ERROR_TRAINS_CAN_ONLY_BE_ALTERED_INSIDE_A_DEPOT);
2078  }
2079 
2080  if (flags & DC_EXEC) {
2081  ToggleBit(v->flags, VRF_REVERSE_DIRECTION);
2082 
2083  front->ConsistChanged(CCF_ARRANGE);
2088  }
2089  } else {
2090  /* turn the whole train around */
2091  if (!v->IsPrimaryVehicle()) return CMD_ERROR;
2092  if ((v->vehstatus & VS_CRASHED) || v->breakdown_ctr != 0) return CMD_ERROR;
2093 
2094  if (flags & DC_EXEC) {
2095  /* Properly leave the station if we are loading and won't be loading anymore */
2096  if (v->current_order.IsType(OT_LOADING)) {
2097  const Vehicle *last = v;
2098  while (last->Next() != nullptr) last = last->Next();
2099 
2100  /* not a station || different station --> leave the station */
2101  if (!IsTileType(last->tile, MP_STATION) || GetStationIndex(last->tile) != GetStationIndex(v->tile)) {
2102  v->LeaveStation();
2103  }
2104  }
2105 
2106  /* We cancel any 'skip signal at dangers' here */
2107  v->force_proceed = TFP_NONE;
2109 
2110  if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL && v->cur_speed != 0) {
2111  ToggleBit(v->flags, VRF_REVERSING);
2112  } else {
2113  v->cur_speed = 0;
2114  v->SetLastSpeed();
2117  }
2118 
2119  /* Unbunching data is no longer valid. */
2120  v->ResetDepotUnbunching();
2121  }
2122  }
2123  return CommandCost();
2124 }
2125 
2133 {
2134  Train *t = Train::GetIfValid(veh_id);
2135  if (t == nullptr) return CMD_ERROR;
2136 
2137  if (!t->IsPrimaryVehicle()) return CMD_ERROR;
2138 
2139  CommandCost ret = CheckOwnership(t->owner);
2140  if (ret.Failed()) return ret;
2141 
2142 
2143  if (flags & DC_EXEC) {
2144  /* If we are forced to proceed, cancel that order.
2145  * If we are marked stuck we would want to force the train
2146  * to proceed to the next signal. In the other cases we
2147  * would like to pass the signal at danger and run till the
2148  * next signal we encounter. */
2149  t->force_proceed = t->force_proceed == TFP_SIGNAL ? TFP_NONE : HasBit(t->flags, VRF_TRAIN_STUCK) || t->IsChainInDepot() ? TFP_STUCK : TFP_SIGNAL;
2151 
2152  /* Unbunching data is no longer valid. */
2153  t->ResetDepotUnbunching();
2154  }
2155 
2156  return CommandCost();
2157 }
2158 
2166 static FindDepotData FindClosestTrainDepot(Train *v, int max_distance)
2167 {
2168  assert(!(v->vehstatus & VS_CRASHED));
2169 
2170  if (IsRailDepotTile(v->tile)) return FindDepotData(v->tile, 0);
2171 
2172  PBSTileInfo origin = FollowTrainReservation(v);
2173  if (IsRailDepotTile(origin.tile)) return FindDepotData(origin.tile, 0);
2174 
2175  return YapfTrainFindNearestDepot(v, max_distance);
2176 }
2177 
2179 {
2180  FindDepotData tfdd = FindClosestTrainDepot(this, 0);
2181  if (tfdd.best_length == UINT_MAX) return ClosestDepot();
2182 
2183  return ClosestDepot(tfdd.tile, GetDepotIndex(tfdd.tile), tfdd.reverse);
2184 }
2185 
2187 void Train::PlayLeaveStationSound(bool force) const
2188 {
2189  static const SoundFx sfx[] = {
2195  };
2196 
2197  if (PlayVehicleSound(this, VSE_START, force)) return;
2198 
2199  SndPlayVehicleFx(sfx[RailVehInfo(this->engine_type)->engclass], this);
2200 }
2201 
2206 static void CheckNextTrainTile(Train *v)
2207 {
2208  /* Don't do any look-ahead if path_backoff_interval is 255. */
2209  if (_settings_game.pf.path_backoff_interval == 255) return;
2210 
2211  /* Exit if we are inside a depot. */
2212  if (v->track == TRACK_BIT_DEPOT) return;
2213 
2214  switch (v->current_order.GetType()) {
2215  /* Exit if we reached our destination depot. */
2216  case OT_GOTO_DEPOT:
2217  if (v->tile == v->dest_tile) return;
2218  break;
2219 
2220  case OT_GOTO_WAYPOINT:
2221  /* If we reached our waypoint, make sure we see that. */
2223  break;
2224 
2225  case OT_NOTHING:
2226  case OT_LEAVESTATION:
2227  case OT_LOADING:
2228  /* Exit if the current order doesn't have a destination, but the train has orders. */
2229  if (v->GetNumOrders() > 0) return;
2230  break;
2231 
2232  default:
2233  break;
2234  }
2235  /* Exit if we are on a station tile and are going to stop. */
2237 
2238  Trackdir td = v->GetVehicleTrackdir();
2239 
2240  /* On a tile with a red non-pbs signal, don't look ahead. */
2241  if (IsTileType(v->tile, MP_RAILWAY) && HasSignalOnTrackdir(v->tile, td) &&
2242  !IsPbsSignal(GetSignalType(v->tile, TrackdirToTrack(td))) &&
2243  GetSignalStateByTrackdir(v->tile, td) == SIGNAL_STATE_RED) return;
2244 
2245  CFollowTrackRail ft(v);
2246  if (!ft.Follow(v->tile, td)) return;
2247 
2249  /* Next tile is not reserved. */
2252  /* If the next tile is a PBS signal, try to make a reservation. */
2255  tracks &= ~TrackCrossesTracks(TrackdirToTrack(ft.old_td));
2256  }
2257  ChooseTrainTrack(v, ft.new_tile, ft.exitdir, tracks, false, nullptr, false);
2258  }
2259  }
2260  }
2261 }
2262 
2269 {
2270  /* bail out if not all wagons are in the same depot or not in a depot at all */
2271  for (const Train *u = v; u != nullptr; u = u->Next()) {
2272  if (u->track != TRACK_BIT_DEPOT || u->tile != v->tile) return false;
2273  }
2274 
2275  /* if the train got no power, then keep it in the depot */
2276  if (v->gcache.cached_power == 0) {
2277  v->vehstatus |= VS_STOPPED;
2279  return true;
2280  }
2281 
2282  /* Check if we should wait here for unbunching. */
2283  if (v->IsWaitingForUnbunching()) return true;
2284 
2285  SigSegState seg_state;
2286 
2287  if (v->force_proceed == TFP_NONE) {
2288  /* force proceed was not pressed */
2289  if (++v->wait_counter < 37) {
2291  return true;
2292  }
2293 
2294  v->wait_counter = 0;
2295 
2297  if (seg_state == SIGSEG_FULL || HasDepotReservation(v->tile)) {
2298  /* Full and no PBS signal in block or depot reserved, can't exit. */
2300  return true;
2301  }
2302  } else {
2304  }
2305 
2306  /* We are leaving a depot, but have to go to the exact same one; re-enter. */
2307  if (v->current_order.IsType(OT_GOTO_DEPOT) && v->tile == v->dest_tile) {
2308  /* Service when depot has no reservation. */
2310  return true;
2311  }
2312 
2313  /* Only leave when we can reserve a path to our destination. */
2314  if (seg_state == SIGSEG_PBS && !TryPathReserve(v) && v->force_proceed == TFP_NONE) {
2315  /* No path and no force proceed. */
2317  MarkTrainAsStuck(v);
2318  return true;
2319  }
2320 
2321  SetDepotReservation(v->tile, true);
2323 
2325  v->LeaveUnbunchingDepot();
2326  v->PlayLeaveStationSound();
2328 
2329  v->track = TRACK_BIT_X;
2330  if (v->direction & 2) v->track = TRACK_BIT_Y;
2331 
2332  v->vehstatus &= ~VS_HIDDEN;
2333  v->cur_speed = 0;
2334 
2335  v->UpdateViewport(true, true);
2336  v->UpdatePosition();
2338  v->UpdateAcceleration();
2340 
2341  return false;
2342 }
2343 
2350 static void ClearPathReservation(const Train *v, TileIndex tile, Trackdir track_dir)
2351 {
2352  DiagDirection dir = TrackdirToExitdir(track_dir);
2353 
2354  if (IsTileType(tile, MP_TUNNELBRIDGE)) {
2355  /* Are we just leaving a tunnel/bridge? */
2356  if (GetTunnelBridgeDirection(tile) == ReverseDiagDir(dir)) {
2357  TileIndex end = GetOtherTunnelBridgeEnd(tile);
2358 
2359  if (TunnelBridgeIsFree(tile, end, v).Succeeded()) {
2360  /* Free the reservation only if no other train is on the tiles. */
2361  SetTunnelBridgeReservation(tile, false);
2362  SetTunnelBridgeReservation(end, false);
2363 
2365  if (IsBridge(tile)) {
2366  MarkBridgeDirty(tile);
2367  } else {
2368  MarkTileDirtyByTile(tile);
2369  MarkTileDirtyByTile(end);
2370  }
2371  }
2372  }
2373  }
2374  } else if (IsRailStationTile(tile)) {
2375  TileIndex new_tile = TileAddByDiagDir(tile, dir);
2376  /* If the new tile is not a further tile of the same station, we
2377  * clear the reservation for the whole platform. */
2378  if (!IsCompatibleTrainStationTile(new_tile, tile)) {
2380  }
2381  } else {
2382  /* Any other tile */
2383  UnreserveRailTrack(tile, TrackdirToTrack(track_dir));
2384  }
2385 }
2386 
2392 {
2393  assert(v->IsFrontEngine());
2394 
2395  TileIndex tile = v->tile;
2396  Trackdir td = v->GetVehicleTrackdir();
2397  bool free_tile = !(IsRailStationTile(v->tile) || IsTileType(v->tile, MP_TUNNELBRIDGE));
2398  StationID station_id = IsRailStationTile(v->tile) ? GetStationIndex(v->tile) : INVALID_STATION;
2399 
2400  /* Can't be holding a reservation if we enter a depot. */
2401  if (IsRailDepotTile(tile) && TrackdirToExitdir(td) != GetRailDepotDirection(tile)) return;
2402  if (v->track == TRACK_BIT_DEPOT) {
2403  /* Front engine is in a depot. We enter if some part is not in the depot. */
2404  for (const Train *u = v; u != nullptr; u = u->Next()) {
2405  if (u->track != TRACK_BIT_DEPOT || u->tile != v->tile) return;
2406  }
2407  }
2408  /* Don't free reservation if it's not ours. */
2410 
2412  while (ft.Follow(tile, td)) {
2413  tile = ft.new_tile;
2415  td = RemoveFirstTrackdir(&bits);
2416  assert(bits == TRACKDIR_BIT_NONE);
2417 
2418  if (!IsValidTrackdir(td)) break;
2419 
2420  if (IsTileType(tile, MP_RAILWAY)) {
2421  if (HasSignalOnTrackdir(tile, td) && !IsPbsSignal(GetSignalType(tile, TrackdirToTrack(td)))) {
2422  /* Conventional signal along trackdir: remove reservation and stop. */
2424  break;
2425  }
2426  if (HasPbsSignalOnTrackdir(tile, td)) {
2427  if (GetSignalStateByTrackdir(tile, td) == SIGNAL_STATE_RED) {
2428  /* Red PBS signal? Can't be our reservation, would be green then. */
2429  break;
2430  } else {
2431  /* Turn the signal back to red. */
2433  MarkTileDirtyByTile(tile);
2434  }
2435  } else if (HasPbsSignalOnTrackdir(tile, ReverseTrackdir(td))) {
2436  /* Reservation passes an opposing path signal. Mark signal for update to re-establish the proper default state. */
2438  } else if (HasSignalOnTrackdir(tile, ReverseTrackdir(td)) && IsOnewaySignal(tile, TrackdirToTrack(td))) {
2439  break;
2440  }
2441  }
2442 
2443  /* Don't free first station/bridge/tunnel if we are on it. */
2444  if (free_tile || (!(ft.is_station && GetStationIndex(ft.new_tile) == station_id) && !ft.is_tunnel && !ft.is_bridge)) ClearPathReservation(v, tile, td);
2445 
2446  free_tile = true;
2447  }
2448 
2450 }
2451 
2452 static const uint8_t _initial_tile_subcoord[6][4][3] = {
2453 {{ 15, 8, 1 }, { 0, 0, 0 }, { 0, 8, 5 }, { 0, 0, 0 }},
2454 {{ 0, 0, 0 }, { 8, 0, 3 }, { 0, 0, 0 }, { 8, 15, 7 }},
2455 {{ 0, 0, 0 }, { 7, 0, 2 }, { 0, 7, 6 }, { 0, 0, 0 }},
2456 {{ 15, 8, 2 }, { 0, 0, 0 }, { 0, 0, 0 }, { 8, 15, 6 }},
2457 {{ 15, 7, 0 }, { 8, 0, 4 }, { 0, 0, 0 }, { 0, 0, 0 }},
2458 {{ 0, 0, 0 }, { 0, 0, 0 }, { 0, 8, 4 }, { 7, 15, 0 }},
2459 };
2460 
2474 static Track DoTrainPathfind(const Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found, bool do_track_reservation, PBSTileInfo *dest, TileIndex *final_dest)
2475 {
2476  if (final_dest != nullptr) *final_dest = INVALID_TILE;
2477  return YapfTrainChooseTrack(v, tile, enterdir, tracks, path_found, do_track_reservation, dest, final_dest);
2478 }
2479 
2485 static PBSTileInfo ExtendTrainReservation(const Train *v, TrackBits *new_tracks, DiagDirection *enterdir)
2486 {
2487  PBSTileInfo origin = FollowTrainReservation(v);
2488 
2489  CFollowTrackRail ft(v);
2490 
2491  std::vector<std::pair<TileIndex, Trackdir>> signals_set_to_red;
2492 
2493  TileIndex tile = origin.tile;
2494  Trackdir cur_td = origin.trackdir;
2495  while (ft.Follow(tile, cur_td)) {
2497  /* Possible signal tile. */
2499  }
2500 
2503  if (ft.new_td_bits == TRACKDIR_BIT_NONE) break;
2504  }
2505 
2506  /* Station, depot or waypoint are a possible target. */
2507  bool target_seen = ft.is_station || (IsTileType(ft.new_tile, MP_RAILWAY) && !IsPlainRail(ft.new_tile));
2508  if (target_seen || KillFirstBit(ft.new_td_bits) != TRACKDIR_BIT_NONE) {
2509  /* Choice found or possible target encountered.
2510  * On finding a possible target, we need to stop and let the pathfinder handle the
2511  * remaining path. This is because we don't know if this target is in one of our
2512  * orders, so we might cause pathfinding to fail later on if we find a choice.
2513  * This failure would cause a bogous call to TryReserveSafePath which might reserve
2514  * a wrong path not leading to our next destination. */
2516 
2517  /* If we did skip some tiles, backtrack to the first skipped tile so the pathfinder
2518  * actually starts its search at the first unreserved tile. */
2519  if (ft.tiles_skipped != 0) ft.new_tile -= TileOffsByDiagDir(ft.exitdir) * ft.tiles_skipped;
2520 
2521  /* Choice found, path valid but not okay. Save info about the choice tile as well. */
2522  if (new_tracks != nullptr) *new_tracks = TrackdirBitsToTrackBits(ft.new_td_bits);
2523  if (enterdir != nullptr) *enterdir = ft.exitdir;
2524  return PBSTileInfo(ft.new_tile, ft.old_td, false);
2525  }
2526 
2527  tile = ft.new_tile;
2528  cur_td = FindFirstTrackdir(ft.new_td_bits);
2529 
2530  Trackdir rev_td = ReverseTrackdir(cur_td);
2531  if (IsSafeWaitingPosition(v, tile, cur_td, true, _settings_game.pf.forbid_90_deg)) {
2532  bool wp_free = IsWaitingPositionFree(v, tile, cur_td, _settings_game.pf.forbid_90_deg);
2533  if (!(wp_free && TryReserveRailTrack(tile, TrackdirToTrack(cur_td)))) break;
2534  /* Green path signal opposing the path? Turn to red. */
2535  if (HasPbsSignalOnTrackdir(tile, rev_td) && GetSignalStateByTrackdir(tile, rev_td) == SIGNAL_STATE_GREEN) {
2536  signals_set_to_red.emplace_back(tile, rev_td);
2538  MarkTileDirtyByTile(tile);
2539  }
2540  /* Safe position is all good, path valid and okay. */
2541  return PBSTileInfo(tile, cur_td, true);
2542  }
2543 
2544  if (!TryReserveRailTrack(tile, TrackdirToTrack(cur_td))) break;
2545 
2546  /* Green path signal opposing the path? Turn to red. */
2547  if (HasPbsSignalOnTrackdir(tile, rev_td) && GetSignalStateByTrackdir(tile, rev_td) == SIGNAL_STATE_GREEN) {
2548  signals_set_to_red.emplace_back(tile, rev_td);
2550  MarkTileDirtyByTile(tile);
2551  }
2552  }
2553 
2554  if (ft.err == CFollowTrackRail::EC_OWNER || ft.err == CFollowTrackRail::EC_NO_WAY) {
2555  /* End of line, path valid and okay. */
2556  return PBSTileInfo(ft.old_tile, ft.old_td, true);
2557  }
2558 
2559  /* Sorry, can't reserve path, back out. */
2560  tile = origin.tile;
2561  cur_td = origin.trackdir;
2562  TileIndex stopped = ft.old_tile;
2563  Trackdir stopped_td = ft.old_td;
2564  while (tile != stopped || cur_td != stopped_td) {
2565  if (!ft.Follow(tile, cur_td)) break;
2566 
2569  assert(ft.new_td_bits != TRACKDIR_BIT_NONE);
2570  }
2572 
2573  tile = ft.new_tile;
2574  cur_td = FindFirstTrackdir(ft.new_td_bits);
2575 
2576  UnreserveRailTrack(tile, TrackdirToTrack(cur_td));
2577  }
2578 
2579  /* Re-instate green signals we turned to red. */
2580  for (auto [sig_tile, td] : signals_set_to_red) {
2582  }
2583 
2584  /* Path invalid. */
2585  return PBSTileInfo();
2586 }
2587 
2598 static bool TryReserveSafeTrack(const Train *v, TileIndex tile, Trackdir td, bool override_railtype)
2599 {
2600  return YapfTrainFindNearestSafeTile(v, tile, td, override_railtype);
2601 }
2602 
2605 private:
2606  Train *v;
2607  Order old_order;
2608  TileIndex old_dest_tile;
2609  StationID old_last_station_visited;
2610  VehicleOrderID index;
2611  bool suppress_implicit_orders;
2612  bool restored;
2613 
2614 public:
2615  VehicleOrderSaver(Train *_v) :
2616  v(_v),
2617  old_order(_v->current_order),
2618  old_dest_tile(_v->dest_tile),
2619  old_last_station_visited(_v->last_station_visited),
2620  index(_v->cur_real_order_index),
2621  suppress_implicit_orders(HasBit(_v->gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS)),
2622  restored(false)
2623  {
2624  }
2625 
2629  void Restore()
2630  {
2631  this->v->current_order = this->old_order;
2632  this->v->dest_tile = this->old_dest_tile;
2633  this->v->last_station_visited = this->old_last_station_visited;
2634  AssignBit(this->v->gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS, suppress_implicit_orders);
2635  this->restored = true;
2636  }
2637 
2642  {
2643  if (!this->restored) this->Restore();
2644  }
2645 
2651  bool SwitchToNextOrder(bool skip_first)
2652  {
2653  if (this->v->GetNumOrders() == 0) return false;
2654 
2655  if (skip_first) ++this->index;
2656 
2657  int depth = 0;
2658 
2659  do {
2660  /* Wrap around. */
2661  if (this->index >= this->v->GetNumOrders()) this->index = 0;
2662 
2663  Order *order = this->v->GetOrder(this->index);
2664  assert(order != nullptr);
2665 
2666  switch (order->GetType()) {
2667  case OT_GOTO_DEPOT:
2668  /* Skip service in depot orders when the train doesn't need service. */
2669  if ((order->GetDepotOrderType() & ODTFB_SERVICE) && !this->v->NeedsServicing()) break;
2670  [[fallthrough]];
2671  case OT_GOTO_STATION:
2672  case OT_GOTO_WAYPOINT:
2673  this->v->current_order = *order;
2674  return UpdateOrderDest(this->v, order, 0, true);
2675  case OT_CONDITIONAL: {
2676  VehicleOrderID next = ProcessConditionalOrder(order, this->v);
2677  if (next != INVALID_VEH_ORDER_ID) {
2678  depth++;
2679  this->index = next;
2680  /* Don't increment next, so no break here. */
2681  continue;
2682  }
2683  break;
2684  }
2685  default:
2686  break;
2687  }
2688  /* Don't increment inside the while because otherwise conditional
2689  * orders can lead to an infinite loop. */
2690  ++this->index;
2691  depth++;
2692  } while (this->index != this->v->cur_real_order_index && depth < this->v->GetNumOrders());
2693 
2694  return false;
2695  }
2696 };
2697 
2698 /* choose a track */
2699 static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool force_res, bool *got_reservation, bool mark_stuck)
2700 {
2701  Track best_track = INVALID_TRACK;
2702  bool do_track_reservation = _settings_game.pf.reserve_paths || force_res;
2703  bool changed_signal = false;
2704  TileIndex final_dest = INVALID_TILE;
2705 
2706  assert((tracks & ~TRACK_BIT_MASK) == 0);
2707 
2708  if (got_reservation != nullptr) *got_reservation = false;
2709 
2710  /* Don't use tracks here as the setting to forbid 90 deg turns might have been switched between reservation and now. */
2711  TrackBits res_tracks = (TrackBits)(GetReservedTrackbits(tile) & DiagdirReachesTracks(enterdir));
2712  /* Do we have a suitable reserved track? */
2713  if (res_tracks != TRACK_BIT_NONE) return FindFirstTrack(res_tracks);
2714 
2715  /* Quick return in case only one possible track is available */
2716  if (KillFirstBit(tracks) == TRACK_BIT_NONE) {
2717  Track track = FindFirstTrack(tracks);
2718  /* We need to check for signals only here, as a junction tile can't have signals. */
2719  if (track != INVALID_TRACK && HasPbsSignalOnTrackdir(tile, TrackEnterdirToTrackdir(track, enterdir))) {
2720  do_track_reservation = true;
2721  changed_signal = true;
2723  } else if (!do_track_reservation) {
2724  return track;
2725  }
2726  best_track = track;
2727  }
2728 
2729  PBSTileInfo res_dest(tile, INVALID_TRACKDIR, false);
2730  DiagDirection dest_enterdir = enterdir;
2731  if (do_track_reservation) {
2732  res_dest = ExtendTrainReservation(v, &tracks, &dest_enterdir);
2733  if (res_dest.tile == INVALID_TILE) {
2734  /* Reservation failed? */
2735  if (mark_stuck) MarkTrainAsStuck(v);
2736  if (changed_signal) SetSignalStateByTrackdir(tile, TrackEnterdirToTrackdir(best_track, enterdir), SIGNAL_STATE_RED);
2737  return FindFirstTrack(tracks);
2738  }
2739  if (res_dest.okay) {
2740  /* Got a valid reservation that ends at a safe target, quick exit. */
2741  if (got_reservation != nullptr) *got_reservation = true;
2742  if (changed_signal) MarkTileDirtyByTile(tile);
2744  return best_track;
2745  }
2746 
2747  /* Check if the train needs service here, so it has a chance to always find a depot.
2748  * Also check if the current order is a service order so we don't reserve a path to
2749  * the destination but instead to the next one if service isn't needed. */
2751  if (v->current_order.IsType(OT_DUMMY) || v->current_order.IsType(OT_CONDITIONAL) || v->current_order.IsType(OT_GOTO_DEPOT)) ProcessOrders(v);
2752  }
2753 
2754  /* Save the current train order. The destructor will restore the old order on function exit. */
2755  VehicleOrderSaver orders(v);
2756 
2757  /* If the current tile is the destination of the current order and
2758  * a reservation was requested, advance to the next order.
2759  * Don't advance on a depot order as depots are always safe end points
2760  * for a path and no look-ahead is necessary. This also avoids a
2761  * problem with depot orders not part of the order list when the
2762  * order list itself is empty. */
2763  if (v->current_order.IsType(OT_LEAVESTATION)) {
2764  orders.SwitchToNextOrder(false);
2765  } else if (v->current_order.IsType(OT_LOADING) || (!v->current_order.IsType(OT_GOTO_DEPOT) && (
2766  v->current_order.IsType(OT_GOTO_STATION) ?
2768  v->tile == v->dest_tile))) {
2769  orders.SwitchToNextOrder(true);
2770  }
2771 
2772  if (res_dest.tile != INVALID_TILE && !res_dest.okay) {
2773  /* Pathfinders are able to tell that route was only 'guessed'. */
2774  bool path_found = true;
2775  TileIndex new_tile = res_dest.tile;
2776 
2777  Track next_track = DoTrainPathfind(v, new_tile, dest_enterdir, tracks, path_found, do_track_reservation, &res_dest, &final_dest);
2778  if (new_tile == tile) best_track = next_track;
2779  v->HandlePathfindingResult(path_found);
2780  }
2781 
2782  /* No track reservation requested -> finished. */
2783  if (!do_track_reservation) return best_track;
2784 
2785  /* A path was found, but could not be reserved. */
2786  if (res_dest.tile != INVALID_TILE && !res_dest.okay) {
2787  if (mark_stuck) MarkTrainAsStuck(v);
2789  return best_track;
2790  }
2791 
2792  /* No possible reservation target found, we are probably lost. */
2793  if (res_dest.tile == INVALID_TILE) {
2794  /* Try to find any safe destination. */
2795  PBSTileInfo origin = FollowTrainReservation(v);
2796  if (TryReserveSafeTrack(v, origin.tile, origin.trackdir, false)) {
2797  TrackBits res = GetReservedTrackbits(tile) & DiagdirReachesTracks(enterdir);
2798  best_track = FindFirstTrack(res);
2800  if (got_reservation != nullptr) *got_reservation = true;
2801  if (changed_signal) MarkTileDirtyByTile(tile);
2802  } else {
2804  if (mark_stuck) MarkTrainAsStuck(v);
2805  }
2806  return best_track;
2807  }
2808 
2809  if (got_reservation != nullptr) *got_reservation = true;
2810 
2811  /* Reservation target found and free, check if it is safe. */
2812  while (!IsSafeWaitingPosition(v, res_dest.tile, res_dest.trackdir, true, _settings_game.pf.forbid_90_deg)) {
2813  /* Extend reservation until we have found a safe position. */
2814  DiagDirection exitdir = TrackdirToExitdir(res_dest.trackdir);
2815  TileIndex next_tile = TileAddByDiagDir(res_dest.tile, exitdir);
2817  if (Rail90DegTurnDisallowed(GetTileRailType(res_dest.tile), GetTileRailType(next_tile))) {
2818  reachable &= ~TrackCrossesTracks(TrackdirToTrack(res_dest.trackdir));
2819  }
2820 
2821  /* Get next order with destination. */
2822  if (orders.SwitchToNextOrder(true)) {
2823  PBSTileInfo cur_dest;
2824  bool path_found;
2825  DoTrainPathfind(v, next_tile, exitdir, reachable, path_found, true, &cur_dest, nullptr);
2826  if (cur_dest.tile != INVALID_TILE) {
2827  res_dest = cur_dest;
2828  if (res_dest.okay) continue;
2829  /* Path found, but could not be reserved. */
2831  if (mark_stuck) MarkTrainAsStuck(v);
2832  if (got_reservation != nullptr) *got_reservation = false;
2833  changed_signal = false;
2834  break;
2835  }
2836  }
2837  /* No order or no safe position found, try any position. */
2838  if (!TryReserveSafeTrack(v, res_dest.tile, res_dest.trackdir, true)) {
2840  if (mark_stuck) MarkTrainAsStuck(v);
2841  if (got_reservation != nullptr) *got_reservation = false;
2842  changed_signal = false;
2843  }
2844  break;
2845  }
2846 
2848 
2849  if (changed_signal) MarkTileDirtyByTile(tile);
2850 
2851  orders.Restore();
2852  if (v->current_order.IsType(OT_GOTO_DEPOT) &&
2854  final_dest != INVALID_TILE && IsRailDepotTile(final_dest)) {
2855  v->current_order.SetDestination(GetDepotIndex(final_dest));
2856  v->dest_tile = final_dest;
2858  }
2859 
2860  return best_track;
2861 }
2862 
2871 bool TryPathReserve(Train *v, bool mark_as_stuck, bool first_tile_okay)
2872 {
2873  assert(v->IsFrontEngine());
2874 
2875  /* We have to handle depots specially as the track follower won't look
2876  * at the depot tile itself but starts from the next tile. If we are still
2877  * inside the depot, a depot reservation can never be ours. */
2878  if (v->track == TRACK_BIT_DEPOT) {
2879  if (HasDepotReservation(v->tile)) {
2880  if (mark_as_stuck) MarkTrainAsStuck(v);
2881  return false;
2882  } else {
2883  /* Depot not reserved, but the next tile might be. */
2885  if (HasReservedTracks(next_tile, DiagdirReachesTracks(GetRailDepotDirection(v->tile)))) return false;
2886  }
2887  }
2888 
2889  Vehicle *other_train = nullptr;
2890  PBSTileInfo origin = FollowTrainReservation(v, &other_train);
2891  /* The path we are driving on is already blocked by some other train.
2892  * This can only happen in certain situations when mixing path and
2893  * block signals or when changing tracks and/or signals.
2894  * Exit here as doing any further reservations will probably just
2895  * make matters worse. */
2896  if (other_train != nullptr && other_train->index != v->index) {
2897  if (mark_as_stuck) MarkTrainAsStuck(v);
2898  return false;
2899  }
2900  /* If we have a reserved path and the path ends at a safe tile, we are finished already. */
2901  if (origin.okay && (v->tile != origin.tile || first_tile_okay)) {
2902  /* Can't be stuck then. */
2904  ClrBit(v->flags, VRF_TRAIN_STUCK);
2905  return true;
2906  }
2907 
2908  /* If we are in a depot, tentatively reserve the depot. */
2909  if (v->track == TRACK_BIT_DEPOT) {
2910  SetDepotReservation(v->tile, true);
2912  }
2913 
2914  DiagDirection exitdir = TrackdirToExitdir(origin.trackdir);
2915  TileIndex new_tile = TileAddByDiagDir(origin.tile, exitdir);
2917 
2919 
2920  bool res_made = false;
2921  ChooseTrainTrack(v, new_tile, exitdir, reachable, true, &res_made, mark_as_stuck);
2922 
2923  if (!res_made) {
2924  /* Free the depot reservation as well. */
2925  if (v->track == TRACK_BIT_DEPOT) SetDepotReservation(v->tile, false);
2926  return false;
2927  }
2928 
2929  if (HasBit(v->flags, VRF_TRAIN_STUCK)) {
2930  v->wait_counter = 0;
2932  }
2933  ClrBit(v->flags, VRF_TRAIN_STUCK);
2934  return true;
2935 }
2936 
2937 
2938 static bool CheckReverseTrain(const Train *v)
2939 {
2941  v->track == TRACK_BIT_DEPOT || v->track == TRACK_BIT_WORMHOLE ||
2942  !(v->direction & 1)) {
2943  return false;
2944  }
2945 
2946  assert(v->track != TRACK_BIT_NONE);
2947 
2948  return YapfTrainCheckReverse(v);
2949 }
2950 
2957 {
2958  if (station == this->last_station_visited) this->last_station_visited = INVALID_STATION;
2959 
2960  const Station *st = Station::Get(station);
2961  if (!(st->facilities & FACIL_TRAIN)) {
2962  /* The destination station has no trainstation tiles. */
2963  this->IncrementRealOrderIndex();
2964  return 0;
2965  }
2966 
2967  return st->xy;
2968 }
2969 
2972 {
2973  Train *v = this;
2974  do {
2975  v->colourmap = PAL_NONE;
2976  v->UpdateViewport(true, false);
2977  } while ((v = v->Next()) != nullptr);
2978 
2979  /* need to update acceleration and cached values since the goods on the train changed. */
2980  this->CargoChanged();
2981  this->UpdateAcceleration();
2982 }
2983 
2992 {
2994  default: NOT_REACHED();
2995  case AM_ORIGINAL:
2996  return this->DoUpdateSpeed(this->acceleration * (this->GetAccelerationStatus() == AS_BRAKE ? -4 : 2), 0, this->GetCurrentMaxSpeed());
2997 
2998  case AM_REALISTIC:
2999  return this->DoUpdateSpeed(this->GetAcceleration(), this->GetAccelerationStatus() == AS_BRAKE ? 0 : 2, this->GetCurrentMaxSpeed());
3000  }
3001 }
3002 
3008 static void TrainEnterStation(Train *v, StationID station)
3009 {
3010  v->last_station_visited = station;
3011 
3012  /* check if a train ever visited this station before */
3013  Station *st = Station::Get(station);
3014  if (!(st->had_vehicle_of_type & HVOT_TRAIN)) {
3015  st->had_vehicle_of_type |= HVOT_TRAIN;
3016  SetDParam(0, st->index);
3018  STR_NEWS_FIRST_TRAIN_ARRIVAL,
3020  v->index,
3021  st->index
3022  );
3023  AI::NewEvent(v->owner, new ScriptEventStationFirstVehicle(st->index, v->index));
3024  Game::NewEvent(new ScriptEventStationFirstVehicle(st->index, v->index));
3025  }
3026 
3027  v->force_proceed = TFP_NONE;
3029 
3030  v->BeginLoading();
3031 
3033  TriggerStationAnimation(st, v->tile, SAT_TRAIN_ARRIVES);
3034 }
3035 
3036 /* Check if the vehicle is compatible with the specified tile */
3037 static inline bool CheckCompatibleRail(const Train *v, TileIndex tile)
3038 {
3039  return IsTileOwner(tile, v->owner) &&
3040  (!v->IsFrontEngine() || HasBit(v->compatible_railtypes, GetRailType(tile)));
3041 }
3042 
3045  uint8_t small_turn;
3046  uint8_t large_turn;
3047  uint8_t z_up;
3048  uint8_t z_down;
3049 };
3050 
3053  /* normal accel */
3054  {256 / 4, 256 / 2, 256 / 4, 2},
3055  {256 / 4, 256 / 2, 256 / 4, 2},
3056  {0, 256 / 2, 256 / 4, 2},
3057 };
3058 
3064 static inline void AffectSpeedByZChange(Train *v, int old_z)
3065 {
3066  if (old_z == v->z_pos || _settings_game.vehicle.train_acceleration_model != AM_ORIGINAL) return;
3067 
3069 
3070  if (old_z < v->z_pos) {
3071  v->cur_speed -= (v->cur_speed * asp->z_up >> 8);
3072  } else {
3073  uint16_t spd = v->cur_speed + asp->z_down;
3074  if (spd <= v->gcache.cached_max_track_speed) v->cur_speed = spd;
3075  }
3076 }
3077 
3078 static bool TrainMovedChangeSignals(TileIndex tile, DiagDirection dir)
3079 {
3080  if (IsTileType(tile, MP_RAILWAY) &&
3083  Trackdir trackdir = FindFirstTrackdir(tracks);
3084  if (UpdateSignalsOnSegment(tile, TrackdirToExitdir(trackdir), GetTileOwner(tile)) == SIGSEG_PBS && HasSignalOnTrackdir(tile, trackdir)) {
3085  /* A PBS block with a non-PBS signal facing us? */
3086  if (!IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir)))) return true;
3087  }
3088  }
3089  return false;
3090 }
3091 
3094 {
3095  for (const Train *u = this; u != nullptr; u = u->Next()) {
3096  switch (u->track) {
3097  case TRACK_BIT_WORMHOLE:
3099  break;
3100  case TRACK_BIT_DEPOT:
3101  break;
3102  default:
3103  TryReserveRailTrack(u->tile, TrackBitsToTrack(u->track));
3104  break;
3105  }
3106  }
3107 }
3108 
3115 uint Train::Crash(bool flooded)
3116 {
3117  uint victims = 0;
3118  if (this->IsFrontEngine()) {
3119  victims += 2; // driver
3120 
3121  /* Remove the reserved path in front of the train if it is not stuck.
3122  * Also clear all reserved tracks the train is currently on. */
3123  if (!HasBit(this->flags, VRF_TRAIN_STUCK)) FreeTrainTrackReservation(this);
3124  for (const Train *v = this; v != nullptr; v = v->Next()) {
3126  if (IsTileType(v->tile, MP_TUNNELBRIDGE)) {
3127  /* ClearPathReservation will not free the wormhole exit
3128  * if the train has just entered the wormhole. */
3130  }
3131  }
3132 
3133  /* we may need to update crossing we were approaching,
3134  * but must be updated after the train has been marked crashed */
3135  TileIndex crossing = TrainApproachingCrossingTile(this);
3136  if (crossing != INVALID_TILE) UpdateLevelCrossing(crossing);
3137 
3138  /* Remove the loading indicators (if any) */
3140  }
3141 
3142  victims += this->GroundVehicleBase::Crash(flooded);
3143 
3144  this->crash_anim_pos = flooded ? 4000 : 1; // max 4440, disappear pretty fast when flooded
3145  return victims;
3146 }
3147 
3154 static uint TrainCrashed(Train *v)
3155 {
3156  uint victims = 0;
3157 
3158  /* do not crash train twice */
3159  if (!(v->vehstatus & VS_CRASHED)) {
3160  victims = v->Crash();
3161  AI::NewEvent(v->owner, new ScriptEventVehicleCrashed(v->index, v->tile, ScriptEventVehicleCrashed::CRASH_TRAIN, victims));
3162  Game::NewEvent(new ScriptEventVehicleCrashed(v->index, v->tile, ScriptEventVehicleCrashed::CRASH_TRAIN, victims));
3163  }
3164 
3165  /* Try to re-reserve track under already crashed train too.
3166  * Crash() clears the reservation! */
3168 
3169  return victims;
3170 }
3171 
3175  uint num;
3176 };
3177 
3184 static Vehicle *FindTrainCollideEnum(Vehicle *v, void *data)
3185 {
3187 
3188  /* not a train or in depot */
3189  if (v->type != VEH_TRAIN || Train::From(v)->track == TRACK_BIT_DEPOT) return nullptr;
3190 
3191  /* do not crash into trains of another company. */
3192  if (v->owner != tcc->v->owner) return nullptr;
3193 
3194  /* get first vehicle now to make most usual checks faster */
3195  Train *coll = Train::From(v)->First();
3196 
3197  /* can't collide with own wagons */
3198  if (coll == tcc->v) return nullptr;
3199 
3200  int x_diff = v->x_pos - tcc->v->x_pos;
3201  int y_diff = v->y_pos - tcc->v->y_pos;
3202 
3203  /* Do fast calculation to check whether trains are not in close vicinity
3204  * and quickly reject trains distant enough for any collision.
3205  * Differences are shifted by 7, mapping range [-7 .. 8] into [0 .. 15]
3206  * Differences are then ORed and then we check for any higher bits */
3207  uint hash = (y_diff + 7) | (x_diff + 7);
3208  if (hash & ~15) return nullptr;
3209 
3210  /* Slower check using multiplication */
3211  int min_diff = (Train::From(v)->gcache.cached_veh_length + 1) / 2 + (tcc->v->gcache.cached_veh_length + 1) / 2 - 1;
3212  if (x_diff * x_diff + y_diff * y_diff > min_diff * min_diff) return nullptr;
3213 
3214  /* Happens when there is a train under bridge next to bridge head */
3215  if (abs(v->z_pos - tcc->v->z_pos) > 5) return nullptr;
3216 
3217  /* crash both trains */
3218  tcc->num += TrainCrashed(tcc->v);
3219  tcc->num += TrainCrashed(coll);
3220 
3221  return nullptr; // continue searching
3222 }
3223 
3232 {
3233  /* can't collide in depot */
3234  if (v->track == TRACK_BIT_DEPOT) return false;
3235 
3236  assert(v->track == TRACK_BIT_WORMHOLE || TileVirtXY(v->x_pos, v->y_pos) == v->tile);
3237 
3238  TrainCollideChecker tcc;
3239  tcc.v = v;
3240  tcc.num = 0;
3241 
3242  /* find colliding vehicles */
3243  if (v->track == TRACK_BIT_WORMHOLE) {
3246  } else {
3248  }
3249 
3250  /* any dead -> no crash */
3251  if (tcc.num == 0) return false;
3252 
3253  SetDParam(0, tcc.num);
3254  AddTileNewsItem(STR_NEWS_TRAIN_CRASH, NT_ACCIDENT, v->tile);
3255 
3256  ModifyStationRatingAround(v->tile, v->owner, -160, 30);
3257  if (_settings_client.sound.disaster) SndPlayVehicleFx(SND_13_TRAIN_COLLISION, v);
3258  return true;
3259 }
3260 
3261 static Vehicle *CheckTrainAtSignal(Vehicle *v, void *data)
3262 {
3263  if (v->type != VEH_TRAIN || (v->vehstatus & VS_CRASHED)) return nullptr;
3264 
3265  Train *t = Train::From(v);
3266  DiagDirection exitdir = *(DiagDirection *)data;
3267 
3268  /* not front engine of a train, inside wormhole or depot, crashed */
3269  if (!t->IsFrontEngine() || !(t->track & TRACK_BIT_MASK)) return nullptr;
3270 
3271  if (t->cur_speed > 5 || VehicleExitDir(t->direction, t->track) != exitdir) return nullptr;
3272 
3273  return t;
3274 }
3275 
3283 bool TrainController(Train *v, Vehicle *nomove, bool reverse)
3284 {
3285  Train *first = v->First();
3286  Train *prev;
3287  bool direction_changed = false; // has direction of any part changed?
3288 
3289  /* For every vehicle after and including the given vehicle */
3290  for (prev = v->Previous(); v != nomove; prev = v, v = v->Next()) {
3291  DiagDirection enterdir = DIAGDIR_BEGIN;
3292  bool update_signals_crossing = false; // will we update signals or crossing state?
3293 
3295  if (v->track != TRACK_BIT_WORMHOLE) {
3296  /* Not inside tunnel */
3297  if (gp.old_tile == gp.new_tile) {
3298  /* Staying in the old tile */
3299  if (v->track == TRACK_BIT_DEPOT) {
3300  /* Inside depot */
3301  gp.x = v->x_pos;
3302  gp.y = v->y_pos;
3303  } else {
3304  /* Not inside depot */
3305 
3306  /* Reverse when we are at the end of the track already, do not move to the new position */
3307  if (v->IsFrontEngine() && !TrainCheckIfLineEnds(v, reverse)) return false;
3308 
3309  uint32_t r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y);
3310  if (HasBit(r, VETS_CANNOT_ENTER)) {
3311  goto invalid_rail;
3312  }
3313  if (HasBit(r, VETS_ENTERED_STATION)) {
3314  /* The new position is the end of the platform */
3316  }
3317  }
3318  } else {
3319  /* A new tile is about to be entered. */
3320 
3321  /* Determine what direction we're entering the new tile from */
3322  enterdir = DiagdirBetweenTiles(gp.old_tile, gp.new_tile);
3323  assert(IsValidDiagDirection(enterdir));
3324 
3325  /* Get the status of the tracks in the new tile and mask
3326  * away the bits that aren't reachable. */
3327  TrackStatus ts = GetTileTrackStatus(gp.new_tile, TRANSPORT_RAIL, 0, ReverseDiagDir(enterdir));
3328  TrackdirBits reachable_trackdirs = DiagdirReachesTrackdirs(enterdir);
3329 
3330  TrackdirBits trackdirbits = TrackStatusToTrackdirBits(ts) & reachable_trackdirs;
3331  TrackBits red_signals = TrackdirBitsToTrackBits(TrackStatusToRedSignals(ts) & reachable_trackdirs);
3332 
3333  TrackBits bits = TrackdirBitsToTrackBits(trackdirbits);
3334  if (Rail90DegTurnDisallowed(GetTileRailType(gp.old_tile), GetTileRailType(gp.new_tile)) && prev == nullptr) {
3335  /* We allow wagons to make 90 deg turns, because forbid_90_deg
3336  * can be switched on halfway a turn */
3337  bits &= ~TrackCrossesTracks(FindFirstTrack(v->track));
3338  }
3339 
3340  if (bits == TRACK_BIT_NONE) goto invalid_rail;
3341 
3342  /* Check if the new tile constrains tracks that are compatible
3343  * with the current train, if not, bail out. */
3344  if (!CheckCompatibleRail(v, gp.new_tile)) goto invalid_rail;
3345 
3346  TrackBits chosen_track;
3347  if (prev == nullptr) {
3348  /* Currently the locomotive is active. Determine which one of the
3349  * available tracks to choose */
3350  chosen_track = TrackToTrackBits(ChooseTrainTrack(v, gp.new_tile, enterdir, bits, false, nullptr, true));
3351  assert(chosen_track & (bits | GetReservedTrackbits(gp.new_tile)));
3352 
3353  if (v->force_proceed != TFP_NONE && IsPlainRailTile(gp.new_tile) && HasSignals(gp.new_tile)) {
3354  /* For each signal we find decrease the counter by one.
3355  * We start at two, so the first signal we pass decreases
3356  * this to one, then if we reach the next signal it is
3357  * decreased to zero and we won't pass that new signal. */
3358  Trackdir dir = FindFirstTrackdir(trackdirbits);
3359  if (HasSignalOnTrackdir(gp.new_tile, dir) ||
3361  GetSignalType(gp.new_tile, TrackdirToTrack(dir)) != SIGTYPE_PBS)) {
3362  /* However, we do not want to be stopped by PBS signals
3363  * entered via the back. */
3364  v->force_proceed = (v->force_proceed == TFP_SIGNAL) ? TFP_STUCK : TFP_NONE;
3366  }
3367  }
3368 
3369  /* Check if it's a red signal and that force proceed is not clicked. */
3370  if ((red_signals & chosen_track) && v->force_proceed == TFP_NONE) {
3371  /* In front of a red signal */
3372  Trackdir i = FindFirstTrackdir(trackdirbits);
3373 
3374  /* Don't handle stuck trains here. */
3375  if (HasBit(v->flags, VRF_TRAIN_STUCK)) return false;
3376 
3378  v->cur_speed = 0;
3379  v->subspeed = 0;
3380  v->progress = 255; // make sure that every bit of acceleration will hit the signal again, so speed stays 0.
3382  } else if (HasSignalOnTrackdir(gp.new_tile, i)) {
3383  v->cur_speed = 0;
3384  v->subspeed = 0;
3385  v->progress = 255; // make sure that every bit of acceleration will hit the signal again, so speed stays 0.
3387  DiagDirection exitdir = TrackdirToExitdir(i);
3388  TileIndex o_tile = TileAddByDiagDir(gp.new_tile, exitdir);
3389 
3390  exitdir = ReverseDiagDir(exitdir);
3391 
3392  /* check if a train is waiting on the other side */
3393  if (!HasVehicleOnPos(o_tile, &exitdir, &CheckTrainAtSignal)) return false;
3394  }
3395  }
3396 
3397  /* If we would reverse but are currently in a PBS block and
3398  * reversing of stuck trains is disabled, don't reverse.
3399  * This does not apply if the reason for reversing is a one-way
3400  * signal blocking us, because a train would then be stuck forever. */
3402  UpdateSignalsOnSegment(v->tile, enterdir, v->owner) == SIGSEG_PBS) {
3403  v->wait_counter = 0;
3404  return false;
3405  }
3406  goto reverse_train_direction;
3407  } else {
3408  TryReserveRailTrack(gp.new_tile, TrackBitsToTrack(chosen_track), false);
3409  }
3410  } else {
3411  /* The wagon is active, simply follow the prev vehicle. */
3412  if (prev->tile == gp.new_tile) {
3413  /* Choose the same track as prev */
3414  if (prev->track == TRACK_BIT_WORMHOLE) {
3415  /* Vehicles entering tunnels enter the wormhole earlier than for bridges.
3416  * However, just choose the track into the wormhole. */
3417  assert(IsTunnel(prev->tile));
3418  chosen_track = bits;
3419  } else {
3420  chosen_track = prev->track;
3421  }
3422  } else {
3423  /* Choose the track that leads to the tile where prev is.
3424  * This case is active if 'prev' is already on the second next tile, when 'v' just enters the next tile.
3425  * I.e. when the tile between them has only space for a single vehicle like
3426  * 1) horizontal/vertical track tiles and
3427  * 2) some orientations of tunnel entries, where the vehicle is already inside the wormhole at 8/16 from the tile edge.
3428  * Is also the train just reversing, the wagon inside the tunnel is 'on' the tile of the opposite tunnel entry.
3429  */
3430  static const TrackBits _connecting_track[DIAGDIR_END][DIAGDIR_END] = {
3435  };
3436  DiagDirection exitdir = DiagdirBetweenTiles(gp.new_tile, prev->tile);
3437  assert(IsValidDiagDirection(exitdir));
3438  chosen_track = _connecting_track[enterdir][exitdir];
3439  }
3440  chosen_track &= bits;
3441  }
3442 
3443  /* Make sure chosen track is a valid track */
3444  assert(
3445  chosen_track == TRACK_BIT_X || chosen_track == TRACK_BIT_Y ||
3446  chosen_track == TRACK_BIT_UPPER || chosen_track == TRACK_BIT_LOWER ||
3447  chosen_track == TRACK_BIT_LEFT || chosen_track == TRACK_BIT_RIGHT);
3448 
3449  /* Update XY to reflect the entrance to the new tile, and select the direction to use */
3450  const uint8_t *b = _initial_tile_subcoord[FindFirstBit(chosen_track)][enterdir];
3451  gp.x = (gp.x & ~0xF) | b[0];
3452  gp.y = (gp.y & ~0xF) | b[1];
3453  Direction chosen_dir = (Direction)b[2];
3454 
3455  /* Call the landscape function and tell it that the vehicle entered the tile */
3456  uint32_t r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y);
3457  if (HasBit(r, VETS_CANNOT_ENTER)) {
3458  goto invalid_rail;
3459  }
3460 
3461  if (!HasBit(r, VETS_ENTERED_WORMHOLE)) {
3462  Track track = FindFirstTrack(chosen_track);
3463  Trackdir tdir = TrackDirectionToTrackdir(track, chosen_dir);
3464  if (v->IsFrontEngine() && HasPbsSignalOnTrackdir(gp.new_tile, tdir)) {
3467  }
3468 
3469  /* Clear any track reservation when the last vehicle leaves the tile */
3470  if (v->Next() == nullptr) ClearPathReservation(v, v->tile, v->GetVehicleTrackdir());
3471 
3472  v->tile = gp.new_tile;
3473 
3475  v->First()->ConsistChanged(CCF_TRACK);
3476  }
3477 
3478  v->track = chosen_track;
3479  assert(v->track);
3480  }
3481 
3482  /* We need to update signal status, but after the vehicle position hash
3483  * has been updated by UpdateInclination() */
3484  update_signals_crossing = true;
3485 
3486  if (chosen_dir != v->direction) {
3487  if (prev == nullptr && _settings_game.vehicle.train_acceleration_model == AM_ORIGINAL) {
3489  DirDiff diff = DirDifference(v->direction, chosen_dir);
3490  v->cur_speed -= (diff == DIRDIFF_45RIGHT || diff == DIRDIFF_45LEFT ? asp->small_turn : asp->large_turn) * v->cur_speed >> 8;
3491  }
3492  direction_changed = true;
3493  v->direction = chosen_dir;
3494  }
3495 
3496  if (v->IsFrontEngine()) {
3497  v->wait_counter = 0;
3498 
3499  /* If we are approaching a crossing that is reserved, play the sound now. */
3501  if (crossing != INVALID_TILE && HasCrossingReservation(crossing) && _settings_client.sound.ambient) SndPlayTileFx(SND_0E_LEVEL_CROSSING, crossing);
3502 
3503  /* Always try to extend the reservation when entering a tile. */
3504  CheckNextTrainTile(v);
3505  }
3506 
3507  if (HasBit(r, VETS_ENTERED_STATION)) {
3508  /* The new position is the location where we want to stop */
3510  }
3511  }
3512  } else {
3514  /* Perform look-ahead on tunnel exit. */
3515  if (v->IsFrontEngine()) {
3517  CheckNextTrainTile(v);
3518  }
3519  /* Prevent v->UpdateInclination() being called with wrong parameters.
3520  * This could happen if the train was reversed inside the tunnel/bridge. */
3521  if (gp.old_tile == gp.new_tile) {
3523  }
3524  } else {
3525  v->x_pos = gp.x;
3526  v->y_pos = gp.y;
3527  v->UpdatePosition();
3528  if ((v->vehstatus & VS_HIDDEN) == 0) v->Vehicle::UpdateViewport(true);
3529  continue;
3530  }
3531  }
3532 
3533  /* update image of train, as well as delta XY */
3534  v->UpdateDeltaXY();
3535 
3536  v->x_pos = gp.x;
3537  v->y_pos = gp.y;
3538  v->UpdatePosition();
3539 
3540  /* update the Z position of the vehicle */
3541  int old_z = v->UpdateInclination(gp.new_tile != gp.old_tile, false);
3542 
3543  if (prev == nullptr) {
3544  /* This is the first vehicle in the train */
3545  AffectSpeedByZChange(v, old_z);
3546  }
3547 
3548  if (update_signals_crossing) {
3549  if (v->IsFrontEngine()) {
3550  if (TrainMovedChangeSignals(gp.new_tile, enterdir)) {
3551  /* We are entering a block with PBS signals right now, but
3552  * not through a PBS signal. This means we don't have a
3553  * reservation right now. As a conventional signal will only
3554  * ever be green if no other train is in the block, getting
3555  * a path should always be possible. If the player built
3556  * such a strange network that it is not possible, the train
3557  * will be marked as stuck and the player has to deal with
3558  * the problem. */
3559  if ((!HasReservedTracks(gp.new_tile, v->track) &&
3560  !TryReserveRailTrack(gp.new_tile, FindFirstTrack(v->track))) ||
3561  !TryPathReserve(v)) {
3562  MarkTrainAsStuck(v);
3563  }
3564  }
3565  }
3566 
3567  /* Signals can only change when the first
3568  * (above) or the last vehicle moves. */
3569  if (v->Next() == nullptr) {
3570  TrainMovedChangeSignals(gp.old_tile, ReverseDiagDir(enterdir));
3572  }
3573  }
3574 
3575  /* Do not check on every tick to save some computing time. */
3577  }
3578 
3579  if (direction_changed) first->tcache.cached_max_curve_speed = first->GetCurveSpeedLimit();
3580 
3581  return true;
3582 
3583 invalid_rail:
3584  /* We've reached end of line?? */
3585  if (prev != nullptr) FatalError("Disconnecting train");
3586 
3587 reverse_train_direction:
3588  if (reverse) {
3589  v->wait_counter = 0;
3590  v->cur_speed = 0;
3591  v->subspeed = 0;
3593  }
3594 
3595  return false;
3596 }
3597 
3605 {
3606  TrackBits *trackbits = (TrackBits *)data;
3607 
3608  if (v->type == VEH_TRAIN && (v->vehstatus & VS_CRASHED) != 0) {
3609  TrackBits train_tbits = Train::From(v)->track;
3610  if (train_tbits == TRACK_BIT_WORMHOLE) {
3611  /* Vehicle is inside a wormhole, v->track contains no useful value then. */
3613  } else if (train_tbits != TRACK_BIT_DEPOT) {
3614  *trackbits |= train_tbits;
3615  }
3616  }
3617 
3618  return nullptr;
3619 }
3620 
3621 static bool IsRailStationPlatformOccupied(TileIndex tile)
3622 {
3624 
3625  for (TileIndex t = tile; IsCompatibleTrainStationTile(t, tile); t -= delta) {
3626  if (HasVehicleOnPos(t, nullptr, &TrainOnTileEnum)) return true;
3627  }
3628  for (TileIndex t = tile + delta; IsCompatibleTrainStationTile(t, tile); t += delta) {
3629  if (HasVehicleOnPos(t, nullptr, &TrainOnTileEnum)) return true;
3630  }
3631 
3632  return false;
3633 }
3634 
3642 static void DeleteLastWagon(Train *v)
3643 {
3644  Train *first = v->First();
3645 
3646  /* Go to the last wagon and delete the link pointing there
3647  * *u is then the one-before-last wagon, and *v the last
3648  * one which will physically be removed */
3649  Train *u = v;
3650  for (; v->Next() != nullptr; v = v->Next()) u = v;
3651  u->SetNext(nullptr);
3652 
3653  if (first != v) {
3654  /* Recalculate cached train properties */
3655  first->ConsistChanged(CCF_ARRANGE);
3656  /* Update the depot window if the first vehicle is in depot -
3657  * if v == first, then it is updated in PreDestructor() */
3658  if (first->track == TRACK_BIT_DEPOT) {
3660  }
3661  v->last_station_visited = first->last_station_visited; // for PreDestructor
3662  }
3663 
3664  /* 'v' shouldn't be accessed after it has been deleted */
3665  TrackBits trackbits = v->track;
3666  TileIndex tile = v->tile;
3667  Owner owner = v->owner;
3668 
3669  delete v;
3670  v = nullptr; // make sure nobody will try to read 'v' anymore
3671 
3672  if (trackbits == TRACK_BIT_WORMHOLE) {
3673  /* Vehicle is inside a wormhole, v->track contains no useful value then. */
3675  }
3676 
3677  Track track = TrackBitsToTrack(trackbits);
3678  if (HasReservedTracks(tile, trackbits)) {
3679  UnreserveRailTrack(tile, track);
3680 
3681  /* If there are still crashed vehicles on the tile, give the track reservation to them */
3682  TrackBits remaining_trackbits = TRACK_BIT_NONE;
3683  FindVehicleOnPos(tile, &remaining_trackbits, CollectTrackbitsFromCrashedVehiclesEnum);
3684 
3685  /* It is important that these two are the first in the loop, as reservation cannot deal with every trackbit combination */
3686  assert(TRACK_BEGIN == TRACK_X && TRACK_Y == TRACK_BEGIN + 1);
3687  for (Track t : SetTrackBitIterator(remaining_trackbits)) TryReserveRailTrack(tile, t);
3688  }
3689 
3690  /* check if the wagon was on a road/rail-crossing */
3691  if (IsLevelCrossingTile(tile)) UpdateLevelCrossing(tile);
3692 
3693  if (IsRailStationTile(tile)) {
3694  bool occupied = IsRailStationPlatformOccupied(tile);
3696  SetRailStationPlatformReservation(tile, dir, occupied);
3697  SetRailStationPlatformReservation(tile, ReverseDiagDir(dir), occupied);
3698  }
3699 
3700  /* Update signals */
3701  if (IsTileType(tile, MP_TUNNELBRIDGE) || IsRailDepotTile(tile)) {
3703  } else {
3704  SetSignalsOnBothDir(tile, track, owner);
3705  }
3706 }
3707 
3713 {
3714  static const DirDiff delta[] = {
3716  };
3717 
3718  do {
3719  /* We don't need to twist around vehicles if they're not visible */
3720  if (!(v->vehstatus & VS_HIDDEN)) {
3721  v->direction = ChangeDir(v->direction, delta[GB(Random(), 0, 2)]);
3722  /* Refrain from updating the z position of the vehicle when on
3723  * a bridge, because UpdateInclination() will put the vehicle under
3724  * the bridge in that case */
3725  if (v->track != TRACK_BIT_WORMHOLE) {
3726  v->UpdatePosition();
3727  v->UpdateInclination(false, true);
3728  } else {
3729  v->UpdateViewport(false, true);
3730  }
3731  }
3732  } while ((v = v->Next()) != nullptr);
3733 }
3734 
3740 static bool HandleCrashedTrain(Train *v)
3741 {
3742  int state = ++v->crash_anim_pos;
3743 
3744  if (state == 4 && !(v->vehstatus & VS_HIDDEN)) {
3746  }
3747 
3748  uint32_t r;
3749  if (state <= 200 && Chance16R(1, 7, r)) {
3750  int index = (r * 10 >> 16);
3751 
3752  Vehicle *u = v;
3753  do {
3754  if (--index < 0) {
3755  r = Random();
3756 
3758  GB(r, 8, 3) + 2,
3759  GB(r, 16, 3) + 2,
3760  GB(r, 0, 3) + 5,
3762  break;
3763  }
3764  } while ((u = u->Next()) != nullptr);
3765  }
3766 
3767  if (state <= 240 && !(v->tick_counter & 3)) ChangeTrainDirRandomly(v);
3768 
3769  if (state >= 4440 && !(v->tick_counter & 0x1F)) {
3770  bool ret = v->Next() != nullptr;
3771  DeleteLastWagon(v);
3772  return ret;
3773  }
3774 
3775  return true;
3776 }
3777 
3779 static const uint16_t _breakdown_speeds[16] = {
3780  225, 210, 195, 180, 165, 150, 135, 120, 105, 90, 75, 60, 45, 30, 15, 15
3781 };
3782 
3783 
3792 static bool TrainApproachingLineEnd(Train *v, bool signal, bool reverse)
3793 {
3794  /* Calc position within the current tile */
3795  uint x = v->x_pos & 0xF;
3796  uint y = v->y_pos & 0xF;
3797 
3798  /* for diagonal directions, 'x' will be 0..15 -
3799  * for other directions, it will be 1, 3, 5, ..., 15 */
3800  switch (v->direction) {
3801  case DIR_N : x = ~x + ~y + 25; break;
3802  case DIR_NW: x = y; [[fallthrough]];
3803  case DIR_NE: x = ~x + 16; break;
3804  case DIR_E : x = ~x + y + 9; break;
3805  case DIR_SE: x = y; break;
3806  case DIR_S : x = x + y - 7; break;
3807  case DIR_W : x = ~y + x + 9; break;
3808  default: break;
3809  }
3810 
3811  /* Do not reverse when approaching red signal. Make sure the vehicle's front
3812  * does not cross the tile boundary when we do reverse, but as the vehicle's
3813  * location is based on their center, use half a vehicle's length as offset.
3814  * Multiply the half-length by two for straight directions to compensate that
3815  * we only get odd x offsets there. */
3816  if (!signal && x + (v->gcache.cached_veh_length + 1) / 2 * (IsDiagonalDirection(v->direction) ? 1 : 2) >= TILE_SIZE) {
3817  /* we are too near the tile end, reverse now */
3818  v->cur_speed = 0;
3819  if (reverse) ReverseTrainDirection(v);
3820  return false;
3821  }
3822 
3823  /* slow down */
3825  uint16_t break_speed = _breakdown_speeds[x & 0xF];
3826  if (break_speed < v->cur_speed) v->cur_speed = break_speed;
3827 
3828  return true;
3829 }
3830 
3831 
3837 static bool TrainCanLeaveTile(const Train *v)
3838 {
3839  /* Exit if inside a tunnel/bridge or a depot */
3840  if (v->track == TRACK_BIT_WORMHOLE || v->track == TRACK_BIT_DEPOT) return false;
3841 
3842  TileIndex tile = v->tile;
3843 
3844  /* entering a tunnel/bridge? */
3845  if (IsTileType(tile, MP_TUNNELBRIDGE)) {
3847  if (DiagDirToDir(dir) == v->direction) return false;
3848  }
3849 
3850  /* entering a depot? */
3851  if (IsRailDepotTile(tile)) {
3853  if (DiagDirToDir(dir) == v->direction) return false;
3854  }
3855 
3856  return true;
3857 }
3858 
3859 
3868 {
3869  assert(v->IsFrontEngine());
3870  assert(!(v->vehstatus & VS_CRASHED));
3871 
3872  if (!TrainCanLeaveTile(v)) return INVALID_TILE;
3873 
3874  DiagDirection dir = VehicleExitDir(v->direction, v->track);
3875  TileIndex tile = v->tile + TileOffsByDiagDir(dir);
3876 
3877  /* not a crossing || wrong axis || unusable rail (wrong type or owner) */
3878  if (!IsLevelCrossingTile(tile) || DiagDirToAxis(dir) == GetCrossingRoadAxis(tile) ||
3879  !CheckCompatibleRail(v, tile)) {
3880  return INVALID_TILE;
3881  }
3882 
3883  return tile;
3884 }
3885 
3886 
3894 static bool TrainCheckIfLineEnds(Train *v, bool reverse)
3895 {
3896  /* First, handle broken down train */
3897 
3898  int t = v->breakdown_ctr;
3899  if (t > 1) {
3901 
3902  uint16_t break_speed = _breakdown_speeds[GB(~t, 4, 4)];
3903  if (break_speed < v->cur_speed) v->cur_speed = break_speed;
3904  } else {
3905  v->vehstatus &= ~VS_TRAIN_SLOWING;
3906  }
3907 
3908  if (!TrainCanLeaveTile(v)) return true;
3909 
3910  /* Determine the non-diagonal direction in which we will exit this tile */
3911  DiagDirection dir = VehicleExitDir(v->direction, v->track);
3912  /* Calculate next tile */
3913  TileIndex tile = v->tile + TileOffsByDiagDir(dir);
3914 
3915  /* Determine the track status on the next tile */
3916  TrackStatus ts = GetTileTrackStatus(tile, TRANSPORT_RAIL, 0, ReverseDiagDir(dir));
3917  TrackdirBits reachable_trackdirs = DiagdirReachesTrackdirs(dir);
3918 
3919  TrackdirBits trackdirbits = TrackStatusToTrackdirBits(ts) & reachable_trackdirs;
3920  TrackdirBits red_signals = TrackStatusToRedSignals(ts) & reachable_trackdirs;
3921 
3922  /* We are sure the train is not entering a depot, it is detected above */
3923 
3924  /* mask unreachable track bits if we are forbidden to do 90deg turns */
3925  TrackBits bits = TrackdirBitsToTrackBits(trackdirbits);
3927  bits &= ~TrackCrossesTracks(FindFirstTrack(v->track));
3928  }
3929 
3930  /* no suitable trackbits at all || unusable rail (wrong type or owner) */
3931  if (bits == TRACK_BIT_NONE || !CheckCompatibleRail(v, tile)) {
3932  return TrainApproachingLineEnd(v, false, reverse);
3933  }
3934 
3935  /* approaching red signal */
3936  if ((trackdirbits & red_signals) != 0) return TrainApproachingLineEnd(v, true, reverse);
3937 
3938  /* approaching a rail/road crossing? then make it red */
3940 
3941  return true;
3942 }
3943 
3944 
3945 static bool TrainLocoHandler(Train *v, bool mode)
3946 {
3947  /* train has crashed? */
3948  if (v->vehstatus & VS_CRASHED) {
3949  return mode ? true : HandleCrashedTrain(v); // 'this' can be deleted here
3950  }
3951 
3952  if (v->force_proceed != TFP_NONE) {
3953  ClrBit(v->flags, VRF_TRAIN_STUCK);
3955  }
3956 
3957  /* train is broken down? */
3958  if (v->HandleBreakdown()) return true;
3959 
3960  if (HasBit(v->flags, VRF_REVERSING) && v->cur_speed == 0) {
3962  }
3963 
3964  /* exit if train is stopped */
3965  if ((v->vehstatus & VS_STOPPED) && v->cur_speed == 0) return true;
3966 
3967  bool valid_order = !v->current_order.IsType(OT_NOTHING) && v->current_order.GetType() != OT_CONDITIONAL;
3968  if (ProcessOrders(v) && CheckReverseTrain(v)) {
3969  v->wait_counter = 0;
3970  v->cur_speed = 0;
3971  v->subspeed = 0;
3972  ClrBit(v->flags, VRF_LEAVING_STATION);
3974  return true;
3975  } else if (HasBit(v->flags, VRF_LEAVING_STATION)) {
3976  /* Try to reserve a path when leaving the station as we
3977  * might not be marked as wanting a reservation, e.g.
3978  * when an overlength train gets turned around in a station. */
3979  DiagDirection dir = VehicleExitDir(v->direction, v->track);
3981 
3983  TryPathReserve(v, true, true);
3984  }
3985  ClrBit(v->flags, VRF_LEAVING_STATION);
3986  }
3987 
3988  v->HandleLoading(mode);
3989 
3990  if (v->current_order.IsType(OT_LOADING)) return true;
3991 
3992  if (CheckTrainStayInDepot(v)) return true;
3993 
3994  if (!mode) v->ShowVisualEffect();
3995 
3996  /* We had no order but have an order now, do look ahead. */
3997  if (!valid_order && !v->current_order.IsType(OT_NOTHING)) {
3998  CheckNextTrainTile(v);
3999  }
4000 
4001  /* Handle stuck trains. */
4002  if (!mode && HasBit(v->flags, VRF_TRAIN_STUCK)) {
4003  ++v->wait_counter;
4004 
4005  /* Should we try reversing this tick if still stuck? */
4007 
4008  if (!turn_around && v->wait_counter % _settings_game.pf.path_backoff_interval != 0 && v->force_proceed == TFP_NONE) return true;
4009  if (!TryPathReserve(v)) {
4010  /* Still stuck. */
4011  if (turn_around) ReverseTrainDirection(v);
4012 
4014  /* Show message to player. */
4016  SetDParam(0, v->index);
4017  AddVehicleAdviceNewsItem(STR_NEWS_TRAIN_IS_STUCK, v->index);
4018  }
4019  v->wait_counter = 0;
4020  }
4021  /* Exit if force proceed not pressed, else reset stuck flag anyway. */
4022  if (v->force_proceed == TFP_NONE) return true;
4023  ClrBit(v->flags, VRF_TRAIN_STUCK);
4024  v->wait_counter = 0;
4026  }
4027  }
4028 
4029  if (v->current_order.IsType(OT_LEAVESTATION)) {
4030  v->current_order.Free();
4032  return true;
4033  }
4034 
4035  int j = v->UpdateSpeed();
4036 
4037  /* we need to invalidate the widget if we are stopping from 'Stopping 0 km/h' to 'Stopped' */
4038  if (v->cur_speed == 0 && (v->vehstatus & VS_STOPPED)) {
4039  /* If we manually stopped, we're not force-proceeding anymore. */
4040  v->force_proceed = TFP_NONE;
4042  }
4043 
4044  int adv_spd = v->GetAdvanceDistance();
4045  if (j < adv_spd) {
4046  /* if the vehicle has speed 0, update the last_speed field. */
4047  if (v->cur_speed == 0) v->SetLastSpeed();
4048  } else {
4050  /* Loop until the train has finished moving. */
4051  for (;;) {
4052  j -= adv_spd;
4053  TrainController(v, nullptr);
4054  /* Don't continue to move if the train crashed. */
4055  if (CheckTrainCollision(v)) break;
4056  /* Determine distance to next map position */
4057  adv_spd = v->GetAdvanceDistance();
4058 
4059  /* No more moving this tick */
4060  if (j < adv_spd || v->cur_speed == 0) break;
4061 
4062  OrderType order_type = v->current_order.GetType();
4063  /* Do not skip waypoints (incl. 'via' stations) when passing through at full speed. */
4064  if ((order_type == OT_GOTO_WAYPOINT || order_type == OT_GOTO_STATION) &&
4066  IsTileType(v->tile, MP_STATION) &&
4068  ProcessOrders(v);
4069  }
4070  }
4071  v->SetLastSpeed();
4072  }
4073 
4074  for (Train *u = v; u != nullptr; u = u->Next()) {
4075  if ((u->vehstatus & VS_HIDDEN) != 0) continue;
4076 
4077  u->UpdateViewport(false, false);
4078  }
4079 
4080  if (v->progress == 0) v->progress = j; // Save unused spd for next time, if TrainController didn't set progress
4081 
4082  return true;
4083 }
4084 
4090 {
4091  Money cost = 0;
4092  const Train *v = this;
4093 
4094  do {
4095  const Engine *e = v->GetEngine();
4096  if (e->u.rail.running_cost_class == INVALID_PRICE) continue;
4097 
4098  uint cost_factor = GetVehicleProperty(v, PROP_TRAIN_RUNNING_COST_FACTOR, e->u.rail.running_cost);
4099  if (cost_factor == 0) continue;
4100 
4101  /* Halve running cost for multiheaded parts */
4102  if (v->IsMultiheaded()) cost_factor /= 2;
4103 
4104  cost += GetPrice(e->u.rail.running_cost_class, cost_factor, e->GetGRF());
4105  } while ((v = v->GetNextVehicle()) != nullptr);
4106 
4107  return cost;
4108 }
4109 
4115 {
4116  this->tick_counter++;
4117 
4118  if (this->IsFrontEngine()) {
4120 
4121  if (!(this->vehstatus & VS_STOPPED) || this->cur_speed > 0) this->running_ticks++;
4122 
4123  this->current_order_time++;
4124 
4125  if (!TrainLocoHandler(this, false)) return false;
4126 
4127  return TrainLocoHandler(this, true);
4128  } else if (this->IsFreeWagon() && (this->vehstatus & VS_CRASHED)) {
4129  /* Delete flooded standalone wagon chain */
4130  if (++this->crash_anim_pos >= 4400) {
4131  delete this;
4132  return false;
4133  }
4134  }
4135 
4136  return true;
4137 }
4138 
4144 {
4145  if (Company::Get(v->owner)->settings.vehicle.servint_trains == 0 || !v->NeedsAutomaticServicing()) return;
4146  if (v->IsChainInDepot()) {
4148  return;
4149  }
4150 
4152 
4153  FindDepotData tfdd = FindClosestTrainDepot(v, max_penalty);
4154  /* Only go to the depot if it is not too far out of our way. */
4155  if (tfdd.best_length == UINT_MAX || tfdd.best_length > max_penalty) {
4156  if (v->current_order.IsType(OT_GOTO_DEPOT)) {
4157  /* If we were already heading for a depot but it has
4158  * suddenly moved farther away, we continue our normal
4159  * schedule? */
4160  v->current_order.MakeDummy();
4162  }
4163  return;
4164  }
4165 
4166  DepotID depot = GetDepotIndex(tfdd.tile);
4167 
4168  if (v->current_order.IsType(OT_GOTO_DEPOT) &&
4169  v->current_order.GetDestination() != depot &&
4170  !Chance16(3, 16)) {
4171  return;
4172  }
4173 
4176  v->dest_tile = tfdd.tile;
4178 }
4179 
4182 {
4183  AgeVehicle(this);
4184 }
4185 
4188 {
4189  EconomyAgeVehicle(this);
4190 
4191  if ((++this->day_counter & 7) == 0) DecreaseVehicleValue(this);
4192 
4193  if (this->IsFrontEngine()) {
4194  CheckVehicleBreakdown(this);
4195 
4197 
4198  CheckOrders(this);
4199 
4200  /* update destination */
4201  if (this->current_order.IsType(OT_GOTO_STATION)) {
4203  if (tile != INVALID_TILE) this->dest_tile = tile;
4204  }
4205 
4206  if (this->running_ticks != 0) {
4207  /* running costs */
4209 
4210  this->profit_this_year -= cost.GetCost();
4211  this->running_ticks = 0;
4212 
4213  SubtractMoneyFromCompanyFract(this->owner, cost);
4214 
4217  }
4218  }
4219 }
4220 
4226 {
4227  if (this->vehstatus & VS_CRASHED) return INVALID_TRACKDIR;
4228 
4229  if (this->track == TRACK_BIT_DEPOT) {
4230  /* We'll assume the train is facing outwards */
4231  return DiagDirToDiagTrackdir(GetRailDepotDirection(this->tile)); // Train in depot
4232  }
4233 
4234  if (this->track == TRACK_BIT_WORMHOLE) {
4235  /* train in tunnel or on bridge, so just use its direction and assume a diagonal track */
4236  return DiagDirToDiagTrackdir(DirToDiagDir(this->direction));
4237  }
4238 
4239  return TrackDirectionToTrackdir(FindFirstTrack(this->track), this->direction);
4240 }
4241 
4242 uint16_t Train::GetMaxWeight() const
4243 {
4244  uint16_t weight = CargoSpec::Get(this->cargo_type)->WeightOfNUnitsInTrain(this->GetEngine()->DetermineCapacity(this));
4245 
4246  /* Vehicle weight is not added for articulated parts. */
4247  if (!this->IsArticulatedPart()) {
4248  weight += GetVehicleProperty(this, PROP_TRAIN_WEIGHT, RailVehInfo(this->engine_type)->weight);
4249  }
4250 
4251  /* Powered wagons have extra weight added. */
4252  if (HasBit(this->flags, VRF_POWEREDWAGON)) {
4253  weight += RailVehInfo(this->gcache.first_engine)->pow_wag_weight;
4254  }
4255 
4256  return weight;
4257 }
Base functions for all AIs.
void AddArticulatedParts(Vehicle *first)
Add the remaining articulated parts to the given vehicle.
void CheckConsistencyOfArticulatedVehicle(const Vehicle *v)
Checks whether the specs of freshly build articulated vehicles are consistent with the information sp...
Functions related to articulated vehicles.
void CheckCargoCapacity(Vehicle *v)
Check the capacity of all vehicles in a chain and spread cargo if needed.
constexpr debug_inline bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr T AssignBit(T &x, const uint8_t y, bool value)
Assigns a bit in a variable.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
constexpr uint8_t FindFirstBit(T x)
Search the first set bit in a value.
constexpr static debug_inline uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
constexpr T ToggleBit(T &x, const uint8_t y)
Toggles a bit in a variable.
constexpr T KillFirstBit(T value)
Clear the first bit in an integer.
constexpr T ClrBit(T &x, const uint8_t y)
Clears a bit in a variable.
const BridgeSpec * GetBridgeSpec(BridgeType i)
Get the specification of a bridge type.
Definition: bridge.h:66
bool IsBridgeTile(Tile t)
checks if there is a bridge on this tile
Definition: bridge_map.h:35
BridgeType GetBridgeType(Tile t)
Determines the type of bridge on a tile.
Definition: bridge_map.h:56
bool IsBridge(Tile t)
Checks if this is a bridge, instead of a tunnel.
Definition: bridge_map.h:24
uint8_t CargoID
Cargo slots to indicate a cargo type within a game.
Definition: cargo_type.h:22
bool IsValidCargoID(CargoID t)
Test whether cargo type is not INVALID_CARGO.
Definition: cargo_type.h:107
static void NewEvent(CompanyID company, ScriptEvent *event)
Queue a new event for an AI.
Definition: ai_core.cpp:243
Common return value for all commands.
Definition: command_type.h:23
void AddCost(const Money &cost)
Adds the given cost to the cost of the command.
Definition: command_type.h:63
Money GetCost() const
The costs as made up to this moment.
Definition: command_type.h:83
bool Failed() const
Did this command fail?
Definition: command_type.h:171
static void NewEvent(class ScriptEvent *event)
Queue a new event for a Game Script.
Definition: game_core.cpp:146
RAII class for measuring multi-step elements of performance.
This struct contains all the info that is needed to draw and construct tracks.
Definition: rail.h:127
RailTypes powered_railtypes
bitmask to the OTHER railtypes on which an engine of THIS railtype generates power
Definition: rail.h:188
RailTypes compatible_railtypes
bitmask to the OTHER railtypes on which an engine of THIS railtype can physically travel
Definition: rail.h:191
uint8_t curve_speed
Multiplier for curve maximum speed advantage.
Definition: rail.h:206
uint8_t acceleration_type
Acceleration type of this rail type.
Definition: rail.h:226
static constexpr TimerGameTick::Ticks DAY_TICKS
1 day is 74 ticks; TimerGameCalendar::date_fract used to be uint16_t and incremented by 885.
static Date date
Current date in days (day counter).
static Year year
Current year, starting at 0.
static constexpr int DAYS_IN_YEAR
days per year
static Date date
Current date in days (day counter).
uint StoredCount() const
Returns sum of cargo on board the vehicle (ie not only reserved).
Definition: cargopacket.h:434
This class will save the current order of a vehicle and restore it on destruction.
Definition: train_cmd.cpp:2604
void Restore()
Restore the saved order to the vehicle.
Definition: train_cmd.cpp:2629
~VehicleOrderSaver()
Restore the saved order to the vehicle, if Restore() has not already been called.
Definition: train_cmd.cpp:2641
bool SwitchToNextOrder(bool skip_first)
Set the current vehicle order to the next order in the order list.
Definition: train_cmd.cpp:2651
Functions related to commands.
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
Definition: command_func.h:28
#define return_cmd_error(errcode)
Returns from a function with a specific StringID as error.
Definition: command_func.h:38
DoCommandFlag
List of flags for a command.
Definition: command_type.h:374
@ DC_AUTOREPLACE
autoreplace/autorenew is in progress, this shall disable vehicle limits when building,...
Definition: command_type.h:383
@ DC_NO_CARGO_CAP_CHECK
when autoreplace/autorenew is in progress, this shall prevent truncating the amount of cargo in the v...
Definition: command_type.h:384
@ DC_EXEC
execute the given command
Definition: command_type.h:376
Definition of stuff that is very close to a company, like the company struct itself.
CommandCost CheckOwnership(Owner owner, TileIndex tile)
Check whether the current owner owns something.
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
Definition: company_cmd.cpp:52
CompanyID _current_company
Company currently doing an action.
Definition: company_cmd.cpp:53
void SubtractMoneyFromCompanyFract(CompanyID company, const CommandCost &cst)
Subtract money from a company, including the money fraction.
Functions related to companies.
Owner
Enum for all companies/owners.
Definition: company_type.h:18
DepotID GetDepotIndex(Tile t)
Get the index of which depot is attached to the tile.
Definition: depot_map.h:52
uint16_t DepotID
Type for the unique identifier of depots.
Definition: depot_type.h:13
DirDiff DirDifference(Direction d0, Direction d1)
Calculate the difference between two directions.
Direction DiagDirToDir(DiagDirection dir)
Convert a DiagDirection to a Direction.
DiagDirection ReverseDiagDir(DiagDirection d)
Returns the reverse direction of the given DiagDirection.
Direction ReverseDir(Direction d)
Return the reverse of a direction.
bool IsValidDiagDirection(DiagDirection d)
Checks if an integer value is a valid DiagDirection.
Direction ChangeDir(Direction d, DirDiff delta)
Change a direction by a given difference.
DiagDirection AxisToDiagDir(Axis a)
Converts an Axis to a DiagDirection.
bool IsDiagonalDirection(Direction dir)
Checks if a given Direction is diagonal.
Axis DiagDirToAxis(DiagDirection d)
Convert a DiagDirection to the axis.
DiagDirection DirToDiagDir(Direction dir)
Convert a Direction to a DiagDirection.
Direction
Defines the 8 directions on the map.
@ DIR_SW
Southwest.
@ DIR_NW
Northwest.
@ DIR_N
North.
@ DIR_SE
Southeast.
@ DIR_S
South.
@ DIR_NE
Northeast.
@ DIR_W
West.
@ DIR_E
East.
Axis
Allow incrementing of DiagDirDiff variables.
DiagDirection
Enumeration for diagonal directions.
@ DIAGDIR_END
Used for iterations.
@ DIAGDIR_BEGIN
Used for iterations.
@ INVALID_DIAGDIR
Flag for an invalid DiagDirection.
DirDiff
Allow incrementing of Direction variables.
@ DIRDIFF_90LEFT
Angle of 90 degrees left.
@ DIRDIFF_45LEFT
Angle of 45 degrees left.
@ DIRDIFF_45RIGHT
Angle of 45 degrees right.
@ DIRDIFF_SAME
Both directions faces to the same direction.
@ DIRDIFF_90RIGHT
Angle of 90 degrees right.
Money GetPrice(Price index, uint cost_factor, const GRFFile *grf_file, int shift)
Determine a certain price.
Definition: economy.cpp:969
@ EXPENSES_TRAIN_RUN
Running costs trains.
Definition: economy_type.h:175
@ EXPENSES_NEW_VEHICLES
New vehicles.
Definition: economy_type.h:174
EffectVehicle * CreateEffectVehicleRel(const Vehicle *v, int x, int y, int z, EffectVehicleType type)
Create an effect vehicle above a particular vehicle.
Functions related to effect vehicles.
@ EV_EXPLOSION_SMALL
Various explosions.
@ EV_EXPLOSION_LARGE
Various explosions.
@ RAILVEH_WAGON
simple wagon, not motorized
Definition: engine_type.h:29
@ RAILVEH_MULTIHEAD
indicates a combination of two locomotives
Definition: engine_type.h:28
static const EngineID INVALID_ENGINE
Constant denoting an invalid engine.
Definition: engine_type.h:206
uint16_t EngineID
Unique identification number of an engine.
Definition: engine_type.h:21
@ ENGINE_EXCLUSIVE_PREVIEW
This vehicle is in the exclusive preview stage, either being used or being offered to a company.
Definition: engine_type.h:184
@ EF_RAIL_TILTS
Rail vehicle tilts in curves.
Definition: engine_type.h:168
@ EF_RAIL_FLIPS
Rail vehicle has old depot-flip handling.
Definition: engine_type.h:172
Functions related to errors.
void ShowErrorMessage(StringID summary_msg, int x, int y, CommandCost cc)
Display an error message in a window.
Definition: error_gui.cpp:367
@ WL_CRITICAL
Critical errors, the MessageBox is shown in all cases.
Definition: error.h:27
Error reporting related functions.
fluid_settings_t * settings
FluidSynth settings handle.
Definition: fluidsynth.cpp:21
Types for recording game performance data.
@ PFE_GL_TRAINS
Time spent processing trains.
Base functions for all Games.
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition: gfx_type.h:18
uint32_t PaletteID
The number of the palette.
Definition: gfx_type.h:19
@ AS_BRAKE
We want to stop.
@ GVF_SUPPRESS_IMPLICIT_ORDERS
Disable insertion and removal of automatic orders until the vehicle completes the real order.
@ GVF_GOINGDOWN_BIT
Vehicle is currently going downhill. (Cached track information for acceleration)
@ GVF_GOINGUP_BIT
Vehicle is currently going uphill. (Cached track information for acceleration)
void UpdateTrainGroupID(Train *v)
Recalculates the groupID of a train.
Definition: group_cmd.cpp:773
void SetTrainGroupID(Train *v, GroupID grp)
Affect the groupID of a train to new_g.
Definition: group_cmd.cpp:745
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:2057
static const GroupID DEFAULT_GROUP
Ungrouped vehicles are in this group.
Definition: group_type.h:17
TrackStatus GetTileTrackStatus(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
Returns information about trackdirs and signal states.
Definition: landscape.cpp:554
int GetSlopePixelZ(int x, int y, bool ground_vehicle)
Return world Z coordinate of a given point of a tile.
Definition: landscape.cpp:303
DiagDirection DiagdirBetweenTiles(TileIndex tile_from, TileIndex tile_to)
Determines the DiagDirection to get from one tile to another.
Definition: map_func.h:620
TileIndex TileAddByDiagDir(TileIndex tile, DiagDirection dir)
Adds a DiagDir to a tile.
Definition: map_func.h:608
TileIndexDiff TileOffsByAxis(Axis axis)
Convert an Axis to a TileIndexDiff.
Definition: map_func.h:552
static debug_inline uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition: map_func.h:425
static debug_inline uint TileX(TileIndex tile)
Get the X component of a tile.
Definition: map_func.h:415
TileIndexDiff TileOffsByDiagDir(DiagDirection dir)
Convert a DiagDirection to a TileIndexDiff.
Definition: map_func.h:567
static debug_inline TileIndex TileVirtXY(uint x, uint y)
Get a tile from the virtual XY-coordinate.
Definition: map_func.h:404
int32_t TileIndexDiff
An offset value between two tiles.
Definition: map_type.h:23
constexpr T abs(const T a)
Returns the absolute value of (scalar) variable.
Definition: math_func.hpp:23
constexpr uint CeilDiv(uint a, uint b)
Computes ceil(a / b) for non-negative a and b.
Definition: math_func.hpp:320
constexpr T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition: math_func.hpp:79
constexpr void Swap(T &a, T &b)
Type safe swap operation.
Definition: math_func.hpp:283
Miscellaneous command definitions.
void HideFillingPercent(TextEffectID *te_id)
Hide vehicle loading indicators.
Definition: misc_gui.cpp:648
bool _networking
are we in networking mode?
Definition: network.cpp:65
Basic functions/variables used all over the place.
ClientID
'Unique' identifier to be given to clients
Definition: network_type.h:49
Base for the NewGRF implementation.
@ SAT_TRAIN_ARRIVES
Trigger platform when train arrives.
@ CBID_VEHICLE_LENGTH
Vehicle length, returns the amount of 1/8's the vehicle is shorter for trains and RVs.
@ CBID_TRAIN_ALLOW_WAGON_ATTACH
Determine whether a wagon can be attached to an already existing train.
@ CBM_VEHICLE_LENGTH
Vehicle length (trains and road vehicles)
@ CBM_VEHICLE_ARTIC_ENGINE
Add articulated engines (trains and road vehicles)
static const uint CALLBACK_FAILED
Different values for Callback result evaluations.
void ErrorUnknownCallbackResult(uint32_t grfid, uint16_t cbid, uint16_t cb_res)
Record that a NewGRF returned an unknown/invalid callback result.
@ GBUG_VEH_CAPACITY
Capacity of vehicle changes when not refitting or arranging.
Definition: newgrf_config.h:47
Functions/types related to NewGRF debugging.
void InvalidateNewGRFInspectWindow(GrfSpecFeature feature, uint index)
Invalidate the inspect window for a given feature and index.
void DeleteNewGRFInspectWindow(GrfSpecFeature feature, uint index)
Delete inspect window for a given feature and index.
uint16_t GetVehicleCallbackParent(CallbackID callback, uint32_t param1, uint32_t param2, EngineID engine, const Vehicle *v, const Vehicle *parent)
Evaluate a newgrf callback for vehicles with a different vehicle for parent scope.
bool UsesWagonOverride(const Vehicle *v)
Check if a wagon is currently using a wagon override.
bool TestVehicleBuildProbability(Vehicle *v, EngineID engine, BuildProbabilityType type)
Test for vehicle build probablity type.
uint16_t GetVehicleCallback(CallbackID callback, uint32_t param1, uint32_t param2, EngineID engine, const Vehicle *v)
Evaluate a newgrf callback for vehicles.
@ PROP_TRAIN_SHORTEN_FACTOR
Shorter vehicles.
@ PROP_TRAIN_USER_DATA
User defined data for vehicle variable 0x42.
@ PROP_TRAIN_WEIGHT
Weight in t (if dualheaded: for each single vehicle)
@ PROP_TRAIN_CARGO_AGE_PERIOD
Number of ticks before carried cargo is aged.
@ PROP_TRAIN_RUNNING_COST_FACTOR
Yearly runningcost (if dualheaded: sum of both vehicles)
@ PROP_TRAIN_SPEED
Max. speed: 1 unit = 1/1.6 mph = 1 km-ish/h.
bool PlayVehicleSound(const Vehicle *v, VehicleSoundEvent event, bool force)
Checks whether a NewGRF wants to play a different vehicle sound effect.
Functions related to NewGRF provided sounds.
@ VSE_START
Vehicle starting, i.e. leaving, the station.
Definition: newgrf_sound.h:19
void TriggerStationRandomisation(Station *st, TileIndex trigger_tile, StationRandomTrigger trigger, CargoID cargo_type)
Trigger station randomisation.
Header file for NewGRF stations.
@ SRT_TRAIN_ARRIVES
Trigger platform when train arrives.
StringID GetGRFStringID(uint32_t grfid, StringID stringid)
Returns the index for this stringid associated with its grfID.
Header of Action 04 "universal holder" structure and functions.
Functions related to news.
void AddVehicleAdviceNewsItem(StringID string, VehicleID vehicle)
Adds a vehicle-advice news item.
Definition: news_func.h:40
void AddVehicleNewsItem(StringID string, NewsType type, VehicleID vehicle, StationID station=INVALID_STATION)
Adds a newsitem referencing a vehicle.
Definition: news_func.h:30
@ NT_ARRIVAL_COMPANY
First vehicle arrived for company.
Definition: news_type.h:24
@ NT_ARRIVAL_OTHER
First vehicle arrived for competitor.
Definition: news_type.h:25
@ NT_ACCIDENT
An accident or disaster has occurred.
Definition: news_type.h:26
@ PM_PAUSED_ERROR
A game paused because a (critical) error.
Definition: openttd.h:73
Functions related to order backups.
bool ProcessOrders(Vehicle *v)
Handle the orders of a vehicle and determine the next place to go to if needed.
Definition: order_cmd.cpp:2127
bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth, bool pbs_look_ahead)
Update the vehicle's destination tile from an order.
Definition: order_cmd.cpp:1998
void CheckOrders(const Vehicle *v)
Check the orders of a vehicle, to see if there are invalid orders and stuff.
Definition: order_cmd.cpp:1711
void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist, bool reset_order_indices)
Delete all orders from a vehicle.
Definition: order_cmd.cpp:1869
VehicleOrderID ProcessConditionalOrder(const Order *order, const Vehicle *v)
Process a conditional order and determine the next order.
Definition: order_cmd.cpp:1968
@ ODATFB_NEAREST_DEPOT
Send the vehicle to the nearest depot.
Definition: order_type.h:105
OrderStopLocation
Where to stop the trains.
Definition: order_type.h:83
@ OSL_PLATFORM_MIDDLE
Stop at the middle of the platform.
Definition: order_type.h:85
@ OSL_PLATFORM_FAR_END
Stop at the far end of the platform.
Definition: order_type.h:86
@ OSL_PLATFORM_NEAR_END
Stop at the near end of the platform.
Definition: order_type.h:84
uint8_t VehicleOrderID
The index of an order within its current vehicle (not pool related)
Definition: order_type.h:15
@ ONSF_NO_STOP_AT_DESTINATION_STATION
The vehicle will stop at any station it passes except the destination.
Definition: order_type.h:75
@ ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS
The vehicle will not stop at any stations it passes except the destination.
Definition: order_type.h:74
@ ODTFB_SERVICE
This depot order is because of the servicing limit.
Definition: order_type.h:95
static const VehicleOrderID INVALID_VEH_ORDER_ID
Invalid vehicle order index (sentinel)
Definition: order_type.h:21
OrderType
Order types.
Definition: order_type.h:35
void SetRailStationPlatformReservation(TileIndex start, DiagDirection dir, bool b)
Set the reservation for a complete station platform.
Definition: pbs.cpp:57
TrackBits GetReservedTrackbits(TileIndex t)
Get the reserved trackbits for any tile, regardless of type.
Definition: pbs.cpp:24
PBSTileInfo FollowTrainReservation(const Train *v, Vehicle **train_on_res)
Follow a train reservation to the last tile.
Definition: pbs.cpp:288
bool TryReserveRailTrack(TileIndex tile, Track t, bool trigger_stations)
Try to reserve a specific track on a tile.
Definition: pbs.cpp:80
bool IsWaitingPositionFree(const Train *v, TileIndex tile, Trackdir trackdir, bool forbid_90deg)
Check if a safe position is free.
Definition: pbs.cpp:426
void UnreserveRailTrack(TileIndex tile, Track t)
Lift the reservation of a specific track on a tile.
Definition: pbs.cpp:140
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:380
bool HasReservedTracks(TileIndex tile, TrackBits tracks)
Check whether some of tracks is reserved on a tile.
Definition: pbs.h:58
RailType GetTileRailType(Tile tile)
Return the rail type of tile, or INVALID_RAILTYPE if this is no rail tile.
Definition: rail.cpp:155
int TicksToLeaveDepot(const Train *v)
Compute number of ticks when next wagon will leave a depot.
Definition: rail_cmd.cpp:2916
const RailTypeInfo * GetRailTypeInfo(RailType railtype)
Returns a pointer to the Railtype information for a given railtype.
Definition: rail.h:307
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:322
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:335
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:357
std::vector< Train * > TrainList
Helper type for lists/vectors of trains.
Definition: rail_cmd.cpp:44
bool HasOnewaySignalBlockingTrackdir(Tile 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
RailType GetRailType(Tile t)
Gets the rail type of the given tile.
Definition: rail_map.h:115
bool HasSignalOnTrackdir(Tile tile, Trackdir trackdir)
Checks for the presence of signals along the given trackdir on the given rail tile.
Definition: rail_map.h:426
static debug_inline RailTileType GetRailTileType(Tile t)
Returns the RailTileType (normal with or without signals, waypoint or depot).
Definition: rail_map.h:36
TrackBits GetTrackBits(Tile tile)
Gets the track bits of the given tile.
Definition: rail_map.h:136
static debug_inline bool IsRailDepotTile(Tile t)
Is this tile rail tile and a rail depot?
Definition: rail_map.h:105
Track GetRailDepotTrack(Tile t)
Returns the track of a depot, ignoring direction.
Definition: rail_map.h:182
DiagDirection GetRailDepotDirection(Tile t)
Returns the direction the depot is facing to.
Definition: rail_map.h:171
void SetSignalStateByTrackdir(Tile tile, Trackdir trackdir, SignalState state)
Sets the state of the signal along the given trackdir.
Definition: rail_map.h:449
bool HasPbsSignalOnTrackdir(Tile tile, Trackdir td)
Is a pbs signal present along the trackdir?
Definition: rail_map.h:463
bool IsOnewaySignal(Tile t, Track track)
One-way signals can't be passed the 'wrong' way.
Definition: rail_map.h:319
void SetDepotReservation(Tile t, bool b)
Set the reservation state of the depot.
Definition: rail_map.h:270
static debug_inline bool IsPlainRail(Tile t)
Returns whether this is plain rails, with or without signals.
Definition: rail_map.h:49
bool HasDepotReservation(Tile t)
Get the reservation state of the depot.
Definition: rail_map.h:258
@ RAIL_TILE_SIGNALS
Normal rail tile with signals.
Definition: rail_map.h:25
bool HasSignals(Tile t)
Checks if a rail tile has signals.
Definition: rail_map.h:72
static debug_inline bool IsPlainRailTile(Tile t)
Checks whether the tile is a rail tile or rail tile with signals.
Definition: rail_map.h:60
SignalState GetSignalStateByTrackdir(Tile tile, Trackdir trackdir)
Gets the state of the signal along the given trackdir.
Definition: rail_map.h:438
@ RAILTYPES_RAIL
Non-electrified rails.
Definition: rail_type.h:46
@ RAILTYPES_NONE
No rail types.
Definition: rail_type.h:45
@ RAILTYPE_RAIL
Standard non-electric rails.
Definition: rail_type.h:29
Pseudo random number generator.
bool Chance16(const uint32_t a, const uint32_t b, const std::source_location location=std::source_location::current())
Flips a coin with given probability.
bool Chance16R(const uint32_t a, const uint32_t b, uint32_t &r, const std::source_location location=std::source_location::current())
Flips a coin with a given probability and saves the randomize-number in a variable.
bool HasCrossingReservation(Tile t)
Get the reservation state of the rail crossing.
Definition: road_map.h:380
bool IsLevelCrossingTile(Tile t)
Return whether a tile is a level crossing tile.
Definition: road_map.h:95
Axis GetCrossingRoadAxis(Tile t)
Get the road axis of a level crossing.
Definition: road_map.h:325
void SetCrossingBarred(Tile t, bool barred)
Set the bar state of a level crossing.
Definition: road_map.h:428
Axis GetCrossingRailAxis(Tile t)
Get the rail axis of a level crossing.
Definition: road_map.h:337
bool IsCrossingBarred(Tile t)
Check if the level crossing is barred.
Definition: road_map.h:416
void SetCrossingReservation(Tile t, bool b)
Set the reservation state of the rail crossing.
Definition: road_map.h:393
A number of safeguards to prevent using unsafe methods.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition: settings.cpp:57
ClientSettings _settings_client
The current settings for this game.
Definition: settings.cpp:56
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:650
static SigSegState UpdateSignalsInBuffer(Owner owner)
Updates blocks in _globset buffer.
Definition: signal.cpp:482
void AddSideToSignalBuffer(TileIndex tile, DiagDirection side, Owner owner)
Add side of tile to signal update buffer.
Definition: signal.cpp:624
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:668
SigSegState
State of the signal segment.
Definition: signal_func.h:49
@ SIGSEG_PBS
Segment is a PBS segment.
Definition: signal_func.h:52
@ SIGSEG_FULL
Occupied by a train.
Definition: signal_func.h:51
@ SIGTYPE_PBS
normal pbs signal
Definition: signal_type.h:28
@ SIGNAL_STATE_RED
The signal is red.
Definition: signal_type.h:43
@ SIGNAL_STATE_GREEN
The signal is green.
Definition: signal_type.h:44
Functions related to sound.
SoundFx
Sound effects from baseset.
Definition: sound_type.h:37
@ SND_04_DEPARTURE_STEAM
2 == 0x02 Station departure: steam engine
Definition: sound_type.h:41
@ SND_41_DEPARTURE_MAGLEV
65 == 0x41 Station departure: maglev engine
Definition: sound_type.h:104
@ SND_13_TRAIN_COLLISION
15 == 0x11 Train+train crash
Definition: sound_type.h:56
@ SND_0E_LEVEL_CROSSING
12 == 0x0C Train passes through level crossing
Definition: sound_type.h:51
@ SND_0A_DEPARTURE_TRAIN
8 == 0x08 Station departure: diesel and electric engine
Definition: sound_type.h:47
@ SND_47_DEPARTURE_MONORAIL
71 == 0x47 Station departure: monorail engine
Definition: sound_type.h:110
Functions to cache sprites in memory.
static const PaletteID PALETTE_CRASH
Recolour sprite greying of crashed vehicles.
Definition: sprites.h:1605
bool IsRailWaypointTile(Tile t)
Is this tile a station tile and a rail waypoint?
Definition: station_map.h:123
bool IsCompatibleTrainStationTile(Tile test_tile, Tile station_tile)
Check if a tile is a valid continuation to a railstation tile.
Definition: station_map.h:544
bool IsRailStationTile(Tile t)
Is this tile a station tile and a rail station?
Definition: station_map.h:102
StationID GetStationIndex(Tile t)
Get StationID from a tile.
Definition: station_map.h:28
Axis GetRailStationAxis(Tile t)
Get the rail direction of a rail station.
Definition: station_map.h:503
@ HVOT_TRAIN
Station has seen a train.
Definition: station_type.h:66
@ FACIL_TRAIN
Station with train station.
Definition: station_type.h:54
Definition of base types and functions in a cross-platform compatible way.
#define lengthof(array)
Return the length of an fixed size array.
Definition: stdafx.h:280
void SetDParam(size_t n, uint64_t v)
Set a string parameter v at index n in the global string parameter array.
Definition: strings.cpp:104
Functions related to OTTD's strings.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
Definition: strings_type.h:16
static const StringID INVALID_STRING_ID
Constant representing an invalid string (16bit in case it is used in savegames)
Definition: strings_type.h:17
Data structure for storing engine speed changes of an acceleration type.
Definition: train_cmd.cpp:3044
uint8_t large_turn
Speed change due to a large turn.
Definition: train_cmd.cpp:3046
uint8_t z_up
Fraction to remove when moving up.
Definition: train_cmd.cpp:3047
uint8_t small_turn
Speed change due to a small turn.
Definition: train_cmd.cpp:3045
uint8_t z_down
Fraction to add when moving down.
Definition: train_cmd.cpp:3048
std::string name
Name of vehicle.
Definition: base_consist.h:18
TimerGameTick::Ticks current_order_time
How many ticks have passed since this order started.
Definition: base_consist.h:21
VehicleOrderID cur_real_order_index
The index to the current real (non-implicit) order.
Definition: base_consist.h:31
uint16_t vehicle_flags
Used for gradual loading and other miscellaneous things (.
Definition: base_consist.h:34
void ResetDepotUnbunching()
Resets all the data used for depot unbunching.
StationFacility facilities
The facilities that this station has.
TileIndex xy
Base tile of the station.
TileArea train_station
Tile area the train 'station' part covers.
VehicleType type
Type of vehicle.
Definition: vehicle_type.h:51
uint16_t speed
maximum travel speed (1 unit = 1/1.6 mph = 1 km-ish/h)
Definition: bridge.h:47
Track follower helper template class (can serve pathfinders and vehicle controllers).
bool Follow(TileIndex old_tile, Trackdir old_td)
main follower routine.
bool is_tunnel
last turn passed tunnel
bool is_bridge
last turn passed bridge ramp
int tiles_skipped
number of skipped tunnel or station tiles
DiagDirection exitdir
exit direction (leaving the old tile)
TrackdirBits new_td_bits
the new set of available trackdirs
TileIndex new_tile
the new tile (the vehicle has entered)
Trackdir old_td
the trackdir (the vehicle was on) before move
bool is_station
last turn passed station
TileIndex old_tile
the origin (vehicle moved from) before move
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo ID.
Definition: cargotype.h:134
SoundSettings sound
sound effect settings
GUISettings gui
settings related to the GUI
Structure to return information about the closest depot location, and whether it could be found.
Definition: vehicle_base.h:230
bool line_reverse_mode
reversing at stations or not
uint16_t cargo_age_period
Number of ticks before carried cargo is aged.
Definition: engine_type.h:159
uint8_t misc_flags
Miscellaneous flags.
Definition: engine_type.h:155
uint16_t callback_mask
Bitmask of vehicle callbacks that have to be called.
Definition: engine_type.h:156
CargoID GetDefaultCargoType() const
Determines the default cargo type of an engine.
Definition: engine_base.h:96
uint32_t GetGRFID() const
Retrieve the GRF ID of the NewGRF the engine is tied to.
Definition: engine.cpp:157
uint16_t reliability_spd_dec
Speed of reliability decay between services (per day).
Definition: engine_base.h:42
uint DetermineCapacity(const Vehicle *v, uint16_t *mail_capacity=nullptr) const
Determines capacity of a given vehicle from scratch.
Definition: engine.cpp:201
uint8_t original_image_index
Original vehicle image index, thus the image index of the overridden vehicle.
Definition: engine_base.h:55
const GRFFile * GetGRF() const
Retrieve the NewGRF the engine is tied to.
Definition: engine_base.h:167
TimerGameCalendar::Date GetLifeLengthInDays() const
Returns the vehicle's (not model's!) life length in days.
Definition: engine.cpp:443
uint16_t reliability
Current reliability of the engine.
Definition: engine_base.h:41
uint8_t flags
Flags of the engine.
Definition: engine_base.h:49
Helper container to find a depot.
uint best_length
The distance towards the depot in penalty, or UINT_MAX if not found.
bool reverse
True if reversing is necessary for the train to get to this depot.
TileIndex tile
The tile of the depot.
uint traininfo_vehicle_width
Width (in pixels) of a 8/8 train vehicle in depot GUI and vehicle details.
Definition: newgrf.h:147
int traininfo_vehicle_pitch
Vertical offset for drawing train images in depot GUI and vehicle details.
Definition: newgrf.h:146
bool lost_vehicle_warn
if a vehicle can't find its destination, show a warning
bool show_track_reservation
highlight reserved tracks.
PathfinderSettings pf
settings for all pathfinders
DifficultySettings difficulty
settings related to the difficulty
VehicleSettings vehicle
options for vehicles
Position information of a vehicle after it moved.
Definition: vehicle_func.h:77
TileIndex new_tile
Tile of the vehicle after moving.
Definition: vehicle_func.h:80
int y
x and y position of the vehicle after moving
Definition: vehicle_func.h:78
TileIndex old_tile
Current tile of the vehicle.
Definition: vehicle_func.h:79
uint32_t cached_weight
Total weight of the consist (valid only for the first engine).
EngineID first_engine
Cached EngineID of the front vehicle. INVALID_ENGINE for the front vehicle itself.
uint32_t cached_power
Total power of the consist (valid only for the first engine).
uint16_t cached_total_length
Length of the whole vehicle (valid only for the first engine).
uint8_t cached_veh_length
Length of this vehicle in units of 1/VEHICLE_LENGTH of normal length. It is cached because this can b...
uint16_t cached_max_track_speed
Maximum consist speed (in internal units) limited by track type (valid only for the first engine).
bool IsChainInDepot() const override
Check whether the whole vehicle chain is in the depot.
void SetFreeWagon()
Set a vehicle as a free wagon.
int UpdateInclination(bool new_tile, bool update_delta)
Checks if the vehicle is in a slope and sets the required flags in that case.
GroundVehicleCache gcache
Cache of often calculated values.
void CargoChanged()
Recalculates the cached weight of a vehicle and its parts.
void SetMultiheaded()
Set a vehicle as a multiheaded engine.
bool IsEngine() const
Check if a vehicle is an engine (can be first in a consist).
bool IsRearDualheaded() const
Tell if we are dealing with the rear end of a multiheaded engine.
bool IsMultiheaded() const
Check if the vehicle is a multiheaded engine.
void SetEngine()
Set engine status.
void SetWagon()
Set a vehicle to be a wagon.
void SetFrontEngine()
Set front engine state.
void ClearFreeWagon()
Clear a vehicle from being a free wagon.
bool IsWagon() const
Check if a vehicle is a wagon.
uint Crash(bool flooded) override
Common code executed for crashed ground vehicles.
bool IsFreeWagon() const
Check if the vehicle is a free wagon (got no engine in front of it).
uint DoUpdateSpeed(uint accel, int min_speed, int max_speed)
Update the speed of the vehicle.
int GetAcceleration() const
Calculates the acceleration of the vehicle under its current conditions.
void ClearFrontEngine()
Remove the front engine state.
void SetLastSpeed()
Update the GUI variant of the current speed of the vehicle.
static void CountVehicle(const Vehicle *v, int delta)
Update num_vehicle when adding or removing a vehicle.
Definition: group_cmd.cpp:133
static debug_inline uint Size()
Get the size of the map.
Definition: map_func.h:288
VehicleSpriteSeq sprite_seq
Vehicle appearance.
Definition: vehicle_base.h:200
static void Backup(const Vehicle *v, uint32_t user)
Create an order backup for the given vehicle.
OrderDepotTypeFlags GetDepotOrderType() const
What caused us going to the depot?
Definition: order_base.h:144
uint16_t 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:201
DestinationID GetDestination() const
Gets the destination of this order.
Definition: order_base.h:103
bool IsType(OrderType type) const
Check whether this order is of the given type.
Definition: order_base.h:70
OrderStopLocation GetStopLocation() const
Where must we stop at the platform?
Definition: order_base.h:142
OrderType GetType() const
Get the type of order of this order.
Definition: order_base.h:76
void MakeDummy()
Makes this order a Dummy order.
Definition: order_cmd.cpp:133
void MakeGoToDepot(DepotID destination, OrderDepotTypeFlags order, OrderNonStopFlags non_stop_type=ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS, OrderDepotActionFlags action=ODATF_SERVICE_ONLY, CargoID cargo=CARGO_NO_REFIT)
Makes this order a Go To Depot order.
Definition: order_cmd.cpp:90
void SetDestination(DestinationID destination)
Sets the destination of this order.
Definition: order_base.h:110
OrderDepotActionFlags GetDepotActionType() const
What are we going to do when in the depot.
Definition: order_base.h:146
void Free()
'Free' the order
Definition: order_cmd.cpp:63
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:2225
OrderNonStopFlags GetNonStopType() const
At which stations must we stop?
Definition: order_base.h:140
TileIndex tile
The base tile of the area.
Definition: tilearea_type.h:19
This struct contains information about the end of a reserved path.
Definition: pbs.h:26
Trackdir trackdir
The reserved trackdir on the tile.
Definition: pbs.h:28
TileIndex tile
Tile the path ends, INVALID_TILE if no valid path was found.
Definition: pbs.h:27
bool okay
True if tile is a safe waiting position, false otherwise.
Definition: pbs.h:29
uint8_t path_backoff_interval
ticks between checks for a free path.
uint8_t wait_for_pbs_path
how long to wait for a path reservation.
uint8_t wait_oneway_signal
waitingtime in days before a oneway signal
bool reserve_paths
always reserve paths regardless of signal type.
YAPFSettings yapf
pathfinder settings for the yet another pathfinder
bool reverse_at_signals
whether to reverse at signals at all
bool forbid_90_deg
forbid trains to make 90 deg turns
uint8_t wait_twoway_signal
waitingtime in days before a twoway signal
Coordinates of a point in 2D.
Tindex index
Index of this pool item.
Definition: pool_type.hpp:238
static Titem * Get(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:339
static bool CanAllocateItem(size_t n=1)
Helper functions so we can use PoolItem::Function() instead of _poolitem_pool.Function()
Definition: pool_type.hpp:309
Information about a rail vehicle.
Definition: engine_type.h:42
uint16_t power
Power of engine (hp); For multiheaded engines the sum of both engine powers.
Definition: engine_type.h:49
uint8_t user_def_data
Property 0x25: "User-defined bit mask" Used only for (very few) NewGRF vehicles.
Definition: engine_type.h:62
uint8_t running_cost
Running cost of engine; For multiheaded engines the sum of both running costs.
Definition: engine_type.h:51
uint8_t shorten_factor
length on main map for this type is 8 - shorten_factor
Definition: engine_type.h:59
uint16_t pow_wag_power
Extra power applied to consist if wagon should be powered.
Definition: engine_type.h:56
uint16_t max_speed
Maximum speed (1 unit = 1/1.6 mph = 1 km-ish/h)
Definition: engine_type.h:48
uint8_t capacity
Cargo capacity of vehicle; For multiheaded engines the capacity of each single engine.
Definition: engine_type.h:54
RailType railtype
Railtype, mangled if elrail is disabled.
Definition: engine_type.h:46
uint8_t pow_wag_weight
Extra weight applied to consist if wagon should be powered.
Definition: engine_type.h:57
Specification of a rectangle with absolute coordinates of all edges.
int Width() const
Get width of Rect.
int Height() const
Get height of Rect.
Iterable ensemble of each set bit in a value.
bool ambient
Play ambient, industry and town sounds.
bool disaster
Play disaster and accident sounds.
static Station * Get(size_t index)
Gets station with given index.
T * Previous() const
Get previous vehicle in the chain.
T * GetLastEnginePart()
Get the last part of an articulated engine.
T * Last()
Get the last vehicle in the chain.
static T * From(Vehicle *v)
Converts a Vehicle to SpecializedVehicle with type checking.
T * GetNextVehicle() const
Get the next real (non-articulated part) vehicle in the consist.
T * Next() const
Get next vehicle in the chain.
void UpdateViewport(bool force_update, bool update_delta)
Update vehicle sprite- and position caches.
T * GetFirstEnginePart()
Get the first part of an articulated engine.
static Pool::IterateWrapper< T > Iterate(size_t from=0)
Returns an iterable ensemble of all valid vehicles of type T.
T * First() const
Get the first vehicle in the chain.
static T * GetIfValid(size_t index)
Returns vehicle if the index is a valid index for this vehicle type.
Station data structure.
Definition: station_base.h:439
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:285
uint16_t cached_max_curve_speed
max consist speed limited by curves
Definition: train.h:81
int16_t cached_curve_speed_mod
curve speed modifier of the entire train
Definition: train.h:80
bool cached_tilt
train can tilt; feature provides a bonus in curves
Definition: train.h:77
Temporary data storage for testing collisions.
Definition: train_cmd.cpp:3173
Train * v
Vehicle we are testing for collision.
Definition: train_cmd.cpp:3174
uint num
Total number of victims if train collided.
Definition: train_cmd.cpp:3175
'Train' is either a loco or a wagon.
Definition: train.h:89
void PlayLeaveStationSound(bool force=false) const override
Play a sound for a train leaving the station.
Definition: train_cmd.cpp:2187
Train * GetNextUnit() const
Get the next real (non-articulated part and non rear part of dualheaded engine) vehicle in the consis...
Definition: train.h:148
void UpdateAcceleration()
Update acceleration of the train from the cached power and weight.
Definition: train_cmd.cpp:430
void OnNewCalendarDay() override
Calendar day handler.
Definition: train_cmd.cpp:4181
Trackdir GetVehicleTrackdir() const override
Get the tracks of the train vehicle.
Definition: train_cmd.cpp:4225
void GetImage(Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) const override
Get the sprite to display the train.
Definition: train_cmd.cpp:494
uint16_t crash_anim_pos
Crash animation counter.
Definition: train.h:91
bool Tick() override
Update train vehicle data for a tick.
Definition: train_cmd.cpp:4114
void ReserveTrackUnderConsist() const
Tries to reserve track under whole train consist.
Definition: train_cmd.cpp:3093
TileIndex GetOrderStationLocation(StationID station) override
Get the location of the next station to visit.
Definition: train_cmd.cpp:2956
int GetDisplayImageWidth(Point *offset=nullptr) const
Get the width of a train vehicle image in the GUI.
Definition: train_cmd.cpp:460
ClosestDepot FindClosestDepot() override
Find the closest depot for this vehicle and tell us the location, DestinationID and whether we should...
Definition: train_cmd.cpp:2178
void UpdateDeltaXY() override
Updates the x and y offsets and the size of the sprite used for this vehicle.
Definition: train_cmd.cpp:1465
int CalcNextVehicleOffset() const
Calculate the offset from this vehicle's center to the following center taking the vehicle lengths in...
Definition: train.h:172
uint16_t GetMaxWeight() const override
Calculates the weight value that this vehicle will have when fully loaded with its current cargo.
Definition: train_cmd.cpp:4242
uint16_t GetCurveSpeedLimit() const
Computes train speed limit caused by curves.
Definition: train_cmd.cpp:307
bool IsPrimaryVehicle() const override
Whether this is the primary vehicle in the chain.
Definition: train.h:116
void MarkDirty() override
Goods at the consist have changed, update the graphics, cargo, and acceleration.
Definition: train_cmd.cpp:2971
int UpdateSpeed()
This function looks at the vehicle and updates its speed (cur_speed and subspeed) variables.
Definition: train_cmd.cpp:2991
uint Crash(bool flooded=false) override
The train vehicle crashed! Update its status and other parts around it.
Definition: train_cmd.cpp:3115
AccelStatus GetAccelerationStatus() const
Checks the current acceleration status of this vehicle.
Definition: train.h:273
void OnNewEconomyDay() override
Economy day handler.
Definition: train_cmd.cpp:4187
void ConsistChanged(ConsistChangeFlags allowed_changes)
Recalculates the cached stuff of a train.
Definition: train_cmd.cpp:110
Money GetRunningCost() const override
Get running cost for the train consist.
Definition: train_cmd.cpp:4089
uint16_t wait_counter
Ticks waiting in front of a signal, ticks being stuck or a counter for forced proceeding through sign...
Definition: train.h:92
int GetCurrentMaxSpeed() const override
Calculates the maximum speed of the vehicle under its current conditions.
Definition: train_cmd.cpp:382
uint16_t cached_max_speed
Maximum speed of the consist (minimum of the max speed of all vehicles in the consist).
Definition: vehicle_base.h:126
UnitID max_trains
max trains in game per company
uint8_t train_acceleration_model
realistic acceleration for trains
bool wagon_speed_limits
enable wagon speed limits
uint8_t freight_trains
value to multiply the weight of cargo by
uint8_t max_train_length
maximum length for trains
Sprite sequence for a vehicle part.
Definition: vehicle_base.h:135
void GetBounds(Rect *bounds) const
Determine shared bounds of all sprites.
Definition: vehicle.cpp:103
void Set(SpriteID sprite)
Assign a single sprite to the sequence.
Definition: vehicle_base.h:168
void Draw(int x, int y, PaletteID default_pal, bool force_pal) const
Draw the sprite sequence.
Definition: vehicle.cpp:131
Vehicle data structure.
Definition: vehicle_base.h:244
EngineID engine_type
The type of engine used for this vehicle.
Definition: vehicle_base.h:323
int32_t z_pos
z coordinate.
Definition: vehicle_base.h:306
Direction direction
facing
Definition: vehicle_base.h:307
const Engine * GetEngine() const
Retrieves the engine of the vehicle.
Definition: vehicle.cpp:747
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:886
bool IsStoppedInDepot() const
Check whether the vehicle is in the depot and stopped.
Definition: vehicle_base.h:560
void LeaveStation()
Perform all actions when leaving a station.
Definition: vehicle.cpp:2350
void AddToShared(Vehicle *shared_chain)
Adds this vehicle to a shared vehicle chain.
Definition: vehicle.cpp:2966
VehicleCargoList cargo
The cargo this vehicle is carrying.
Definition: vehicle_base.h:341
uint8_t x_extent
x-extent of vehicle bounding box
Definition: vehicle_base.h:316
TimerGameEconomy::Date date_of_last_service
Last economy date the vehicle had a service at a depot.
Definition: vehicle_base.h:295
uint16_t cargo_cap
total capacity
Definition: vehicle_base.h:344
StationID last_loading_station
Last station the vehicle has stopped at and could possibly leave from with any cargo loaded.
Definition: vehicle_base.h:338
VehicleOrderID GetNumOrders() const
Get the number of orders this vehicle has.
Definition: vehicle_base.h:738
uint16_t random_bits
Bits used for randomized variational spritegroups.
Definition: vehicle_base.h:335
void ReleaseUnitNumber()
Release the vehicle's unit number.
Definition: vehicle.cpp:2419
uint8_t day_counter
Increased by one for each day.
Definition: vehicle_base.h:349
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:2430
Money profit_this_year
Profit this year << 8, low 8 bits are fract.
Definition: vehicle_base.h:273
SpriteID colourmap
NOSAVE: cached colour mapping.
Definition: vehicle_base.h:288
uint8_t breakdown_ctr
Counter for managing breakdown events.
Definition: vehicle_base.h:299
uint GetAdvanceDistance()
Determines the vehicle "progress" needed for moving a step.
Definition: vehicle_base.h:457
GroupID group_id
Index of group Pool array.
Definition: vehicle_base.h:366
uint8_t z_extent
z-extent of vehicle bounding box
Definition: vehicle_base.h:318
TimerGameCalendar::Date date_of_last_service_newgrf
Last calendar date the vehicle had a service at a depot, unchanged by the date cheat to protect again...
Definition: vehicle_base.h:296
Order * GetOrder(int index) const
Returns order 'index' of a vehicle or nullptr when it doesn't exists.
Definition: vehicle_base.h:922
uint8_t subspeed
fractional speed
Definition: vehicle_base.h:329
bool IsArticulatedPart() const
Check if the vehicle is an articulated part of an engine.
Definition: vehicle_base.h:954
void LeaveUnbunchingDepot()
Leave an unbunching depot and calculate the next departure time for shared order vehicles.
Definition: vehicle.cpp:2514
int8_t y_offs
y offset for vehicle sprite
Definition: vehicle_base.h:322
Vehicle * Next() const
Get the next vehicle of this vehicle.
Definition: vehicle_base.h:632
debug_inline bool IsFrontEngine() const
Check if the vehicle is a front engine.
Definition: vehicle_base.h:945
uint8_t acceleration
used by train & aircraft
Definition: vehicle_base.h:330
int8_t x_bb_offs
x offset of vehicle bounding box
Definition: vehicle_base.h:319
Order current_order
The current order (+ status, like: loading)
Definition: vehicle_base.h:356
CargoID cargo_type
type of cargo this vehicle is carrying
Definition: vehicle_base.h:342
void HandlePathfindingResult(bool path_found)
Handle the pathfinding result, especially the lost status.
Definition: vehicle.cpp:791
int8_t x_offs
x offset for vehicle sprite
Definition: vehicle_base.h:321
int32_t y_pos
y coordinate.
Definition: vehicle_base.h:305
int32_t x_pos
x coordinate.
Definition: vehicle_base.h:304
const GRFFile * GetGRF() const
Retrieve the NewGRF the vehicle is tied to.
Definition: vehicle.cpp:757
OrderList * orders
Pointer to the order list for this vehicle.
Definition: vehicle_base.h:359
uint8_t y_extent
y-extent of vehicle bounding box
Definition: vehicle_base.h:317
Money value
Value of the vehicle.
Definition: vehicle_base.h:275
uint16_t refit_cap
Capacity left over from before last refit.
Definition: vehicle_base.h:345
void InvalidateNewGRFCache()
Invalidates cached NewGRF variables.
Definition: vehicle_base.h:495
uint8_t vehstatus
Status.
Definition: vehicle_base.h:354
VehicleCache vcache
Cache of often used vehicle values.
Definition: vehicle_base.h:364
uint32_t GetGRFID() const
Retrieve the GRF ID of the NewGRF the vehicle is tied to.
Definition: vehicle.cpp:767
int8_t y_bb_offs
y offset of vehicle bounding box
Definition: vehicle_base.h:320
void BeginLoading()
Prepare everything to begin the loading when arriving at a station.
Definition: vehicle.cpp:2203
uint8_t spritenum
currently displayed sprite index 0xfd == custom sprite, 0xfe == custom second head sprite 0xff == res...
Definition: vehicle_base.h:315
uint16_t cur_speed
current speed
Definition: vehicle_base.h:328
uint8_t cargo_subtype
Used for livery refits (NewGRF variations)
Definition: vehicle_base.h:343
bool IsWaitingForUnbunching() const
Check whether a vehicle inside a depot is waiting for unbunching.
Definition: vehicle.cpp:2561
TextEffectID fill_percent_te_id
a text-effect id to a loading indicator object
Definition: vehicle_base.h:325
void SetNext(Vehicle *next)
Set the next vehicle of this vehicle.
Definition: vehicle.cpp:2937
TimerGameCalendar::Date max_age
Maximum age.
Definition: vehicle_base.h:294
MutableSpriteCache sprite_cache
Cache of sprites and values related to recalculating them, see MutableSpriteCache.
Definition: vehicle_base.h:368
uint16_t reliability
Reliability.
Definition: vehicle_base.h:297
bool HandleBreakdown()
Handle all of the aspects of a vehicle breakdown This includes adding smoke and sounds,...
Definition: vehicle.cpp:1363
uint8_t progress
The percentage (if divided by 256) this vehicle already crossed the tile unit.
Definition: vehicle_base.h:332
uint16_t reliability_spd_dec
Reliability decrease speed.
Definition: vehicle_base.h:298
uint8_t tick_counter
Increased by one for each tick.
Definition: vehicle_base.h:350
TileIndex tile
Current tile index.
Definition: vehicle_base.h:264
TileIndex dest_tile
Heading for this tile.
Definition: vehicle_base.h:271
void CopyVehicleConfigAndStatistics(Vehicle *src)
Copy certain configurations and statistics of a vehicle after successful autoreplace/renew The functi...
Definition: vehicle_base.h:765
void UpdatePosition()
Update the position of the vehicle.
Definition: vehicle.cpp:1693
StationID last_station_visited
The last station we stopped at.
Definition: vehicle_base.h:337
void ShowVisualEffect() const
Draw visual effects (smoke and/or sparks) for a vehicle chain.
Definition: vehicle.cpp:2787
TimerGameCalendar::Year build_year
Year the vehicle has been built.
Definition: vehicle_base.h:291
Owner owner
Which company owns the vehicle?
Definition: vehicle_base.h:309
UnitID unitnumber
unit number, for display purposes only
Definition: vehicle_base.h:326
bool NeedsAutomaticServicing() const
Checks if the current order should be interrupted for a service-in-depot order.
Definition: vehicle.cpp:272
uint8_t running_ticks
Number of ticks this vehicle was not stopped this day.
Definition: vehicle_base.h:351
uint32_t maximum_go_to_depot_penalty
What is the maximum penalty that may be endured for going to a depot.
@ VETS_CANNOT_ENTER
The vehicle cannot enter the tile.
Definition: tile_cmd.h:24
@ VETS_ENTERED_WORMHOLE
The vehicle either entered a bridge, tunnel or depot tile (this includes the last tile of the bridge/...
Definition: tile_cmd.h:23
@ VETS_ENTERED_STATION
The vehicle entered a station.
Definition: tile_cmd.h:22
@ VETS_STATION_ID_OFFSET
Shift the VehicleEnterTileStatus this many bits to the right to get the station ID when VETS_ENTERED_...
Definition: tile_cmd.h:31
VehicleEnterTileStatus VehicleEnterTile(Vehicle *v, TileIndex tile, int x, int y)
Call the tile callback function for a vehicle entering a tile.
Definition: vehicle.cpp:1838
bool IsTileOwner(Tile tile, Owner owner)
Checks if a tile belongs to the given owner.
Definition: tile_map.h:214
Owner GetTileOwner(Tile tile)
Returns the owner of a tile.
Definition: tile_map.h:178
static debug_inline bool IsTileType(Tile tile, TileType type)
Checks if a tile is a given tiletype.
Definition: tile_map.h:150
static const uint TILE_SIZE
Tile size in world coordinates.
Definition: tile_type.h:15
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition: tile_type.h:95
@ MP_STATION
A tile of a station.
Definition: tile_type.h:53
@ MP_TUNNELBRIDGE
Tunnel entry/exit and bridge heads.
Definition: tile_type.h:57
@ MP_RAILWAY
A railway.
Definition: tile_type.h:49
Definition of the game-calendar-timer.
Definition of the game-economy-timer.
Trackdir RemoveFirstTrackdir(TrackdirBits *trackdirs)
Removes first Trackdir from TrackdirBits and returns it.
Definition: track_func.h:156
Track TrackdirToTrack(Trackdir trackdir)
Returns the Track that a given Trackdir represents.
Definition: track_func.h:262
TrackBits TrackToTrackBits(Track track)
Maps a Track to the corresponding TrackBits value.
Definition: track_func.h:77
TrackdirBits TrackBitsToTrackdirBits(TrackBits bits)
Converts TrackBits to TrackdirBits while allowing both directions.
Definition: track_func.h:319
DiagDirection VehicleExitDir(Direction direction, TrackBits track)
Determine the side in which the vehicle will leave the tile.
Definition: track_func.h:714
TrackdirBits TrackStatusToTrackdirBits(TrackStatus ts)
Returns the present-trackdir-information of a TrackStatus.
Definition: track_func.h:352
Track TrackBitsToTrack(TrackBits tracks)
Converts TrackBits to Track.
Definition: track_func.h:193
TrackBits TrackCrossesTracks(Track track)
Maps a track to all tracks that make 90 deg turns with it.
Definition: track_func.h:420
Trackdir ReverseTrackdir(Trackdir trackdir)
Maps a trackdir to the reverse trackdir.
Definition: track_func.h:247
bool TracksOverlap(TrackBits bits)
Checks if the given tracks overlap, ie form a crossing.
Definition: track_func.h:645
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:498
bool IsValidTrackdir(Trackdir trackdir)
Checks if a Trackdir is valid for non-road vehicles.
Definition: track_func.h:52
Trackdir FindFirstTrackdir(TrackdirBits trackdirs)
Returns first Trackdir from TrackdirBits or INVALID_TRACKDIR.
Definition: track_func.h:211
TrackdirBits TrackdirCrossesTrackdirs(Trackdir trackdir)
Maps a trackdir to all trackdirs that make 90 deg turns with it.
Definition: track_func.h:606
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:584
TrackdirBits DiagdirReachesTrackdirs(DiagDirection diagdir)
Returns all trackdirs that can be reached when entering a tile from a given (diagonal) direction.
Definition: track_func.h:555
Track FindFirstTrack(TrackBits tracks)
Returns first Track from TrackBits or INVALID_TRACK.
Definition: track_func.h:177
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:486
TrackBits DiagdirReachesTracks(DiagDirection diagdir)
Returns all tracks that can be reached when entering a tile from a given (diagonal) direction.
Definition: track_func.h:573
TrackBits DiagDirToDiagTrackBits(DiagDirection diagdir)
Maps a (4-way) direction to the diagonal track bits incidating with that diagdir.
Definition: track_func.h:524
Trackdir DiagDirToDiagTrackdir(DiagDirection diagdir)
Maps a (4-way) direction to the diagonal trackdir that runs in that direction.
Definition: track_func.h:537
TrackdirBits TrackStatusToRedSignals(TrackStatus ts)
Returns the red-signal-information of a TrackStatus.
Definition: track_func.h:376
DiagDirection TrackdirToExitdir(Trackdir trackdir)
Maps a trackdir to the (4-way) direction the tile is exited when following that trackdir.
Definition: track_func.h:439
Track DiagDirToDiagTrack(DiagDirection diagdir)
Maps a (4-way) direction to the diagonal track incidating with that diagdir.
Definition: track_func.h:512
TrackBits TrackdirBitsToTrackBits(TrackdirBits bits)
Discards all directional information from a TrackdirBits value.
Definition: track_func.h:308
TrackBits
Allow incrementing of Track variables.
Definition: track_type.h:35
@ TRACK_BIT_WORMHOLE
Bitflag for a wormhole (used for tunnels)
Definition: track_type.h:52
@ TRACK_BIT_UPPER
Upper track.
Definition: track_type.h:39
@ TRACK_BIT_DEPOT
Bitflag for a depot.
Definition: track_type.h:53
@ TRACK_BIT_LEFT
Left track.
Definition: track_type.h:41
@ TRACK_BIT_Y
Y-axis track.
Definition: track_type.h:38
@ TRACK_BIT_NONE
No track.
Definition: track_type.h:36
@ TRACK_BIT_X
X-axis track.
Definition: track_type.h:37
@ TRACK_BIT_MASK
Bitmask for the first 6 bits.
Definition: track_type.h:51
@ TRACK_BIT_LOWER
Lower track.
Definition: track_type.h:40
@ TRACK_BIT_RIGHT
Right track.
Definition: track_type.h:42
Trackdir
Enumeration for tracks and directions.
Definition: track_type.h:67
@ INVALID_TRACKDIR
Flag for an invalid trackdir.
Definition: track_type.h:86
TrackdirBits
Allow incrementing of Trackdir variables.
Definition: track_type.h:98
@ TRACKDIR_BIT_NONE
No track build.
Definition: track_type.h:99
Track
These are used to specify a single track.
Definition: track_type.h:19
@ INVALID_TRACK
Flag for an invalid track.
Definition: track_type.h:28
@ TRACK_Y
Track along the y-axis (north-west to south-east)
Definition: track_type.h:22
@ TRACK_BEGIN
Used for iterations.
Definition: track_type.h:20
@ TRACK_X
Track along the x-axis (north-east to south-west)
Definition: track_type.h:21
@ VRF_POWEREDWAGON
Wagon is powered.
Definition: train.h:27
@ VRF_LEAVING_STATION
Train is just leaving a station.
Definition: train.h:33
@ VRF_TOGGLE_REVERSE
Used for vehicle var 0xFE bit 8 (toggled each time the train is reversed, accurate for first vehicle ...
Definition: train.h:31
@ VRF_REVERSE_DIRECTION
Reverse the visible direction of the vehicle.
Definition: train.h:28
@ VRF_EL_ENGINE_ALLOWED_NORMAL_RAIL
Electric train engine is allowed to run on normal rail. *‍/.
Definition: train.h:30
@ VRF_TRAIN_STUCK
Train can't get a path reservation.
Definition: train.h:32
ConsistChangeFlags
Flags for Train::ConsistChanged.
Definition: train.h:44
@ CCF_CAPACITY
Allow vehicles to change capacity.
Definition: train.h:46
@ CCF_ARRANGE
Valid changes for arranging the consist in a depot.
Definition: train.h:52
@ CCF_LENGTH
Allow vehicles to change length.
Definition: train.h:45
@ CCF_TRACK
Valid changes while vehicle is driving, and possibly changing tracks.
Definition: train.h:48
@ TFP_SIGNAL
Ignore next signal, after the signal ignore being stuck.
Definition: train.h:40
@ TFP_NONE
Normal operation.
Definition: train.h:38
@ TFP_STUCK
Proceed till next signal, but ignore being stuck till then. This includes force leaving depots.
Definition: train.h:39
static void AffectSpeedByZChange(Train *v, int old_z)
Modify the speed of the vehicle due to a change in altitude.
Definition: train_cmd.cpp:3064
CommandCost CmdBuildRailVehicle(DoCommandFlag flags, TileIndex tile, const Engine *e, Vehicle **ret)
Build a railroad vehicle.
Definition: train_cmd.cpp:750
static void NormaliseTrainHead(Train *head)
Normalise the head of the train again, i.e.
Definition: train_cmd.cpp:1163
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:1102
static bool CheckTrainStayInDepot(Train *v)
Will the train stay in the depot the next tick?
Definition: train_cmd.cpp:2268
static FindDepotData FindClosestTrainDepot(Train *v, int max_distance)
Try to find a depot nearby.
Definition: train_cmd.cpp:2166
void UpdateLevelCrossing(TileIndex tile, bool sound, bool force_bar)
Update a level crossing to barred or open (crossing may include multiple adjacent tiles).
Definition: train_cmd.cpp:1773
static Vehicle * CollectTrackbitsFromCrashedVehiclesEnum(Vehicle *v, void *data)
Collect trackbits of all crashed train vehicles on a tile.
Definition: train_cmd.cpp:3604
static void MakeTrainBackup(TrainList &list, Train *t)
Make a backup of a train into a train list.
Definition: train_cmd.cpp:852
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:2206
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:1122
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:2871
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's destination.
Definition: train_cmd.cpp:2598
static const uint16_t _breakdown_speeds[16]
Maximum speeds for train that is broken down or approaching line end.
Definition: train_cmd.cpp:3779
static bool TrainApproachingLineEnd(Train *v, bool signal, bool reverse)
Train is approaching line end, slow down and possibly reverse.
Definition: train_cmd.cpp:3792
static bool CheckTrainCollision(Train *v)
Checks whether the specified train has a collision with another vehicle.
Definition: train_cmd.cpp:3231
static void InsertInConsist(Train *dst, Train *chain)
Inserts a chain into the train at dst.
Definition: train_cmd.cpp:901
void UpdateAdjacentLevelCrossingTilesOnLevelCrossingRemoval(TileIndex tile, Axis road_axis)
Update adjacent level crossing tiles in this multi-track crossing, due to removal of a level crossing...
Definition: train_cmd.cpp:1822
static void SwapTrainFlags(uint16_t *swap_flag1, uint16_t *swap_flag2)
Swap the two up/down flags in two ways:
Definition: train_cmd.cpp:1565
CommandCost CmdMoveRailVehicle(DoCommandFlag flags, VehicleID src_veh, VehicleID dest_veh, bool move_chain)
Move a rail vehicle around inside the depot.
Definition: train_cmd.cpp:1193
static void UpdateLevelCrossingTile(TileIndex tile, bool sound, bool force_barred)
Sets a level crossing tile to the correct state.
Definition: train_cmd.cpp:1751
static Vehicle * TrainOnTileEnum(Vehicle *v, void *)
Check if the vehicle is a train.
Definition: train_cmd.cpp:1672
static bool HandleCrashedTrain(Train *v)
Handle a crashed train.
Definition: train_cmd.cpp:3740
void NormalizeTrainVehInDepot(const Train *u)
Move all free vehicles in the depot to the train.
Definition: train_cmd.cpp:693
static bool CheckLevelCrossing(TileIndex tile)
Check if a level crossing should be barred.
Definition: train_cmd.cpp:1738
uint8_t FreightWagonMult(CargoID cargo)
Return the cargo weight multiplier to use for a rail vehicle.
Definition: train_cmd.cpp:69
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:969
static void AdvanceWagonsBeforeSwap(Train *v)
Advances wagons for train reversing, needed for variable length wagons.
Definition: train_cmd.cpp:1874
static void AdvanceWagonsAfterSwap(Train *v)
Advances wagons for train reversing, needed for variable length wagons.
Definition: train_cmd.cpp:1902
static bool TrainCheckIfLineEnds(Train *v, bool reverse=true)
Checks for line end.
Definition: train_cmd.cpp:3894
void ReverseTrainDirection(Train *v)
Turn a train around.
Definition: train_cmd.cpp:1967
void FreeTrainTrackReservation(const Train *v)
Free the reserved path in front of a vehicle.
Definition: train_cmd.cpp:2391
CommandCost CmdSellRailWagon(DoCommandFlag flags, Vehicle *t, bool sell_chain, bool backup_order, ClientID user)
Sell a (single) train wagon/engine.
Definition: train_cmd.cpp:1391
static uint TrainCrashed(Train *v)
Marks train as crashed and creates an AI event.
Definition: train_cmd.cpp:3154
static void NormaliseDualHeads(Train *t)
Normalise the dual heads in the train, i.e.
Definition: train_cmd.cpp:915
static CommandCost CheckTrainAttachment(Train *t)
Check whether the train parts can be attached.
Definition: train_cmd.cpp:993
static const AccelerationSlowdownParams _accel_slowdown[]
Speed update fractions for each acceleration type.
Definition: train_cmd.cpp:3052
static Track DoTrainPathfind(const Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found, bool do_track_reservation, PBSTileInfo *dest, TileIndex *final_dest)
Perform pathfinding for a train.
Definition: train_cmd.cpp:2474
static CommandCost CmdBuildRailWagon(DoCommandFlag flags, TileIndex tile, const Engine *e, Vehicle **ret)
Build a railroad wagon.
Definition: train_cmd.cpp:616
CommandCost CmdForceTrainProceed(DoCommandFlag flags, VehicleID veh_id)
Force a train through a red signal.
Definition: train_cmd.cpp:2132
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:2350
void CheckTrainsLengths()
Checks if lengths of all rail vehicles are valid.
Definition: train_cmd.cpp:76
static void MaybeBarCrossingWithSound(TileIndex tile)
Bars crossing and plays ding-ding sound if not barred already.
Definition: train_cmd.cpp:1860
bool TrainOnCrossing(TileIndex tile)
Check if a level crossing tile has a train on it.
Definition: train_cmd.cpp:1683
static void ChangeTrainDirRandomly(Train *v)
Rotate all vehicles of a (crashed) train chain randomly to animate the crash.
Definition: train_cmd.cpp:3712
void MarkDirtyAdjacentLevelCrossingTiles(TileIndex tile, Axis road_axis)
Find adjacent level crossing tiles in this multi-track crossing and mark them dirty.
Definition: train_cmd.cpp:1805
static Vehicle * FindTrainCollideEnum(Vehicle *v, void *data)
Collision test function.
Definition: train_cmd.cpp:3184
static void NormaliseSubtypes(Train *chain)
Normalise the sub types of the parts in this chain.
Definition: train_cmd.cpp:937
bool TrainController(Train *v, Vehicle *nomove, bool reverse=true)
Move a vehicle chain one movement stop forwards.
Definition: train_cmd.cpp:3283
static TileIndex TrainApproachingCrossingTile(const Train *v)
Determines whether train is approaching a rail-road crossing (thus making it barred)
Definition: train_cmd.cpp:3867
static void RemoveFromConsist(Train *part, bool chain=false)
Remove the given wagon from its consist.
Definition: train_cmd.cpp:884
static void RestoreTrainBackup(TrainList &list)
Restore the train from the backup list.
Definition: train_cmd.cpp:861
static void DeleteLastWagon(Train *v)
Deletes/Clears the last wagon of a crashed train.
Definition: train_cmd.cpp:3642
static bool TrainCanLeaveTile(const Train *v)
Determines whether train would like to leave the tile.
Definition: train_cmd.cpp:3837
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:263
static Vehicle * TrainApproachingCrossingEnum(Vehicle *v, void *data)
Checks if a train is approaching a rail-road crossing.
Definition: train_cmd.cpp:1697
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:3008
static void MarkTrainAsStuck(Train *v)
Mark a train as stuck and stop it if it isn't stopped right now.
Definition: train_cmd.cpp:1541
static bool TrainApproachingCrossing(TileIndex tile)
Finds a vehicle approaching rail-road crossing.
Definition: train_cmd.cpp:1718
void ReverseTrainSwapVeh(Train *v, int l, int r)
Swap vehicles l and r in consist v, and reverse their direction.
Definition: train_cmd.cpp:1630
static PBSTileInfo ExtendTrainReservation(const Train *v, TrackBits *new_tracks, DiagDirection *enterdir)
Extend a train path as far as possible.
Definition: train_cmd.cpp:2485
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:581
static void CheckIfTrainNeedsService(Train *v)
Check whether a train needs service, and if so, find a depot or service it.
Definition: train_cmd.cpp:4143
std::vector< Train * > TrainList
Helper type for lists/vectors of trains.
Definition: train_cmd.cpp:845
static void UpdateStatusAfterSwap(Train *v)
Updates some variables after swapping the vehicle.
Definition: train_cmd.cpp:1593
CommandCost CmdReverseTrainDirection(DoCommandFlag flags, VehicleID veh_id, bool reverse_single_veh)
Reverse train.
Definition: train_cmd.cpp:2059
Command definitions related to trains.
Sprites to use for trains.
@ TRANSPORT_RAIL
Transport by train.
bool IsTunnel(Tile t)
Is this a tunnel (entrance)?
Definition: tunnel_map.h:23
void MarkBridgeDirty(TileIndex begin, TileIndex end, DiagDirection direction, uint bridge_height)
Mark bridge tiles dirty.
DiagDirection GetTunnelBridgeDirection(Tile t)
Get the direction pointing to the other end.
TileIndex GetOtherTunnelBridgeEnd(Tile t)
Determines type of the wormhole and returns its other end.
void SetTunnelBridgeReservation(Tile t, bool b)
Set the reservation state of the rail tunnel/bridge.
void VehicleEnterDepot(Vehicle *v)
Vehicle entirely entered the depot, update its status, orders, vehicle windows, service it,...
Definition: vehicle.cpp:1552
UnitID GetFreeUnitNumber(VehicleType type)
Get an unused unit number for a vehicle (if allowed).
Definition: vehicle.cpp:1895
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:346
void VehicleServiceInDepot(Vehicle *v)
Service a vehicle and all subsequent vehicles in the consist.
Definition: vehicle.cpp:167
void FindVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc)
Find a vehicle from a specific location.
Definition: vehicle.cpp:445
GetNewVehiclePosResult GetNewVehiclePos(const Vehicle *v)
Get position information of a vehicle when moving one pixel in the direction it is facing.
Definition: vehicle.cpp:1784
bool HasVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
Checks whether a vehicle is on a specific location.
Definition: vehicle.cpp:520
void FindVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
Find a vehicle from a specific location.
Definition: vehicle.cpp:505
void DecreaseVehicleValue(Vehicle *v)
Decrease the value of a vehicle.
Definition: vehicle.cpp:1301
void EconomyAgeVehicle(Vehicle *v)
Update economy age of a vehicle.
Definition: vehicle.cpp:1429
CommandCost TunnelBridgeIsFree(TileIndex tile, TileIndex endtile, const Vehicle *ignore)
Finds vehicle in tunnel / bridge.
Definition: vehicle.cpp:575
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:317
void AgeVehicle(Vehicle *v)
Update age of a vehicle.
Definition: vehicle.cpp:1441
@ VF_BUILT_AS_PROTOTYPE
Vehicle is a prototype (accepted as exclusive preview).
Definition: vehicle_base.h:47
@ VS_TRAIN_SLOWING
Train is slowing down.
Definition: vehicle_base.h:37
@ VS_STOPPED
Vehicle is stopped by the player.
Definition: vehicle_base.h:34
@ VS_HIDDEN
Vehicle is not visible.
Definition: vehicle_base.h:33
@ VS_CRASHED
Vehicle is crashed.
Definition: vehicle_base.h:40
@ VS_DEFPAL
Use default vehicle palette.
Definition: vehicle_base.h:36
@ VE_DISABLE_WAGON_POWER
Flag to disable wagon power.
Definition: vehicle_base.h:95
Functions related to vehicles.
@ VIWD_CONSIST_CHANGED
Vehicle composition was changed.
Definition: vehicle_gui.h:37
EngineImageType
Visualisation contexts of vehicles and engines.
Definition: vehicle_type.h:78
@ VEH_TRAIN
Train vehicle type.
Definition: vehicle_type.h:24
uint32_t VehicleID
The type all our vehicle IDs have.
Definition: vehicle_type.h:16
static const VehicleID INVALID_VEHICLE
Constant representing a non-existing vehicle.
Definition: vehicle_type.h:54
static const uint VEHICLE_LENGTH
The length of a vehicle in tile units.
Definition: vehicle_type.h:69
@ WID_VV_REFIT
Open the refit window.
@ WID_VV_START_STOP
Start or stop this vehicle, and show information about the current state.
Functions related to (drawing on) viewports.
void CloseWindowById(WindowClass cls, WindowNumber number, bool force, int data)
Close a window by its class and window number (if it is open).
Definition: window.cpp:1140
void SetWindowClassesDirty(WindowClass cls)
Mark all windows of a particular class as dirty (in need of repainting)
Definition: window.cpp:3119
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:3211
void SetWindowWidgetDirty(WindowClass cls, WindowNumber number, WidgetID widget_index)
Mark a particular widget in a particular window as dirty (in need of repainting)
Definition: window.cpp:3106
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting)
Definition: window.cpp:3093
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:3228
@ WC_VEHICLE_ORDERS
Vehicle orders; Window numbers:
Definition: window_type.h:212
@ WC_VEHICLE_DEPOT
Depot view; Window numbers:
Definition: window_type.h:351
@ WC_TRAINS_LIST
Trains list; Window numbers:
Definition: window_type.h:308
@ WC_VEHICLE_REFIT
Vehicle refit; Window numbers:
Definition: window_type.h:206
@ WC_VEHICLE_DETAILS
Vehicle details; Window numbers:
Definition: window_type.h:200
@ WC_COMPANY
Company view; Window numbers:
Definition: window_type.h:369
@ WC_VEHICLE_VIEW
Vehicle view; Window numbers:
Definition: window_type.h:339
@ WC_VEHICLE_TIMETABLE
Vehicle timetable; Window numbers:
Definition: window_type.h:224
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:612
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:625
bool YapfTrainCheckReverse(const Train *v)
Returns true if it is better to reverse the train before leaving station using YAPF.
Definition: yapf_rail.cpp:559
Track YapfTrainChooseTrack(const Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found, bool reserve_track, struct PBSTileInfo *target, TileIndex *dest)
Finds the best path for given train using YAPF.
Definition: yapf_rail.cpp:550
Base includes/functions for YAPF.
Functions related to zooming.
int ScaleSpriteTrad(int value)
Scale traditional pixel dimensions to GUI zoom level, for drawing sprites.
Definition: zoom_func.h:107
int UnScaleGUI(int value)
Short-hand to apply GUI zoom level.
Definition: zoom_func.h:77