OpenTTD Source 20260911-master-gee2b2ac12a
roadveh_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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
10#include "stdafx.h"
11#include "roadveh.h"
12#include "command_func.h"
13#include "error_func.h"
14#include "news_func.h"
15#include "station_base.h"
16#include "company_func.h"
18#include "newgrf_sound.h"
20#include "strings_func.h"
21#include "tunnelbridge_map.h"
22#include "script/api/script_event_types.hpp"
25#include "vehicle_func.h"
26#include "sound_func.h"
27#include "ai/ai.hpp"
28#include "game/game.hpp"
29#include "depot_map.h"
30#include "effectvehicle_func.h"
31#include "roadstop_base.h"
32#include "core/random_func.hpp"
33#include "company_base.h"
34#include "core/backup_type.hpp"
35#include "newgrf.h"
36#include "zoom_func.h"
37#include "framerate_type.h"
38#include "roadveh_cmd.h"
39#include "road_cmd.h"
40#include "newgrf_roadstop.h"
41
42#include "table/strings.h"
43
44#include "safeguards.h"
45
46static const uint16_t _roadveh_images[] = {
47 0xCD4, 0xCDC, 0xCE4, 0xCEC, 0xCF4, 0xCFC, 0xD0C, 0xD14,
48 0xD24, 0xD1C, 0xD2C, 0xD04, 0xD1C, 0xD24, 0xD6C, 0xD74,
49 0xD7C, 0xC14, 0xC1C, 0xC24, 0xC2C, 0xC34, 0xC3C, 0xC4C,
50 0xC54, 0xC64, 0xC5C, 0xC6C, 0xC44, 0xC5C, 0xC64, 0xCAC,
51 0xCB4, 0xCBC, 0xD94, 0xD9C, 0xDA4, 0xDAC, 0xDB4, 0xDBC,
52 0xDCC, 0xDD4, 0xDE4, 0xDDC, 0xDEC, 0xDC4, 0xDDC, 0xDE4,
53 0xE2C, 0xE34, 0xE3C, 0xC14, 0xC1C, 0xC2C, 0xC3C, 0xC4C,
54 0xC5C, 0xC64, 0xC6C, 0xC74, 0xC84, 0xC94, 0xCA4
55};
56
57static const uint16_t _roadveh_full_adder[] = {
58 0, 88, 0, 0, 0, 0, 48, 48,
59 48, 48, 0, 0, 64, 64, 0, 16,
60 16, 0, 88, 0, 0, 0, 0, 48,
61 48, 48, 48, 0, 0, 64, 64, 0,
62 16, 16, 0, 88, 0, 0, 0, 0,
63 48, 48, 48, 48, 0, 0, 64, 64,
64 0, 16, 16, 0, 8, 8, 8, 8,
65 0, 0, 0, 8, 8, 8, 8
66};
67static_assert(lengthof(_roadveh_images) == lengthof(_roadveh_full_adder));
68
70template <>
71bool IsValidImageIndex<VehicleType::Road>(uint8_t image_index)
72{
73 return image_index < lengthof(_roadveh_images);
74}
75
80
86{
87 assert(this->IsFrontEngine());
89}
90
97{
98 int reference_width = ROADVEHINFO_DEFAULT_VEHICLE_WIDTH;
99
100 if (offset != nullptr) {
101 offset->x = ScaleSpriteTrad(reference_width) / 2;
102 offset->y = 0;
103 }
104 return ScaleSpriteTrad(this->gcache.cached_veh_length * reference_width / VEHICLE_LENGTH);
105}
106
107static void GetRoadVehIcon(EngineID engine, EngineImageType image_type, VehicleSpriteSeq *result)
108{
109 const Engine *e = Engine::Get(engine);
110 uint8_t spritenum = e->VehInfo<RoadVehicleInfo>().image_index;
111
112 if (IsCustomVehicleSpriteNum(spritenum)) {
113 GetCustomVehicleIcon(engine, Direction::W, image_type, result);
114 if (result->IsValid()) return;
115
116 spritenum = e->original_image_index;
117 }
118
119 assert(IsValidImageIndex<VehicleType::Road>(spritenum));
120 result->Set(to_underlying(Direction::W) + _roadveh_images[spritenum]);
121}
122
124{
125 uint8_t spritenum = this->spritenum;
126
127 if (IsCustomVehicleSpriteNum(spritenum)) {
129 GetCustomVehicleSprite(this, direction, image_type, result);
130 if (result->IsValid()) return;
131
133 }
134
136 SpriteID sprite = to_underlying(direction) + _roadveh_images[spritenum];
137
138 if (this->cargo.StoredCount() >= this->cargo_cap / 2U) sprite += _roadveh_full_adder[spritenum];
139
140 result->Set(sprite);
141}
142
153void DrawRoadVehEngine(int left, int right, int preferred_x, int y, EngineID engine, PaletteID pal, EngineImageType image_type)
154{
156 GetRoadVehIcon(engine, image_type, &seq);
157
158 Rect rect;
159 seq.GetBounds(&rect);
160 preferred_x = Clamp(preferred_x,
161 left - UnScaleGUI(rect.left),
162 right - UnScaleGUI(rect.right));
163
164 seq.Draw(preferred_x, y, pal, pal == PALETTE_CRASH);
165}
166
176void GetRoadVehSpriteSize(EngineID engine, uint &width, uint &height, int &xoffs, int &yoffs, EngineImageType image_type)
177{
179 GetRoadVehIcon(engine, image_type, &seq);
180
181 Rect rect;
182 seq.GetBounds(&rect);
183
184 width = UnScaleGUI(rect.Width());
185 height = UnScaleGUI(rect.Height());
186 xoffs = UnScaleGUI(rect.left);
187 yoffs = UnScaleGUI(rect.top);
188}
189
195static uint GetRoadVehLength(const RoadVehicle *v)
196{
197 const Engine *e = v->GetEngine();
198 uint length = VEHICLE_LENGTH;
199
200 uint16_t veh_len = CALLBACK_FAILED;
201 if (e->GetGRF() != nullptr && e->GetGRF()->grf_version >= 8) {
202 /* Use callback 36 */
203 veh_len = GetVehicleProperty(v, PROP_ROADVEH_SHORTEN_FACTOR, CALLBACK_FAILED);
204 if (veh_len != CALLBACK_FAILED && veh_len >= VEHICLE_LENGTH) ErrorUnknownCallbackResult(e->GetGRFID(), CBID_VEHICLE_LENGTH, veh_len);
205 } else {
206 /* Use callback 11 */
207 veh_len = GetVehicleCallback(CBID_VEHICLE_LENGTH, 0, 0, v->engine_type, v);
208 }
209 if (veh_len == CALLBACK_FAILED) veh_len = e->VehInfo<RoadVehicleInfo>().shorten_factor;
210 if (veh_len != 0) {
211 length -= Clamp(veh_len, 0, VEHICLE_LENGTH - 1);
212 }
213
214 return length;
215}
216
223void RoadVehUpdateCache(RoadVehicle *v, bool same_length)
224{
225 assert(v->type == VehicleType::Road);
226 assert(v->IsFrontEngine());
227
229
231
232 for (RoadVehicle *u = v; u != nullptr; u = u->Next()) {
233 /* Check the v->first cache. */
234 assert(u->First() == v);
235
236 /* Update the 'first engine' */
237 u->gcache.first_engine = (v == u) ? EngineID::Invalid() : v->engine_type;
238
239 /* Update the length of the vehicle. */
240 uint veh_len = GetRoadVehLength(u);
241 /* Verify length hasn't changed. */
242 if (same_length && veh_len != u->gcache.cached_veh_length) VehicleLengthChanged(u);
243
244 u->gcache.cached_veh_length = veh_len;
245 v->gcache.cached_total_length += u->gcache.cached_veh_length;
246
247 /* Update visual effect */
248 u->UpdateVisualEffect();
249
250 /* Update cargo aging period. */
251 u->vcache.cached_cargo_age_period = GetVehicleProperty(u, PROP_ROADVEH_CARGO_AGE_PERIOD, EngInfo(u->engine_type)->cargo_age_period);
252 }
253
254 uint max_speed = GetVehicleProperty(v, PROP_ROADVEH_SPEED, 0);
255 v->vcache.cached_max_speed = (max_speed != 0) ? max_speed * 4 : RoadVehInfo(v->engine_type)->max_speed;
256}
257
267{
268 /* Check that the vehicle can drive on the road in question */
269 RoadType rt = e->VehInfo<RoadVehicleInfo>().roadtype;
270 const RoadTypeInfo *rti = GetRoadTypeInfo(rt);
271 if (!HasTileAnyRoadType(tile, rti->powered_roadtypes)) return CommandCost(STR_ERROR_DEPOT_WRONG_DEPOT_TYPE);
272
273 if (flags.Test(DoCommandFlag::Execute)) {
274 const RoadVehicleInfo *rvi = &e->VehInfo<RoadVehicleInfo>();
275
277 *ret = v;
279 v->owner = _current_company;
280
281 v->tile = tile;
282 int x = TileX(tile) * TILE_SIZE + TILE_SIZE / 2;
283 int y = TileY(tile) * TILE_SIZE + TILE_SIZE / 2;
284 v->x_pos = x;
285 v->y_pos = y;
286 v->z_pos = GetSlopePixelZ(x, y, true);
287
288 v->state = RVSB_IN_DEPOT;
290
291 v->spritenum = rvi->image_index;
292 v->cargo_type = e->GetDefaultCargoType();
293 assert(IsValidCargoType(v->cargo_type));
294 v->cargo_cap = rvi->capacity;
295 v->refit_cap = 0;
296
297 v->last_station_visited = StationID::Invalid();
298 v->last_loading_station = StationID::Invalid();
299 v->engine_type = e->index;
300 v->gcache.first_engine = EngineID::Invalid(); // needs to be set before first callback
301
302 v->reliability = e->reliability;
303 v->reliability_spd_dec = e->reliability_spd_dec;
304 v->max_age = e->GetLifeLengthInDays();
305
306 v->SetServiceInterval(Company::Get(v->owner)->settings.vehicle.servint_roadveh);
307
308 v->date_of_last_service = TimerGameEconomy::date;
309 v->date_of_last_service_newgrf = TimerGameCalendar::date;
310 v->build_year = TimerGameCalendar::year;
311
312 v->sprite_cache.sprite_seq.Set(SPR_IMG_QUERY);
313 v->random_bits = Random();
314 v->SetFrontEngine();
315
316 v->roadtype = rt;
317 v->compatible_roadtypes = rti->powered_roadtypes;
318 v->gcache.cached_veh_length = VEHICLE_LENGTH;
319
321 v->SetServiceIntervalIsPercent(Company::Get(_current_company)->settings.vehicle.servint_ispercent);
322
324 v->InvalidateNewGRFCacheOfChain();
325
326 /* Call various callbacks after the whole consist has been constructed */
327 for (RoadVehicle *u = v; u != nullptr; u = u->Next()) {
328 u->cargo_cap = u->GetEngine()->DetermineCapacity(u);
329 u->refit_cap = 0;
330 v->InvalidateNewGRFCache();
331 u->InvalidateNewGRFCache();
332 }
334 /* Initialize cached values for realistic acceleration. */
335 if (_settings_game.vehicle.roadveh_acceleration_model != AccelerationModel::Original) v->CargoChanged();
336
337 v->UpdatePosition();
338
340 }
341
342 return CommandCost();
343}
344
345static FindDepotData FindClosestRoadDepot(const RoadVehicle *v, int max_distance)
346{
347 if (IsRoadDepotTile(v->tile)) return FindDepotData(v->tile, 0);
348
349 return YapfRoadVehicleFindNearestDepot(v, max_distance);
350}
351
353{
354 FindDepotData rfdd = FindClosestRoadDepot(this, 0);
355 if (rfdd.best_length == UINT_MAX) return ClosestDepot();
356
357 return ClosestDepot(rfdd.tile, GetDepotIndex(rfdd.tile));
358}
359
367{
369 if (v == nullptr) return CMD_ERROR;
370
371 if (!v->IsPrimaryVehicle()) return CMD_ERROR;
372
374 if (ret.Failed()) return ret;
375
376 if (v->vehstatus.Any({VehState::Stopped, VehState::Crashed}) ||
377 v->breakdown_ctr != 0 ||
378 v->overtaking != 0 ||
379 v->state == RVSB_WORMHOLE ||
380 v->IsInDepot() ||
381 v->current_order.IsType(OT_LOADING)) {
382 return CMD_ERROR;
383 }
384
386
388
389 if (flags.Test(DoCommandFlag::Execute)) {
390 v->reverse_ctr = 180;
391
392 /* Unbunching data is no longer valid. */
394 }
395
396 return CommandCost();
397}
398
399
401{
402 for (RoadVehicle *v = this; v != nullptr; v = v->Next()) {
403 v->colourmap = PAL_NONE;
404 v->UpdateViewport(true, false);
405 }
406 RoadVehUpdateCache(this, true);
407 this->CargoChanged();
408}
409
411{
412 /* Set common defaults. */
413 this->bounds = {{-1, -1, 0}, {3, 3, 6}, {}};
414
415 if (!IsDiagonalDirection(this->direction)) {
416 static const DiagDirectionIndexArray<Point> _sign_table{{{
417 /* x, y */
418 {-1, -1}, // Direction::N
419 {-1, 1}, // Direction::E
420 { 1, 1}, // Direction::S
421 { 1, -1}, // Direction::W
422 }}};
423
424 int half_shorten = (VEHICLE_LENGTH - this->gcache.cached_veh_length) / 2;
425
426 /* For all straight directions, move the bound box to the centre of the vehicle, but keep the size. */
427 this->bounds.offset.x -= half_shorten * _sign_table[DirToDiagDir(this->direction)].x;
428 this->bounds.offset.y -= half_shorten * _sign_table[DirToDiagDir(this->direction)].y;
429 } else {
430 /* Unlike trains, road vehicles do not have their offsets moved to the centre. */
431 switch (this->direction) {
432 /* Shorten southern corner of the bounding box according the vehicle length. */
433 case Direction::NE:
434 this->bounds.origin.x = -3;
435 this->bounds.extent.x = this->gcache.cached_veh_length;
436 this->bounds.offset.x = 1;
437 break;
438
439 case Direction::NW:
440 this->bounds.origin.y = -3;
441 this->bounds.extent.y = this->gcache.cached_veh_length;
442 this->bounds.offset.y = 1;
443 break;
444
445 /* Move northern corner of the bounding box down according to vehicle length. */
446 case Direction::SW:
447 this->bounds.origin.x = -3 + (VEHICLE_LENGTH - this->gcache.cached_veh_length);
448 this->bounds.extent.x = this->gcache.cached_veh_length;
449 this->bounds.offset.x = 1 - (VEHICLE_LENGTH - this->gcache.cached_veh_length);
450 break;
451
452 case Direction::SE:
453 this->bounds.origin.y = -3 + (VEHICLE_LENGTH - this->gcache.cached_veh_length);
454 this->bounds.extent.y = this->gcache.cached_veh_length;
455 this->bounds.offset.y = 1 - (VEHICLE_LENGTH - this->gcache.cached_veh_length);
456 break;
457
458 default:
459 NOT_REACHED();
460 }
461 }
462}
463
469{
470 int max_speed = this->gcache.cached_max_track_speed;
471
472 /* Limit speed to 50% while reversing, 75% in curves. */
473 for (const RoadVehicle *u = this; u != nullptr; u = u->Next()) {
474 if (_settings_game.vehicle.roadveh_acceleration_model == AccelerationModel::Realistic) {
475 if (this->state <= RVSB_TRACKDIR_MASK && IsReversingRoadTrackdir(static_cast<Trackdir>(this->state))) {
476 max_speed = this->gcache.cached_max_track_speed / 2;
477 break;
478 } else if (!IsDiagonalDirection(u->direction)) {
479 max_speed = this->gcache.cached_max_track_speed * 3 / 4;
480 }
481 }
482
483 /* Vehicle is on the middle part of a bridge. */
484 if (u->state == RVSB_WORMHOLE && !u->vehstatus.Test(VehState::Hidden)) {
485 max_speed = std::min(max_speed, GetBridgeSpec(GetBridgeType(u->tile))->speed * 2);
486 }
487 }
488
489 return std::min(max_speed, this->current_order.GetMaxSpeed() * 2);
490}
491
497{
498 RoadVehicle *first = v->First();
499 Vehicle *u = v;
500 for (; v->Next() != nullptr; v = v->Next()) u = v;
501 u->SetNext(nullptr);
502 v->last_station_visited = first->last_station_visited; // for PreDestructor
503
504 /* Only leave the road stop when we're really gone. */
505 if (IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END)) RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile))->Leave(v);
506
507 delete v;
508}
509
510static void RoadVehSetRandomDirection(RoadVehicle *v)
511{
512 static const DirDiff delta[] = {
514 };
515
516 do {
517 uint32_t r = Random();
518
519 v->direction = ChangeDir(v->direction, delta[r & 3]);
520 v->UpdateViewport(true, true);
521 } while ((v = v->Next()) != nullptr);
522}
523
530{
531 v->crashed_ctr++;
532 if (v->crashed_ctr == 2) {
534 } else if (v->crashed_ctr <= 45) {
535 if ((v->tick_counter & 7) == 0) RoadVehSetRandomDirection(v);
536 } else if (v->crashed_ctr >= 2220 && !(v->tick_counter & 0x1F)) {
537 bool ret = v->Next() != nullptr;
539 return ret;
540 }
541
542 return true;
543}
544
545uint RoadVehicle::Crash(bool flooded)
546{
547 uint victims = this->GroundVehicleBase::Crash(flooded);
548 if (this->IsFrontEngine()) {
549 victims += 1; // driver
550
551 /* If we're in a drive through road stop we ought to leave it */
552 if (IsInsideMM(this->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END)) {
553 RoadStop::GetByTile(this->tile, GetRoadStopType(this->tile))->Leave(this);
554 }
555 }
556 this->crashed_ctr = flooded ? 2000 : 1; // max 2220, disappear pretty fast when flooded
557 return victims;
558}
559
560static void RoadVehCrash(RoadVehicle *v)
561{
562 uint victims = v->Crash();
563
564 AI::NewEvent(v->owner, new ScriptEventVehicleCrashed(v->index, v->tile, ScriptEventVehicleCrashed::CRASH_RV_LEVEL_CROSSING, victims, v->owner));
565 Game::NewEvent(new ScriptEventVehicleCrashed(v->index, v->tile, ScriptEventVehicleCrashed::CRASH_RV_LEVEL_CROSSING, victims, v->owner));
566
567 EncodedString headline = (victims == 1)
568 ? GetEncodedString(STR_NEWS_ROAD_VEHICLE_CRASH_DRIVER)
569 : GetEncodedString(STR_NEWS_ROAD_VEHICLE_CRASH, victims);
571
572 AddTileNewsItem(std::move(headline), newstype, v->tile);
573
574 ModifyStationRatingAround(v->tile, v->owner, -160, 22);
575 if (_settings_client.sound.disaster) SndPlayVehicleFx(SND_12_EXPLOSION, v);
576}
577
578static bool RoadVehCheckTrainCrash(RoadVehicle *v)
579{
580 for (RoadVehicle *u = v; u != nullptr; u = u->Next()) {
581 if (u->state == RVSB_WORMHOLE) continue;
582
583 TileIndex tile = u->tile;
584
585 if (!IsLevelCrossingTile(tile)) continue;
586
587 if (HasVehicleNearTileXY(v->x_pos, v->y_pos, 4, [&u](const Vehicle *t) {
588 return t->type == VehicleType::Train && abs(t->z_pos - u->z_pos) <= 6;
589 })) {
590 RoadVehCrash(v);
591 return true;
592 }
593 }
594
595 return false;
596}
597
599{
600 if (station == this->last_station_visited) this->last_station_visited = StationID::Invalid();
601
602 const Station *st = Station::Get(station);
603 if (!CanVehicleUseStation(this, st)) {
604 /* There is no stop left at the station, so don't even TRY to go there */
606 return TileIndex{};
607 }
608
609 return st->xy;
610}
611
612static void StartRoadVehSound(const RoadVehicle *v)
613{
614 if (!PlayVehicleSound(v, VSE_START)) {
615 SoundID s = RoadVehInfo(v->engine_type)->sfx;
616 if (s == SND_19_DEPARTURE_OLD_RV_1 && (v->tick_counter & 3) == 0) {
618 }
619 SndPlayVehicleFx(s, v);
620 }
621}
622
624 int x;
625 int y;
626 const Vehicle *veh;
627 Vehicle *best;
628 uint best_diff;
629 Direction dir;
630};
631
632static void FindClosestBlockingRoadVeh(Vehicle *v, RoadVehFindData *rvf)
633{
634 static constexpr DirectionIndexArray<int8_t> dist_x{-4, -8, -4, -1, 4, 8, 4, 1};
635 static constexpr DirectionIndexArray<int8_t> dist_y{-4, -1, 4, 8, 4, 1, -4, -8};
636
637 int x_diff = v->x_pos - rvf->x;
638 int y_diff = v->y_pos - rvf->y;
639
640 /* Not a close Road vehicle when it's not a road vehicle, in the depot, or ourself. */
641 if (v->type != VehicleType::Road || v->IsInDepot() || rvf->veh->First() == v->First()) return;
642
643 /* Not close when at a different height or when going in a different direction. */
644 if (abs(v->z_pos - rvf->veh->z_pos) >= 6 || v->direction != rvf->dir) return;
645
646 /* We 'return' the closest vehicle, in distance and then VehicleID as tie-breaker. */
647 uint diff = abs(x_diff) + abs(y_diff);
648 if (diff > rvf->best_diff || (diff == rvf->best_diff && v->index > rvf->best->index)) return;
649
650 auto IsCloseOnAxis = [](int dist, int diff) {
651 if (dist < 0) return diff > dist && diff <= 0;
652 return diff < dist && diff >= 0;
653 };
654
655 if (IsCloseOnAxis(dist_x[v->direction], x_diff) && IsCloseOnAxis(dist_y[v->direction], y_diff)) {
656 rvf->best = v;
657 rvf->best_diff = diff;
658 }
659}
660
661static RoadVehicle *RoadVehFindCloseTo(RoadVehicle *v, int x, int y, Direction dir, bool update_blocked_ctr = true)
662{
663 RoadVehFindData rvf;
664 RoadVehicle *front = v->First();
665
666 if (front->reverse_ctr != 0) return nullptr;
667
668 rvf.x = x;
669 rvf.y = y;
670 rvf.dir = dir;
671 rvf.veh = v;
672 rvf.best_diff = UINT_MAX;
673
674 if (front->state == RVSB_WORMHOLE) {
675 for (Vehicle *u : VehiclesOnTile(v->tile)) {
676 FindClosestBlockingRoadVeh(u, &rvf);
677 }
679 FindClosestBlockingRoadVeh(u, &rvf);
680 }
681 } else {
682 for (Vehicle *u : VehiclesNearTileXY(x, y, 8)) {
683 FindClosestBlockingRoadVeh(u, &rvf);
684 }
685 }
686
687 /* This code protects a roadvehicle from being blocked for ever
688 * If more than 1480 / 74 days a road vehicle is blocked, it will
689 * drive just through it. The ultimate backup-code of TTD.
690 * It can be disabled. */
691 if (rvf.best_diff == UINT_MAX) {
692 front->blocked_ctr = 0;
693 return nullptr;
694 }
695
696 if (update_blocked_ctr && ++front->blocked_ctr > 1480) return nullptr;
697
698 return RoadVehicle::From(rvf.best);
699}
700
706static void RoadVehArrivesAt(const RoadVehicle *v, Station *st)
707{
708 if (v->IsBus()) {
709 /* Check if station was ever visited before */
710 if (!st->had_vehicle_of_type.Test(StationVehicleType::Bus)) {
711 st->had_vehicle_of_type.Set(StationVehicleType::Bus);
713 GetEncodedString(RoadTypeIsRoad(v->roadtype) ? STR_NEWS_FIRST_BUS_ARRIVAL : STR_NEWS_FIRST_PASSENGER_TRAM_ARRIVAL, st->index),
715 v->index,
716 st->index
717 );
718 AI::NewEvent(v->owner, new ScriptEventStationFirstVehicle(st->index, v->index));
719 Game::NewEvent(new ScriptEventStationFirstVehicle(st->index, v->index));
720 }
721 } else {
722 /* Check if station was ever visited before */
723 if (!st->had_vehicle_of_type.Test(StationVehicleType::Truck)) {
724 st->had_vehicle_of_type.Set(StationVehicleType::Truck);
726 GetEncodedString(RoadTypeIsRoad(v->roadtype) ? STR_NEWS_FIRST_TRUCK_ARRIVAL : STR_NEWS_FIRST_CARGO_TRAM_ARRIVAL, st->index),
728 v->index,
729 st->index
730 );
731 AI::NewEvent(v->owner, new ScriptEventStationFirstVehicle(st->index, v->index));
732 Game::NewEvent(new ScriptEventStationFirstVehicle(st->index, v->index));
733 }
734 }
735}
736
745{
746 switch (_settings_game.vehicle.roadveh_acceleration_model) {
747 default: NOT_REACHED();
749 return this->DoUpdateSpeed(this->overtaking != 0 ? 512 : 256, 0, this->GetCurrentMaxSpeed());
750
752 return this->DoUpdateSpeed(this->GetAcceleration() + (this->overtaking != 0 ? 256 : 0), this->GetAccelerationStatus() == AS_BRAKE ? 0 : 4, this->GetCurrentMaxSpeed());
753 }
754}
755
756static Direction RoadVehGetNewDirection(const RoadVehicle *v, int x, int y)
757{
758 static const Direction _roadveh_new_dir[] = {
762 };
763
764 x = x - v->x_pos + 1;
765 y = y - v->y_pos + 1;
766
767 if ((uint)x > 2 || (uint)y > 2) return v->direction;
768 return _roadveh_new_dir[y * 4 + x];
769}
770
771static Direction RoadVehGetSlidingDirection(const RoadVehicle *v, int x, int y)
772{
773 Direction new_dir = RoadVehGetNewDirection(v, x, y);
774 Direction old_dir = v->direction;
775
776 if (new_dir == old_dir) return old_dir;
777 DirDiff dirdiff = DirDifference(new_dir, old_dir);
778 return ChangeDir(old_dir, LimitDirDiff(dirdiff));
779}
780
782 const RoadVehicle *u;
783 const RoadVehicle *v;
784 TileIndex tile;
785 Trackdir trackdir;
786};
787
795{
796 if (!HasTileAnyRoadType(od->tile, od->v->compatible_roadtypes)) return true;
797 TrackStatus ts = GetTileTrackStatus(od->tile, TransportType::Road, GetRoadTramType(od->v->roadtype));
799
800 /* Track does not continue along overtaking direction || track has junction || levelcrossing is barred */
801 if (!ts.trackdirs.Test(od->trackdir) || trackbits.Any({Track::Upper, Track::Lower, Track::Left, Track::Right}) || ts.signals.Any()) return true;
802
803 /* Are there more vehicles on the tile except the two vehicles involved in overtaking */
804 return HasVehicleOnTile(od->tile, [&](const Vehicle *v) {
805 return v->type == VehicleType::Road && v->First() == v && v != od->u && v != od->v;
806 });
807}
808
809static void RoadVehCheckOvertake(RoadVehicle *v, RoadVehicle *u)
810{
811 OvertakeData od;
812
813 od.v = v;
814 od.u = u;
815
816 /* Trams can't overtake other trams */
817 if (RoadTypeIsTram(v->roadtype)) return;
818
819 /* Don't overtake in stations */
821
822 /* For now, articulated road vehicles can't overtake anything. */
823 if (v->HasArticulatedPart()) return;
824
825 /* Vehicles are not driving in same direction || direction is not a diagonal direction */
826 if (v->direction != u->direction || !IsDiagonalDirection(v->direction)) return;
827
828 /* Check if vehicle is in a road stop, depot, tunnel or bridge or not on a straight road */
829 if (v->state >= RVSB_IN_ROAD_STOP || !IsStraightRoadTrackdir(static_cast<Trackdir>(v->state & RVSB_TRACKDIR_MASK))) return;
830
831 /* Can't overtake a vehicle that is moving faster than us. If the vehicle in front is
832 * accelerating, take the maximum speed for the comparison, else the current speed.
833 * Original acceleration always accelerates, so always use the maximum speed. */
834 int u_speed = (_settings_game.vehicle.roadveh_acceleration_model == AccelerationModel::Original || u->GetAcceleration() > 0) ? u->GetCurrentMaxSpeed() : u->cur_speed;
835 if (u_speed >= v->GetCurrentMaxSpeed() &&
837 u->cur_speed != 0) {
838 return;
839 }
840
842
843 /* Are the current and the next tile suitable for overtaking?
844 * - Does the track continue along od.trackdir
845 * - No junctions
846 * - No barred levelcrossing
847 * - No other vehicles in the way
848 */
849 od.tile = v->tile;
850 if (CheckRoadBlockedForOvertaking(&od)) return;
851
852 od.tile = v->tile + TileOffsByDiagDir(DirToDiagDir(v->direction));
853 if (CheckRoadBlockedForOvertaking(&od)) return;
854
855 /* When the vehicle in front of us is stopped we may only take
856 * half the time to pass it than when the vehicle is moving. */
857 v->overtaking_ctr = (od.u->cur_speed == 0 || od.u->vehstatus.Test(VehState::Stopped)) ? RV_OVERTAKE_TIMEOUT / 2 : 0;
859}
860
861static void RoadZPosAffectSpeed(RoadVehicle *v, int old_z)
862{
863 if (old_z == v->z_pos || _settings_game.vehicle.roadveh_acceleration_model != AccelerationModel::Original) return;
864
865 if (old_z < v->z_pos) {
866 v->cur_speed = v->cur_speed * 232 / 256; // slow down by ~10%
867 } else {
868 uint16_t spd = v->cur_speed + 2;
869 if (spd <= v->gcache.cached_max_track_speed) v->cur_speed = spd;
870 }
871}
872
882{
883 bool path_found = true;
884
885 TrackStatus ts = GetTileTrackStatus(tile, TransportType::Road, GetRoadTramType(v->roadtype));
886
887 /* Replaces the given trackdir with Trackdir::Invalid when there is red signal for that trackdir. */
888 auto FilterRedSignal = [&ts](Trackdir trackdir) {
889 if (ts.signals.Test(trackdir)) return Trackdir::Invalid;
890 return trackdir;
891 };
892
893 if (IsTileType(tile, TileType::Road)) {
894 if (IsRoadDepot(tile) && (!IsTileOwner(tile, v->owner) || GetRoadDepotDirection(tile) == enterdir)) {
895 /* Road depot owned by another company or with the wrong orientation */
896 ts.trackdirs.Reset();
897 }
898 } else if (IsTileType(tile, TileType::Station) && IsBayRoadStopTile(tile)) {
899 /* Standard road stop (drive-through stops are treated as normal road) */
900
901 if (!IsTileOwner(tile, v->owner) || GetBayRoadStopDir(tile) == enterdir || v->HasArticulatedPart()) {
902 /* different station owner or wrong orientation or the vehicle has articulated parts */
903 ts.trackdirs.Reset();
904 } else {
905 /* Our station */
907
908 if (GetRoadStopType(tile) != rstype) {
909 /* Wrong station type */
910 ts.trackdirs.Reset();
911 } else {
912 /* Proper station type, check if there is free loading bay */
913 if (!_settings_game.pf.roadveh_queue && IsBayRoadStopTile(tile) &&
914 !RoadStop::GetByTile(tile, rstype)->HasFreeBay()) {
915 /* Station is full and RV queuing is off */
916 ts.trackdirs.Reset();
917 }
918 }
919 }
920 }
921 /* The above lookups should be moved to GetTileTrackStatus in the
922 * future, but that requires more changes to the pathfinder and other
923 * stuff, probably even more arguments to GTTS.
924 */
925
926 /* Remove tracks unreachable from the enter dir */
927 ts.trackdirs &= DiagdirReachesTrackdirs(enterdir);
928 if (ts.trackdirs.None()) {
929 /* If vehicle expected a path, it no longer exists, so invalidate it. */
930 if (!v->path.empty()) v->path.clear();
931 /* No reachable tracks, so we'll reverse */
932 return FilterRedSignal(_road_reverse_table[enterdir]);
933 }
934
935 if (v->reverse_ctr != 0) {
936 bool reverse = true;
937 if (RoadTypeIsTram(v->roadtype)) {
938 /* Trams may only reverse on a tile if it contains at least the straight
939 * trackbits or when it is a valid turning tile (i.e. one roadbit) */
941 RoadBits straight = AxisToRoadBits(DiagDirToAxis(enterdir));
942 reverse = rb.All(straight) ||
943 rb == DiagDirToRoadBits(enterdir);
944 }
945 if (reverse) {
946 v->reverse_ctr = 0;
947 if (v->tile != tile) {
948 return FilterRedSignal(_road_reverse_table[enterdir]);
949 }
950 }
951 }
952
953 if (v->dest_tile == INVALID_TILE) {
954 /* We've got no destination, pick a random track */
955 return FilterRedSignal(ts.trackdirs.GetNthSetBit(RandomRange(ts.trackdirs.Count())).value());
956 }
957
958 /* Only one track to choose between? */
959 if (ts.trackdirs.Count() == 1) {
960 if (!v->path.empty() && v->path.back().tile == tile) {
961 /* Vehicle expected a choice here, invalidate its path. */
962 v->path.clear();
963 }
964 return FilterRedSignal(ts.trackdirs.GetNthSetBit(0).value());
965 }
966
967 /* Attempt to follow cached path. */
968 if (!v->path.empty()) {
969 if (v->path.back().tile != tile) {
970 /* Vehicle didn't expect a choice here, invalidate its path. */
971 v->path.clear();
972 } else {
973 Trackdir trackdir = v->path.back().trackdir;
974
975 if (ts.trackdirs.Test(trackdir)) {
976 v->path.pop_back();
977 return FilterRedSignal(trackdir);
978 }
979
980 /* Vehicle expected a choice which is no longer available. */
981 v->path.clear();
982 }
983 }
984
985 Trackdir best_track = YapfRoadVehicleChooseTrack(v, tile, enterdir, ts.trackdirs, path_found, v->path);
986
987 v->HandlePathfindingResult(path_found);
988
989 return FilterRedSignal(best_track);
990}
991
993 uint8_t x, y;
994};
995
997
998bool RoadVehLeaveDepot(RoadVehicle *v, bool first)
999{
1000 /* Don't leave unless v and following wagons are in the depot. */
1001 for (const RoadVehicle *u = v; u != nullptr; u = u->Next()) {
1002 if (u->state != RVSB_IN_DEPOT || u->tile != v->tile) return false;
1003 }
1004
1006 v->direction = DiagDirToDir(dir);
1007
1008 Trackdir tdir = DiagDirToDiagTrackdir(dir);
1009 const RoadDriveEntry *rdp = _road_drive_data[GetRoadTramType(v->roadtype)][(to_underlying(_settings_game.vehicle.road_side) << RVS_DRIVE_SIDE) + to_underlying(tdir)];
1010
1011 int x = TileX(v->tile) * TILE_SIZE + (rdp[RVC_DEPOT_START_FRAME].x & 0xF);
1012 int y = TileY(v->tile) * TILE_SIZE + (rdp[RVC_DEPOT_START_FRAME].y & 0xF);
1013
1014 if (first) {
1015 /* We are leaving a depot, but have to go to the exact same one; re-enter */
1016 if (v->current_order.IsType(OT_GOTO_DEPOT) && v->tile == v->dest_tile) {
1018 return true;
1019 }
1020
1021 if (RoadVehFindCloseTo(v, x, y, v->direction, false) != nullptr) return true;
1022
1025
1026 StartRoadVehSound(v);
1027
1028 /* Vehicle is about to leave a depot */
1029 v->cur_speed = 0;
1030 }
1031
1033 v->state = to_underlying(tdir);
1034 v->frame = RVC_DEPOT_START_FRAME;
1035
1036 v->x_pos = x;
1037 v->y_pos = y;
1038 v->UpdatePosition();
1039 v->UpdateInclination(true, true);
1040
1041 InvalidateWindowData(WindowClass::VehicleDepot, v->tile);
1042
1043 return true;
1044}
1045
1046static Trackdir FollowPreviousRoadVehicle(const RoadVehicle *v, const RoadVehicle *prev, TileIndex tile, DiagDirection entry_dir, bool already_reversed)
1047{
1048 if (prev->tile == v->tile && !already_reversed) {
1049 /* If the previous vehicle is on the same tile as this vehicle is
1050 * then it must have reversed. */
1051 return _road_reverse_table[entry_dir];
1052 }
1053
1054 uint8_t prev_state = prev->state;
1055 Trackdir dir;
1056
1057 if (prev_state == RVSB_WORMHOLE || prev_state == RVSB_IN_DEPOT) {
1059
1061 diag_dir = GetTunnelBridgeDirection(tile);
1062 } else if (IsRoadDepotTile(tile)) {
1063 diag_dir = ReverseDiagDir(GetRoadDepotDirection(tile));
1064 }
1065
1066 if (diag_dir == DiagDirection::Invalid) return Trackdir::Invalid;
1067 dir = DiagDirToDiagTrackdir(diag_dir);
1068 } else {
1069 if (already_reversed && (prev->tile != tile || (static_cast<Trackdir>(prev_state) < Trackdir::End && IsReversingRoadTrackdir(static_cast<Trackdir>(prev_state))))) {
1070 /*
1071 * The vehicle has reversed, but did not go straight back.
1072 * It immediately turn onto another tile. This means that
1073 * the roadstate of the previous vehicle cannot be used
1074 * as the direction we have to go with this vehicle.
1075 *
1076 * Next table is build in the following way:
1077 * - first row for when the vehicle in front went to the northern or
1078 * western tile, second for southern and eastern.
1079 * - columns represent the entry direction.
1080 * - cell values are determined by the Trackdir one has to take from
1081 * the entry dir (column) to the tile in north or south by only
1082 * going over the trackdirs used for turning 90 degrees, i.e.
1083 * TRACKDIR_{UPPER,RIGHT,LOWER,LEFT}_{N,E,S,W}.
1084 */
1085 bool north;
1086 if (prev->tile != tile) {
1087 north = prev->tile < tile;
1088 } else {
1089 north = static_cast<Trackdir>(prev_state) == Trackdir::RvRev_NW || static_cast<Trackdir>(prev_state) == Trackdir::RvRev_NE;
1090 }
1091 static const DiagDirectionIndexArray<Trackdir> reversed_turn_lookup[2] = {
1094 dir = reversed_turn_lookup[north ? 0 : 1][ReverseDiagDir(entry_dir)];
1095 } else if (HasBit(prev_state, RVS_IN_DT_ROAD_STOP)) {
1096 dir = static_cast<Trackdir>(prev_state & RVSB_ROAD_STOP_TRACKDIR_MASK);
1097 } else if (static_cast<Trackdir>(prev_state) < Trackdir::End) {
1098 dir = static_cast<Trackdir>(prev_state);
1099 } else {
1100 return Trackdir::Invalid;
1101 }
1102 }
1103
1104 /* Do some sanity checking. */
1105 static const RoadBits required_roadbits[] = {
1106 ROAD_X,
1107 ROAD_Y,
1112 ROAD_X,
1113 ROAD_Y,
1114 };
1115 RoadBits required = required_roadbits[to_underlying(dir) & 0x07];
1116
1117 if (!required.Any(GetAnyRoadBits(tile, GetRoadTramType(v->roadtype), true))) {
1118 dir = Trackdir::Invalid;
1119 }
1120
1121 return dir;
1122}
1123
1132static bool CanBuildTramTrackOnTile(CompanyID c, TileIndex t, RoadType rt, RoadBits r)
1133{
1134 /* The 'current' company is not necessarily the owner of the vehicle. */
1135 AutoRestoreBackup cur_company(_current_company, c);
1136 return Command<Commands::BuildRoad>::Do(DoCommandFlag::NoWater, t, r, rt, {}, TownID::Invalid()).Succeeded();
1137}
1138
1139bool IndividualRoadVehicleController(RoadVehicle *v, const RoadVehicle *prev)
1140{
1141 if (v->overtaking != 0) {
1143 /* Force us to be not overtaking! */
1144 v->overtaking = 0;
1145 } else if (++v->overtaking_ctr >= RV_OVERTAKE_TIMEOUT) {
1146 /* If overtaking just aborts at a random moment, we can have a out-of-bound problem,
1147 * if the vehicle started a corner. To protect that, only allow an abort of
1148 * overtake if we are on straight roads */
1149 if (v->state < RVSB_IN_ROAD_STOP && IsStraightRoadTrackdir(static_cast<Trackdir>(v->state))) {
1150 v->overtaking = 0;
1151 }
1152 }
1153 }
1154
1155 /* If this vehicle is in a depot and we've reached this point it must be
1156 * one of the articulated parts. It will stay in the depot until activated
1157 * by the previous vehicle in the chain when it gets to the right place. */
1158 if (v->IsInDepot()) return true;
1159
1160 if (v->state == RVSB_WORMHOLE) {
1161 /* Vehicle is entering a depot or is on a bridge or in a tunnel */
1163
1164 if (v->IsFrontEngine()) {
1165 const Vehicle *u = RoadVehFindCloseTo(v, gp.x, gp.y, v->direction);
1166 if (u != nullptr) {
1167 v->cur_speed = u->First()->cur_speed;
1168 return false;
1169 }
1170 }
1171
1173 /* Vehicle has just entered a bridge or tunnel */
1174 v->x_pos = gp.x;
1175 v->y_pos = gp.y;
1176 v->UpdatePosition();
1177 v->UpdateInclination(true, true);
1178 return true;
1179 }
1180
1181 v->x_pos = gp.x;
1182 v->y_pos = gp.y;
1183 v->UpdatePosition();
1184 if (!v->vehstatus.Test(VehState::Hidden)) v->Vehicle::UpdateViewport(true);
1185 return true;
1186 }
1187
1188 /* Get move position data for next frame.
1189 * For a drive-through road stop use 'straight road' move data.
1190 * In this case v->state is masked to give the road stop entry direction. */
1191 RoadDriveEntry rd = _road_drive_data[GetRoadTramType(v->roadtype)][(
1193 (to_underlying(_settings_game.vehicle.road_side) << RVS_DRIVE_SIDE)) ^ v->overtaking][v->frame + 1];
1194
1195 if (rd.x & RDE_NEXT_TILE) {
1196 DiagDirection diagdir = static_cast<DiagDirection>(rd.x & 3);
1197 TileIndex tile = v->tile + TileOffsByDiagDir(diagdir);
1198 Trackdir dir;
1199
1200 if (v->IsFrontEngine()) {
1201 /* If this is the front engine, look for the right path. */
1203 dir = RoadFindPathToDest(v, tile, diagdir);
1204 } else {
1205 dir = _road_reverse_table[diagdir];
1206 }
1207 } else {
1208 dir = FollowPreviousRoadVehicle(v, prev, tile, diagdir, false);
1209 }
1210
1211 if (dir == Trackdir::Invalid) {
1212 if (!v->IsFrontEngine()) FatalError("Disconnecting road vehicle.");
1213 v->cur_speed = 0;
1214 return false;
1215 }
1216
1217again:
1218 uint start_frame = RVC_DEFAULT_START_FRAME;
1219 if (IsReversingRoadTrackdir(dir)) {
1220 /* When turning around we can't be overtaking. */
1221 v->overtaking = 0;
1222
1223 /* Turning around */
1224 if (RoadTypeIsTram(v->roadtype)) {
1225 /* Determine the road bits the tram needs to be able to turn around
1226 * using the 'big' corner loop. */
1227 RoadBit needed;
1228 switch (dir) {
1229 default: NOT_REACHED();
1230 case Trackdir::RvRev_NE: needed = RoadBit::SW; break;
1231 case Trackdir::RvRev_SE: needed = RoadBit::NW; break;
1232 case Trackdir::RvRev_SW: needed = RoadBit::NE; break;
1233 case Trackdir::RvRev_NW: needed = RoadBit::SE; break;
1234 }
1235 if ((v->Previous() != nullptr && v->Previous()->tile == tile) ||
1236 (v->IsFrontEngine() && IsNormalRoadTile(tile) && !HasRoadWorks(tile) &&
1238 GetRoadBits(tile, RoadTramType::Tram).Test(needed))) {
1239 /*
1240 * Taking the 'big' corner for trams only happens when:
1241 * - The previous vehicle in this (articulated) tram chain is
1242 * already on the 'next' tile, we just follow them regardless of
1243 * anything. When it is NOT on the 'next' tile, the tram started
1244 * doing a reversing turn when the piece of tram track on the next
1245 * tile did not exist yet. Do not use the big tram loop as that is
1246 * going to cause the tram to split up.
1247 * - Or the front of the tram can drive over the next tile.
1248 */
1249 } else if (!v->IsFrontEngine() || !CanBuildTramTrackOnTile(v->owner, tile, v->roadtype, needed) || GetAnyRoadBits(v->tile, RoadTramType::Tram, false).Reset(needed).Any()) {
1250 /*
1251 * Taking the 'small' corner for trams only happens when:
1252 * - We are not the from vehicle of an articulated tram.
1253 * - Or when the company cannot build on the next tile.
1254 *
1255 * The 'small' corner means that the vehicle is on the end of a
1256 * tram track and needs to start turning there. To do this properly
1257 * the tram needs to start at an offset in the tram turning 'code'
1258 * for 'big' corners. It furthermore does not go to the next tile,
1259 * so that needs to be fixed too.
1260 */
1261 tile = v->tile;
1262 start_frame = RVC_TURN_AROUND_START_FRAME_SHORT_TRAM;
1263 } else {
1264 /* The company can build on the next tile, so wait till they do. */
1265 v->cur_speed = 0;
1266 return false;
1267 }
1268 } else if (IsNormalRoadTile(v->tile) && GetDisallowedRoadDirections(v->tile).Any()) {
1269 v->cur_speed = 0;
1270 return false;
1271 } else {
1272 tile = v->tile;
1273 }
1274 }
1275
1276 /* Get position data for first frame on the new tile */
1277 const RoadDriveEntry *rdp = _road_drive_data[GetRoadTramType(v->roadtype)][(to_underlying(dir) + (to_underlying(_settings_game.vehicle.road_side) << RVS_DRIVE_SIDE)) ^ v->overtaking];
1278
1279 int x = TileX(tile) * TILE_SIZE + rdp[start_frame].x;
1280 int y = TileY(tile) * TILE_SIZE + rdp[start_frame].y;
1281
1282 Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
1283 if (v->IsFrontEngine()) {
1284 const Vehicle *u = RoadVehFindCloseTo(v, x, y, new_dir);
1285 if (u != nullptr) {
1286 v->cur_speed = u->First()->cur_speed;
1287 /* We might be blocked, prevent pathfinding rerun as we already know where we are heading to. */
1288 v->path.emplace_back(dir, tile);
1289 return false;
1290 }
1291 }
1292
1293 auto vets = VehicleEnterTile(v, tile, x, y);
1294 if (vets.Test(VehicleEnterTileState::CannotEnter)) {
1295 if (!IsTileType(tile, TileType::TunnelBridge)) {
1296 v->cur_speed = 0;
1297 return false;
1298 }
1299 /* Try an about turn to re-enter the previous tile */
1300 dir = _road_reverse_table[static_cast<DiagDirection>(rd.x & 3)];
1301 goto again;
1302 }
1303
1304 if (IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) && IsTileType(v->tile, TileType::Station)) {
1305 if (IsReversingRoadTrackdir(dir) && IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END)) {
1306 /* New direction is trying to turn vehicle around.
1307 * We can't turn at the exit of a road stop so wait.*/
1308 v->cur_speed = 0;
1309 return false;
1310 }
1311
1312 /* If we are a drive through road stop and the next tile is of
1313 * the same road stop and the next tile isn't this one (i.e. we
1314 * are not reversing), then keep the reservation and state.
1315 * This way we will not be shortly unregister from the road
1316 * stop. It also makes it possible to load when on the edge of
1317 * two road stops; otherwise you could get vehicles that should
1318 * be loading but are not actually loading. */
1319 if (IsDriveThroughStopTile(v->tile) &&
1321 v->tile != tile) {
1322 /* So, keep 'our' state */
1323 dir = static_cast<Trackdir>(v->state);
1324 } else if (IsStationRoadStop(v->tile)) {
1325 /* We're not continuing our drive through road stop, so leave. */
1327 }
1328 }
1329
1331 TileIndex old_tile = v->tile;
1332
1333 v->tile = tile;
1334 v->state = (uint8_t)dir;
1335 v->frame = start_frame;
1336 RoadTramType rtt = GetRoadTramType(v->roadtype);
1337 if (GetRoadType(old_tile, rtt) != GetRoadType(tile, rtt)) {
1338 if (v->IsFrontEngine()) {
1340 }
1341 v->First()->CargoChanged();
1342 }
1343 }
1344 if (new_dir != v->direction) {
1345 v->direction = new_dir;
1346 if (_settings_game.vehicle.roadveh_acceleration_model == AccelerationModel::Original) v->cur_speed -= v->cur_speed >> 2;
1347 }
1348 v->x_pos = x;
1349 v->y_pos = y;
1350 v->UpdatePosition();
1351 RoadZPosAffectSpeed(v, v->UpdateInclination(true, true));
1352 return true;
1353 }
1354
1355 if (rd.x & RDE_TURNED) {
1356 /* Vehicle has finished turning around, it will now head back onto the same tile */
1357 Trackdir dir;
1358 uint turn_around_start_frame = RVC_TURN_AROUND_START_FRAME;
1359
1360 if (RoadTypeIsTram(v->roadtype) && !IsRoadDepotTile(v->tile) && GetAnyRoadBits(v->tile, RoadTramType::Tram, true).Count() == 1) {
1361 /*
1362 * The tram is turning around with one tram 'roadbit'. This means that
1363 * it is using the 'big' corner 'drive data'. However, to support the
1364 * trams to take a small corner, there is a 'turned' marker in the middle
1365 * of the turning 'drive data'. When the tram took the long corner, we
1366 * will still use the 'big' corner drive data, but we advance it one
1367 * frame. We furthermore set the driving direction so the turning is
1368 * going to be properly shown.
1369 */
1370 turn_around_start_frame = RVC_START_FRAME_AFTER_LONG_TRAM;
1371 switch (static_cast<DiagDirection>(rd.x & 0x3)) {
1372 default: NOT_REACHED();
1373 case DiagDirection::NW: dir = Trackdir::RvRev_SE; break;
1374 case DiagDirection::NE: dir = Trackdir::RvRev_SW; break;
1375 case DiagDirection::SE: dir = Trackdir::RvRev_NW; break;
1376 case DiagDirection::SW: dir = Trackdir::RvRev_NE; break;
1377 }
1378 } else {
1379 if (v->IsFrontEngine()) {
1380 /* If this is the front engine, look for the right path. */
1381 dir = RoadFindPathToDest(v, v->tile, (DiagDirection)(rd.x & 3));
1382 } else {
1383 dir = FollowPreviousRoadVehicle(v, prev, v->tile, (DiagDirection)(rd.x & 3), true);
1384 }
1385 }
1386
1387 if (dir == Trackdir::Invalid) {
1388 v->cur_speed = 0;
1389 return false;
1390 }
1391
1392 const RoadDriveEntry *rdp = _road_drive_data[GetRoadTramType(v->roadtype)][(to_underlying(_settings_game.vehicle.road_side) << RVS_DRIVE_SIDE) + to_underlying(dir)];
1393
1394 int x = TileX(v->tile) * TILE_SIZE + rdp[turn_around_start_frame].x;
1395 int y = TileY(v->tile) * TILE_SIZE + rdp[turn_around_start_frame].y;
1396
1397 Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
1398 if (v->IsFrontEngine()) {
1399 const Vehicle *u = RoadVehFindCloseTo(v, x, y, new_dir);
1400 if (u != nullptr) {
1401 v->cur_speed = u->First()->cur_speed;
1402 /* We might be blocked, prevent pathfinding rerun as we already know where we are heading to. */
1403 v->path.emplace_back(dir, v->tile);
1404 return false;
1405 }
1406 }
1407
1408 auto vets = VehicleEnterTile(v, v->tile, x, y);
1409 if (vets.Test(VehicleEnterTileState::CannotEnter)) {
1410 v->cur_speed = 0;
1411 return false;
1412 }
1413
1414 v->state = to_underlying(dir);
1415 v->frame = turn_around_start_frame;
1416
1417 if (new_dir != v->direction) {
1418 v->direction = new_dir;
1419 if (_settings_game.vehicle.roadveh_acceleration_model == AccelerationModel::Original) v->cur_speed -= v->cur_speed >> 2;
1420 }
1421
1422 v->x_pos = x;
1423 v->y_pos = y;
1424 v->UpdatePosition();
1425 RoadZPosAffectSpeed(v, v->UpdateInclination(true, true));
1426 return true;
1427 }
1428
1429 /* This vehicle is not in a wormhole and it hasn't entered a new tile. If
1430 * it's on a depot tile, check if it's time to activate the next vehicle in
1431 * the chain yet. */
1432 if (v->Next() != nullptr && IsRoadDepotTile(v->tile)) {
1433 if (v->frame == v->gcache.cached_veh_length + RVC_DEPOT_START_FRAME) {
1434 RoadVehLeaveDepot(v->Next(), false);
1435 }
1436 }
1437
1438 /* Calculate new position for the vehicle */
1439 int x = (v->x_pos & ~15) + (rd.x & 15);
1440 int y = (v->y_pos & ~15) + (rd.y & 15);
1441
1442 Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
1443
1444 if (v->IsFrontEngine() && !IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END)) {
1445 /* Vehicle is not in a road stop.
1446 * Check for another vehicle to overtake */
1447 RoadVehicle *u = RoadVehFindCloseTo(v, x, y, new_dir);
1448
1449 if (u != nullptr) {
1450 u = u->First();
1451 /* There is a vehicle in front overtake it if possible */
1452 if (v->overtaking == 0) RoadVehCheckOvertake(v, u);
1453 if (v->overtaking == 0) v->cur_speed = u->cur_speed;
1454
1455 /* In case an RV is stopped in a road stop, why not try to load? */
1456 if (v->cur_speed == 0 && IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) &&
1458 v->owner == GetTileOwner(v->tile) && !v->current_order.IsType(OT_LEAVESTATION) &&
1461 v->last_station_visited = st->index;
1462 RoadVehArrivesAt(v, st);
1463 v->BeginLoading();
1465 TriggerRoadStopAnimation(st, v->tile, StationAnimationTrigger::VehicleArrives);
1466 }
1467 return false;
1468 }
1469 }
1470
1471 Direction old_dir = v->direction;
1472 if (new_dir != old_dir) {
1473 v->direction = new_dir;
1474 if (_settings_game.vehicle.roadveh_acceleration_model == AccelerationModel::Original) v->cur_speed -= v->cur_speed >> 2;
1475
1476 /* Delay the vehicle in curves by making it require one additional frame per turning direction (two in total).
1477 * A vehicle has to spend at least 9 frames on a tile, so the following articulated part can follow.
1478 * (The following part may only be one tile behind, and the front part is moved before the following ones.)
1479 * The short (inner) curve has 8 frames, this elongates it to 10. */
1480 v->UpdateViewport(true, true);
1481 return true;
1482 }
1483
1484 /* If the vehicle is in a normal road stop and the frame equals the stop frame OR
1485 * if the vehicle is in a drive-through road stop and this is the destination station
1486 * and it's the correct type of stop (bus or truck) and the frame equals the stop frame...
1487 * (the station test and stop type test ensure that other vehicles, using the road stop as
1488 * a through route, do not stop) */
1489 if (v->IsFrontEngine() && ((IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END) &&
1490 _road_stop_stop_frame[v->state - RVSB_IN_ROAD_STOP + (to_underlying(_settings_game.vehicle.road_side) << RVS_DRIVE_SIDE)] == v->frame) ||
1491 (IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) &&
1493 v->owner == GetTileOwner(v->tile) &&
1495 v->frame == RVC_DRIVE_THROUGH_STOP_FRAME))) {
1496
1499
1500 /* Vehicle is at the stop position (at a bay) in a road stop.
1501 * Note, if vehicle is loading/unloading it has already been handled,
1502 * so if we get here the vehicle has just arrived or is just ready to leave. */
1503 if (!HasBit(v->state, RVS_ENTERED_STOP)) {
1504 /* Vehicle has arrived at a bay in a road stop */
1505
1506 if (IsDriveThroughStopTile(v->tile)) {
1507 TileIndex next_tile = TileAddByDir(v->tile, v->direction);
1508
1509 /* Check if next inline bay is free and has compatible road. */
1511 v->frame++;
1512 v->x_pos = x;
1513 v->y_pos = y;
1514 v->UpdatePosition();
1515 RoadZPosAffectSpeed(v, v->UpdateInclination(true, false));
1516 return true;
1517 }
1518 }
1519
1520 rs->SetEntranceBusy(false);
1522
1523 v->last_station_visited = st->index;
1524
1525 if (IsDriveThroughStopTile(v->tile) || (v->current_order.IsType(OT_GOTO_STATION) && v->current_order.GetDestination() == st->index)) {
1526 RoadVehArrivesAt(v, st);
1527 v->BeginLoading();
1529 TriggerRoadStopAnimation(st, v->tile, StationAnimationTrigger::VehicleArrives);
1530 return false;
1531 }
1532 } else {
1533 /* Vehicle is ready to leave a bay in a road stop */
1534 if (rs->IsEntranceBusy()) {
1535 /* Road stop entrance is busy, so wait as there is nowhere else to go */
1536 v->cur_speed = 0;
1537 return false;
1538 }
1539 if (v->current_order.IsType(OT_LEAVESTATION)) v->current_order.Free();
1540 }
1541
1542 if (IsBayRoadStopTile(v->tile)) rs->SetEntranceBusy(true);
1543
1544 StartRoadVehSound(v);
1545 SetWindowWidgetDirty(WindowClass::VehicleView, v->index, WID_VV_START_STOP);
1546 }
1547
1548 /* Check tile position conditions - i.e. stop position in depot,
1549 * entry onto bridge or into tunnel */
1550 auto vets = VehicleEnterTile(v, v->tile, x, y);
1551 if (vets.Test(VehicleEnterTileState::CannotEnter)) {
1552 v->cur_speed = 0;
1553 return false;
1554 }
1555
1556 if (v->current_order.IsType(OT_LEAVESTATION) && IsDriveThroughStopTile(v->tile)) {
1557 v->current_order.Free();
1558 }
1559
1560 /* Move to next frame unless vehicle arrived at a stop position
1561 * in a depot or entered a tunnel/bridge */
1562 if (!vets.Test(VehicleEnterTileState::EnteredWormhole)) v->frame++;
1563 v->x_pos = x;
1564 v->y_pos = y;
1565 v->UpdatePosition();
1566 RoadZPosAffectSpeed(v, v->UpdateInclination(false, true));
1567 return true;
1568}
1569
1570static bool RoadVehController(RoadVehicle *v)
1571{
1572 /* decrease counters */
1573 v->current_order_time++;
1574 if (v->reverse_ctr != 0) v->reverse_ctr--;
1575
1576 /* handle crashed */
1577 if (v->vehstatus.Test(VehState::Crashed) || RoadVehCheckTrainCrash(v)) {
1578 return RoadVehIsCrashed(v);
1579 }
1580
1581 /* road vehicle has broken down? */
1582 if (v->HandleBreakdown()) return true;
1584 v->SetLastSpeed();
1585 return true;
1586 }
1587
1588 ProcessOrders(v);
1589 v->HandleLoading();
1590
1591 if (v->current_order.IsType(OT_LOADING)) return true;
1592
1593 if (v->IsInDepot()) {
1594 /* Check if we should wait here for unbunching. */
1595 if (v->IsWaitingForUnbunching()) return true;
1596 if (RoadVehLeaveDepot(v, true)) return true;
1597 }
1598
1599 v->ShowVisualEffect();
1600
1601 /* Check how far the vehicle needs to proceed */
1602 int j = v->UpdateSpeed();
1603
1604 int adv_spd = v->GetAdvanceDistance();
1605 bool blocked = false;
1606 while (j >= adv_spd) {
1607 j -= adv_spd;
1608
1609 RoadVehicle *u = v;
1610 for (RoadVehicle *prev = nullptr; u != nullptr; prev = u, u = u->Next()) {
1611 if (!IndividualRoadVehicleController(u, prev)) {
1612 blocked = true;
1613 break;
1614 }
1615 }
1616 if (blocked) break;
1617
1618 /* Determine distance to next map position */
1619 adv_spd = v->GetAdvanceDistance();
1620
1621 /* Test for a collision, but only if another movement will occur. */
1622 if (j >= adv_spd && RoadVehCheckTrainCrash(v)) break;
1623 }
1624
1625 v->SetLastSpeed();
1626
1627 for (RoadVehicle *u = v; u != nullptr; u = u->Next()) {
1628 if (u->vehstatus.Test(VehState::Hidden)) continue;
1629
1630 u->UpdateViewport(false, false);
1631 }
1632
1633 /* If movement is blocked, set 'progress' to its maximum, so the roadvehicle does
1634 * not accelerate again before it can actually move. I.e. make sure it tries to advance again
1635 * on next tick to discover whether it is still blocked. */
1636 if (v->progress == 0) v->progress = blocked ? adv_spd - 1 : j;
1637
1638 return true;
1639}
1640
1642{
1643 const Engine *e = this->GetEngine();
1644 if (e->VehInfo<RoadVehicleInfo>().running_cost_class == Price::Invalid) return 0;
1645
1646 uint cost_factor = GetVehicleProperty(this, PROP_ROADVEH_RUNNING_COST_FACTOR, e->VehInfo<RoadVehicleInfo>().running_cost);
1647 if (cost_factor == 0) return 0;
1648
1649 return GetPrice(e->VehInfo<RoadVehicleInfo>().running_cost_class, cost_factor, e->GetGRF());
1650}
1651
1653{
1655
1656 this->tick_counter++;
1657
1658 if (this->IsFrontEngine()) {
1659 if (!this->vehstatus.Test(VehState::Stopped)) this->running_ticks++;
1660 return RoadVehController(this);
1661 }
1662
1663 return true;
1664}
1665
1667{
1668 if (tile == this->dest_tile) return;
1669 this->path.clear();
1670 this->dest_tile = tile;
1671}
1672
1673static void CheckIfRoadVehNeedsService(RoadVehicle *v)
1674{
1675 /* If we already got a slot at a stop, use that FIRST, and go to a depot later */
1676 if (Company::Get(v->owner)->settings.vehicle.servint_roadveh == 0 || !v->NeedsAutomaticServicing()) return;
1677 if (v->IsChainInDepot()) {
1679 return;
1680 }
1681
1682 uint max_penalty = _settings_game.pf.yapf.maximum_go_to_depot_penalty;
1683
1684 FindDepotData rfdd = FindClosestRoadDepot(v, max_penalty);
1685 /* Only go to the depot if it is not too far out of our way. */
1686 if (rfdd.best_length == UINT_MAX || rfdd.best_length > max_penalty) {
1687 if (v->current_order.IsType(OT_GOTO_DEPOT)) {
1688 /* If we were already heading for a depot but it has
1689 * suddenly moved farther away, we continue our normal
1690 * schedule? */
1692 SetWindowWidgetDirty(WindowClass::VehicleView, v->index, WID_VV_START_STOP);
1693 }
1694 return;
1695 }
1696
1697 DepotID depot = GetDepotIndex(rfdd.tile);
1698
1699 if (v->current_order.IsType(OT_GOTO_DEPOT) &&
1701 !Chance16(1, 20)) {
1702 return;
1703 }
1704
1707 v->SetDestTile(rfdd.tile);
1708 SetWindowWidgetDirty(WindowClass::VehicleView, v->index, WID_VV_START_STOP);
1709}
1710
1713{
1714 if (!this->IsFrontEngine()) return;
1715 AgeVehicle(this);
1716}
1717
1720{
1721 if (!this->IsFrontEngine()) return;
1722 EconomyAgeVehicle(this);
1723
1724 if ((++this->day_counter & 7) == 0) DecreaseVehicleValue(this);
1725 if (this->blocked_ctr == 0) CheckVehicleBreakdown(this);
1726
1727 CheckIfRoadVehNeedsService(this);
1728
1729 CheckOrders(this);
1730
1731 if (this->running_ticks == 0) return;
1732
1734
1735 this->profit_this_year -= cost.GetCost();
1736 this->running_ticks = 0;
1737
1739
1740 SetWindowDirty(WindowClass::VehicleDetails, this->index);
1741 SetWindowClassesDirty(WindowClass::RoadVehicleList);
1742}
1743
1745{
1746 if (this->vehstatus.Test(VehState::Crashed)) return Trackdir::Invalid;
1747
1748 if (this->IsInDepot()) {
1749 /* We'll assume the road vehicle is facing outwards */
1750 return DiagDirToDiagTrackdir(GetRoadDepotDirection(this->tile));
1751 }
1752
1753 if (IsBayRoadStopTile(this->tile)) {
1754 /* We'll assume the road vehicle is facing outwards */
1755 return DiagDirToDiagTrackdir(GetBayRoadStopDir(this->tile)); // Road vehicle in a station
1756 }
1757
1758 /* Drive through road stops / wormholes (tunnels) */
1760
1761 /* If vehicle's state is a valid track direction (vehicle is not turning around) return it,
1762 * otherwise transform it into a valid track direction */
1763 return static_cast<Trackdir>(IsReversingRoadTrackdir(static_cast<Trackdir>(this->state)) ? (this->state - 6) : this->state);
1764}
1765
1767{
1768 uint16_t weight = CargoSpec::Get(this->cargo_type)->WeightOfNUnits(this->GetEngine()->DetermineCapacity(this));
1769
1770 /* Vehicle weight is not added for articulated parts. */
1771 if (!this->IsArticulatedPart()) {
1772 /* Road vehicle weight is in units of 1/4 t. */
1773 weight += GetVehicleProperty(this, PROP_ROADVEH_WEIGHT, RoadVehInfo(this->engine_type)->weight) / 4;
1774 }
1775
1776 return weight;
1777}
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.
Class for backupping variables and making sure they are restored later.
@ BuiltAsPrototype
Vehicle is a prototype (accepted as exclusive preview).
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
const BridgeSpec * GetBridgeSpec(BridgeType i)
Get the specification of a bridge type.
Definition bridge.h:63
BridgeType GetBridgeType(Tile t)
Determines the type of bridge on a tile.
Definition bridge_map.h:56
bool IsValidCargoType(CargoType cargo)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:110
@ Passengers
Passengers.
Definition cargotype.h:51
bool IsCargoInClass(CargoType cargo, CargoClasses cc)
Does cargo c have cargo class cc?
Definition cargotype.h:238
static void NewEvent(CompanyID company, ScriptEvent *event)
Queue a new event for an AI.
Definition ai_core.cpp:231
uint Count() const
Count the number of set bits.
constexpr bool All(const Timpl &other) const
Test if all of the values are set.
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
constexpr bool None() const
Test if none of the values are set.
constexpr Timpl & Reset()
Reset all bits.
constexpr Timpl & Set()
Set all bits.
constexpr bool Any(const Timpl &other) const
Test if any of the given values are set.
std::optional< Tvalue_type > GetNthSetBit(uint n) const
Get the value of the Nth set bit.
Common return value for all commands.
Money GetCost() const
The costs as made up to this moment.
bool Failed() const
Did this command fail?
Container for an encoded string, created by GetEncodedString.
uint16_t reliability_spd_dec
Speed of reliability decay between services (per day).
Definition engine_base.h:52
const GRFFile * GetGRF() const
Retrieve the NewGRF the engine is tied to.
GrfID GetGRFID() const
Retrieve the GRF ID of the NewGRF the engine is tied to.
Definition engine.cpp:183
EngineFlags flags
Flags of the engine.
Definition engine_base.h:59
uint8_t original_image_index
Original vehicle image index, thus the image index of the overridden vehicle.
Definition engine_base.h:63
TimerGameCalendar::Date GetLifeLengthInDays() const
Returns the vehicle's (not model's!) life length in days.
Definition engine.cpp:469
CargoType GetDefaultCargoType() const
Determines the default cargo type of an engine.
Definition engine_base.h:96
uint16_t reliability
Current reliability of the engine.
Definition engine_base.h:51
static void NewEvent(class ScriptEvent *event)
Queue a new event for the game script.
RAII class for measuring multi-step elements of performance.
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 Date date
Current date in days (day counter).
Iterate over all vehicles near a given world coordinate.
Iterate over all vehicles on a tile.
Functions related to commands.
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
@ NoWater
don't allow building on water
@ Execute
execute the given command
EnumBitSet< DoCommandFlag, uint16_t > DoCommandFlags
Bitset of DoCommandFlag elements.
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.
CompanyID _current_company
Company currently doing an action.
void SubtractMoneyFromCompanyFract(CompanyID company, const CommandCost &cst)
Subtract money from a company, including the money fraction.
Functions related to companies.
Map related accessors for depots.
DepotID GetDepotIndex(Tile t)
Get the index of which depot is attached to the tile.
Definition depot_map.h:56
PoolID< uint16_t, struct DepotIDTag, 64000, 0xFFFF > DepotID
Type for the unique identifier of depots.
Definition depot_type.h:15
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.
Direction ChangeDir(Direction d, DirDiff delta)
Change a direction by a given difference.
bool IsDiagonalDirection(Direction dir)
Checks if a given Direction is diagonal.
Axis DiagDirToAxis(DiagDirection d)
Convert a DiagDirection to the axis.
DirDiff LimitDirDiff(DirDiff d)
Limit a direction difference to up to 45 degrees.
DiagDirection DirToDiagDir(Direction dir)
Convert a Direction to a DiagDirection.
DirDiff
Enumeration for the difference between two directions.
@ Left45
Angle of 45 degrees left.
@ Same
Both directions faces to the same direction.
@ Right45
Angle of 45 degrees right.
EnumIndexArray< T, DiagDirection, DiagDirection::End > DiagDirectionIndexArray
Array with DiagDirection as index.
Direction
Defines the 8 directions on the map.
@ Invalid
Flag for an invalid direction.
@ SW
Southwest.
@ NW
Northwest.
@ NE
Northeast.
@ SE
Southeast.
EnumIndexArray< T, Direction, Direction::End > DirectionIndexArray
Array with Direction as index.
DiagDirection
Enumeration for diagonal directions.
@ Invalid
Flag for an invalid DiagDirection.
@ SW
Southwest.
@ NW
Northwest.
@ NE
Northeast, upper right on your monitor.
@ SE
Southeast.
Money GetPrice(Price index, uint cost_factor, const GRFFile *grf_file, int shift)
Determine a certain price.
Definition economy.cpp:937
@ RoadVehRun
Running costs road vehicles.
@ Invalid
Invalid base price.
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_LARGE
Various explosions.
PoolID< uint16_t, struct EngineIDTag, 64000, 0xFFFF > EngineID
Unique identification number of an engine.
Definition engine_type.h:26
@ ExclusivePreview
This vehicle is in the exclusive preview stage, either being used or being offered to a company.
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23).
Definition enum_type.hpp:21
Error reporting related functions.
fluid_settings_t * settings
FluidSynth settings handle.
Types for recording game performance data.
@ GameLoopRoadVehicles
Time spend processing road vehicles.
Base functions for all Games.
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition gfx_type.h:17
uint32_t PaletteID
The number of the palette.
Definition gfx_type.h:18
@ AS_BRAKE
We want to stop.
TrackStatus GetTileTrackStatus(TileIndex tile, TransportType mode, RoadTramType sub_mode, DiagDirection side)
Returns information about trackdirs and signal states.
int GetSlopePixelZ(int x, int y, bool ground_vehicle)
Return world Z coordinate of a given point of a tile.
#define Rect
Macro that prevents name conflicts between included headers.
#define Point
Macro that prevents name conflicts between included headers.
TileIndex TileAddByDir(TileIndex tile, Direction dir)
Adds a Direction to a tile.
Definition map_func.h:603
static uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition map_func.h:429
static uint TileX(TileIndex tile)
Get the X component of a tile.
Definition map_func.h:419
TileIndexDiff TileOffsByDiagDir(DiagDirection dir)
Convert a DiagDirection to a TileIndexDiff.
Definition map_func.h:574
constexpr bool IsInsideMM(const size_t x, const size_t min, const size_t max) noexcept
Checks if a value is in an interval.
constexpr T abs(const T a)
Returns the absolute value of (scalar) variable.
Definition math_func.hpp:23
constexpr T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition math_func.hpp:79
Base for the NewGRF implementation.
@ CBID_VEHICLE_LENGTH
Vehicle length, returns the amount of 1/8's the vehicle is shorter for trains and RVs.
static const uint CALLBACK_FAILED
Different values for Callback result evaluations.
void ErrorUnknownCallbackResult(GrfID grfid, uint16_t cbid, uint16_t cb_res)
Record that a NewGRF returned an unknown/invalid callback result.
uint16_t GetVehicleCallback(CallbackID callback, uint32_t param1, uint32_t param2, EngineID engine, const Vehicle *v, std::span< int32_t > regs100)
Evaluate a newgrf callback for vehicles.
@ PROP_ROADVEH_CARGO_AGE_PERIOD
Number of ticks before carried cargo is aged.
@ PROP_ROADVEH_WEIGHT
Weight in 1/4 t.
@ PROP_ROADVEH_RUNNING_COST_FACTOR
Yearly runningcost.
@ PROP_ROADVEH_SHORTEN_FACTOR
Shorter vehicles.
@ PROP_ROADVEH_SPEED
Max. speed: 1 unit = 1/0.8 mph = 2 km-ish/h.
void TriggerRoadStopRandomisation(BaseStation *st, TileIndex tile, StationRandomTrigger trigger, CargoType cargo_type)
Trigger road stop randomisation.
NewGRF definitions and structures for road stops.
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.
Functions related to news.
void AddVehicleNewsItem(EncodedString &&headline, NewsType type, VehicleID vehicle, StationID station=StationID::Invalid())
Adds a newsitem referencing a vehicle.
Definition news_func.h:32
NewsType
Type of news.
Definition news_type.h:29
@ ArrivalCompany
First vehicle arrived for company.
Definition news_type.h:30
@ AccidentOther
An accident or disaster has occurred.
Definition news_type.h:33
@ ArrivalOther
First vehicle arrived for competitor.
Definition news_type.h:31
@ Accident
An accident or disaster has occurred.
Definition news_type.h:32
bool ProcessOrders(Vehicle *v)
Handle the orders of a vehicle and determine the next place to go to if needed.
void CheckOrders(const Vehicle *v)
Check the orders of a vehicle, to see if there are invalid orders and stuff.
@ NonStop
The vehicle will not stop at any stations it passes except the destination, aka non-stop.
Definition order_type.h:88
@ Service
This depot order is because of the servicing limit.
Definition order_type.h:109
Pseudo random number generator.
uint32_t RandomRange(uint32_t limit, const std::source_location location=std::source_location::current())
Pick a random number between 0 and limit - 1, inclusive.
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.
const RoadTypeInfo * GetRoadTypeInfo(RoadType roadtype)
Returns a pointer to the Roadtype information for a given roadtype.
Definition road.h:217
Road related functions.
RoadBits AxisToRoadBits(Axis a)
Create the road-part which belongs to the given Axis.
Definition road_func.h:93
RoadBits DiagDirToRoadBits(DiagDirection d)
Create the road-part which belongs to the given DiagDirection.
Definition road_func.h:78
RoadBits GetAnyRoadBits(Tile tile, RoadTramType rtt, bool straight_tunnel_bridge_entrance)
Returns the RoadBits on an arbitrary tile Special behaviour:
Definition road_map.cpp:54
bool IsLevelCrossingTile(Tile t)
Return whether a tile is a level crossing tile.
Definition road_map.h:79
RoadBits GetRoadBits(Tile t, RoadTramType rtt)
Get the present road bits for a specific road type.
Definition road_map.h:112
static bool IsRoadDepotTile(Tile t)
Return whether a tile is a road depot tile.
Definition road_map.h:100
bool HasTileAnyRoadType(Tile t, RoadTypes rts)
Check if a tile has one of the specified road types.
Definition road_map.h:232
DisallowedRoadDirections GetDisallowedRoadDirections(Tile t)
Gets the disallowed directions.
Definition road_map.h:311
DiagDirection GetRoadDepotDirection(Tile t)
Get the direction of the exit of a road depot.
Definition road_map.h:565
static bool IsRoadDepot(Tile t)
Return whether a tile is a road depot.
Definition road_map.h:90
RoadType GetRoadType(Tile t, RoadTramType rtt)
Get the road type for the given RoadTramType.
Definition road_map.h:175
static bool IsNormalRoadTile(Tile t)
Return whether a tile is a normal road tile.
Definition road_map.h:58
bool HasRoadWorks(Tile t)
Check if a tile has road works.
Definition road_map.h:508
static constexpr RoadBits ROAD_X
Full road along the x-axis (south-west + north-east).
Definition road_type.h:67
EnumBitSet< RoadBit, uint8_t > RoadBits
Bitset of RoadBit elements.
Definition road_type.h:65
RoadBit
Enumeration for the road parts on a tile.
Definition road_type.h:57
@ SW
South-west part.
Definition road_type.h:59
@ NW
North-west part.
Definition road_type.h:58
@ NE
North-east part.
Definition road_type.h:61
@ SE
South-east part.
Definition road_type.h:60
static constexpr RoadBits ROAD_Y
Full road along the y-axis (north-west + south-east).
Definition road_type.h:68
RoadType
The different roadtypes we support.
Definition road_type.h:24
RoadTramType
The different types of road type.
Definition road_type.h:38
@ Tram
Tram type.
Definition road_type.h:40
Base class for roadstops.
Road vehicle states.
@ RVSB_IN_DT_ROAD_STOP
The vehicle is in a drive-through road stop.
Definition roadveh.h:51
@ RVS_ENTERED_STOP
Only set when a vehicle has entered the stop.
Definition roadveh.h:43
@ RVSB_IN_ROAD_STOP
The vehicle is in a road stop.
Definition roadveh.h:49
@ RVSB_ROAD_STOP_TRACKDIR_MASK
Only bits 0 and 3 are used to encode the trackdir for road stops.
Definition roadveh.h:57
@ RVS_IN_DT_ROAD_STOP
The vehicle is in a drive-through road stop.
Definition roadveh.h:46
@ RVSB_TRACKDIR_MASK
The mask used to extract track dirs.
Definition roadveh.h:56
@ RVSB_DRIVE_SIDE
The vehicle is at the opposite side of the road.
Definition roadveh.h:54
@ RVSB_IN_DEPOT
The vehicle is in a depot.
Definition roadveh.h:38
@ RVSB_WORMHOLE
The vehicle is in a tunnel and/or bridge.
Definition roadveh.h:39
@ RVS_DRIVE_SIDE
Only used when retrieving move data.
Definition roadveh.h:44
static const uint RDE_TURNED
We just finished turning.
Definition roadveh.h:63
static const uint RVC_DRIVE_THROUGH_STOP_FRAME
Stop frame for a vehicle in a drive-through stop.
Definition roadveh.h:82
static const uint8_t RV_OVERTAKE_TIMEOUT
The number of ticks a vehicle has for overtaking.
Definition roadveh.h:86
void RoadVehUpdateCache(RoadVehicle *v, bool same_length=false)
Update the cache of a road vehicle.
static const uint RDE_NEXT_TILE
We should enter the next tile.
Definition roadveh.h:62
bool IsValidImageIndex< VehicleType::Road >(uint8_t image_index)
Helper to check whether an image index is valid for a particular vehicle.
static constexpr DiagDirectionIndexArray< Trackdir > _road_reverse_table
Track direction to use when reversing for each diagonal direction.
static bool RoadVehIsCrashed(RoadVehicle *v)
Road vehicle chain has crashed.
static uint GetRoadVehLength(const RoadVehicle *v)
Get length of a road vehicle.
static void RoadVehArrivesAt(const RoadVehicle *v, Station *st)
A road vehicle arrives at a station.
static bool CheckRoadBlockedForOvertaking(OvertakeData *od)
Check if overtaking is possible on a piece of track.
void RoadVehUpdateCache(RoadVehicle *v, bool same_length)
Update the cache of a road vehicle.
static bool CanBuildTramTrackOnTile(CompanyID c, TileIndex t, RoadType rt, RoadBits r)
Can a tram track build without destruction on the given tile?
void GetRoadVehSpriteSize(EngineID engine, uint &width, uint &height, int &xoffs, int &yoffs, EngineImageType image_type)
Get the size of the sprite of a road vehicle sprite heading west (used for lists).
CommandCost CmdBuildRoadVehicle(DoCommandFlags flags, TileIndex tile, const Engine *e, Vehicle **ret)
Build a road vehicle.
CommandCost CmdTurnRoadVeh(DoCommandFlags flags, VehicleID veh_id)
Turn a roadvehicle around.
void DrawRoadVehEngine(int left, int right, int preferred_x, int y, EngineID engine, PaletteID pal, EngineImageType image_type)
Draw a road vehicle engine.
static Trackdir RoadFindPathToDest(RoadVehicle *v, TileIndex tile, DiagDirection enterdir)
Returns direction to for a road vehicle to take or Trackdir::Invalid if the direction is currently bl...
static void DeleteLastRoadVeh(RoadVehicle *v)
Delete last vehicle of a chain road vehicles.
Command definitions related to road vehicles.
Data about how a road vehicle must drive on a tile.
static const EnumIndexArray< const RoadDriveEntry *const *, RoadTramType, RoadTramType::End > _road_drive_data
Road drive data for all RoadTramTypes.
const uint8_t _road_stop_stop_frame[]
Table of road stop stop frames, when to stop at a road stop.
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:61
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:60
Functions related to sound.
@ SND_19_DEPARTURE_OLD_RV_1
23 == 0x17 Station departure: truck and old bus (1) (non-toyland)
Definition sound_type.h:71
@ SND_12_EXPLOSION
16 == 0x10 Destruction, crashes, disasters, ...
Definition sound_type.h:64
@ SND_1A_DEPARTURE_OLD_RV_2
24 == 0x18 Station departure: truck and old bus (2) (random variation of SND_19_DEPARTURE_OLD_RV_1) (...
Definition sound_type.h:72
static const PaletteID PALETTE_CRASH
Recolour sprite greying of crashed vehicles.
Definition sprites.h:1794
static const SpriteID SPR_IMG_QUERY
Definition sprites.h:1275
Base classes/functions for stations.
void ModifyStationRatingAround(TileIndex tile, Owner owner, int amount, uint radius)
Forcibly modify station ratings near a given tile.
bool IsBayRoadStopTile(Tile t)
Is tile t a bay (non-drive through) road stop station?
bool IsDriveThroughStopTile(Tile t)
Is tile t a drive through road stop station or waypoint?
StationID GetStationIndex(Tile t)
Get StationID from a tile.
Definition station_map.h:28
bool IsStationRoadStop(Tile t)
Is the station at t a road station?
DiagDirection GetBayRoadStopDir(Tile t)
Gets the direction the bay road stop entrance points towards.
RoadStopType GetRoadStopType(Tile t)
Get the road stop type of this tile.
Definition station_map.h:56
RoadStopType
Types of RoadStops.
@ Bus
A standard stop for buses.
@ Truck
A standard stop for trucks.
@ VehicleArrives
Trigger platform when train arrives.
@ VehicleArrives
Trigger platform when train arrives.
@ Bus
Station has seen a bus.
@ Truck
Station has seen a truck.
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:261
EncodedString GetEncodedString(StringID str)
Encode a string with no parameters into an encoded string.
Definition strings.cpp:90
Functions related to OTTD's strings.
Class to backup a specific variable and restore it upon destruction of this object to prevent stack v...
TimerGameTick::Ticks current_order_time
How many ticks have passed since this order started.
void ResetDepotUnbunching()
Resets all the data used for depot unbunching.
TileIndex xy
Base tile of the station.
static BaseStation * GetByTile(TileIndex tile)
Get the base station belonging to a specific tile.
VehicleType type
Type of vehicle.
uint16_t speed
maximum travel speed (1 unit = 1/1.6 mph = 1 km-ish/h)
Definition bridge.h:41
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo type.
Definition cargotype.h:141
Structure to return information about the closest depot location, and whether it could be found.
T y
Y coordinate.
T x
X coordinate.
Helper container to find a depot.
uint best_length
The distance towards the depot in penalty, or UINT_MAX if not found.
TileIndex tile
The tile of the depot.
Position information of a vehicle after it moved.
TileIndex new_tile
Tile of the vehicle after moving.
int y
x and y position of the vehicle after moving
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...
bool IsChainInDepot() const override
Check whether the whole vehicle chain is in the depot.
int UpdateInclination(bool new_tile, bool update_delta)
Checks if the vehicle is in a slope and sets the required flags in that case.
GroundVehicleFlags gv_flags
uint Crash(bool flooded) override
Common code executed for crashed ground vehicles.
uint DoUpdateSpeed(uint accel, int min_speed, int max_speed)
void SetLastSpeed()
Update the GUI variant of the current speed of the vehicle.
DestinationID GetDestination() const
Gets the destination of this order.
Definition order_base.h:100
bool IsType(OrderType type) const
Check whether this order is of the given type.
Definition order_base.h:67
void MakeDummy()
Makes this order a Dummy order.
void Free()
'Free' the order
Definition order_cmd.cpp:48
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...
void MakeGoToDepot(DestinationID destination, OrderDepotTypeFlags order, OrderNonStopFlags non_stop_type=OrderNonStopFlag::NonStop, OrderDepotActionFlags action={}, CargoType cargo=CARGO_NO_REFIT)
Makes this order a Go To Depot order.
Definition order_cmd.cpp:74
OrderNonStopFlags GetNonStopType() const
At which stations must we stop?
Definition order_base.h:158
static T * Create(Targs &&... args)
static Engine * Get(auto index)
static Vehicle * GetIfValid(auto index)
int Width() const
Get width of Rect.
int Height() const
Get height of Rect.
A Stop for a Road Vehicle.
void SetEntranceBusy(bool busy)
Makes an entrance occupied or free.
void Leave(RoadVehicle *rv)
Leave the road stop.
Definition roadstop.cpp:203
bool IsEntranceBusy() const
Checks whether the entrance of the road stop is occupied by a vehicle.
static bool IsDriveThroughRoadStopContinuation(TileIndex rs, TileIndex next)
Checks whether the 'next' tile is still part of the road same drive through stop 'rs' in the same dir...
Definition roadstop.cpp:292
static RoadStop * GetByTile(TileIndex tile, RoadStopType type)
Find a roadstop at given tile.
Definition roadstop.cpp:253
Information about a road vehicle.
Buses, trucks and trams belong to this class.
Definition roadveh.h:105
uint Crash(bool flooded=false) override
Common code executed for crashed ground vehicles.
TileIndex GetOrderStationLocation(StationID station) override
Determine the location for the station where the vehicle goes to next.
void OnNewEconomyDay() override
Economy day handler.
uint8_t state
Definition roadveh.h:107
void SetDestTile(TileIndex tile) override
Set the destination of this vehicle.
int GetDisplayImageWidth(Point *offset=nullptr) const
Get the width of a road vehicle image in the GUI.
Money GetRunningCost() const override
Gets the running cost of a vehicle.
bool IsPrimaryVehicle() const override
Whether this is the primary vehicle in the chain.
Definition roadveh.h:128
uint16_t GetMaxWeight() const override
Calculates the weight value that this vehicle will have when fully loaded with its current cargo.
RoadTypes compatible_roadtypes
NOSAVE: Roadtypes this consist is powered on.
Definition roadveh.h:117
AccelStatus GetAccelerationStatus() const
Checks the current acceleration status of this vehicle.
Definition roadveh.h:229
void UpdateDeltaXY() override
Updates the x and y offsets and the size of the sprite used for this vehicle.
uint16_t crashed_ctr
Animation counter when the vehicle has crashed.
Definition roadveh.h:112
bool IsBus() const
Check whether a roadvehicle is a bus.
uint8_t overtaking_ctr
The length of the current overtake attempt.
Definition roadveh.h:111
void OnNewCalendarDay() override
Calender day handler.
bool IsInDepot() const override
Check whether the vehicle is in the depot.
Definition roadveh.h:134
void GetImage(Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) const override
Gets the sprite to show for the given direction.
RoadVehPathCache path
Cached path.
Definition roadveh.h:106
Trackdir GetVehicleTrackdir() const override
Returns the Trackdir on which the vehicle is currently located.
int GetCurrentMaxSpeed() const override
Calculates the maximum speed of the vehicle under its current conditions.
RoadType roadtype
NOSAVE: Roadtype of this vehicle.
Definition roadveh.h:115
uint8_t overtaking
Set to RVSB_DRIVE_SIDE when overtaking, otherwise 0.
Definition roadveh.h:110
int UpdateSpeed()
This function looks at the vehicle and updates its speed (cur_speed and subspeed) variables.
bool Tick() override
Calls the tick handler of the vehicle.
ClosestDepot FindClosestDepot() override
Find the closest depot for this vehicle and tell us the location, DestinationID and whether we should...
void MarkDirty() override
Marks the vehicles to be redrawn and updates cached variables.
static Station * Get(auto index)
T * Next() const
Get next vehicle in the chain.
T * Previous() const
Get previous vehicle in the chain.
static RoadVehicle * From(Vehicle *v)
T * First() const
Get the first vehicle in the chain.
void UpdateViewport(bool force_update, bool update_delta)
Update vehicle sprite- and position caches.
Station data structure.
Track status of a tile.
Definition track_type.h:105
TrackdirBits signals
Red signals on the tile.
Definition track_type.h:107
TrackdirBits trackdirs
Trackdirs present on the tile.
Definition track_type.h:106
uint16_t cached_max_speed
Maximum speed of the consist (minimum of the max speed of all vehicles in the consist).
Sprite sequence for a vehicle part.
bool IsValid() const
Check whether the sequence contains any sprites.
void GetBounds(Rect *bounds) const
Determine shared bounds of all sprites.
Definition vehicle.cpp:124
void Set(SpriteID sprite)
Assign a single sprite to the sequence.
void Draw(int x, int y, PaletteID default_pal, bool force_pal) const
Draw the sprite sequence.
Definition vehicle.cpp:152
Vehicle data structure.
EngineID engine_type
The type of engine used for this vehicle.
int32_t z_pos
z coordinate.
Direction direction
facing
const Engine * GetEngine() const
Retrieves the engine of the vehicle.
Definition vehicle.cpp:749
void IncrementRealOrderIndex()
Advanced cur_real_order_index to the next real order, keeps care of the wrap-around and invalidates t...
VehicleCargoList cargo
The cargo this vehicle is carrying.
uint8_t day_counter
Increased by one for each day.
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:2453
Money profit_this_year
Profit this year << 8, low 8 bits are fract.
bool HasArticulatedPart() const
Check if an engine has an articulated part.
SpriteID colourmap
NOSAVE: cached colour mapping.
uint8_t breakdown_ctr
Counter for managing breakdown events.
uint GetAdvanceDistance()
Determines the vehicle "progress" needed for moving a step.
VehStates vehstatus
Status.
bool IsArticulatedPart() const
Check if the vehicle is an articulated part of an engine.
void LeaveUnbunchingDepot()
Leave an unbunching depot and calculate the next departure time for shared order vehicles.
Definition vehicle.cpp:2533
CargoType cargo_type
type of cargo this vehicle is carrying
Vehicle * First() const
Get the first vehicle of this vehicle chain.
Order current_order
The current order (+ status, like: loading).
void HandlePathfindingResult(bool path_found)
Handle the pathfinding result, especially the lost status.
Definition vehicle.cpp:793
int32_t y_pos
y coordinate.
int32_t x_pos
x coordinate.
VehicleCache vcache
Cache of often used vehicle values.
SpriteBounds bounds
Bounding box of vehicle.
void BeginLoading()
Prepare everything to begin the loading when arriving at a station.
Definition vehicle.cpp:2228
uint8_t spritenum
currently displayed sprite index 0xfd == custom sprite, 0xfe == custom second head sprite 0xff == res...
uint16_t cur_speed
current speed
bool IsFrontEngine() const
Check if the vehicle is a front engine.
bool IsWaitingForUnbunching() const
Check whether a vehicle inside a depot is waiting for unbunching.
Definition vehicle.cpp:2580
void SetNext(Vehicle *next)
Set the next vehicle of this vehicle.
Definition vehicle.cpp:2985
bool HandleBreakdown()
Handle all of the aspects of a vehicle breakdown This includes adding smoke and sounds,...
Definition vehicle.cpp:1375
uint8_t progress
The percentage (if divided by 256) this vehicle already crossed the tile unit.
uint8_t tick_counter
Increased by one for each tick.
virtual bool IsInDepot() const
Check whether the vehicle is in the depot.
TileIndex tile
Current tile index.
TileIndex dest_tile
Heading for this tile.
void UpdatePosition()
Update the position of the vehicle.
Definition vehicle.cpp:1700
StationID last_station_visited
The last station we stopped at.
void InvalidateNewGRFCacheOfChain()
Invalidates cached NewGRF variables of all vehicles in the chain (after the current vehicle).
void ShowVisualEffect() const
Draw visual effects (smoke and/or sparks) for a vehicle chain.
Definition vehicle.cpp:2834
Owner owner
Which company owns the vehicle?
bool NeedsAutomaticServicing() const
Checks if the current order should be interrupted for a service-in-depot order.
Definition vehicle.cpp:293
uint8_t running_ticks
Number of ticks this vehicle was not stopped this day.
@ CannotEnter
The vehicle cannot enter the tile.
Definition tile_cmd.h:27
@ EnteredWormhole
The vehicle either entered a bridge, tunnel or depot tile (this includes the last tile of the bridge/...
Definition tile_cmd.h:26
VehicleEnterTileStates VehicleEnterTile(Vehicle *v, TileIndex tile, int x, int y)
Call the tile callback function for a vehicle entering a tile.
Definition vehicle.cpp:1864
static bool IsTileType(Tile tile, TileType type)
Checks if a tile is a given tiletype.
Definition tile_map.h:150
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
StrongType::Typedef< uint32_t, struct TileIndexTag, StrongType::Compare, StrongType::Integer, StrongType::Compatible< int32_t >, StrongType::Compatible< int64_t > > TileIndex
The index/ID of a Tile.
Definition tile_type.h:92
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:100
static constexpr uint TILE_SIZE
Tile size in world coordinates.
Definition tile_type.h:15
@ TunnelBridge
Tunnel entry/exit and bridge heads.
Definition tile_type.h:58
@ Station
A tile of a station or airport.
Definition tile_type.h:54
@ Road
A tile with road and/or tram tracks.
Definition tile_type.h:51
Definition of the game-calendar-timer.
Definition of the game-economy-timer.
bool IsReversingRoadTrackdir(Trackdir dir)
Checks whether the trackdir means that we are reversing.
Definition track_func.h:568
TrackdirBits DiagdirReachesTrackdirs(DiagDirection diagdir)
Returns all trackdirs that can be reached when entering a tile from a given (diagonal) direction.
Definition track_func.h:450
bool IsStraightRoadTrackdir(Trackdir dir)
Checks whether the given trackdir is a straight road.
Definition track_func.h:579
Trackdir DiagDirToDiagTrackdir(DiagDirection diagdir)
Maps a (4-way) direction to the diagonal trackdir that runs in that direction.
Definition track_func.h:432
TrackBits TrackdirBitsToTrackBits(TrackdirBits bits)
Discards all directional information from a TrackdirBits value.
Definition track_func.h:281
EnumBitSet< Track, uint8_t > TrackBits
Bitset of Track elements.
Definition track_type.h:43
Trackdir
Enumeration for tracks and directions.
Definition track_type.h:63
@ Right_N
Right track and direction to north.
Definition track_type.h:77
@ Right_S
Right track and direction to south.
Definition track_type.h:69
@ Left_S
Left track and direction to south.
Definition track_type.h:68
@ Lower_E
Lower track and direction to east.
Definition track_type.h:67
@ Invalid
Flag for an invalid trackdir.
Definition track_type.h:82
@ RvRev_NW
(Road vehicle) reverse direction north-west
Definition track_type.h:79
@ Upper_W
Upper track and direction to west.
Definition track_type.h:74
@ End
End marker.
Definition track_type.h:81
@ RvRev_NE
(Road vehicle) reverse direction north-east
Definition track_type.h:70
@ Upper_E
Upper track and direction to east.
Definition track_type.h:66
@ RvRev_SW
(Road vehicle) reverse direction south-west
Definition track_type.h:78
@ Left_N
Left track and direction to north.
Definition track_type.h:76
@ Lower_W
Lower track and direction to west.
Definition track_type.h:75
@ RvRev_SE
(Road vehicle) reverse direction south-east
Definition track_type.h:71
@ Road
Transport by road vehicle.
Functions that have tunnels and bridges in common.
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 VehicleEnterDepot(Vehicle *v)
Vehicle entirely entered the depot, update its status, orders, vehicle windows, service it,...
Definition vehicle.cpp:1563
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:364
void VehicleServiceInDepot(Vehicle *v)
Service a vehicle and all subsequent vehicles in the consist.
Definition vehicle.cpp:188
void CheckVehicleBreakdown(Vehicle *v)
Periodic check for a vehicle to maybe break down.
Definition vehicle.cpp:1319
GetNewVehiclePosResult GetNewVehiclePos(const Vehicle *v)
Get position information of a vehicle when moving one pixel in the direction it is facing.
Definition vehicle.cpp:1803
void DecreaseVehicleValue(Vehicle *v)
Decrease the value of a vehicle.
Definition vehicle.cpp:1298
void EconomyAgeVehicle(Vehicle *v)
Update economy age of a vehicle.
Definition vehicle.cpp:1441
bool CanVehicleUseStation(EngineID engine_type, const Station *st)
Can this station be used by the given engine type?
Definition vehicle.cpp:3112
void AgeVehicle(Vehicle *v)
Update age of a vehicle.
Definition vehicle.cpp:1453
@ Crashed
Vehicle is crashed.
@ Hidden
Vehicle is not visible.
@ DefaultPalette
Use default vehicle palette.
@ Stopped
Vehicle is stopped by the player.
Functions related to vehicles.
bool HasVehicleNearTileXY(int32_t x, int32_t y, uint max_dist, UnaryPred &&predicate)
Loop over vehicles near a given world coordinate, and check whether a predicate is true for any of th...
bool IsValidImageIndex(uint8_t image_index)
Helper to check whether an image index is valid for a particular vehicle.
@ CUSTOM_VEHICLE_SPRITENUM_REVERSED
Vehicle sprite from NewGRF with reverse driving direction (from articulation callback).
bool HasVehicleOnTile(TileIndex tile, UnaryPred &&predicate)
Loop over vehicles on a tile, and check whether a predicate is true for any of them.
EngineImageType
Visualisation contexts of vehicles and engines.
PoolID< uint32_t, struct VehicleIDTag, 0xFF000, 0xFFFFF > VehicleID
The type all our vehicle IDs have.
@ Road
Road vehicle type.
@ Original
Original acceleration model.
@ Realistic
"Realistic" acceleration model.
@ SuppressImplicitOrders
Disable insertion and removal of automatic orders until the vehicle completes the real order.
static const uint VEHICLE_LENGTH
The length of a vehicle in tile units.
@ WID_VV_START_STOP
Start or stop this vehicle, and show information about the current state.
void SetWindowClassesDirty(WindowClass cls)
Mark all windows of a particular class as dirty (in need of repainting).
Definition window.cpp:3242
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:3334
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:3228
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting).
Definition window.cpp:3212
Entry point for OpenTTD to YAPF.
Trackdir YapfRoadVehicleChooseTrack(const RoadVehicle *v, TileIndex tile, DiagDirection enterdir, TrackdirBits trackdirs, bool &path_found, RoadVehPathCache &path_cache)
Finds the best path for given road vehicle using YAPF.
FindDepotData YapfRoadVehicleFindNearestDepot(const RoadVehicle *v, int max_penalty)
Used when user sends road vehicle to the nearest depot or if road vehicle needs servicing using 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