OpenTTD Source 20260107-master-g88a467db19
engine.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
10#include "stdafx.h"
12#include "company_func.h"
13#include "command_func.h"
14#include "news_func.h"
15#include "aircraft.h"
16#include "newgrf.h"
17#include "newgrf_engine.h"
18#include "strings_func.h"
19#include "core/random_func.hpp"
20#include "window_func.h"
21#include "autoreplace_gui.h"
22#include "string_func.h"
23#include "ai/ai.hpp"
24#include "core/pool_func.hpp"
25#include "engine_gui.h"
26#include "engine_func.h"
27#include "engine_base.h"
28#include "company_base.h"
29#include "vehicle_func.h"
31#include "error.h"
32#include "engine_base.h"
33#include "timer/timer.h"
36
37#include "table/strings.h"
38#include "table/engines.h"
39
40#include "safeguards.h"
41
42EnginePool _engine_pool("Engine");
44
45EngineOverrideManager _engine_mngr;
46
52
54const uint8_t _engine_counts[4] = {
55 lengthof(_orig_rail_vehicle_info),
56 lengthof(_orig_road_vehicle_info),
57 lengthof(_orig_ship_vehicle_info),
58 lengthof(_orig_aircraft_vehicle_info),
59};
60
62const uint8_t _engine_offsets[4] = {
63 0,
64 lengthof(_orig_rail_vehicle_info),
65 lengthof(_orig_rail_vehicle_info) + lengthof(_orig_road_vehicle_info),
66 lengthof(_orig_rail_vehicle_info) + lengthof(_orig_road_vehicle_info) + lengthof(_orig_ship_vehicle_info),
67};
68
69static_assert(lengthof(_orig_rail_vehicle_info) + lengthof(_orig_road_vehicle_info) + lengthof(_orig_ship_vehicle_info) + lengthof(_orig_aircraft_vehicle_info) == lengthof(_orig_engine_info));
70
71Engine::Engine(EngineID index, VehicleType type, uint16_t local_id) : EnginePool::PoolItem<&_engine_pool>(index)
72{
73 this->type = type;
74
75 /* Called in the context of loading a savegame. The rest comes from the loader. */
76 if (type == VEH_INVALID) return;
77
78 this->grf_prop.local_id = local_id;
79 this->list_position = local_id;
80 this->preview_company = CompanyID::Invalid();
81 this->display_last_variant = EngineID::Invalid();
82
83 /* Check if this base engine is within the original engine data range */
84 if (local_id >= _engine_counts[type]) {
85 /* Initialise default type-specific information. */
86 switch (type) {
87 case VEH_TRAIN: this->vehicle_info.emplace<RailVehicleInfo>(); break;
88 case VEH_ROAD: this->vehicle_info.emplace<RoadVehicleInfo>(); break;
89 case VEH_SHIP: this->vehicle_info.emplace<ShipVehicleInfo>(); break;
90 case VEH_AIRCRAFT: this->vehicle_info.emplace<AircraftVehicleInfo>(); break;
91 default: break;
92 }
93 /* Set model life to maximum to make wagons available */
94 this->info.base_life = TimerGameCalendar::Year{0xFF};
95 /* Aircraft must have CT_INVALID as default, as there is no property */
96 this->info.cargo_type = INVALID_CARGO;
97 this->info.cargo_label = (type == VEH_AIRCRAFT) ? CT_INVALID : CT_PASSENGERS;
98 /* Set cargo aging period to the default value. */
99 this->info.cargo_age_period = Ticks::CARGO_AGING_TICKS;
100 /* Not a variant */
101 this->info.variant_id = EngineID::Invalid();
102 return;
103 }
104
105 /* Copy the original engine info for this slot */
106 this->info = _orig_engine_info[_engine_offsets[type] + local_id];
107
108 /* Copy the original engine data for this slot */
109 switch (type) {
110 default: NOT_REACHED();
111
112 case VEH_TRAIN: {
113 RailVehicleInfo &rvi = this->vehicle_info.emplace<RailVehicleInfo>(_orig_rail_vehicle_info[local_id]);
114 this->original_image_index = rvi.image_index;
115 this->info.string_id = STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_KIRBY_PAUL_TANK_STEAM + local_id;
116
117 /* Set the default model life of original wagons to "infinite" */
118 if (rvi.railveh_type == RAILVEH_WAGON) this->info.base_life = TimerGameCalendar::Year{0xFF};
119
120 break;
121 }
122
123 case VEH_ROAD: {
124 RoadVehicleInfo &rvi = this->vehicle_info.emplace<RoadVehicleInfo>(_orig_road_vehicle_info[local_id]);
125 this->original_image_index = rvi.image_index;
126 this->info.string_id = STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_REGAL_BUS + local_id;
127 break;
128 }
129
130 case VEH_SHIP: {
131 ShipVehicleInfo &svi = this->vehicle_info.emplace<ShipVehicleInfo>(_orig_ship_vehicle_info[local_id]);
132 this->original_image_index = svi.image_index;
133 this->info.string_id = STR_VEHICLE_NAME_SHIP_MPS_OIL_TANKER + local_id;
134 break;
135 }
136
137 case VEH_AIRCRAFT: {
138 AircraftVehicleInfo &avi = this->vehicle_info.emplace<AircraftVehicleInfo>(_orig_aircraft_vehicle_info[local_id]);
139 this->original_image_index = avi.image_index;
140 this->info.string_id = STR_VEHICLE_NAME_AIRCRAFT_SAMPSON_U52 + local_id;
141 break;
142 }
143 }
144}
145
151{
152 return this->info.string_id != STR_NEWGRF_INVALID_ENGINE && this->info.climates.Test(_settings_game.game_creation.landscape);
153}
154
160uint32_t Engine::GetGRFID() const
161{
162 const GRFFile *file = this->GetGRF();
163 return file == nullptr ? 0 : file->grfid;
164}
165
172{
173 /* For engines that can appear in a consist (i.e. rail vehicles and (articulated) road vehicles), a capacity
174 * of zero is a special case, to define the vehicle to not carry anything. The default cargotype is still used
175 * for livery selection etc.
176 * Note: Only the property is tested. A capacity callback returning 0 does not have the same effect.
177 */
178 switch (this->type) {
179 case VEH_TRAIN:
180 if (this->VehInfo<RailVehicleInfo>().capacity == 0) return false;
181 break;
182
183 case VEH_ROAD:
184 if (this->VehInfo<RoadVehicleInfo>().capacity == 0) return false;
185 break;
186
187 case VEH_SHIP:
188 case VEH_AIRCRAFT:
189 break;
190
191 default: NOT_REACHED();
192 }
194}
195
196
204uint Engine::DetermineCapacity(const Vehicle *v, uint16_t *mail_capacity) const
205{
206 assert(v == nullptr || this->index == v->engine_type);
207 if (mail_capacity != nullptr) *mail_capacity = 0;
208
209 if (!this->CanCarryCargo()) return 0;
210
211 bool new_multipliers = this->info.misc_flags.Test(EngineMiscFlag::NoDefaultCargoMultiplier);
212 CargoType default_cargo = this->GetDefaultCargoType();
213 CargoType cargo_type = (v != nullptr) ? v->cargo_type : default_cargo;
214
215 if (mail_capacity != nullptr && this->type == VEH_AIRCRAFT && IsCargoInClass(cargo_type, CargoClass::Passengers)) {
216 *mail_capacity = GetEngineProperty(this->index, PROP_AIRCRAFT_MAIL_CAPACITY, this->VehInfo<AircraftVehicleInfo>().mail_capacity, v);
217 }
218
219 /* Check the refit capacity callback if we are not in the default configuration, or if we are using the new multiplier algorithm. */
221 (new_multipliers || default_cargo != cargo_type || (v != nullptr && v->cargo_subtype != 0))) {
222 uint16_t callback = GetVehicleCallback(CBID_VEHICLE_REFIT_CAPACITY, 0, 0, this->index, v);
223 if (callback != CALLBACK_FAILED) return callback;
224 }
225
226 /* Get capacity according to property resp. CB */
227 uint capacity;
228 uint extra_mail_cap = 0;
229 switch (this->type) {
230 case VEH_TRAIN:
231 capacity = GetEngineProperty(this->index, PROP_TRAIN_CARGO_CAPACITY, this->VehInfo<RailVehicleInfo>().capacity, v);
232
233 /* In purchase list add the capacity of the second head. Always use the plain property for this. */
234 if (v == nullptr && this->VehInfo<RailVehicleInfo>().railveh_type == RAILVEH_MULTIHEAD) capacity += this->VehInfo<RailVehicleInfo>().capacity;
235 break;
236
237 case VEH_ROAD:
238 capacity = GetEngineProperty(this->index, PROP_ROADVEH_CARGO_CAPACITY, this->VehInfo<RoadVehicleInfo>().capacity, v);
239 break;
240
241 case VEH_SHIP:
242 capacity = GetEngineProperty(this->index, PROP_SHIP_CARGO_CAPACITY, this->VehInfo<ShipVehicleInfo>().capacity, v);
243 break;
244
245 case VEH_AIRCRAFT:
246 capacity = GetEngineProperty(this->index, PROP_AIRCRAFT_PASSENGER_CAPACITY, this->VehInfo<AircraftVehicleInfo>().passenger_capacity, v);
247 if (!IsCargoInClass(cargo_type, CargoClass::Passengers)) {
248 extra_mail_cap = GetEngineProperty(this->index, PROP_AIRCRAFT_MAIL_CAPACITY, this->VehInfo<AircraftVehicleInfo>().mail_capacity, v);
249 }
250 if (IsValidCargoType(GetCargoTypeByLabel(CT_MAIL))) {
251 if (!new_multipliers && cargo_type == GetCargoTypeByLabel(CT_MAIL)) return capacity + extra_mail_cap;
252 }
253 default_cargo = GetCargoTypeByLabel(CT_PASSENGERS); // Always use 'passengers' wrt. cargo multipliers
254 break;
255
256 default: NOT_REACHED();
257 }
258
259 if (!new_multipliers) {
260 /* Use the passenger multiplier for mail as well */
261 capacity += extra_mail_cap;
262 extra_mail_cap = 0;
263 }
264
265 /* Apply multipliers depending on cargo- and vehicletype. */
266 if (new_multipliers || (this->type != VEH_SHIP && default_cargo != cargo_type)) {
267 uint16_t default_multiplier = new_multipliers ? 0x100 : CargoSpec::Get(default_cargo)->multiplier;
268 uint16_t cargo_multiplier = CargoSpec::Get(cargo_type)->multiplier;
269 capacity *= cargo_multiplier;
270 if (extra_mail_cap > 0 && IsValidCargoType(GetCargoTypeByLabel(CT_MAIL))) {
271 uint mail_multiplier = CargoSpec::Get(GetCargoTypeByLabel(CT_MAIL))->multiplier;
272 capacity += (default_multiplier * extra_mail_cap * cargo_multiplier + mail_multiplier / 2) / mail_multiplier;
273 }
274 capacity = (capacity + default_multiplier / 2) / default_multiplier;
275 }
276
277 return capacity;
278}
279
285{
286 Price base_price;
287 uint cost_factor;
288 switch (this->type) {
289 case VEH_ROAD:
290 base_price = this->VehInfo<RoadVehicleInfo>().running_cost_class;
291 if (base_price == INVALID_PRICE) return 0;
292 cost_factor = GetEngineProperty(this->index, PROP_ROADVEH_RUNNING_COST_FACTOR, this->VehInfo<RoadVehicleInfo>().running_cost);
293 break;
294
295 case VEH_TRAIN:
296 base_price = this->VehInfo<RailVehicleInfo>().running_cost_class;
297 if (base_price == INVALID_PRICE) return 0;
298 cost_factor = GetEngineProperty(this->index, PROP_TRAIN_RUNNING_COST_FACTOR, this->VehInfo<RailVehicleInfo>().running_cost);
299 break;
300
301 case VEH_SHIP:
302 base_price = PR_RUNNING_SHIP;
303 cost_factor = GetEngineProperty(this->index, PROP_SHIP_RUNNING_COST_FACTOR, this->VehInfo<ShipVehicleInfo>().running_cost);
304 break;
305
306 case VEH_AIRCRAFT:
307 base_price = PR_RUNNING_AIRCRAFT;
308 cost_factor = GetEngineProperty(this->index, PROP_AIRCRAFT_RUNNING_COST_FACTOR, this->VehInfo<AircraftVehicleInfo>().running_cost);
309 break;
310
311 default: NOT_REACHED();
312 }
313
314 return GetPrice(base_price, cost_factor, this->GetGRF(), -8);
315}
316
322{
323 Price base_price;
324 uint cost_factor;
325 switch (this->type) {
326 case VEH_ROAD:
327 base_price = PR_BUILD_VEHICLE_ROAD;
328 cost_factor = GetEngineProperty(this->index, PROP_ROADVEH_COST_FACTOR, this->VehInfo<RoadVehicleInfo>().cost_factor);
329 break;
330
331 case VEH_TRAIN:
332 if (this->VehInfo<RailVehicleInfo>().railveh_type == RAILVEH_WAGON) {
333 base_price = PR_BUILD_VEHICLE_WAGON;
334 cost_factor = GetEngineProperty(this->index, PROP_TRAIN_COST_FACTOR, this->VehInfo<RailVehicleInfo>().cost_factor);
335 } else {
336 base_price = PR_BUILD_VEHICLE_TRAIN;
337 cost_factor = GetEngineProperty(this->index, PROP_TRAIN_COST_FACTOR, this->VehInfo<RailVehicleInfo>().cost_factor);
338 }
339 break;
340
341 case VEH_SHIP:
342 base_price = PR_BUILD_VEHICLE_SHIP;
343 cost_factor = GetEngineProperty(this->index, PROP_SHIP_COST_FACTOR, this->VehInfo<ShipVehicleInfo>().cost_factor);
344 break;
345
346 case VEH_AIRCRAFT:
347 base_price = PR_BUILD_VEHICLE_AIRCRAFT;
348 cost_factor = GetEngineProperty(this->index, PROP_AIRCRAFT_COST_FACTOR, this->VehInfo<AircraftVehicleInfo>().cost_factor);
349 break;
350
351 default: NOT_REACHED();
352 }
353
354 return GetPrice(base_price, cost_factor, this->GetGRF(), -8);
355}
356
362{
363 switch (this->type) {
364 case VEH_TRAIN:
365 return GetEngineProperty(this->index, PROP_TRAIN_SPEED, this->VehInfo<RailVehicleInfo>().max_speed);
366
367 case VEH_ROAD: {
368 uint max_speed = GetEngineProperty(this->index, PROP_ROADVEH_SPEED, 0);
369 return (max_speed != 0) ? max_speed * 2 : this->VehInfo<RoadVehicleInfo>().max_speed / 2;
370 }
371
372 case VEH_SHIP:
373 return GetEngineProperty(this->index, PROP_SHIP_SPEED, this->VehInfo<ShipVehicleInfo>().max_speed) / 2;
374
375 case VEH_AIRCRAFT: {
376 uint max_speed = GetEngineProperty(this->index, PROP_AIRCRAFT_SPEED, 0);
377 if (max_speed != 0) {
378 return (max_speed * 128) / 10;
379 }
380 return this->VehInfo<AircraftVehicleInfo>().max_speed;
381 }
382
383 default: NOT_REACHED();
384 }
385}
386
394{
395 /* Only trains and road vehicles have 'power'. */
396 switch (this->type) {
397 case VEH_TRAIN:
398 return GetEngineProperty(this->index, PROP_TRAIN_POWER, this->VehInfo<RailVehicleInfo>().power);
399 case VEH_ROAD:
400 return GetEngineProperty(this->index, PROP_ROADVEH_POWER, this->VehInfo<RoadVehicleInfo>().power) * 10;
401
402 default: NOT_REACHED();
403 }
404}
405
412{
413 /* Only trains and road vehicles have 'weight'. */
414 switch (this->type) {
415 case VEH_TRAIN:
416 return GetEngineProperty(this->index, PROP_TRAIN_WEIGHT, this->VehInfo<RailVehicleInfo>().weight) << (this->VehInfo<RailVehicleInfo>().railveh_type == RAILVEH_MULTIHEAD ? 1 : 0);
417 case VEH_ROAD:
418 return GetEngineProperty(this->index, PROP_ROADVEH_WEIGHT, this->VehInfo<RoadVehicleInfo>().weight) / 4;
419
420 default: NOT_REACHED();
421 }
422}
423
430{
431 /* Only trains and road vehicles have 'tractive effort'. */
432 switch (this->type) {
433 case VEH_TRAIN:
434 return (GROUND_ACCELERATION * this->GetDisplayWeight() * GetEngineProperty(this->index, PROP_TRAIN_TRACTIVE_EFFORT, this->VehInfo<RailVehicleInfo>().tractive_effort)) / 256;
435 case VEH_ROAD:
436 return (GROUND_ACCELERATION * this->GetDisplayWeight() * GetEngineProperty(this->index, PROP_ROADVEH_TRACTIVE_EFFORT, this->VehInfo<RoadVehicleInfo>().tractive_effort)) / 256;
437
438 default: NOT_REACHED();
439 }
440}
441
447{
448 /* Assume leap years; this gives the player a bit more than the given amount of years, but never less. */
450}
451
456uint16_t Engine::GetRange() const
457{
458 switch (this->type) {
459 case VEH_AIRCRAFT:
460 return GetEngineProperty(this->index, PROP_AIRCRAFT_RANGE, this->VehInfo<AircraftVehicleInfo>().max_range);
461
462 default: NOT_REACHED();
463 }
464}
465
471{
472 switch (this->type) {
473 case VEH_AIRCRAFT:
474 switch (this->VehInfo<AircraftVehicleInfo>().subtype) {
475 case AIR_HELI: return STR_LIVERY_HELICOPTER;
476 case AIR_CTOL: return STR_LIVERY_SMALL_PLANE;
477 case AIR_CTOL | AIR_FAST: return STR_LIVERY_LARGE_PLANE;
478 default: NOT_REACHED();
479 }
480
481 default: NOT_REACHED();
482 }
483}
484
491{
492 /* In case company is spectator. */
493 if (c >= MAX_COMPANIES) return false;
494
495 /* Shortcut if this engine is explicitly hidden. */
496 if (this->IsHidden(c)) return true;
497
498 /* Check for hidden parent variants. This is a bit convoluted as we must check hidden status of
499 * the last display variant rather than the actual parent variant. */
500 const Engine *re = this;
501 const Engine *ve = re->GetDisplayVariant();
502 while (!(ve->IsHidden(c)) && re->info.variant_id != EngineID::Invalid()) {
503 re = Engine::Get(re->info.variant_id);
504 ve = re->GetDisplayVariant();
505 }
506 return ve->IsHidden(c);
507}
508
513{
514 EngineID id = EngineID::Begin();
515 for (VehicleType type = VEH_TRAIN; type <= VEH_AIRCRAFT; type++) {
516 auto &map = this->mappings[type];
517 map.clear();
518 for (uint internal_id = 0; internal_id < _engine_counts[type]; internal_id++, ++id) {
519 map.emplace_back(INVALID_GRFID, internal_id, type, internal_id, id);
520 }
521 }
522}
523
533EngineID EngineOverrideManager::GetID(VehicleType type, uint16_t grf_local_id, uint32_t grfid)
534{
535 const auto &map = this->mappings[type];
536 const auto key = EngineIDMapping::Key(grfid, grf_local_id);
537 auto it = std::ranges::lower_bound(map, key, std::less{}, EngineIDMappingKeyProjection{});
538 if (it == std::end(map) || it->Key() != key) return EngineID::Invalid();
539 return it->engine;
540}
541
552EngineID EngineOverrideManager::UseUnreservedID(VehicleType type, uint16_t grf_local_id, uint32_t grfid, bool static_access)
553{
554 auto &map = _engine_mngr.mappings[type];
555 const auto key = EngineIDMapping::Key(INVALID_GRFID, grf_local_id);
556 auto it = std::ranges::lower_bound(map, key, std::less{}, EngineIDMappingKeyProjection{});
557 if (it == std::end(map) || it->Key() != key) return EngineID::Invalid();
558
559 if (!static_access && grfid != INVALID_GRFID) {
560 /* Reserve the engine slot for the new grfid. */
561 it->grfid = grfid;
562
563 /* Relocate entry to its new position in the mapping list to keep it sorted. */
564 auto p = std::ranges::lower_bound(map, EngineIDMapping::Key(grfid, grf_local_id), std::less{}, EngineIDMappingKeyProjection{});
565 it = Slide(it, std::next(it), p).first;
566 }
567
568 return it->engine;
569}
570
571void EngineOverrideManager::SetID(VehicleType type, uint16_t grf_local_id, uint32_t grfid, uint8_t substitute_id, EngineID engine)
572{
573 auto &map = this->mappings[type];
574 const auto key = EngineIDMapping::Key(grfid, grf_local_id);
575 auto it = std::ranges::lower_bound(map, key, std::less{}, EngineIDMappingKeyProjection{});
576 if (it == std::end(map) || it->Key() != key) {
577 map.emplace(it, grfid, grf_local_id, type, substitute_id, engine);
578 } else {
579 it->engine = engine;
580 }
581}
582
589{
590 for (const Vehicle *v : Vehicle::Iterate()) {
591 if (IsCompanyBuildableVehicleType(v)) return false;
592 }
593
594 /* Reset the engines, they will get new EngineIDs */
595 _engine_mngr.ResetToDefaultMapping();
597
598 return true;
599}
600
605{
607 _engine_pool.CleanPool();
608
609 for (VehicleType type = VEH_BEGIN; type != VEH_COMPANY_END; type++) {
610 const auto &mapping = _engine_mngr.mappings[type];
611
612 /* Verify that the engine override manager has at least been set up with the default engines. */
613 assert(std::size(mapping) >= _engine_counts[type]);
614
615 for (const EngineIDMapping &eid : mapping) {
616 Engine::CreateAtIndex(eid.engine, type, eid.internal_id);
617 }
618 }
619}
620
621void ShowEnginePreviewWindow(EngineID engine);
622
628static bool IsWagon(EngineID index)
629{
630 const Engine *e = Engine::Get(index);
631 return e->type == VEH_TRAIN && e->VehInfo<RailVehicleInfo>().railveh_type == RAILVEH_WAGON;
632}
633
639static void ClearLastVariant(EngineID engine_id, VehicleType type)
640{
641 for (Engine *e : Engine::IterateType(type)) {
642 if (e->display_last_variant == engine_id) e->display_last_variant = EngineID::Invalid();
643 }
644}
645
650void CalcEngineReliability(Engine *e, bool new_month)
651{
652 /* Get source engine for reliability age. This is normally our engine unless variant reliability syncing is requested. */
653 Engine *re = e;
654 while (re->info.variant_id != EngineID::Invalid() && re->info.extra_flags.Test(ExtraEngineFlag::SyncReliability)) {
655 re = Engine::Get(re->info.variant_id);
656 }
657
658 uint32_t age = re->age;
659 if (new_month && re->index > e->index && age != INT32_MAX) age++; /* parent variant's age has not yet updated. */
660
661 /* Check for early retirement */
662 if (e->company_avail.Any() && !_settings_game.vehicle.never_expire_vehicles && e->info.base_life != 0xFF) {
663 int retire_early = e->info.retire_early;
664 uint retire_early_max_age = std::max(0, e->duration_phase_1 + e->duration_phase_2 - retire_early * 12);
665 if (retire_early != 0 && age >= retire_early_max_age) {
666 /* Early retirement is enabled and we're past the date... */
670 }
671 }
672
673 if (age < e->duration_phase_1) {
674 uint start = e->reliability_start;
675 e->reliability = age * (e->reliability_max - start) / e->duration_phase_1 + start;
676 } else if ((age -= e->duration_phase_1) < e->duration_phase_2 || _settings_game.vehicle.never_expire_vehicles || e->info.base_life == 0xFF) {
677 /* We are at the peak of this engines life. It will have max reliability.
678 * This is also true if the engines never expire. They will not go bad over time */
680 } else if ((age -= e->duration_phase_2) < e->duration_phase_3) {
681 uint max = e->reliability_max;
682 e->reliability = (int)age * (int)(e->reliability_final - max) / e->duration_phase_3 + max;
683 } else {
684 /* time's up for this engine.
685 * We will now completely retire this design */
688 /* Kick this engine out of the lists */
691 }
692
693}
694
697{
698 /* Determine last engine aging year, default to 2050 as previously. */
700
701 for (const Engine *e : Engine::Iterate()) {
702 const EngineInfo *ei = &e->info;
703
704 /* Exclude certain engines */
706 if (e->type == VEH_TRAIN && e->VehInfo<RailVehicleInfo>().railveh_type == RAILVEH_WAGON) continue;
707
708 /* Base year ending date on half the model life */
709 TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(ei->base_intro + (ei->lifelength.base() * CalendarTime::DAYS_IN_LEAP_YEAR) / 2);
710
712 }
713}
714
721void StartupOneEngine(Engine *e, const TimerGameCalendar::YearMonthDay &aging_ymd, uint32_t seed)
722{
723 const EngineInfo *ei = &e->info;
724
725 e->age = 0;
726 e->flags = {};
729
730 /* Vehicles with the same base_intro date shall be introduced at the same time.
731 * Make sure they use the same randomisation of the date. */
732 SavedRandomSeeds saved_seeds;
733 SaveRandomSeeds(&saved_seeds);
735 ei->base_intro.base() ^
736 e->type ^
737 e->GetGRFID());
738 uint32_t r = Random();
739
740 /* Don't randomise the start-date in the first two years after gamestart to ensure availability
741 * of engines in early starting games.
742 * Note: TTDP uses fixed 1922 */
745 TimerGameCalendar::YearMonthDay intro_ymd = TimerGameCalendar::ConvertDateToYMD(e->intro_date);
746 int aging_months = aging_ymd.year.base() * 12 + aging_ymd.month;
747 int intro_months = intro_ymd.year.base() * 12 + intro_ymd.month;
748 if (intro_ymd.day > 1) intro_months++; // Engines are introduced at the first month start at/after intro date.
749 e->age = aging_months - intro_months;
750 e->company_avail.Set();
752 }
753
754 /* Get parent variant index for syncing reliability via random seed. */
755 const Engine *re = e;
756 while (re->info.variant_id != EngineID::Invalid() && re->info.extra_flags.Test(ExtraEngineFlag::SyncReliability)) {
757 re = Engine::Get(re->info.variant_id);
758 }
759
761 (re->index.base() << 16) ^ (re->info.base_intro.base() << 12) ^ (re->info.decay_speed << 8) ^
762 (re->info.lifelength.base() << 4) ^ re->info.retire_early ^
763 e->type ^
764 e->GetGRFID());
765
766 /* Base reliability defined as a percentage of UINT16_MAX. */
767 const uint16_t RELIABILITY_START = UINT16_MAX * 48 / 100;
768 const uint16_t RELIABILITY_MAX = UINT16_MAX * 75 / 100;
769 const uint16_t RELIABILITY_FINAL = UINT16_MAX * 25 / 100;
770
771 static_assert(RELIABILITY_START == 0x7AE0);
772 static_assert(RELIABILITY_MAX == 0xBFFF);
773 static_assert(RELIABILITY_FINAL == 0x3FFF);
774
775 r = Random();
776 /* 14 bits gives a value between 0 and 16383, which is up to an additional 25%p reliability on top of the base reliability. */
777 e->reliability_start = GB(r, 16, 14) + RELIABILITY_START;
778 e->reliability_max = GB(r, 0, 14) + RELIABILITY_MAX;
779
780 r = Random();
781 e->reliability_final = GB(r, 16, 14) + RELIABILITY_FINAL;
782
783 e->duration_phase_1 = GB(r, 0, 5) + 7;
784 e->duration_phase_2 = std::max(0, int(GB(r, 5, 4)) + ei->base_life.base() * 12 - 96);
785 e->duration_phase_3 = GB(r, 9, 7) + 120;
786
787 RestoreRandomSeeds(saved_seeds);
788
789 e->reliability_spd_dec = ei->decay_speed << 2;
790
791 /* prevent certain engines from ever appearing. */
795 }
796}
797
803{
804 /* Aging of vehicles stops, so account for that when starting late */
806 TimerGameCalendar::YearMonthDay aging_ymd = TimerGameCalendar::ConvertDateToYMD(aging_date);
807 uint32_t seed = Random();
808
809 for (Engine *e : Engine::Iterate()) {
810 StartupOneEngine(e, aging_ymd, seed);
811 }
812 for (Engine *e : Engine::Iterate()) {
813 CalcEngineReliability(e, false);
814 }
815
816 /* Update the bitmasks for the vehicle lists */
817 for (Company *c : Company::Iterate()) {
818 c->avail_railtypes = GetCompanyRailTypes(c->index);
819 c->avail_roadtypes = GetCompanyRoadTypes(c->index);
820 }
821
822 /* Invalidate any open purchase lists */
824
827}
828
835{
836 Engine *e = Engine::Get(eid);
837 Company *c = Company::Get(company);
838
839 e->company_avail.Set(company);
840 if (e->type == VEH_TRAIN) {
842 } else if (e->type == VEH_ROAD) {
844 }
845
846 if (company == _local_company) {
848
849 /* Update the toolbar. */
854 }
855}
856
863{
864 Engine *e = Engine::Get(eid);
865 Company *c = Company::Get(company);
866
867 e->company_avail.Reset(company);
868 if (e->type == VEH_TRAIN) {
870 } else if (e->type == VEH_ROAD) {
872 }
873
874 if (company == _local_company) {
877 }
878}
879
886static void AcceptEnginePreview(EngineID eid, CompanyID company, int recursion_depth = 0)
887{
888 Engine *e = Engine::Get(eid);
889
890 e->preview_company = CompanyID::Invalid();
891 e->preview_asked.Set();
892
893 EnableEngineForCompany(eid, company);
894
895 /* Notify preview window, that it might want to close.
896 * Note: We cannot directly close the window.
897 * In singleplayer this function is called from the preview window, so
898 * we have to use the GUI-scope scheduling of InvalidateWindowData.
899 */
901
902 /* Don't search for variants to include if we are 10 levels deep already. */
903 if (recursion_depth >= 10) return;
904
905 /* Find variants to be included in preview. */
906 for (Engine *ve : Engine::IterateType(e->type)) {
907 if (ve->index != eid && ve->info.variant_id == eid && ve->info.extra_flags.Test(ExtraEngineFlag::JoinPreview)) {
908 AcceptEnginePreview(ve->index, company, recursion_depth + 1);
909 }
910 }
911}
912
919{
920 CompanyID best_company = CompanyID::Invalid();
921
922 /* For trains the cargomask has no useful meaning, since you can attach other wagons */
923 CargoTypes cargomask = e->type != VEH_TRAIN ? GetUnionOfArticulatedRefitMasks(e->index, true) : ALL_CARGOTYPES;
924
925 int32_t best_hist = -1;
926 for (const Company *c : Company::Iterate()) {
927 if (c->block_preview == 0 && !e->preview_asked.Test(c->index) &&
928 c->old_economy[0].performance_history > best_hist) {
929
930 /* Check whether the company uses similar vehicles */
931 for (const Vehicle *v : Vehicle::Iterate()) {
932 if (v->owner != c->index || v->type != e->type) continue;
933 if (!v->GetEngine()->CanCarryCargo() || !HasBit(cargomask, v->cargo_type)) continue;
934
935 best_hist = c->old_economy[0].performance_history;
936 best_company = c->index;
937 break;
938 }
939 }
940 }
941
942 return best_company;
943}
944
952static bool IsVehicleTypeDisabled(VehicleType type, bool ai)
953{
954 switch (type) {
959
960 default: NOT_REACHED();
961 }
962}
963
965static const IntervalTimer<TimerGameCalendar> _calendar_engines_daily({TimerGameCalendar::DAY, TimerGameCalendar::Priority::ENGINE}, [](auto)
966{
967 for (Company *c : Company::Iterate()) {
968 c->avail_railtypes = AddDateIntroducedRailTypes(c->avail_railtypes, TimerGameCalendar::date);
969 c->avail_roadtypes = AddDateIntroducedRoadTypes(c->avail_roadtypes, TimerGameCalendar::date);
970 }
971
973
974 for (Engine *e : Engine::Iterate()) {
975 EngineID i = e->index;
976 if (e->flags.Test(EngineFlag::ExclusivePreview)) {
977 if (e->preview_company != CompanyID::Invalid()) {
978 if (!--e->preview_wait) {
980 e->preview_company = CompanyID::Invalid();
981 }
982 } else if (e->preview_asked.Count() < MAX_COMPANIES) {
983 e->preview_company = GetPreviewCompany(e);
984
985 if (e->preview_company == CompanyID::Invalid()) {
986 e->preview_asked.Set();
987 continue;
988 }
989
990 e->preview_asked.Set(e->preview_company);
991 e->preview_wait = 20;
992 /* AIs are intentionally not skipped for preview even if they cannot build a certain
993 * vehicle type. This is done to not give poor performing human companies an "unfair"
994 * boost that they wouldn't have gotten against other human companies. The check on
995 * the line below is just to make AIs not notice that they have a preview if they
996 * cannot build the vehicle. */
997 if (!IsVehicleTypeDisabled(e->type, true)) AI::NewEvent(e->preview_company, new ScriptEventEnginePreview(i));
998 if (IsInteractiveCompany(e->preview_company)) ShowEnginePreviewWindow(i);
999 }
1000 }
1001 }
1002});
1003
1009{
1010 for (Engine *e : Engine::Iterate()) {
1011 e->company_hidden.Reset(cid);
1012 }
1013}
1014
1023{
1024 Engine *e = Engine::GetIfValid(engine_id);
1025 if (e == nullptr || _current_company >= MAX_COMPANIES) return CMD_ERROR;
1027
1028 if (flags.Test(DoCommandFlag::Execute)) {
1031 }
1032
1033 return CommandCost();
1034}
1035
1044{
1045 Engine *e = Engine::GetIfValid(engine_id);
1046 if (e == nullptr || !e->flags.Test(EngineFlag::ExclusivePreview) || e->preview_company != _current_company) return CMD_ERROR;
1047
1049
1050 return CommandCost();
1051}
1052
1061CommandCost CmdEngineCtrl(DoCommandFlags flags, EngineID engine_id, CompanyID company_id, bool allow)
1062{
1063 if (_current_company != OWNER_DEITY) return CMD_ERROR;
1064
1065 if (!Engine::IsValidID(engine_id) || !Company::IsValidID(company_id)) return CMD_ERROR;
1066
1067 if (flags.Test(DoCommandFlag::Execute)) {
1068 if (allow) {
1069 EnableEngineForCompany(engine_id, company_id);
1070 } else {
1071 DisableEngineForCompany(engine_id, company_id);
1072 }
1073 }
1074
1075 return CommandCost();
1076}
1077
1084{
1085 EngineID index = e->index;
1086
1087 /* In case the company didn't build the vehicle during the intro period,
1088 * prevent that company from getting future intro periods for a while. */
1090 for (Company *c : Company::Iterate()) {
1091 if (!e->company_avail.Test(c->index)) continue;
1092
1093 /* Check the company's 'ALL_GROUP' group statistics. This only includes countable vehicles, which is fine
1094 * as those are the only engines that can be given exclusive previews. */
1095 if (GetGroupNumEngines(c->index, ALL_GROUP, e->index) == 0) {
1096 /* The company did not build this engine during preview. */
1097 c->block_preview = 20;
1098 }
1099 }
1100 }
1101
1104
1105 /* Now available for all companies */
1106 e->company_avail.Set();
1107
1108 /* Do not introduce new rail wagons */
1109 if (IsWagon(index)) return;
1110
1111 if (e->type == VEH_TRAIN) {
1112 /* maybe make another rail type available */
1113 assert(e->VehInfo<RailVehicleInfo>().railtypes != RailTypes{});
1115 for (Company *c : Company::Iterate()) c->avail_railtypes = AddDateIntroducedRailTypes(c->avail_railtypes | introduced, TimerGameCalendar::date);
1116 } else if (e->type == VEH_ROAD) {
1117 /* maybe make another road type available */
1118 assert(e->VehInfo<RoadVehicleInfo>().roadtype < ROADTYPE_END);
1119 for (Company *c : Company::Iterate()) c->avail_roadtypes = AddDateIntroducedRoadTypes(c->avail_roadtypes | GetRoadTypeInfo(e->VehInfo<RoadVehicleInfo>().roadtype)->introduces_roadtypes, TimerGameCalendar::date);
1120 }
1121
1122 /* Only broadcast event if AIs are able to build this vehicle type. */
1123 if (!IsVehicleTypeDisabled(e->type, true)) AI::BroadcastNewEvent(new ScriptEventEngineAvailable(index));
1124
1125 /* Only provide the "New Vehicle available" news paper entry, if engine can be built. */
1126 if (!IsVehicleTypeDisabled(e->type, false) && !e->info.extra_flags.Test(ExtraEngineFlag::NoNews)) {
1127 AddNewsItem(GetEncodedString(STR_NEWS_NEW_VEHICLE_NOW_AVAILABLE_WITH_TYPE,
1128 GetEngineCategoryName(index),
1131 }
1132
1133 /* Update the toolbar. */
1137
1138 /* Close pending preview windows */
1140}
1141
1144{
1146 bool refresh = false;
1147 for (Engine *e : Engine::Iterate()) {
1148 /* Age the vehicle */
1149 if (e->flags.Test(EngineFlag::Available) && e->age != INT32_MAX) {
1150 e->age++;
1151 CalcEngineReliability(e, true);
1152 refresh = true;
1153 }
1154
1155 /* Do not introduce invalid engines */
1156 if (!e->IsEnabled()) continue;
1157
1158 if (!e->flags.Test(EngineFlag::Available) && TimerGameCalendar::date >= (e->intro_date + CalendarTime::DAYS_IN_YEAR)) {
1159 /* Introduce it to all companies */
1161 } else if (!e->flags.Any({EngineFlag::Available, EngineFlag::ExclusivePreview}) && TimerGameCalendar::date >= e->intro_date) {
1162 /* Introduction date has passed...
1163 * Check if it is allowed to build this vehicle type at all
1164 * based on the current game settings. If not, it does not
1165 * make sense to show the preview dialog to any company. */
1166 if (IsVehicleTypeDisabled(e->type, false)) continue;
1167
1168 /* Do not introduce new rail wagons */
1169 if (IsWagon(e->index)) continue;
1170
1171 /* Engine has no preview */
1172 if (e->info.extra_flags.Test(ExtraEngineFlag::NoPreview)) continue;
1173
1174 /* Show preview dialog to one of the companies. */
1175 e->flags.Set(EngineFlag::ExclusivePreview);
1176 e->preview_company = CompanyID::Invalid();
1177 e->preview_asked = CompanyMask{};
1178 }
1179 }
1180
1181 InvalidateWindowClassesData(WC_BUILD_VEHICLE); // rebuild the purchase list (esp. when sorted by reliability)
1182
1183 if (refresh) {
1186 }
1187 }
1188}
1189
1190static const IntervalTimer<TimerGameCalendar> _calendar_engines_monthly({TimerGameCalendar::MONTH, TimerGameCalendar::Priority::ENGINE}, [](auto)
1191{
1193});
1194
1200static bool IsUniqueEngineName(const std::string &name)
1201{
1202 for (const Engine *e : Engine::Iterate()) {
1203 if (!e->name.empty() && e->name == name) return false;
1204 }
1205
1206 return true;
1207}
1208
1216CommandCost CmdRenameEngine(DoCommandFlags flags, EngineID engine_id, const std::string &text)
1217{
1218 Engine *e = Engine::GetIfValid(engine_id);
1219 if (e == nullptr) return CMD_ERROR;
1220
1221 bool reset = text.empty();
1222
1223 if (!reset) {
1225 if (!IsUniqueEngineName(text)) return CommandCost(STR_ERROR_NAME_MUST_BE_UNIQUE);
1226 }
1227
1228 if (flags.Test(DoCommandFlag::Execute)) {
1229 if (reset) {
1230 e->name.clear();
1231 } else {
1232 e->name = text;
1233 }
1234
1236 }
1237
1238 return CommandCost();
1239}
1240
1241
1251{
1252 const Engine *e = Engine::GetIfValid(engine);
1253
1254 /* check if it's an engine that is in the engine array */
1255 if (e == nullptr) return false;
1256
1257 /* check if it's an engine of specified type */
1258 if (e->type != type) return false;
1259
1260 /* check if it's available ... */
1261 if (company == OWNER_DEITY) {
1262 /* ... for any company (preview does not count) */
1263 if (!e->flags.Test(EngineFlag::Available) || e->company_avail.None()) return false;
1264 } else {
1265 /* ... for this company */
1266 if (!e->company_avail.Test(company)) return false;
1267 }
1268
1269 if (!e->IsEnabled()) return false;
1270
1271 if (type == VEH_TRAIN && company != OWNER_DEITY) {
1272 /* Check if the rail type is available to this company */
1273 const Company *c = Company::Get(company);
1274 if (!GetAllCompatibleRailTypes(e->VehInfo<RailVehicleInfo>().railtypes).Any(c->avail_railtypes)) return false;
1275 }
1276 if (type == VEH_ROAD && company != OWNER_DEITY) {
1277 /* Check if the road type is available to this company */
1278 const Company *c = Company::Get(company);
1279 if (!GetRoadTypeInfo(e->VehInfo<RoadVehicleInfo>().roadtype)->powered_roadtypes.Any(c->avail_roadtypes)) return false;
1280 }
1281
1282 return true;
1283}
1284
1292{
1293 const Engine *e = Engine::GetIfValid(engine);
1294
1295 /* check if it's an engine that is in the engine array */
1296 if (e == nullptr) return false;
1297
1298 if (!e->CanCarryCargo()) return false;
1299
1300 const EngineInfo *ei = &e->info;
1301 if (ei->refit_mask == 0) return false;
1302
1303 /* Are there suffixes?
1304 * Note: This does not mean the suffixes are actually available for every consist at any time. */
1306
1307 /* Is there any cargo except the default cargo? */
1308 CargoType default_cargo = e->GetDefaultCargoType();
1309 CargoTypes default_cargo_mask = 0;
1310 SetBit(default_cargo_mask, default_cargo);
1311 return IsValidCargoType(default_cargo) && ei->refit_mask != default_cargo_mask;
1312}
1313
1318{
1319 TimerGameCalendar::Date min_date{INT32_MAX};
1320
1321 for (const Engine *e : Engine::Iterate()) {
1322 if (!e->IsEnabled()) continue;
1323
1324 /* Don't consider train wagons, we need a powered engine available. */
1325 if (e->type == VEH_TRAIN && e->VehInfo<RailVehicleInfo>().railveh_type == RAILVEH_WAGON) continue;
1326
1327 /* We have an available engine... yay! */
1328 if (e->flags.Test(EngineFlag::Available) && e->company_avail.Any()) return;
1329
1330 /* Okay, try to find the earliest date. */
1331 min_date = std::min(min_date, e->info.base_intro);
1332 }
1333
1334 if (min_date < INT32_MAX) {
1335 ShowErrorMessage(GetEncodedString(STR_ERROR_NO_VEHICLES_AVAILABLE_YET),
1336 GetEncodedString(STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION, min_date), WL_WARNING);
1337 } else {
1338 ShowErrorMessage(GetEncodedString(STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL),
1339 GetEncodedString(STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION), WL_WARNING);
1340 }
1341}
Base functions for all AIs.
Base for aircraft.
CargoTypes GetUnionOfArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type)
Ors the refit_masks of all articulated parts.
Functions related to articulated vehicles.
void AddRemoveEngineFromAutoreplaceAndBuildWindows(VehicleType type)
When an engine is made buildable or is removed from being buildable, add/remove it from the build/aut...
Functions related to the autoreplace GUIs.
static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
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.
static constexpr CargoLabel CT_INVALID
Invalid cargo type.
Definition cargo_type.h:70
uint8_t CargoType
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:21
bool IsValidCargoType(CargoType cargo)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:104
static constexpr CargoLabel CT_PASSENGERS
Available types of cargo Labels may be re-used between different climates.
Definition cargo_type.h:29
@ Passengers
Passengers.
bool IsCargoInClass(CargoType cargo, CargoClasses cc)
Does cargo c have cargo class cc?
Definition cargotype.h:236
static void BroadcastNewEvent(ScriptEvent *event, CompanyID skip_company=CompanyID::Invalid())
Broadcast a new event to all active AIs.
Definition ai_core.cpp:255
static void NewEvent(CompanyID company, ScriptEvent *event)
Queue a new event for an AI.
Definition ai_core.cpp:235
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.
Common return value for all commands.
StringID GetAircraftTypeText() const
Get the name of the aircraft type for display purposes.
Definition engine.cpp:470
uint GetPower() const
Returns the power of the engine for display and sorting purposes.
Definition engine.cpp:393
const Engine * GetDisplayVariant() const
Get the last display variant for an engine.
uint16_t GetRange() const
Get the range of an aircraft type.
Definition engine.cpp:456
uint32_t GetGRFID() const
Retrieve the GRF ID of the NewGRF the engine is tied to.
Definition engine.cpp:160
uint16_t reliability_spd_dec
Speed of reliability decay between services (per day).
Definition engine_base.h:50
Money GetCost() const
Return how much a new engine costs.
Definition engine.cpp:321
uint16_t reliability_start
Initial reliability of the engine.
Definition engine_base.h:51
TimerGameCalendar::Date intro_date
Date of introduction of the engine.
Definition engine_base.h:46
const GRFFile * GetGRF() const
Retrieve the NewGRF the engine is tied to.
static Pool::IterateWrapperFiltered< Engine, EngineTypeFilter > IterateType(VehicleType vt, size_t from=0)
Returns an iterable ensemble of all valid engines of the given type.
uint GetDisplayMaxSpeed() const
Returns max speed of the engine for display purposes.
Definition engine.cpp:361
uint DetermineCapacity(const Vehicle *v, uint16_t *mail_capacity=nullptr) const
Determines capacity of a given vehicle from scratch.
Definition engine.cpp:204
EngineFlags flags
Flags of the engine.
Definition engine_base.h:57
CompanyMask company_avail
Bit for each company whether the engine is available for that company.
Definition engine_base.h:40
uint16_t reliability_max
Maximal reliability of the engine.
Definition engine_base.h:52
uint GetDisplayWeight() const
Returns the weight of the engine for display purposes.
Definition engine.cpp:411
bool IsEnabled() const
Checks whether the engine is a valid (non-articulated part of an) engine.
Definition engine.cpp:150
VehicleType type
Vehicle type, ie VEH_ROAD, VEH_TRAIN, etc.
Definition engine_base.h:62
bool IsVariantHidden(CompanyID c) const
Check whether the engine variant chain is hidden in the GUI for the given company.
Definition engine.cpp:490
uint16_t reliability_final
Final reliability of the engine.
Definition engine_base.h:53
CompanyID preview_company
Company which is currently being offered a preview CompanyID::Invalid() means no company.
Definition engine_base.h:59
TimerGameCalendar::Date GetLifeLengthInDays() const
Returns the vehicle's (not model's!) life length in days.
Definition engine.cpp:446
uint16_t duration_phase_3
Third reliability phase in months, decaying to reliability_final.
Definition engine_base.h:56
uint16_t duration_phase_2
Second reliability phase in months, keeping reliability_max.
Definition engine_base.h:55
CargoType GetDefaultCargoType() const
Determines the default cargo type of an engine.
Definition engine_base.h:94
CompanyMask company_hidden
Bit for each company whether the engine is normally hidden in the build gui for that company.
Definition engine_base.h:41
Money GetRunningCost() const
Return how much the running costs of this engine are.
Definition engine.cpp:284
uint16_t reliability
Current reliability of the engine.
Definition engine_base.h:49
CompanyMask preview_asked
Bit for each company which has already been offered a preview.
Definition engine_base.h:42
uint GetDisplayMaxTractiveEffort() const
Returns the tractive effort of the engine for display purposes.
Definition engine.cpp:429
int32_t age
Age of the engine in months.
Definition engine_base.h:47
bool IsHidden(CompanyID c) const
Check whether the engine is hidden in the GUI for the given company.
bool CanCarryCargo() const
Determines whether an engine can carry something.
Definition engine.cpp:171
std::string name
Custom name of engine.
Definition engine_base.h:44
uint16_t duration_phase_1
First reliability phase in months, increasing reliability from reliability_start to reliability_max.
Definition engine_base.h:54
Enum-as-bit-set wrapper.
An interval timer will fire every interval, and will continue to fire until it is deleted.
Definition timer.h:76
RoadTypes powered_roadtypes
bitmask to the OTHER roadtypes on which a vehicle of THIS roadtype generates power
Definition road.h:96
RoadTypes introduces_roadtypes
Bitmask of which other roadtypes are introduced when this roadtype is introduced.
Definition road.h:151
static constexpr TimerGameTick::Ticks CARGO_AGING_TICKS
Cycle duration for aging cargo.
static Date ConvertYMDToDate(Year year, Month month, Day day)
Converts a tuple of Year, Month and Day to a Date.
static YearMonthDay ConvertDateToYMD(Date date)
Converts a Date to a Year, Month & Day.
static Date date
Current date in days (day counter).
static Year year
Current year, starting at 0.
static constexpr int DAYS_IN_YEAR
days per year
static constexpr int DAYS_IN_LEAP_YEAR
sometimes, you need one day more...
Functions related to commands.
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
@ Execute
execute the given command
Definition of stuff that is very close to a company, like the company struct itself.
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.
Functions related to companies.
bool IsInteractiveCompany(CompanyID company)
Is the user representing company?
static constexpr Owner OWNER_DEITY
The object is owned by a superuser / goal script.
Some simple functions to help with accessing containers.
auto Slide(TIter first, TIter last, TIter position) -> std::pair< TIter, TIter >
Move elements between first and last to a new position, rotating elements in between as necessary.
Money GetPrice(Price index, uint cost_factor, const GRFFile *grf_file, int shift)
Determine a certain price.
Definition economy.cpp:940
Price
Enumeration of all base prices for use with Prices.
void ClearEnginesHiddenFlagOfCompany(CompanyID cid)
Clear the 'hidden' flag for all engines of a new company.
Definition engine.cpp:1008
void SetYearEngineAgingStops()
Compute the value for _year_engine_aging_stops.
Definition engine.cpp:696
static void NewVehicleAvailable(Engine *e)
An engine has become available for general use.
Definition engine.cpp:1083
const uint8_t _engine_counts[4]
Number of engines of each vehicle type in original engine data.
Definition engine.cpp:54
void SetupEngines()
Initialise the engine pool with the data from the original vehicles.
Definition engine.cpp:604
static CompanyID GetPreviewCompany(Engine *e)
Get the best company for an engine preview.
Definition engine.cpp:918
const uint8_t _engine_offsets[4]
Offset of the first engine of each vehicle type in original engine data.
Definition engine.cpp:62
static void ClearLastVariant(EngineID engine_id, VehicleType type)
Ensure engine is not set as the last used variant for any other engine.
Definition engine.cpp:639
static bool IsVehicleTypeDisabled(VehicleType type, bool ai)
Checks if a vehicle type is disabled for all/ai companies.
Definition engine.cpp:952
static void AcceptEnginePreview(EngineID eid, CompanyID company, int recursion_depth=0)
Company company accepts engine eid for preview.
Definition engine.cpp:886
CommandCost CmdRenameEngine(DoCommandFlags flags, EngineID engine_id, const std::string &text)
Rename an engine.
Definition engine.cpp:1216
CommandCost CmdWantEnginePreview(DoCommandFlags flags, EngineID engine_id)
Accept an engine prototype.
Definition engine.cpp:1043
void CalendarEnginesMonthlyLoop()
Monthly update of the availability, reliability, and preview offers of the engines.
Definition engine.cpp:1143
static bool IsUniqueEngineName(const std::string &name)
Is name still free as name for an engine?
Definition engine.cpp:1200
bool IsEngineBuildable(EngineID engine, VehicleType type, CompanyID company)
Check if an engine is buildable.
Definition engine.cpp:1250
static const IntervalTimer< TimerGameCalendar > _calendar_engines_daily({TimerGameCalendar::DAY, TimerGameCalendar::Priority::ENGINE}, [](auto) { for(Company *c :Company::Iterate()) { c->avail_railtypes=AddDateIntroducedRailTypes(c->avail_railtypes, TimerGameCalendar::date);c->avail_roadtypes=AddDateIntroducedRoadTypes(c->avail_roadtypes, TimerGameCalendar::date);} if(TimerGameCalendar::year >=_year_engine_aging_stops) return;for(Engine *e :Engine::Iterate()) { EngineID i=e->index;if(e->flags.Test(EngineFlag::ExclusivePreview)) { if(e->preview_company !=CompanyID::Invalid()) { if(!--e->preview_wait) { CloseWindowById(WC_ENGINE_PREVIEW, i);e->preview_company=CompanyID::Invalid();} } else if(e->preview_asked.Count()< MAX_COMPANIES) { e->preview_company=GetPreviewCompany(e);if(e->preview_company==CompanyID::Invalid()) { e->preview_asked.Set();continue;} e->preview_asked.Set(e->preview_company);e->preview_wait=20;if(!IsVehicleTypeDisabled(e->type, true)) AI::NewEvent(e->preview_company, new ScriptEventEnginePreview(i));if(IsInteractiveCompany(e->preview_company)) ShowEnginePreviewWindow(i);} } } })
Daily check to offer an exclusive engine preview to the companies.
static TimerGameCalendar::Year _year_engine_aging_stops
Year that engine aging stops.
Definition engine.cpp:51
static void DisableEngineForCompany(EngineID eid, CompanyID company)
Forbids engine eid to be used by a company company.
Definition engine.cpp:862
void StartupEngines()
Start/initialise all our engines.
Definition engine.cpp:802
static bool IsWagon(EngineID index)
Determine whether an engine type is a wagon (and not a loco).
Definition engine.cpp:628
CommandCost CmdEngineCtrl(DoCommandFlags flags, EngineID engine_id, CompanyID company_id, bool allow)
Allow or forbid a specific company to use an engine.
Definition engine.cpp:1061
void StartupOneEngine(Engine *e, const TimerGameCalendar::YearMonthDay &aging_ymd, uint32_t seed)
Start/initialise one engine.
Definition engine.cpp:721
void CheckEngines()
Check for engines that have an appropriate availability.
Definition engine.cpp:1317
bool IsEngineRefittable(EngineID engine)
Check if an engine is refittable.
Definition engine.cpp:1291
CommandCost CmdSetVehicleVisibility(DoCommandFlags flags, EngineID engine_id, bool hide)
Set the visibility of an engine.
Definition engine.cpp:1022
void CalcEngineReliability(Engine *e, bool new_month)
Update Engine::reliability and (if needed) update the engine GUIs.
Definition engine.cpp:650
static void EnableEngineForCompany(EngineID eid, CompanyID company)
Allows engine eid to be used by a company company.
Definition engine.cpp:834
Base class for engines.
Functions related to engines.
StringID GetEngineCategoryName(EngineID engine)
Return the category of an engine.
Engine GUI functions, used by build_vehicle_gui and autoreplace_gui.
@ AIR_CTOL
Conventional Take Off and Landing, i.e. planes.
@ SyncReliability
Engine reliability will be synced with variant parent.
@ NoNews
No 'new vehicle' news will be generated.
@ JoinPreview
Engine will join exclusive preview with variant parent.
@ NoPreview
No exclusive preview will be offered.
@ NoDefaultCargoMultiplier
Use the new capacity algorithm. The default cargotype of the vehicle does not affect capacity multipl...
static const uint MAX_LENGTH_ENGINE_NAME_CHARS
The maximum length of an engine name in characters including '\0'.
uint64_t PackEngineNameDParam(EngineID engine_id, EngineNameContext context, uint32_t extra_data=0)
Combine an engine ID and a name context to an engine name dparam.
@ Available
This vehicle is available to everyone.
@ ExclusivePreview
This vehicle is in the exclusive preview stage, either being used or being offered to a company.
@ PreviewNews
Name is shown in exclusive preview or newspaper.
@ RAILVEH_WAGON
simple wagon, not motorized
Definition engine_type.h:34
@ RAILVEH_MULTIHEAD
indicates a combination of two locomotives
Definition engine_type.h:33
This file contains all the data for vehicles.
Functions related to errors.
@ WL_WARNING
Other information.
Definition error.h:25
void ShowErrorMessage(EncodedString &&summary_msg, int x, int y, CommandCost &cc)
Display an error message in a window.
uint GetGroupNumEngines(CompanyID company, GroupID id_g, EngineID id_e)
Get the number of engines with EngineID id_e in the group with GroupID id_g and its sub-groups.
void MarkWholeScreenDirty()
This function mark the whole screen as dirty.
Definition gfx.cpp:1549
static constexpr GroupID ALL_GROUP
All vehicles are in this group.
Definition group_type.h:17
@ Random
Randomise borders.
Base for the NewGRF implementation.
void ReloadNewGRFData()
Reload all NewGRF files during a running game.
@ RefitCapacity
Cargo capacity after refit.
@ CargoSuffix
Show suffix after cargo name.
@ CBID_VEHICLE_REFIT_CAPACITY
Refit capacity, the passed vehicle needs to have its ->cargo_type set to the cargo we are refitting t...
static const uint CALLBACK_FAILED
Different values for Callback result evaluations.
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.
Functions for NewGRF engines.
@ PROP_AIRCRAFT_PASSENGER_CAPACITY
Passenger Capacity.
@ PROP_ROADVEH_WEIGHT
Weight in 1/4 t.
@ PROP_TRAIN_COST_FACTOR
Purchase cost (if dualheaded: sum of both vehicles)
@ PROP_TRAIN_WEIGHT
Weight in t (if dualheaded: for each single vehicle)
@ PROP_AIRCRAFT_RANGE
Aircraft range.
@ PROP_TRAIN_CARGO_CAPACITY
Capacity (if dualheaded: for each single vehicle)
@ PROP_AIRCRAFT_RUNNING_COST_FACTOR
Yearly runningcost.
@ PROP_ROADVEH_RUNNING_COST_FACTOR
Yearly runningcost.
@ PROP_TRAIN_TRACTIVE_EFFORT
Tractive effort coefficient in 1/256.
@ PROP_SHIP_CARGO_CAPACITY
Capacity.
@ PROP_ROADVEH_TRACTIVE_EFFORT
Tractive effort coefficient in 1/256.
@ PROP_SHIP_COST_FACTOR
Purchase cost.
@ PROP_ROADVEH_CARGO_CAPACITY
Capacity.
@ PROP_AIRCRAFT_SPEED
Max. speed: 1 unit = 8 mph = 12.8 km-ish/h.
@ PROP_AIRCRAFT_MAIL_CAPACITY
Mail Capacity.
@ PROP_SHIP_SPEED
Max. speed: 1 unit = 1/3.2 mph = 0.5 km-ish/h.
@ PROP_SHIP_RUNNING_COST_FACTOR
Yearly runningcost.
@ PROP_ROADVEH_COST_FACTOR
Purchase cost.
@ PROP_ROADVEH_POWER
Power in 10 HP.
@ PROP_AIRCRAFT_COST_FACTOR
Purchase cost.
@ PROP_TRAIN_RUNNING_COST_FACTOR
Yearly runningcost (if dualheaded: sum of both vehicles)
@ PROP_TRAIN_POWER
Power in hp (if dualheaded: sum of both vehicles)
@ PROP_TRAIN_SPEED
Max. speed: 1 unit = 1/1.6 mph = 1 km-ish/h.
@ PROP_ROADVEH_SPEED
Max. speed: 1 unit = 1/0.8 mph = 2 km-ish/h.
Functions related to news.
void AddNewsItem(EncodedString &&headline, NewsType type, NewsStyle style, NewsFlags flags, NewsReference ref1={}, NewsReference ref2={}, std::unique_ptr< NewsAllocatedData > &&data=nullptr, AdviceType advice_type=AdviceType::Invalid)
Add a new newsitem to be shown.
Definition news_gui.cpp:900
@ NewVehicles
New vehicle has become available.
@ Vehicle
Vehicle news item. (new engine available)
Some methods of Pool are placed here in order to reduce compilation time and binary size.
#define INSTANTIATE_POOL_METHODS(name)
Force instantiation of pool methods so we don't get linker errors.
RailTypes GetCompanyRailTypes(CompanyID company, bool introduces)
Get the rail types the given company can build.
Definition rail.cpp:135
RailTypes AddDateIntroducedRailTypes(RailTypes current, TimerGameCalendar::Date date)
Add the rail types that are to be introduced at the given date.
Definition rail.cpp:102
RailTypes GetAllIntroducesRailTypes(RailTypes railtypes)
Returns all introduced railtypes for a set of railtypes.
Definition rail.h:336
RailTypes GetAllCompatibleRailTypes(RailTypes railtypes)
Returns all compatible railtypes for a set of railtypes.
Definition rail.h:312
void SetRandomSeed(uint32_t seed)
(Re)set the state of the random number generators.
Pseudo random number generator.
void SaveRandomSeeds(SavedRandomSeeds *storage)
Saves the current seeds.
void RestoreRandomSeeds(const SavedRandomSeeds &storage)
Restores previously saved seeds.
RoadTypes GetCompanyRoadTypes(CompanyID company, bool introduces)
Get the road types the given company can build.
Definition road.cpp:210
RoadTypes AddDateIntroducedRoadTypes(RoadTypes current, TimerGameCalendar::Date date)
Add the road types that are to be introduced at the given date.
Definition road.cpp:177
const RoadTypeInfo * GetRoadTypeInfo(RoadType roadtype)
Returns a pointer to the Roadtype information for a given roadtype.
Definition road.h:215
@ ROADTYPE_END
Used for iterations.
Definition road_type.h:27
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
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:271
size_t Utf8StringLength(std::string_view str)
Get the length of an UTF-8 encoded string in number of characters and thus not the number of bytes th...
Definition string.cpp:349
Functions related to low-level strings.
EncodedString GetEncodedString(StringID str)
Encode a string with no parameters into an encoded string.
Definition strings.cpp:90
Functions related to OTTD's strings.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
bool ai_disable_veh_roadveh
disable types for AI
bool ai_disable_veh_ship
disable types for AI
bool ai_disable_veh_train
disable types for AI
bool ai_disable_veh_aircraft
disable types for AI
Information about a aircraft vehicle.
uint16_t multiplier
Capacity multiplier for vehicles. (8 fractional bits)
Definition cargotype.h:80
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo type.
Definition cargotype.h:137
RoadTypes avail_roadtypes
Road types available to this company.
RailTypes avail_railtypes
Rail types available to this company.
Projection to get a unique key of an EngineIDMapping, used for sorting in EngineOverrideManager.
Information about a vehicle.
TimerGameCalendar::Year base_life
Basic duration of engine availability (without random parts). 0xFF means infinite life.
LandscapeTypes climates
Climates supported by the engine.
EngineMiscFlags misc_flags
Miscellaneous flags.
EngineID variant_id
Engine variant ID. If set, will be treated specially in purchase lists.
StringID string_id
Default name of engine.
VehicleCallbackMasks callback_mask
Bitmask of vehicle callbacks that have to be called.
TimerGameCalendar::Date base_intro
Basic date of engine introduction (without random parts).
int8_t retire_early
Number of years early to retire vehicle.
TimerGameCalendar::Year lifelength
Lifetime of a single vehicle.
Stores the mapping of EngineID to the internal id of newgrfs.
static bool ResetToCurrentNewGRFConfig()
Tries to reset the engine mapping to match the current NewGRF configuration.
Definition engine.cpp:588
void ResetToDefaultMapping()
Initializes the EngineOverrideManager with the default engines.
Definition engine.cpp:512
EngineID UseUnreservedID(VehicleType type, uint16_t grf_local_id, uint32_t grfid, bool static_access)
Look for an unreserved EngineID matching the local id, and reserve it if found.
Definition engine.cpp:552
EngineID GetID(VehicleType type, uint16_t grf_local_id, uint32_t grfid)
Looks up an EngineID in the EngineOverrideManager.
Definition engine.cpp:533
Dynamic data of a loaded NewGRF.
Definition newgrf.h:114
LandscapeType landscape
the landscape we're currently in
TimerGameCalendar::Year starting_year
starting date
uint32_t generation_seed
noise seed for world generation
AISettings ai
what may the AI do?
GameCreationSettings game_creation
settings used during the creation of a game (map)
VehicleSettings vehicle
options for vehicles
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
static T * CreateAtIndex(Tindex index, Targs &&... args)
Creates a new T-object in the associated pool.
static Titem * Get(auto index)
Returns Titem with given index.
static bool IsValidID(auto index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
const Tindex index
Index of this pool item.
static Titem * GetIfValid(auto index)
Returns Titem with given index.
Base class for all pools.
void CleanPool() override
Virtual method that deletes all items in the pool.
Information about a rail vehicle.
Definition engine_type.h:74
RailTypes railtypes
Railtypes, mangled if elrail is disabled.
Definition engine_type.h:78
Information about a road vehicle.
RoadType roadtype
Road type.
Stores the state of all random number generators.
Information about a ship vehicle.
Definition engine_type.h:99
Templated helper to make a type-safe 'typedef' representing a single POD value.
UnitID max_ships
max ships in game per company
UnitID max_trains
max trains in game per company
uint8_t extend_vehicle_life
extend vehicle life by this many years
UnitID max_aircraft
max planes in game per company
UnitID max_roadveh
max trucks in game per company
bool never_expire_vehicles
never expire vehicles
Vehicle data structure.
EngineID engine_type
The type of engine used for this vehicle.
CargoType cargo_type
type of cargo this vehicle is carrying
uint8_t cargo_subtype
Used for livery refits (NewGRF variations)
Definition of Interval and OneShot timers.
Definition of the game-calendar-timer.
Definition of the tick-based game-timer.
@ TRANSPORT_ROAD
Transport by road vehicle.
@ TRANSPORT_WATER
Transport over water.
@ TRANSPORT_AIR
Transport through air.
Functions related to vehicles.
bool IsCompanyBuildableVehicleType(VehicleType type)
Is the given vehicle type buildable by a company?
VehicleType
Available vehicle types.
@ VEH_INVALID
Non-existing type of vehicle.
@ VEH_ROAD
Road vehicle type.
@ VEH_AIRCRAFT
Aircraft vehicle type.
@ VEH_SHIP
Ship vehicle type.
@ VEH_TRAIN
Train vehicle type.
@ VEH_COMPANY_END
Last company-ownable type.
static const int GROUND_ACCELERATION
Acceleration due to gravity, 9.8 m/s^2.
void CloseWindowById(WindowClass cls, WindowNumber number, bool force, int data)
Close a window by its class and window number (if it is open).
Definition window.cpp:1195
void CloseWindowByClass(WindowClass cls, int data)
Close all windows of a given class.
Definition window.cpp:1207
void SetWindowClassesDirty(WindowClass cls)
Mark all windows of a particular class as dirty (in need of repainting)
Definition window.cpp:3208
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:3300
void InvalidateWindowClassesData(WindowClass cls, int data, bool gui_scope)
Mark window data of all windows of a given class as invalid (in need of re-computing) Note that by de...
Definition window.cpp:3318
Window functions not directly related to making/drawing windows.
@ WC_BUILD_TOOLBAR
Build toolbar; Window numbers:
Definition window_type.h:78
@ WC_REPLACE_VEHICLE
Replace vehicle window; Window numbers:
@ WC_ENGINE_PREVIEW
Engine preview window; Window numbers:
@ WC_MAIN_TOOLBAR
Main toolbar (the long bar at the top); Window numbers:
Definition window_type.h:63
@ WC_BUILD_VEHICLE
Build vehicle; Window numbers: