OpenTTD Source 20241224-master-gf74b0cf984
articulated_vehicles.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6 */
7
10#include "stdafx.h"
11#include "core/bitmath_func.hpp"
12#include "core/random_func.hpp"
13#include "train.h"
14#include "roadveh.h"
15#include "vehicle_func.h"
16#include "engine_func.h"
17#include "company_func.h"
18#include "newgrf.h"
19
20#include "table/strings.h"
21
22#include "safeguards.h"
23
24static const uint MAX_ARTICULATED_PARTS = 100;
25
34static EngineID GetNextArticulatedPart(uint index, EngineID front_type, Vehicle *front = nullptr, bool *mirrored = nullptr)
35{
36 assert(front == nullptr || front->engine_type == front_type);
37
38 const Engine *front_engine = Engine::Get(front_type);
39
40 uint16_t callback = GetVehicleCallback(CBID_VEHICLE_ARTIC_ENGINE, index, 0, front_type, front);
41 if (callback == CALLBACK_FAILED) return INVALID_ENGINE;
42
43 if (front_engine->GetGRF()->grf_version < 8) {
44 /* 8 bits, bit 7 for mirroring */
45 callback = GB(callback, 0, 8);
46 if (callback == 0xFF) return INVALID_ENGINE;
47 if (mirrored != nullptr) *mirrored = HasBit(callback, 7);
48 callback = GB(callback, 0, 7);
49 } else {
50 /* 15 bits, bit 14 for mirroring */
51 if (callback == 0x7FFF) return INVALID_ENGINE;
52 if (mirrored != nullptr) *mirrored = HasBit(callback, 14);
53 callback = GB(callback, 0, 14);
54 }
55
56 return GetNewEngineID(front_engine->GetGRF(), front_engine->type, callback);
57}
58
65{
66 return HasBit(EngInfo(engine_type)->callback_mask, CBM_VEHICLE_ARTIC_ENGINE);
67}
68
75uint CountArticulatedParts(EngineID engine_type, bool purchase_window)
76{
77 if (!HasBit(EngInfo(engine_type)->callback_mask, CBM_VEHICLE_ARTIC_ENGINE)) return 0;
78
79 /* If we can't allocate a vehicle now, we can't allocate it in the command
80 * either, so it doesn't matter how many articulated parts there are. */
81 if (!Vehicle::CanAllocateItem()) return 0;
82
83 Vehicle *v = nullptr;
84 if (!purchase_window) {
85 v = new Vehicle();
86 v->engine_type = engine_type;
88 }
89
90 uint i;
91 for (i = 1; i < MAX_ARTICULATED_PARTS; i++) {
92 if (GetNextArticulatedPart(i, engine_type, v) == INVALID_ENGINE) break;
93 }
94
95 delete v;
96
97 return i - 1;
98}
99
100
106static inline std::pair<CargoID, uint16_t> GetVehicleDefaultCapacity(EngineID engine)
107{
108 const Engine *e = Engine::Get(engine);
109 CargoID cargo = e->CanCarryCargo() ? e->GetDefaultCargoType() : INVALID_CARGO;
110 return {cargo, IsValidCargoID(cargo) ? e->GetDisplayDefaultCapacity() : 0};
111}
112
119static inline CargoTypes GetAvailableVehicleCargoTypes(EngineID engine, bool include_initial_cargo_type)
120{
121 const Engine *e = Engine::Get(engine);
122 if (!e->CanCarryCargo()) return 0;
123
124 CargoTypes cargoes = e->info.refit_mask;
125
126 if (include_initial_cargo_type) {
127 SetBit(cargoes, e->GetDefaultCargoType());
128 }
129
130 return cargoes;
131}
132
139{
140 CargoArray capacity{};
141 const Engine *e = Engine::Get(engine);
142
143 if (auto [cargo, cap] = GetVehicleDefaultCapacity(engine); IsValidCargoID(cargo)) {
144 capacity[cargo] = cap;
145 }
146
147 if (!e->IsGroundVehicle()) return capacity;
148
149 if (!HasBit(e->info.callback_mask, CBM_VEHICLE_ARTIC_ENGINE)) return capacity;
150
151 for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) {
152 EngineID artic_engine = GetNextArticulatedPart(i, engine);
153 if (artic_engine == INVALID_ENGINE) break;
154
155 if (auto [cargo, cap] = GetVehicleDefaultCapacity(artic_engine); IsValidCargoID(cargo)) {
156 capacity[cargo] += cap;
157 }
158 }
159
160 return capacity;
161}
162
169{
170 CargoTypes cargoes = 0;
171 const Engine *e = Engine::Get(engine);
172
173 if (auto [cargo, cap] = GetVehicleDefaultCapacity(engine); IsValidCargoID(cargo) && cap > 0) {
174 SetBit(cargoes, cargo);
175 }
176
177 if (!e->IsGroundVehicle()) return cargoes;
178
179 if (!HasBit(e->info.callback_mask, CBM_VEHICLE_ARTIC_ENGINE)) return cargoes;
180
181 for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) {
182 EngineID artic_engine = GetNextArticulatedPart(i, engine);
183 if (artic_engine == INVALID_ENGINE) break;
184
185 if (auto [cargo, cap] = GetVehicleDefaultCapacity(artic_engine); IsValidCargoID(cargo) && cap > 0) {
186 SetBit(cargoes, cargo);
187 }
188 }
189
190 return cargoes;
191}
192
199{
200 if (IsEngineRefittable(engine)) return true;
201
202 const Engine *e = Engine::Get(engine);
203 if (!e->IsGroundVehicle()) return false;
204
205 if (!HasBit(e->info.callback_mask, CBM_VEHICLE_ARTIC_ENGINE)) return false;
206
207 for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) {
208 EngineID artic_engine = GetNextArticulatedPart(i, engine);
209 if (artic_engine == INVALID_ENGINE) break;
210
211 if (IsEngineRefittable(artic_engine)) return true;
212 }
213
214 return false;
215}
216
224void GetArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type, CargoTypes *union_mask, CargoTypes *intersection_mask)
225{
226 const Engine *e = Engine::Get(engine);
227 CargoTypes veh_cargoes = GetAvailableVehicleCargoTypes(engine, include_initial_cargo_type);
228 *union_mask = veh_cargoes;
229 *intersection_mask = (veh_cargoes != 0) ? veh_cargoes : ALL_CARGOTYPES;
230
231 if (!e->IsGroundVehicle()) return;
232 if (!HasBit(e->info.callback_mask, CBM_VEHICLE_ARTIC_ENGINE)) return;
233
234 for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) {
235 EngineID artic_engine = GetNextArticulatedPart(i, engine);
236 if (artic_engine == INVALID_ENGINE) break;
237
238 veh_cargoes = GetAvailableVehicleCargoTypes(artic_engine, include_initial_cargo_type);
239 *union_mask |= veh_cargoes;
240 if (veh_cargoes != 0) *intersection_mask &= veh_cargoes;
241 }
242}
243
250CargoTypes GetUnionOfArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type)
251{
252 CargoTypes union_mask, intersection_mask;
253 GetArticulatedRefitMasks(engine, include_initial_cargo_type, &union_mask, &intersection_mask);
254 return union_mask;
255}
256
264CargoTypes GetCargoTypesOfArticulatedVehicle(const Vehicle *v, CargoID *cargo_type)
265{
266 CargoTypes cargoes = 0;
267 CargoID first_cargo = INVALID_CARGO;
268
269 do {
271 SetBit(cargoes, v->cargo_type);
272 if (!IsValidCargoID(first_cargo)) first_cargo = v->cargo_type;
273 if (first_cargo != v->cargo_type) {
274 if (cargo_type != nullptr) {
275 *cargo_type = INVALID_CARGO;
276 cargo_type = nullptr;
277 }
278 }
279 }
280
281 v = v->HasArticulatedPart() ? v->GetNextArticulatedPart() : nullptr;
282 } while (v != nullptr);
283
284 if (cargo_type != nullptr) *cargo_type = first_cargo;
285 return cargoes;
286}
287
297{
298 const Engine *engine = v->GetEngine();
299
300 CargoTypes purchase_refit_union, purchase_refit_intersection;
301 GetArticulatedRefitMasks(v->engine_type, true, &purchase_refit_union, &purchase_refit_intersection);
302 CargoArray purchase_default_capacity = GetCapacityOfArticulatedParts(v->engine_type);
303
304 CargoTypes real_refit_union = 0;
305 CargoTypes real_refit_intersection = ALL_CARGOTYPES;
306 CargoTypes real_default_cargoes = 0;
307
308 do {
309 CargoTypes refit_mask = GetAvailableVehicleCargoTypes(v->engine_type, true);
310 real_refit_union |= refit_mask;
311 if (refit_mask != 0) real_refit_intersection &= refit_mask;
312
313 assert(v->cargo_type < NUM_CARGO);
314 if (v->cargo_cap > 0) SetBit(real_default_cargoes, v->cargo_type);
315
316 v = v->HasArticulatedPart() ? v->GetNextArticulatedPart() : nullptr;
317 } while (v != nullptr);
318
319 /* Check whether the vehicle carries more cargoes than expected */
320 bool carries_more = false;
321 for (CargoID cid : SetCargoBitIterator(real_default_cargoes)) {
322 if (purchase_default_capacity[cid] == 0) {
323 carries_more = true;
324 break;
325 }
326 }
327
328 /* show a warning once for each GRF after each game load */
329 if (real_refit_union != purchase_refit_union || real_refit_intersection != purchase_refit_intersection || carries_more) {
330 ShowNewGrfVehicleError(engine->index, STR_NEWGRF_BUGGY, STR_NEWGRF_BUGGY_ARTICULATED_CARGO, GBUG_VEH_REFIT, false);
331 }
332}
333
339{
340 VehicleType type = first->type;
341 if (!HasBit(EngInfo(first->engine_type)->callback_mask, CBM_VEHICLE_ARTIC_ENGINE)) return;
342
343 Vehicle *v = first;
344 for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) {
345 bool flip_image;
346 EngineID engine_type = GetNextArticulatedPart(i, first->engine_type, first, &flip_image);
347 if (engine_type == INVALID_ENGINE) return;
348
349 /* In the (very rare) case the GRF reported wrong number of articulated parts
350 * and we run out of available vehicles, bail out. */
351 if (!Vehicle::CanAllocateItem()) return;
352
354 gcache->first_engine = v->engine_type; // Needs to be set before first callback
355
356 const Engine *e_artic = Engine::Get(engine_type);
357 switch (type) {
358 default: NOT_REACHED();
359
360 case VEH_TRAIN: {
361 Train *front = Train::From(first);
362 Train *t = new Train();
363 v->SetNext(t);
364 v = t;
365
366 t->subtype = 0;
367 t->track = front->track;
368 t->railtype = front->railtype;
369
370 t->spritenum = e_artic->u.rail.image_index;
371 if (e_artic->CanCarryCargo()) {
372 t->cargo_type = e_artic->GetDefaultCargoType();
373 t->cargo_cap = e_artic->u.rail.capacity; // Callback 36 is called when the consist is finished
374 } else {
375 t->cargo_type = front->cargo_type; // Needed for livery selection
376 t->cargo_cap = 0;
377 }
378 t->refit_cap = 0;
379
381 break;
382 }
383
384 case VEH_ROAD: {
385 RoadVehicle *front = RoadVehicle::From(first);
386 RoadVehicle *rv = new RoadVehicle();
387 v->SetNext(rv);
388 v = rv;
389
390 rv->subtype = 0;
391 gcache->cached_veh_length = VEHICLE_LENGTH; // Callback is called when the consist is finished
392 rv->state = RVSB_IN_DEPOT;
393
394 rv->roadtype = front->roadtype;
396
397 rv->spritenum = e_artic->u.road.image_index;
398 if (e_artic->CanCarryCargo()) {
399 rv->cargo_type = e_artic->GetDefaultCargoType();
400 assert(IsValidCargoID(rv->cargo_type));
401 rv->cargo_cap = e_artic->u.road.capacity; // Callback 36 is called when the consist is finished
402 } else {
403 rv->cargo_type = front->cargo_type; // Needed for livery selection
404 rv->cargo_cap = 0;
405 }
406 rv->refit_cap = 0;
407
408 rv->SetArticulatedPart();
409 break;
410 }
411 }
412
413 /* get common values from first engine */
414 v->direction = first->direction;
415 v->owner = first->owner;
416 v->tile = first->tile;
417 v->x_pos = first->x_pos;
418 v->y_pos = first->y_pos;
419 v->z_pos = first->z_pos;
422 v->build_year = first->build_year;
423 v->vehstatus = first->vehstatus & ~VS_STOPPED;
424
425 v->cargo_subtype = 0;
426 v->max_age = 0;
427 v->engine_type = engine_type;
428 v->value = 0;
429 v->sprite_cache.sprite_seq.Set(SPR_IMG_QUERY);
430 v->random_bits = Random();
431
432 if (flip_image) v->spritenum++;
433
434 if (v->type == VEH_TRAIN && TestVehicleBuildProbability(v, v->engine_type, BuildProbabilityType::Reversed)) SetBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION);
435 v->UpdatePosition();
436 }
437}
CargoTypes GetUnionOfArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type)
Ors the refit_masks of all articulated parts.
CargoTypes GetCargoTypesOfArticulatedVehicle(const Vehicle *v, CargoID *cargo_type)
Get cargo mask of all cargoes carried by an articulated vehicle.
bool IsArticulatedEngine(EngineID engine_type)
Does a NewGRF report that this should be an articulated vehicle?
static const uint MAX_ARTICULATED_PARTS
Maximum of articulated parts per vehicle, i.e. when to abort calling the articulated vehicle callback...
void AddArticulatedParts(Vehicle *first)
Add the remaining articulated parts to the given vehicle.
CargoArray GetCapacityOfArticulatedParts(EngineID engine)
Get the capacity of the parts of a given engine.
bool IsArticulatedVehicleRefittable(EngineID engine)
Checks whether any of the articulated parts is refittable.
void GetArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type, CargoTypes *union_mask, CargoTypes *intersection_mask)
Merges the refit_masks of all articulated parts.
static std::pair< CargoID, uint16_t > GetVehicleDefaultCapacity(EngineID engine)
Returns the default (non-refitted) cargo and capacity of a specific EngineID.
void CheckConsistencyOfArticulatedVehicle(const Vehicle *v)
Checks whether the specs of freshly build articulated vehicles are consistent with the information sp...
CargoTypes GetCargoTypesOfArticulatedParts(EngineID engine)
Get the cargo mask of the parts of a given engine.
static EngineID GetNextArticulatedPart(uint index, EngineID front_type, Vehicle *front=nullptr, bool *mirrored=nullptr)
Determines the next articulated part to attach.
uint CountArticulatedParts(EngineID engine_type, bool purchase_window)
Count the number of articulated parts of an engine.
static CargoTypes GetAvailableVehicleCargoTypes(EngineID engine, bool include_initial_cargo_type)
Returns all cargoes a vehicle can carry.
Functions related to bit mathematics.
debug_inline constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
debug_inline static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
uint8_t CargoID
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:22
bool IsValidCargoID(CargoID t)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:107
static const CargoID NUM_CARGO
Maximum number of cargo types in a game.
Definition cargo_type.h:74
CompanyID _current_company
Company currently doing an action.
Functions related to companies.
bool IsEngineRefittable(EngineID engine)
Check if an engine is refittable.
Definition engine.cpp:1295
Functions related to engines.
static const EngineID INVALID_ENGINE
Constant denoting an invalid engine.
uint16_t EngineID
Unique identification number of an engine.
Definition engine_type.h:21
EngineID GetNewEngineID(const GRFFile *file, VehicleType type, uint16_t internal_id)
Return the ID of a new engine.
Definition newgrf.cpp:711
Base for the NewGRF implementation.
@ CBID_VEHICLE_ARTIC_ENGINE
Builds articulated engines for trains and RVs.
@ CBM_VEHICLE_ARTIC_ENGINE
Add articulated engines (trains and road vehicles)
static const uint CALLBACK_FAILED
Different values for Callback result evaluations.
@ GBUG_VEH_REFIT
Articulated vehicles carry different cargoes resp. are differently refittable than specified in purch...
bool TestVehicleBuildProbability(Vehicle *v, EngineID engine, BuildProbabilityType type)
Test for vehicle build probablity type.
uint16_t GetVehicleCallback(CallbackID callback, uint32_t param1, uint32_t param2, EngineID engine, const Vehicle *v)
Evaluate a newgrf callback for vehicles.
Pseudo random number generator.
Road vehicle states.
@ RVSB_IN_DEPOT
The vehicle is in a depot.
Definition roadveh.h:38
A number of safeguards to prevent using unsafe methods.
Definition of base types and functions in a cross-platform compatible way.
VehicleType type
Type of vehicle.
Class for storing amounts of cargo.
Definition cargo_type.h:114
uint16_t callback_mask
Bitmask of vehicle callbacks that have to be called.
CargoID GetDefaultCargoType() const
Determines the default cargo type of an engine.
const GRFFile * GetGRF() const
Retrieve the NewGRF the engine is tied to.
VehicleType type
Vehicle type, ie VEH_ROAD, VEH_TRAIN, etc.
Definition engine_base.h:60
uint GetDisplayDefaultCapacity(uint16_t *mail_capacity=nullptr) const
Determines the default cargo capacity of an engine for display purposes.
bool CanCarryCargo() const
Determines whether an engine can carry something.
Definition engine.cpp:168
bool IsGroundVehicle() const
Check if the engine is a ground vehicle.
Cached, frequently calculated values.
EngineID first_engine
Cached EngineID of the front vehicle. INVALID_ENGINE for the front vehicle itself.
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...
void SetArticulatedPart()
Set a vehicle to be an articulated part.
VehicleSpriteSeq sprite_seq
Vehicle appearance.
Tindex index
Index of this pool item.
static bool CanAllocateItem(size_t n=1)
Helper functions so we can use PoolItem::Function() instead of _poolitem_pool.Function()
static Titem * Get(size_t index)
Returns Titem with given index.
uint8_t capacity
Cargo capacity of vehicle; For multiheaded engines the capacity of each single engine.
Definition engine_type.h:55
Buses, trucks and trams belong to this class.
Definition roadveh.h:98
uint8_t state
Definition roadveh.h:100
RoadTypes compatible_roadtypes
NOSAVE: Roadtypes this consist is powered on.
Definition roadveh.h:110
RoadType roadtype
NOSAVE: Roadtype of this vehicle.
Definition roadveh.h:108
Iterable ensemble of each set bit in a value.
static T * From(Vehicle *v)
Converts a Vehicle to SpecializedVehicle with type checking.
'Train' is either a loco or a wagon.
Definition train.h:89
void Set(SpriteID sprite)
Assign a single sprite to the sequence.
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:747
Vehicle * GetNextArticulatedPart() const
Get the next part of an articulated engine.
TimerGameEconomy::Date date_of_last_service
Last economy date the vehicle had a service at a depot.
uint16_t cargo_cap
total capacity
uint8_t subtype
subtype (Filled with values from AircraftSubType/DisasterSubType/EffectVehicleType/GroundVehicleSubty...
uint16_t random_bits
Bits used for randomized variational spritegroups.
bool HasArticulatedPart() const
Check if an engine has an articulated part.
TimerGameCalendar::Date date_of_last_service_newgrf
Last calendar date the vehicle had a service at a depot, unchanged by the date cheat to protect again...
CargoID cargo_type
type of cargo this vehicle is carrying
int32_t y_pos
y coordinate.
int32_t x_pos
x coordinate.
Money value
Value of the vehicle.
uint16_t refit_cap
Capacity left over from before last refit.
uint8_t vehstatus
Status.
GroundVehicleCache * GetGroundVehicleCache()
Access the ground vehicle cache of the vehicle.
Definition vehicle.cpp:3155
uint8_t spritenum
currently displayed sprite index 0xfd == custom sprite, 0xfe == custom second head sprite 0xff == res...
uint8_t cargo_subtype
Used for livery refits (NewGRF variations)
void SetNext(Vehicle *next)
Set the next vehicle of this vehicle.
Definition vehicle.cpp:2937
TimerGameCalendar::Date max_age
Maximum age.
MutableSpriteCache sprite_cache
Cache of sprites and values related to recalculating them, see MutableSpriteCache.
TileIndex tile
Current tile index.
void UpdatePosition()
Update the position of the vehicle.
Definition vehicle.cpp:1693
TimerGameCalendar::Year build_year
Year the vehicle has been built.
Owner owner
Which company owns the vehicle?
Base for the train class.
@ VRF_REVERSE_DIRECTION
Reverse the visible direction of the vehicle.
Definition train.h:28
void ShowNewGrfVehicleError(EngineID engine, StringID part1, StringID part2, GRFBugs bug_type, bool critical)
Displays a "NewGrf Bug" error message for a engine, and pauses the game if not networking.
Definition vehicle.cpp:317
Functions related to vehicles.
VehicleType
Available vehicle types.
@ VEH_ROAD
Road vehicle type.
@ VEH_TRAIN
Train vehicle type.
static const uint VEHICLE_LENGTH
The length of a vehicle in tile units.