OpenTTD Source 20250205-master-gfd85ab1e2c
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 <http://www.gnu.org/licenses/>.
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(VehicleType type, uint16_t local_id)
72{
73 this->type = type;
74 this->grf_prop.local_id = local_id;
75 this->list_position = local_id;
78
79 /* Check if this base engine is within the original engine data range */
80 if (local_id >= _engine_counts[type]) {
81 /* 'power' defaults to zero, so we also have to default to 'wagon' */
82 if (type == VEH_TRAIN) this->u.rail.railveh_type = RAILVEH_WAGON;
83 /* Set model life to maximum to make wagons available */
84 this->info.base_life = TimerGameCalendar::Year{0xFF};
85 /* Set road vehicle tractive effort to the default value */
86 if (type == VEH_ROAD) this->u.road.tractive_effort = 0x4C;
87 /* Aircraft must have CT_INVALID as default, as there is no property */
88 this->info.cargo_type = INVALID_CARGO;
89 this->info.cargo_label = (type == VEH_AIRCRAFT) ? CT_INVALID : CT_PASSENGERS;
90 /* Ships must have a non-zero acceleration. */
91 if (type == VEH_SHIP) this->u.ship.acceleration = 1;
92 /* Set visual effect to the default value */
93 switch (type) {
94 case VEH_TRAIN: this->u.rail.visual_effect = VE_DEFAULT; break;
95 case VEH_ROAD: this->u.road.visual_effect = VE_DEFAULT; break;
96 case VEH_SHIP: this->u.ship.visual_effect = VE_DEFAULT; break;
97 default: break; // The aircraft, disasters and especially visual effects have no NewGRF configured visual effects
98 }
99 /* Set cargo aging period to the default value. */
101 /* Not a variant */
102 this->info.variant_id = INVALID_ENGINE;
103 return;
104 }
105
106 /* Copy the original engine info for this slot */
107 this->info = _orig_engine_info[_engine_offsets[type] + local_id];
108
109 /* Copy the original engine data for this slot */
110 switch (type) {
111 default: NOT_REACHED();
112
113 case VEH_TRAIN:
114 this->u.rail = _orig_rail_vehicle_info[local_id];
115 this->original_image_index = this->u.rail.image_index;
116 this->info.string_id = STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_KIRBY_PAUL_TANK_STEAM + local_id;
117
118 /* Set the default model life of original wagons to "infinite" */
119 if (this->u.rail.railveh_type == RAILVEH_WAGON) this->info.base_life = TimerGameCalendar::Year{0xFF};
120
121 break;
122
123 case VEH_ROAD:
124 this->u.road = _orig_road_vehicle_info[local_id];
125 this->original_image_index = this->u.road.image_index;
126 this->info.string_id = STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_REGAL_BUS + local_id;
127 break;
128
129 case VEH_SHIP:
130 this->u.ship = _orig_ship_vehicle_info[local_id];
131 this->original_image_index = this->u.ship.image_index;
132 this->info.string_id = STR_VEHICLE_NAME_SHIP_MPS_OIL_TANKER + local_id;
133 break;
134
135 case VEH_AIRCRAFT:
136 this->u.air = _orig_aircraft_vehicle_info[local_id];
137 this->original_image_index = this->u.air.image_index;
138 this->info.string_id = STR_VEHICLE_NAME_AIRCRAFT_SAMPSON_U52 + local_id;
139 break;
140 }
141}
142
148{
149 return this->info.string_id != STR_NEWGRF_INVALID_ENGINE && this->info.climates.Test(_settings_game.game_creation.landscape);
150}
151
157uint32_t Engine::GetGRFID() const
158{
159 const GRFFile *file = this->GetGRF();
160 return file == nullptr ? 0 : file->grfid;
161}
162
169{
170 /* For engines that can appear in a consist (i.e. rail vehicles and (articulated) road vehicles), a capacity
171 * of zero is a special case, to define the vehicle to not carry anything. The default cargotype is still used
172 * for livery selection etc.
173 * Note: Only the property is tested. A capacity callback returning 0 does not have the same effect.
174 */
175 switch (this->type) {
176 case VEH_TRAIN:
177 if (this->u.rail.capacity == 0) return false;
178 break;
179
180 case VEH_ROAD:
181 if (this->u.road.capacity == 0) return false;
182 break;
183
184 case VEH_SHIP:
185 case VEH_AIRCRAFT:
186 break;
187
188 default: NOT_REACHED();
189 }
191}
192
193
201uint Engine::DetermineCapacity(const Vehicle *v, uint16_t *mail_capacity) const
202{
203 assert(v == nullptr || this->index == v->engine_type);
204 if (mail_capacity != nullptr) *mail_capacity = 0;
205
206 if (!this->CanCarryCargo()) return 0;
207
208 bool new_multipliers = this->info.misc_flags.Test(EngineMiscFlag::NoDefaultCargoMultiplier);
209 CargoType default_cargo = this->GetDefaultCargoType();
210 CargoType cargo_type = (v != nullptr) ? v->cargo_type : default_cargo;
211
212 if (mail_capacity != nullptr && this->type == VEH_AIRCRAFT && IsCargoInClass(cargo_type, CC_PASSENGERS)) {
213 *mail_capacity = GetEngineProperty(this->index, PROP_AIRCRAFT_MAIL_CAPACITY, this->u.air.mail_capacity, v);
214 }
215
216 /* Check the refit capacity callback if we are not in the default configuration, or if we are using the new multiplier algorithm. */
218 (new_multipliers || default_cargo != cargo_type || (v != nullptr && v->cargo_subtype != 0))) {
219 uint16_t callback = GetVehicleCallback(CBID_VEHICLE_REFIT_CAPACITY, 0, 0, this->index, v);
220 if (callback != CALLBACK_FAILED) return callback;
221 }
222
223 /* Get capacity according to property resp. CB */
224 uint capacity;
225 uint extra_mail_cap = 0;
226 switch (this->type) {
227 case VEH_TRAIN:
228 capacity = GetEngineProperty(this->index, PROP_TRAIN_CARGO_CAPACITY, this->u.rail.capacity, v);
229
230 /* In purchase list add the capacity of the second head. Always use the plain property for this. */
231 if (v == nullptr && this->u.rail.railveh_type == RAILVEH_MULTIHEAD) capacity += this->u.rail.capacity;
232 break;
233
234 case VEH_ROAD:
235 capacity = GetEngineProperty(this->index, PROP_ROADVEH_CARGO_CAPACITY, this->u.road.capacity, v);
236 break;
237
238 case VEH_SHIP:
239 capacity = GetEngineProperty(this->index, PROP_SHIP_CARGO_CAPACITY, this->u.ship.capacity, v);
240 break;
241
242 case VEH_AIRCRAFT:
243 capacity = GetEngineProperty(this->index, PROP_AIRCRAFT_PASSENGER_CAPACITY, this->u.air.passenger_capacity, v);
244 if (!IsCargoInClass(cargo_type, CC_PASSENGERS)) {
245 extra_mail_cap = GetEngineProperty(this->index, PROP_AIRCRAFT_MAIL_CAPACITY, this->u.air.mail_capacity, v);
246 }
247 if (IsValidCargoType(GetCargoTypeByLabel(CT_MAIL))) {
248 if (!new_multipliers && cargo_type == GetCargoTypeByLabel(CT_MAIL)) return capacity + extra_mail_cap;
249 }
250 default_cargo = GetCargoTypeByLabel(CT_PASSENGERS); // Always use 'passengers' wrt. cargo multipliers
251 break;
252
253 default: NOT_REACHED();
254 }
255
256 if (!new_multipliers) {
257 /* Use the passenger multiplier for mail as well */
258 capacity += extra_mail_cap;
259 extra_mail_cap = 0;
260 }
261
262 /* Apply multipliers depending on cargo- and vehicletype. */
263 if (new_multipliers || (this->type != VEH_SHIP && default_cargo != cargo_type)) {
264 uint16_t default_multiplier = new_multipliers ? 0x100 : CargoSpec::Get(default_cargo)->multiplier;
265 uint16_t cargo_multiplier = CargoSpec::Get(cargo_type)->multiplier;
266 capacity *= cargo_multiplier;
267 if (extra_mail_cap > 0 && IsValidCargoType(GetCargoTypeByLabel(CT_MAIL))) {
268 uint mail_multiplier = CargoSpec::Get(GetCargoTypeByLabel(CT_MAIL))->multiplier;
269 capacity += (default_multiplier * extra_mail_cap * cargo_multiplier + mail_multiplier / 2) / mail_multiplier;
270 }
271 capacity = (capacity + default_multiplier / 2) / default_multiplier;
272 }
273
274 return capacity;
275}
276
282{
283 Price base_price;
284 uint cost_factor;
285 switch (this->type) {
286 case VEH_ROAD:
287 base_price = this->u.road.running_cost_class;
288 if (base_price == INVALID_PRICE) return 0;
289 cost_factor = GetEngineProperty(this->index, PROP_ROADVEH_RUNNING_COST_FACTOR, this->u.road.running_cost);
290 break;
291
292 case VEH_TRAIN:
293 base_price = this->u.rail.running_cost_class;
294 if (base_price == INVALID_PRICE) return 0;
295 cost_factor = GetEngineProperty(this->index, PROP_TRAIN_RUNNING_COST_FACTOR, this->u.rail.running_cost);
296 break;
297
298 case VEH_SHIP:
299 base_price = PR_RUNNING_SHIP;
300 cost_factor = GetEngineProperty(this->index, PROP_SHIP_RUNNING_COST_FACTOR, this->u.ship.running_cost);
301 break;
302
303 case VEH_AIRCRAFT:
304 base_price = PR_RUNNING_AIRCRAFT;
305 cost_factor = GetEngineProperty(this->index, PROP_AIRCRAFT_RUNNING_COST_FACTOR, this->u.air.running_cost);
306 break;
307
308 default: NOT_REACHED();
309 }
310
311 return GetPrice(base_price, cost_factor, this->GetGRF(), -8);
312}
313
319{
320 Price base_price;
321 uint cost_factor;
322 switch (this->type) {
323 case VEH_ROAD:
324 base_price = PR_BUILD_VEHICLE_ROAD;
325 cost_factor = GetEngineProperty(this->index, PROP_ROADVEH_COST_FACTOR, this->u.road.cost_factor);
326 break;
327
328 case VEH_TRAIN:
329 if (this->u.rail.railveh_type == RAILVEH_WAGON) {
330 base_price = PR_BUILD_VEHICLE_WAGON;
331 cost_factor = GetEngineProperty(this->index, PROP_TRAIN_COST_FACTOR, this->u.rail.cost_factor);
332 } else {
333 base_price = PR_BUILD_VEHICLE_TRAIN;
334 cost_factor = GetEngineProperty(this->index, PROP_TRAIN_COST_FACTOR, this->u.rail.cost_factor);
335 }
336 break;
337
338 case VEH_SHIP:
339 base_price = PR_BUILD_VEHICLE_SHIP;
340 cost_factor = GetEngineProperty(this->index, PROP_SHIP_COST_FACTOR, this->u.ship.cost_factor);
341 break;
342
343 case VEH_AIRCRAFT:
344 base_price = PR_BUILD_VEHICLE_AIRCRAFT;
345 cost_factor = GetEngineProperty(this->index, PROP_AIRCRAFT_COST_FACTOR, this->u.air.cost_factor);
346 break;
347
348 default: NOT_REACHED();
349 }
350
351 return GetPrice(base_price, cost_factor, this->GetGRF(), -8);
352}
353
359{
360 switch (this->type) {
361 case VEH_TRAIN:
362 return GetEngineProperty(this->index, PROP_TRAIN_SPEED, this->u.rail.max_speed);
363
364 case VEH_ROAD: {
365 uint max_speed = GetEngineProperty(this->index, PROP_ROADVEH_SPEED, 0);
366 return (max_speed != 0) ? max_speed * 2 : this->u.road.max_speed / 2;
367 }
368
369 case VEH_SHIP:
370 return GetEngineProperty(this->index, PROP_SHIP_SPEED, this->u.ship.max_speed) / 2;
371
372 case VEH_AIRCRAFT: {
373 uint max_speed = GetEngineProperty(this->index, PROP_AIRCRAFT_SPEED, 0);
374 if (max_speed != 0) {
375 return (max_speed * 128) / 10;
376 }
377 return this->u.air.max_speed;
378 }
379
380 default: NOT_REACHED();
381 }
382}
383
391{
392 /* Only trains and road vehicles have 'power'. */
393 switch (this->type) {
394 case VEH_TRAIN:
395 return GetEngineProperty(this->index, PROP_TRAIN_POWER, this->u.rail.power);
396 case VEH_ROAD:
397 return GetEngineProperty(this->index, PROP_ROADVEH_POWER, this->u.road.power) * 10;
398
399 default: NOT_REACHED();
400 }
401}
402
409{
410 /* Only trains and road vehicles have 'weight'. */
411 switch (this->type) {
412 case VEH_TRAIN:
413 return GetEngineProperty(this->index, PROP_TRAIN_WEIGHT, this->u.rail.weight) << (this->u.rail.railveh_type == RAILVEH_MULTIHEAD ? 1 : 0);
414 case VEH_ROAD:
415 return GetEngineProperty(this->index, PROP_ROADVEH_WEIGHT, this->u.road.weight) / 4;
416
417 default: NOT_REACHED();
418 }
419}
420
427{
428 /* Only trains and road vehicles have 'tractive effort'. */
429 switch (this->type) {
430 case VEH_TRAIN:
431 return (GROUND_ACCELERATION * this->GetDisplayWeight() * GetEngineProperty(this->index, PROP_TRAIN_TRACTIVE_EFFORT, this->u.rail.tractive_effort)) / 256;
432 case VEH_ROAD:
433 return (GROUND_ACCELERATION * this->GetDisplayWeight() * GetEngineProperty(this->index, PROP_ROADVEH_TRACTIVE_EFFORT, this->u.road.tractive_effort)) / 256;
434
435 default: NOT_REACHED();
436 }
437}
438
444{
445 /* Assume leap years; this gives the player a bit more than the given amount of years, but never less. */
447}
448
453uint16_t Engine::GetRange() const
454{
455 switch (this->type) {
456 case VEH_AIRCRAFT:
457 return GetEngineProperty(this->index, PROP_AIRCRAFT_RANGE, this->u.air.max_range);
458
459 default: NOT_REACHED();
460 }
461}
462
468{
469 switch (this->type) {
470 case VEH_AIRCRAFT:
471 switch (this->u.air.subtype) {
472 case AIR_HELI: return STR_LIVERY_HELICOPTER;
473 case AIR_CTOL: return STR_LIVERY_SMALL_PLANE;
474 case AIR_CTOL | AIR_FAST: return STR_LIVERY_LARGE_PLANE;
475 default: NOT_REACHED();
476 }
477
478 default: NOT_REACHED();
479 }
480}
481
488{
489 /* In case company is spectator. */
490 if (c >= MAX_COMPANIES) return false;
491
492 /* Shortcut if this engine is explicitly hidden. */
493 if (this->IsHidden(c)) return true;
494
495 /* Check for hidden parent variants. This is a bit convoluted as we must check hidden status of
496 * the last display variant rather than the actual parent variant. */
497 const Engine *re = this;
498 const Engine *ve = re->GetDisplayVariant();
499 while (!(ve->IsHidden(c)) && re->info.variant_id != INVALID_ENGINE) {
500 re = Engine::Get(re->info.variant_id);
501 ve = re->GetDisplayVariant();
502 }
503 return ve->IsHidden(c);
504}
505
510{
511 EngineID id = 0;
512 for (VehicleType type = VEH_TRAIN; type <= VEH_AIRCRAFT; type++) {
513 auto &map = this->mappings[type];
514 map.clear();
515 for (uint internal_id = 0; internal_id < _engine_counts[type]; internal_id++, id++) {
516 map.emplace_back(INVALID_GRFID, internal_id, type, internal_id, id);
517 }
518 }
519}
520
530EngineID EngineOverrideManager::GetID(VehicleType type, uint16_t grf_local_id, uint32_t grfid)
531{
532 const auto &map = this->mappings[type];
533 const auto key = EngineIDMapping::Key(grfid, grf_local_id);
534 auto it = std::ranges::lower_bound(map, key, std::less{}, EngineIDMappingKeyProjection{});
535 if (it == std::end(map) || it->Key() != key) return INVALID_ENGINE;
536 return it->engine;
537}
538
549EngineID EngineOverrideManager::UseUnreservedID(VehicleType type, uint16_t grf_local_id, uint32_t grfid, bool static_access)
550{
551 auto &map = _engine_mngr.mappings[type];
552 const auto key = EngineIDMapping::Key(INVALID_GRFID, grf_local_id);
553 auto it = std::ranges::lower_bound(map, key, std::less{}, EngineIDMappingKeyProjection{});
554 if (it == std::end(map) || it->Key() != key) return INVALID_ENGINE;
555
556 if (!static_access && grfid != INVALID_GRFID) {
557 /* Reserve the engine slot for the new grfid. */
558 it->grfid = grfid;
559
560 /* Relocate entry to its new position in the mapping list to keep it sorted. */
561 auto p = std::ranges::lower_bound(map, EngineIDMapping::Key(grfid, grf_local_id), std::less{}, EngineIDMappingKeyProjection{});
562 it = Slide(it, std::next(it), p).first;
563 }
564
565 return it->engine;
566}
567
568void EngineOverrideManager::SetID(VehicleType type, uint16_t grf_local_id, uint32_t grfid, uint8_t substitute_id, EngineID engine)
569{
570 auto &map = this->mappings[type];
571 const auto key = EngineIDMapping::Key(grfid, grf_local_id);
572 auto it = std::ranges::lower_bound(map, key, std::less{}, EngineIDMappingKeyProjection{});
573 if (it == std::end(map) || it->Key() != key) {
574 map.emplace(it, grfid, grf_local_id, type, substitute_id, engine);
575 } else {
576 it->engine = engine;
577 }
578}
579
586{
587 for (const Vehicle *v : Vehicle::Iterate()) {
588 if (IsCompanyBuildableVehicleType(v)) return false;
589 }
590
591 /* Reset the engines, they will get new EngineIDs */
592 _engine_mngr.ResetToDefaultMapping();
594
595 return true;
596}
597
602{
604 _engine_pool.CleanPool();
605
606 for (VehicleType type = VEH_BEGIN; type != VEH_COMPANY_END; type++) {
607 const auto &mapping = _engine_mngr.mappings[type];
608
609 /* Verify that the engine override manager has at least been set up with the default engines. */
610 assert(std::size(mapping) >= _engine_counts[type]);
611
612 for (const EngineIDMapping &eid : mapping) {
613 new (eid.engine) Engine(type, eid.internal_id);
614 }
615 }
616}
617
618void ShowEnginePreviewWindow(EngineID engine);
619
625static bool IsWagon(EngineID index)
626{
627 const Engine *e = Engine::Get(index);
628 return e->type == VEH_TRAIN && e->u.rail.railveh_type == RAILVEH_WAGON;
629}
630
636static void ClearLastVariant(EngineID engine_id, VehicleType type)
637{
638 for (Engine *e : Engine::IterateType(type)) {
639 if (e->display_last_variant == engine_id) e->display_last_variant = INVALID_ENGINE;
640 }
641}
642
647void CalcEngineReliability(Engine *e, bool new_month)
648{
649 /* Get source engine for reliability age. This is normally our engine unless variant reliability syncing is requested. */
650 Engine *re = e;
651 while (re->info.variant_id != INVALID_ENGINE && re->info.extra_flags.Test(ExtraEngineFlag::SyncReliability)) {
652 re = Engine::Get(re->info.variant_id);
653 }
654
655 uint32_t age = re->age;
656 if (new_month && re->index > e->index && age != INT32_MAX) age++; /* parent variant's age has not yet updated. */
657
658 /* Check for early retirement */
659 if (e->company_avail != 0 && !_settings_game.vehicle.never_expire_vehicles && e->info.base_life != 0xFF) {
660 int retire_early = e->info.retire_early;
661 uint retire_early_max_age = std::max(0, e->duration_phase_1 + e->duration_phase_2 - retire_early * 12);
662 if (retire_early != 0 && age >= retire_early_max_age) {
663 /* Early retirement is enabled and we're past the date... */
664 e->company_avail = 0;
667 }
668 }
669
670 if (age < e->duration_phase_1) {
671 uint start = e->reliability_start;
672 e->reliability = age * (e->reliability_max - start) / e->duration_phase_1 + start;
673 } else if ((age -= e->duration_phase_1) < e->duration_phase_2 || _settings_game.vehicle.never_expire_vehicles || e->info.base_life == 0xFF) {
674 /* We are at the peak of this engines life. It will have max reliability.
675 * This is also true if the engines never expire. They will not go bad over time */
677 } else if ((age -= e->duration_phase_2) < e->duration_phase_3) {
678 uint max = e->reliability_max;
679 e->reliability = (int)age * (int)(e->reliability_final - max) / e->duration_phase_3 + max;
680 } else {
681 /* time's up for this engine.
682 * We will now completely retire this design */
683 e->company_avail = 0;
685 /* Kick this engine out of the lists */
688 }
689
690}
691
694{
695 /* Determine last engine aging year, default to 2050 as previously. */
697
698 for (const Engine *e : Engine::Iterate()) {
699 const EngineInfo *ei = &e->info;
700
701 /* Exclude certain engines */
703 if (e->type == VEH_TRAIN && e->u.rail.railveh_type == RAILVEH_WAGON) continue;
704
705 /* Base year ending date on half the model life */
706 TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(ei->base_intro + (ei->lifelength.base() * CalendarTime::DAYS_IN_LEAP_YEAR) / 2);
707
709 }
710}
711
718void StartupOneEngine(Engine *e, const TimerGameCalendar::YearMonthDay &aging_ymd, uint32_t seed)
719{
720 const EngineInfo *ei = &e->info;
721
722 e->age = 0;
723 e->flags = {};
724 e->company_avail = 0;
725 e->company_hidden = 0;
726
727 /* Vehicles with the same base_intro date shall be introduced at the same time.
728 * Make sure they use the same randomisation of the date. */
729 SavedRandomSeeds saved_seeds;
730 SaveRandomSeeds(&saved_seeds);
732 ei->base_intro.base() ^
733 e->type ^
734 e->GetGRFID());
735 uint32_t r = Random();
736
737 /* Don't randomise the start-date in the first two years after gamestart to ensure availability
738 * of engines in early starting games.
739 * Note: TTDP uses fixed 1922 */
740 e->intro_date = ei->base_intro <= TimerGameCalendar::ConvertYMDToDate(_settings_game.game_creation.starting_year + 2, 0, 1) ? ei->base_intro : (TimerGameCalendar::Date)GB(r, 0, 9) + ei->base_intro;
742 TimerGameCalendar::YearMonthDay intro_ymd = TimerGameCalendar::ConvertDateToYMD(e->intro_date);
743 int aging_months = aging_ymd.year.base() * 12 + aging_ymd.month;
744 int intro_months = intro_ymd.year.base() * 12 + intro_ymd.month;
745 if (intro_ymd.day > 1) intro_months++; // Engines are introduced at the first month start at/after intro date.
746 e->age = aging_months - intro_months;
747 e->company_avail = std::numeric_limits<CompanyMask>::max();
749 }
750
751 /* Get parent variant index for syncing reliability via random seed. */
752 const Engine *re = e;
753 while (re->info.variant_id != INVALID_ENGINE && re->info.extra_flags.Test(ExtraEngineFlag::SyncReliability)) {
754 re = Engine::Get(re->info.variant_id);
755 }
756
758 (re->index << 16) ^ (re->info.base_intro.base() << 12) ^ (re->info.decay_speed << 8) ^
759 (re->info.lifelength.base() << 4) ^ re->info.retire_early ^
760 e->type ^
761 e->GetGRFID());
762
763 /* Base reliability defined as a percentage of UINT16_MAX. */
764 const uint16_t RELIABILITY_START = UINT16_MAX * 48 / 100;
765 const uint16_t RELIABILITY_MAX = UINT16_MAX * 75 / 100;
766 const uint16_t RELIABILITY_FINAL = UINT16_MAX * 25 / 100;
767
768 static_assert(RELIABILITY_START == 0x7AE0);
769 static_assert(RELIABILITY_MAX == 0xBFFF);
770 static_assert(RELIABILITY_FINAL == 0x3FFF);
771
772 r = Random();
773 /* 14 bits gives a value between 0 and 16383, which is up to an additional 25%p reliability on top of the base reliability. */
774 e->reliability_start = GB(r, 16, 14) + RELIABILITY_START;
775 e->reliability_max = GB(r, 0, 14) + RELIABILITY_MAX;
776
777 r = Random();
778 e->reliability_final = GB(r, 16, 14) + RELIABILITY_FINAL;
779
780 e->duration_phase_1 = GB(r, 0, 5) + 7;
781 e->duration_phase_2 = std::max(0, int(GB(r, 5, 4)) + ei->base_life.base() * 12 - 96);
782 e->duration_phase_3 = GB(r, 9, 7) + 120;
783
784 RestoreRandomSeeds(saved_seeds);
785
786 e->reliability_spd_dec = ei->decay_speed << 2;
787
788 /* prevent certain engines from ever appearing. */
791 e->company_avail = 0;
792 }
793}
794
800{
801 /* Aging of vehicles stops, so account for that when starting late */
802 const TimerGameCalendar::Date aging_date = std::min(TimerGameCalendar::date, TimerGameCalendar::ConvertYMDToDate(_year_engine_aging_stops, 0, 1));
803 TimerGameCalendar::YearMonthDay aging_ymd = TimerGameCalendar::ConvertDateToYMD(aging_date);
804 uint32_t seed = Random();
805
806 for (Engine *e : Engine::Iterate()) {
807 StartupOneEngine(e, aging_ymd, seed);
808 }
809 for (Engine *e : Engine::Iterate()) {
810 CalcEngineReliability(e, false);
811 }
812
813 /* Update the bitmasks for the vehicle lists */
814 for (Company *c : Company::Iterate()) {
815 c->avail_railtypes = GetCompanyRailTypes(c->index);
816 c->avail_roadtypes = GetCompanyRoadTypes(c->index);
817 }
818
819 /* Invalidate any open purchase lists */
821
824}
825
832{
833 Engine *e = Engine::Get(eid);
834 Company *c = Company::Get(company);
835
836 SetBit(e->company_avail, company);
837 if (e->type == VEH_TRAIN) {
839 } else if (e->type == VEH_ROAD) {
841 }
842
843 if (company == _local_company) {
845
846 /* Update the toolbar. */
851 }
852}
853
860{
861 Engine *e = Engine::Get(eid);
862 Company *c = Company::Get(company);
863
864 ClrBit(e->company_avail, company);
865 if (e->type == VEH_TRAIN) {
867 } else if (e->type == VEH_ROAD) {
869 }
870
871 if (company == _local_company) {
874 }
875}
876
883static void AcceptEnginePreview(EngineID eid, CompanyID company, int recursion_depth = 0)
884{
885 Engine *e = Engine::Get(eid);
886
888 e->preview_asked = std::numeric_limits<CompanyMask>::max();
889
890 EnableEngineForCompany(eid, company);
891
892 /* Notify preview window, that it might want to close.
893 * Note: We cannot directly close the window.
894 * In singleplayer this function is called from the preview window, so
895 * we have to use the GUI-scope scheduling of InvalidateWindowData.
896 */
898
899 /* Don't search for variants to include if we are 10 levels deep already. */
900 if (recursion_depth >= 10) return;
901
902 /* Find variants to be included in preview. */
903 for (Engine *ve : Engine::IterateType(e->type)) {
904 if (ve->index != eid && ve->info.variant_id == eid && ve->info.extra_flags.Test(ExtraEngineFlag::JoinPreview)) {
905 AcceptEnginePreview(ve->index, company, recursion_depth + 1);
906 }
907 }
908}
909
916{
917 CompanyID best_company = INVALID_COMPANY;
918
919 /* For trains the cargomask has no useful meaning, since you can attach other wagons */
920 CargoTypes cargomask = e->type != VEH_TRAIN ? GetUnionOfArticulatedRefitMasks(e->index, true) : ALL_CARGOTYPES;
921
922 int32_t best_hist = -1;
923 for (const Company *c : Company::Iterate()) {
924 if (c->block_preview == 0 && !HasBit(e->preview_asked, c->index) &&
925 c->old_economy[0].performance_history > best_hist) {
926
927 /* Check whether the company uses similar vehicles */
928 for (const Vehicle *v : Vehicle::Iterate()) {
929 if (v->owner != c->index || v->type != e->type) continue;
930 if (!v->GetEngine()->CanCarryCargo() || !HasBit(cargomask, v->cargo_type)) continue;
931
932 best_hist = c->old_economy[0].performance_history;
933 best_company = c->index;
934 break;
935 }
936 }
937 }
938
939 return best_company;
940}
941
949static bool IsVehicleTypeDisabled(VehicleType type, bool ai)
950{
951 switch (type) {
956
957 default: NOT_REACHED();
958 }
959}
960
962static IntervalTimer<TimerGameCalendar> _calendar_engines_daily({TimerGameCalendar::DAY, TimerGameCalendar::Priority::ENGINE}, [](auto)
963{
964 for (Company *c : Company::Iterate()) {
965 c->avail_railtypes = AddDateIntroducedRailTypes(c->avail_railtypes, TimerGameCalendar::date);
966 c->avail_roadtypes = AddDateIntroducedRoadTypes(c->avail_roadtypes, TimerGameCalendar::date);
967 }
968
970
971 for (Engine *e : Engine::Iterate()) {
972 EngineID i = e->index;
973 if (e->flags.Test(EngineFlag::ExclusivePreview)) {
974 if (e->preview_company != INVALID_COMPANY) {
975 if (!--e->preview_wait) {
977 e->preview_company = INVALID_COMPANY;
978 }
979 } else if (CountBits(e->preview_asked) < MAX_COMPANIES) {
980 e->preview_company = GetPreviewCompany(e);
981
982 if (e->preview_company == INVALID_COMPANY) {
983 e->preview_asked = std::numeric_limits<CompanyMask>::max();
984 continue;
985 }
986
987 SetBit(e->preview_asked, e->preview_company);
988 e->preview_wait = 20;
989 /* AIs are intentionally not skipped for preview even if they cannot build a certain
990 * vehicle type. This is done to not give poor performing human companies an "unfair"
991 * boost that they wouldn't have gotten against other human companies. The check on
992 * the line below is just to make AIs not notice that they have a preview if they
993 * cannot build the vehicle. */
994 if (!IsVehicleTypeDisabled(e->type, true)) AI::NewEvent(e->preview_company, new ScriptEventEnginePreview(i));
995 if (IsInteractiveCompany(e->preview_company)) ShowEnginePreviewWindow(i);
996 }
997 }
998 }
999});
1000
1006{
1007 for (Engine *e : Engine::Iterate()) {
1008 SB(e->company_hidden, cid, 1, 0);
1009 }
1010}
1011
1020{
1021 Engine *e = Engine::GetIfValid(engine_id);
1022 if (e == nullptr || _current_company >= MAX_COMPANIES) return CMD_ERROR;
1024
1025 if ((flags & DC_EXEC) != 0) {
1028 }
1029
1030 return CommandCost();
1031}
1032
1041{
1042 Engine *e = Engine::GetIfValid(engine_id);
1043 if (e == nullptr || !e->flags.Test(EngineFlag::ExclusivePreview) || e->preview_company != _current_company) return CMD_ERROR;
1044
1045 if (flags & DC_EXEC) AcceptEnginePreview(engine_id, _current_company);
1046
1047 return CommandCost();
1048}
1049
1058CommandCost CmdEngineCtrl(DoCommandFlag flags, EngineID engine_id, CompanyID company_id, bool allow)
1059{
1060 if (_current_company != OWNER_DEITY) return CMD_ERROR;
1061
1062 if (!Engine::IsValidID(engine_id) || !Company::IsValidID(company_id)) return CMD_ERROR;
1063
1064 if (flags & DC_EXEC) {
1065 if (allow) {
1066 EnableEngineForCompany(engine_id, company_id);
1067 } else {
1068 DisableEngineForCompany(engine_id, company_id);
1069 }
1070 }
1071
1072 return CommandCost();
1073}
1074
1081{
1082 EngineID index = e->index;
1083
1084 /* In case the company didn't build the vehicle during the intro period,
1085 * prevent that company from getting future intro periods for a while. */
1087 for (Company *c : Company::Iterate()) {
1088 uint block_preview = c->block_preview;
1089
1090 if (!HasBit(e->company_avail, c->index)) continue;
1091
1092 /* We assume the user did NOT build it.. prove me wrong ;) */
1093 c->block_preview = 20;
1094
1095 for (const Vehicle *v : Vehicle::Iterate()) {
1096 if (v->type == VEH_TRAIN || v->type == VEH_ROAD || v->type == VEH_SHIP ||
1097 (v->type == VEH_AIRCRAFT && Aircraft::From(v)->IsNormalAircraft())) {
1098 if (v->owner == c->index && v->engine_type == index) {
1099 /* The user did prove me wrong, so restore old value */
1100 c->block_preview = block_preview;
1101 break;
1102 }
1103 }
1104 }
1105 }
1106 }
1107
1110
1111 /* Now available for all companies */
1112 e->company_avail = std::numeric_limits<CompanyMask>::max();
1113
1114 /* Do not introduce new rail wagons */
1115 if (IsWagon(index)) return;
1116
1117 if (e->type == VEH_TRAIN) {
1118 /* maybe make another rail type available */
1119 assert(e->u.rail.railtype < RAILTYPE_END);
1120 for (Company *c : Company::Iterate()) c->avail_railtypes = AddDateIntroducedRailTypes(c->avail_railtypes | GetRailTypeInfo(e->u.rail.railtype)->introduces_railtypes, TimerGameCalendar::date);
1121 } else if (e->type == VEH_ROAD) {
1122 /* maybe make another road type available */
1123 assert(e->u.road.roadtype < ROADTYPE_END);
1124 for (Company *c : Company::Iterate()) c->avail_roadtypes = AddDateIntroducedRoadTypes(c->avail_roadtypes | GetRoadTypeInfo(e->u.road.roadtype)->introduces_roadtypes, TimerGameCalendar::date);
1125 }
1126
1127 /* Only broadcast event if AIs are able to build this vehicle type. */
1128 if (!IsVehicleTypeDisabled(e->type, true)) AI::BroadcastNewEvent(new ScriptEventEngineAvailable(index));
1129
1130 /* Only provide the "New Vehicle available" news paper entry, if engine can be built. */
1131 if (!IsVehicleTypeDisabled(e->type, false) && !e->info.extra_flags.Test(ExtraEngineFlag::NoNews)) {
1134 AddNewsItem(STR_NEWS_NEW_VEHICLE_NOW_AVAILABLE_WITH_TYPE, NT_NEW_VEHICLES, NF_VEHICLE, NR_ENGINE, index);
1135 }
1136
1137 /* Update the toolbar. */
1141
1142 /* Close pending preview windows */
1144}
1145
1148{
1150 bool refresh = false;
1151 for (Engine *e : Engine::Iterate()) {
1152 /* Age the vehicle */
1153 if (e->flags.Test(EngineFlag::Available) && e->age != INT32_MAX) {
1154 e->age++;
1155 CalcEngineReliability(e, true);
1156 refresh = true;
1157 }
1158
1159 /* Do not introduce invalid engines */
1160 if (!e->IsEnabled()) continue;
1161
1162 if (!e->flags.Test(EngineFlag::Available) && TimerGameCalendar::date >= (e->intro_date + CalendarTime::DAYS_IN_YEAR)) {
1163 /* Introduce it to all companies */
1165 } else if (!e->flags.Any({EngineFlag::Available, EngineFlag::ExclusivePreview}) && TimerGameCalendar::date >= e->intro_date) {
1166 /* Introduction date has passed...
1167 * Check if it is allowed to build this vehicle type at all
1168 * based on the current game settings. If not, it does not
1169 * make sense to show the preview dialog to any company. */
1170 if (IsVehicleTypeDisabled(e->type, false)) continue;
1171
1172 /* Do not introduce new rail wagons */
1173 if (IsWagon(e->index)) continue;
1174
1175 /* Engine has no preview */
1176 if (e->info.extra_flags.Test(ExtraEngineFlag::NoPreview)) continue;
1177
1178 /* Show preview dialog to one of the companies. */
1179 e->flags.Set(EngineFlag::ExclusivePreview);
1180 e->preview_company = INVALID_COMPANY;
1181 e->preview_asked = 0;
1182 }
1183 }
1184
1185 InvalidateWindowClassesData(WC_BUILD_VEHICLE); // rebuild the purchase list (esp. when sorted by reliability)
1186
1187 if (refresh) {
1190 }
1191 }
1192}
1193
1194static IntervalTimer<TimerGameCalendar> _calendar_engines_monthly({TimerGameCalendar::MONTH, TimerGameCalendar::Priority::ENGINE}, [](auto)
1195{
1197});
1198
1204static bool IsUniqueEngineName(const std::string &name)
1205{
1206 for (const Engine *e : Engine::Iterate()) {
1207 if (!e->name.empty() && e->name == name) return false;
1208 }
1209
1210 return true;
1211}
1212
1220CommandCost CmdRenameEngine(DoCommandFlag flags, EngineID engine_id, const std::string &text)
1221{
1222 Engine *e = Engine::GetIfValid(engine_id);
1223 if (e == nullptr) return CMD_ERROR;
1224
1225 bool reset = text.empty();
1226
1227 if (!reset) {
1229 if (!IsUniqueEngineName(text)) return CommandCost(STR_ERROR_NAME_MUST_BE_UNIQUE);
1230 }
1231
1232 if (flags & DC_EXEC) {
1233 if (reset) {
1234 e->name.clear();
1235 } else {
1236 e->name = text;
1237 }
1238
1240 }
1241
1242 return CommandCost();
1243}
1244
1245
1255{
1256 const Engine *e = Engine::GetIfValid(engine);
1257
1258 /* check if it's an engine that is in the engine array */
1259 if (e == nullptr) return false;
1260
1261 /* check if it's an engine of specified type */
1262 if (e->type != type) return false;
1263
1264 /* check if it's available ... */
1265 if (company == OWNER_DEITY) {
1266 /* ... for any company (preview does not count) */
1267 if (!e->flags.Test(EngineFlag::Available) || e->company_avail == 0) return false;
1268 } else {
1269 /* ... for this company */
1270 if (!HasBit(e->company_avail, company)) return false;
1271 }
1272
1273 if (!e->IsEnabled()) return false;
1274
1275 if (type == VEH_TRAIN && company != OWNER_DEITY) {
1276 /* Check if the rail type is available to this company */
1277 const Company *c = Company::Get(company);
1278 if (((GetRailTypeInfo(e->u.rail.railtype))->compatible_railtypes & c->avail_railtypes) == 0) return false;
1279 }
1280 if (type == VEH_ROAD && company != OWNER_DEITY) {
1281 /* Check if the road type is available to this company */
1282 const Company *c = Company::Get(company);
1283 if ((GetRoadTypeInfo(e->u.road.roadtype)->powered_roadtypes & c->avail_roadtypes) == ROADTYPES_NONE) return false;
1284 }
1285
1286 return true;
1287}
1288
1296{
1297 const Engine *e = Engine::GetIfValid(engine);
1298
1299 /* check if it's an engine that is in the engine array */
1300 if (e == nullptr) return false;
1301
1302 if (!e->CanCarryCargo()) return false;
1303
1304 const EngineInfo *ei = &e->info;
1305 if (ei->refit_mask == 0) return false;
1306
1307 /* Are there suffixes?
1308 * Note: This does not mean the suffixes are actually available for every consist at any time. */
1310
1311 /* Is there any cargo except the default cargo? */
1312 CargoType default_cargo = e->GetDefaultCargoType();
1313 CargoTypes default_cargo_mask = 0;
1314 SetBit(default_cargo_mask, default_cargo);
1315 return IsValidCargoType(default_cargo) && ei->refit_mask != default_cargo_mask;
1316}
1317
1322{
1323 TimerGameCalendar::Date min_date{INT32_MAX};
1324
1325 for (const Engine *e : Engine::Iterate()) {
1326 if (!e->IsEnabled()) continue;
1327
1328 /* Don't consider train wagons, we need a powered engine available. */
1329 if (e->type == VEH_TRAIN && e->u.rail.railveh_type == RAILVEH_WAGON) continue;
1330
1331 /* We have an available engine... yay! */
1332 if (e->flags.Test(EngineFlag::Available) && e->company_avail != 0) return;
1333
1334 /* Okay, try to find the earliest date. */
1335 min_date = std::min(min_date, e->info.base_intro);
1336 }
1337
1338 if (min_date < INT32_MAX) {
1339 SetDParam(0, min_date);
1340 ShowErrorMessage(STR_ERROR_NO_VEHICLES_AVAILABLE_YET, STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION, WL_WARNING);
1341 } else {
1342 ShowErrorMessage(STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL, STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION, WL_WARNING);
1343 }
1344}
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.
debug_inline constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr T AssignBit(T &x, const uint8_t y, bool value)
Assigns a bit in a variable.
constexpr T SB(T &x, const uint8_t s, const uint8_t n, const U d)
Set n bits in x starting at bit s to d.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
constexpr uint CountBits(T value)
Counts the number of set bits 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.
constexpr T ClrBit(T &x, const uint8_t y)
Clears a bit in a variable.
static constexpr CargoLabel CT_INVALID
Invalid cargo type.
Definition cargo_type.h:71
uint8_t CargoType
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:22
bool IsValidCargoType(CargoType t)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:105
static constexpr CargoLabel CT_PASSENGERS
Available types of cargo Labels may be re-used between different climates.
Definition cargo_type.h:30
bool IsCargoInClass(CargoType c, CargoClass cc)
Does cargo c have cargo class cc?
Definition cargotype.h:240
@ CC_PASSENGERS
Passengers.
Definition cargotype.h:51
static void BroadcastNewEvent(ScriptEvent *event, CompanyID skip_company=MAX_COMPANIES)
Broadcast a new event to all active AIs.
Definition ai_core.cpp:263
static void NewEvent(CompanyID company, ScriptEvent *event)
Queue a new event for an AI.
Definition ai_core.cpp:243
Common return value for all commands.
constexpr EnumBitSet & Set(Tenum value)
Set the enum value.
constexpr EnumBitSet & Reset(Tenum value)
Reset the enum value to not set.
constexpr bool Test(Tenum value) const
Test if the enum value is set.
An interval timer will fire every interval, and will continue to fire until it is deleted.
Definition timer.h:76
RailTypes introduces_railtypes
Bitmask of which other railtypes are introduced when this railtype is introduced.
Definition rail.h:256
RoadTypes powered_roadtypes
bitmask to the OTHER roadtypes on which a vehicle of THIS roadtype generates power
Definition road.h:112
RoadTypes introduces_roadtypes
Bitmask of which other roadtypes are introduced when this roadtype is introduced.
Definition road.h:167
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.
DoCommandFlag
List of flags for a command.
@ DC_EXEC
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?
Owner
Enum for all companies/owners.
@ INVALID_COMPANY
An invalid company.
@ OWNER_DEITY
The object is owned by a superuser / goal script.
@ MAX_COMPANIES
Maximum number of companies.
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:966
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:1005
void SetYearEngineAgingStops()
Compute the value for _year_engine_aging_stops.
Definition engine.cpp:693
static void NewVehicleAvailable(Engine *e)
An engine has become available for general use.
Definition engine.cpp:1080
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:601
CommandCost CmdSetVehicleVisibility(DoCommandFlag flags, EngineID engine_id, bool hide)
Set the visibility of an engine.
Definition engine.cpp:1019
static CompanyID GetPreviewCompany(Engine *e)
Get the best company for an engine preview.
Definition engine.cpp:915
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:636
static bool IsVehicleTypeDisabled(VehicleType type, bool ai)
Checks if a vehicle type is disabled for all/ai companies.
Definition engine.cpp:949
CommandCost CmdWantEnginePreview(DoCommandFlag flags, EngineID engine_id)
Accept an engine prototype.
Definition engine.cpp:1040
CommandCost CmdEngineCtrl(DoCommandFlag flags, EngineID engine_id, CompanyID company_id, bool allow)
Allow or forbid a specific company to use an engine.
Definition engine.cpp:1058
static void AcceptEnginePreview(EngineID eid, CompanyID company, int recursion_depth=0)
Company company accepts engine eid for preview.
Definition engine.cpp:883
void CalendarEnginesMonthlyLoop()
Monthly update of the availability, reliability, and preview offers of the engines.
Definition engine.cpp:1147
static bool IsUniqueEngineName(const std::string &name)
Is name still free as name for an engine?
Definition engine.cpp:1204
bool IsEngineBuildable(EngineID engine, VehicleType type, CompanyID company)
Check if an engine is buildable.
Definition engine.cpp:1254
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:859
void StartupEngines()
Start/initialise all our engines.
Definition engine.cpp:799
static bool IsWagon(EngineID index)
Determine whether an engine type is a wagon (and not a loco).
Definition engine.cpp:625
void StartupOneEngine(Engine *e, const TimerGameCalendar::YearMonthDay &aging_ymd, uint32_t seed)
Start/initialise one engine.
Definition engine.cpp:718
void CheckEngines()
Check for engines that have an appropriate availability.
Definition engine.cpp:1321
static 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 !=INVALID_COMPANY) { if(!--e->preview_wait) { CloseWindowById(WC_ENGINE_PREVIEW, i);e->preview_company=INVALID_COMPANY;} } else if(CountBits(e->preview_asked)< MAX_COMPANIES) { e->preview_company=GetPreviewCompany(e);if(e->preview_company==INVALID_COMPANY) { e->preview_asked=std::numeric_limits< CompanyMask >::max();continue;} SetBit(e->preview_asked, 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.
bool IsEngineRefittable(EngineID engine)
Check if an engine is refittable.
Definition engine.cpp:1295
void CalcEngineReliability(Engine *e, bool new_month)
Update Engine::reliability and (if needed) update the engine GUIs.
Definition engine.cpp:647
static void EnableEngineForCompany(EngineID eid, CompanyID company)
Allows engine eid to be used by a company company.
Definition engine.cpp:831
CommandCost CmdRenameEngine(DoCommandFlag flags, EngineID engine_id, const std::string &text)
Rename an engine.
Definition engine.cpp:1220
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.
Definition engine_type.h:97
@ 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'.
static const EngineID INVALID_ENGINE
Constant denoting an invalid engine.
uint16_t EngineID
Unique identification number of an engine.
Definition engine_type.h:23
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:31
@ RAILVEH_MULTIHEAD
indicates a combination of two locomotives
Definition engine_type.h:30
This file contains all the data for vehicles.
Functions related to errors.
@ WL_WARNING
Other information.
Definition error.h:25
void ShowErrorMessage(StringID summary_msg, int x, int y, CommandCost cc)
Display an error message in a window.
void MarkWholeScreenDirty()
This function mark the whole screen as dirty.
Definition gfx.cpp:1529
@ 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)
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(StringID string, NewsType type, NewsFlag flags, NewsReferenceType reftype1=NR_NONE, uint32_t ref1=UINT32_MAX, NewsReferenceType reftype2=NR_NONE, uint32_t ref2=UINT32_MAX, std::unique_ptr< NewsAllocatedData > &&data=nullptr, AdviceType advice_type=AdviceType::Invalid)
Add a new newsitem to be shown.
Definition news_gui.cpp:899
@ NT_NEW_VEHICLES
New vehicle has become available.
Definition news_type.h:36
@ NR_ENGINE
Reference engine.
Definition news_type.h:74
@ NF_VEHICLE
Vehicle news item. (new engine available)
Definition news_type.h:97
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:251
RailTypes AddDateIntroducedRailTypes(RailTypes current, TimerGameCalendar::Date date)
Add the rail types that are to be introduced at the given date.
Definition rail.cpp:218
const RailTypeInfo * GetRailTypeInfo(RailType railtype)
Returns a pointer to the Railtype information for a given railtype.
Definition rail.h:297
@ RAILTYPE_END
Used for iterations.
Definition rail_type.h:33
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:199
RoadTypes AddDateIntroducedRoadTypes(RoadTypes current, TimerGameCalendar::Date date)
Add the road types that are to be introduced at the given date.
Definition road.cpp:166
const RoadTypeInfo * GetRoadTypeInfo(RoadType roadtype)
Returns a pointer to the Roadtype information for a given roadtype.
Definition road.h:217
@ ROADTYPES_NONE
No roadtypes.
Definition road_type.h:39
@ ROADTYPE_END
Used for iterations.
Definition road_type.h:29
A number of safeguards to prevent using unsafe methods.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition settings.cpp:57
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:277
size_t Utf8StringLength(const char *s)
Get the length of an UTF-8 encoded string in number of characters and thus not the number of bytes th...
Definition string.cpp:359
Functions related to low-level strings.
void SetDParam(size_t n, uint64_t v)
Set a string parameter v at index n in the global string parameter array.
Definition strings.cpp:104
Functions related to OTTD's strings.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
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
bool IsNormalAircraft() const
Check if the aircraft type is a normal flying device; eg not a rotor or a shadow.
Definition aircraft.h:121
uint16_t multiplier
Capacity multiplier for vehicles. (8 fractional bits)
Definition cargotype.h:83
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo type.
Definition cargotype.h:140
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.
uint16_t cargo_age_period
Number of ticks before carried cargo is aged.
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:585
void ResetToDefaultMapping()
Initializes the EngineOverrideManager with the default engines.
Definition engine.cpp:509
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:549
EngineID GetID(VehicleType type, uint16_t grf_local_id, uint32_t grfid)
Looks up an EngineID in the EngineOverrideManager.
Definition engine.cpp:530
StringID GetAircraftTypeText() const
Get the name of the aircraft type for display purposes.
Definition engine.cpp:467
uint GetPower() const
Returns the power of the engine for display and sorting purposes.
Definition engine.cpp:390
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:453
GRFFilePropsBase< NUM_CARGO+2 > grf_prop
Properties related the the grf file.
Definition engine_base.h:83
uint32_t GetGRFID() const
Retrieve the GRF ID of the NewGRF the engine is tied to.
Definition engine.cpp:157
uint16_t reliability_spd_dec
Speed of reliability decay between services (per day).
Definition engine_base.h:49
Money GetCost() const
Return how much a new engine costs.
Definition engine.cpp:318
uint16_t reliability_start
Initial reliability of the engine.
Definition engine_base.h:50
TimerGameCalendar::Date intro_date
Date of introduction of the engine.
Definition engine_base.h:45
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:358
uint DetermineCapacity(const Vehicle *v, uint16_t *mail_capacity=nullptr) const
Determines capacity of a given vehicle from scratch.
Definition engine.cpp:201
EngineFlags flags
Flags of the engine.
Definition engine_base.h:56
CompanyMask company_avail
Bit for each company whether the engine is available for that company.
Definition engine_base.h:39
uint16_t reliability_max
Maximal reliability of the engine.
Definition engine_base.h:51
uint GetDisplayWeight() const
Returns the weight of the engine for display purposes.
Definition engine.cpp:408
uint8_t original_image_index
Original vehicle image index, thus the image index of the overridden vehicle.
Definition engine_base.h:60
bool IsEnabled() const
Checks whether the engine is a valid (non-articulated part of an) engine.
Definition engine.cpp:147
VehicleType type
Vehicle type, ie VEH_ROAD, VEH_TRAIN, etc.
Definition engine_base.h:61
bool IsVariantHidden(CompanyID c) const
Check whether the engine variant chain is hidden in the GUI for the given company.
Definition engine.cpp:487
uint16_t reliability_final
Final reliability of the engine.
Definition engine_base.h:52
CompanyID preview_company
Company which is currently being offered a preview INVALID_COMPANY means no company.
Definition engine_base.h:58
TimerGameCalendar::Date GetLifeLengthInDays() const
Returns the vehicle's (not model's!) life length in days.
Definition engine.cpp:443
uint16_t duration_phase_3
Third reliability phase in months, decaying to reliability_final.
Definition engine_base.h:55
uint16_t duration_phase_2
Second reliability phase in months, keeping reliability_max.
Definition engine_base.h:54
CargoType GetDefaultCargoType() const
Determines the default cargo type of an engine.
CompanyMask company_hidden
Bit for each company whether the engine is normally hidden in the build gui for that company.
Definition engine_base.h:40
Money GetRunningCost() const
Return how much the running costs of this engine are.
Definition engine.cpp:281
uint16_t reliability
Current reliability of the engine.
Definition engine_base.h:48
CompanyMask preview_asked
Bit for each company which has already been offered a preview.
Definition engine_base.h:41
uint GetDisplayMaxTractiveEffort() const
Returns the tractive effort of the engine for display purposes.
Definition engine.cpp:426
int32_t age
Age of the engine in months.
Definition engine_base.h:46
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:168
std::string name
Custom name of engine.
Definition engine_base.h:43
EngineID display_last_variant
NOSAVE client-side-only last variant selected.
Definition engine_base.h:64
uint16_t duration_phase_1
First reliability phase in months, increasing reliability from reliability_start to reliability_max.
Definition engine_base.h:53
uint16_t local_id
id defined by the grf file for this entity
Dynamic data of a loaded NewGRF.
Definition newgrf.h:109
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
Tindex index
Index of this pool item.
static bool IsValidID(size_t index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
static Titem * GetIfValid(size_t index)
Returns Titem with given index.
static Titem * Get(size_t index)
Returns Titem with given index.
Base class for all pools.
Definition pool_type.hpp:79
void CleanPool() override
Virtual method that deletes all items in the pool.
RailType railtype
Railtype, mangled if elrail is disabled.
Definition engine_type.h:48
RoadType roadtype
Road type.
Stores the state of all random number generators.
static Aircraft * From(Vehicle *v)
Converts a Vehicle to SpecializedVehicle with type checking.
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.
@ VE_DEFAULT
Default value to indicate that visual effect should be based on engine class.
Functions related to vehicles.
bool IsCompanyBuildableVehicleType(VehicleType type)
Is the given vehicle type buildable by a company?
VehicleType
Available vehicle types.
@ 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:1137
void CloseWindowByClass(WindowClass cls, int data)
Close all windows of a given class.
Definition window.cpp:1149
void SetWindowClassesDirty(WindowClass cls)
Mark all windows of a particular class as dirty (in need of repainting)
Definition window.cpp:3125
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:3217
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:3234
Window functions not directly related to making/drawing windows.
@ WC_BUILD_TOOLBAR
Build toolbar; Window numbers:
Definition window_type.h:75
@ 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:60
@ WC_BUILD_VEHICLE
Build vehicle; Window numbers: