OpenTTD Source 20260311-master-g511d3794ce
vehicle_cmd.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
10#include "stdafx.h"
11#include "roadveh.h"
12#include "news_func.h"
13#include "airport.h"
14#include "command_func.h"
15#include "company_func.h"
16#include "train.h"
17#include "aircraft.h"
18#include "newgrf_text.h"
19#include "vehicle_func.h"
20#include "string_func.h"
21#include "depot_map.h"
22#include "vehiclelist.h"
23#include "engine_func.h"
25#include "autoreplace_gui.h"
26#include "group.h"
27#include "order_backup.h"
28#include "ship.h"
29#include "newgrf.h"
30#include "company_base.h"
31#include "core/random_func.hpp"
32#include "vehicle_cmd.h"
33#include "aircraft_cmd.h"
34#include "autoreplace_cmd.h"
35#include "group_cmd.h"
36#include "order_cmd.h"
37#include "roadveh_cmd.h"
38#include "train_cmd.h"
39#include "ship_cmd.h"
40#include <charconv>
41
42#include "table/strings.h"
43
44#include "safeguards.h"
45
53 STR_ERROR_CAN_T_BUY_TRAIN,
54 STR_ERROR_CAN_T_BUY_ROAD_VEHICLE,
55 STR_ERROR_CAN_T_BUY_SHIP,
56 STR_ERROR_CAN_T_BUY_AIRCRAFT,
57};
58
61 STR_ERROR_CAN_T_SELL_TRAIN,
62 STR_ERROR_CAN_T_SELL_ROAD_VEHICLE,
63 STR_ERROR_CAN_T_SELL_SHIP,
64 STR_ERROR_CAN_T_SELL_AIRCRAFT,
65};
66
69 STR_ERROR_CAN_T_SELL_ALL_TRAIN,
70 STR_ERROR_CAN_T_SELL_ALL_ROAD_VEHICLE,
71 STR_ERROR_CAN_T_SELL_ALL_SHIP,
72 STR_ERROR_CAN_T_SELL_ALL_AIRCRAFT,
73};
74
77 STR_ERROR_CAN_T_AUTOREPLACE_TRAIN,
78 STR_ERROR_CAN_T_AUTOREPLACE_ROAD_VEHICLE,
79 STR_ERROR_CAN_T_AUTOREPLACE_SHIP,
80 STR_ERROR_CAN_T_AUTOREPLACE_AIRCRAFT,
81};
82
85 STR_ERROR_CAN_T_REFIT_TRAIN,
86 STR_ERROR_CAN_T_REFIT_ROAD_VEHICLE,
87 STR_ERROR_CAN_T_REFIT_SHIP,
88 STR_ERROR_CAN_T_REFIT_AIRCRAFT,
89};
90
93 STR_ERROR_CAN_T_SEND_TRAIN_TO_DEPOT,
94 STR_ERROR_CAN_T_SEND_ROAD_VEHICLE_TO_DEPOT,
95 STR_ERROR_CAN_T_SEND_SHIP_TO_DEPOT,
96 STR_ERROR_CAN_T_SEND_AIRCRAFT_TO_HANGAR,
97};
98
99
100
111std::tuple<CommandCost, VehicleID, uint, uint16_t, CargoArray> CmdBuildVehicle(DoCommandFlags flags, TileIndex tile, EngineID eid, bool use_free_vehicles, CargoType cargo, ClientID client_id)
112{
113 /* Elementary check for valid location. */
114 if (!IsDepotTile(tile) || !IsTileOwner(tile, _current_company)) return { CMD_ERROR, VehicleID::Invalid(), 0, 0, {} };
115
116 VehicleType type = GetDepotVehicleType(tile);
117
118 /* Validate the engine type. */
119 if (!IsEngineBuildable(eid, type, _current_company)) return { CommandCost(STR_ERROR_RAIL_VEHICLE_NOT_AVAILABLE + type), VehicleID::Invalid(), 0, 0, {} };
120
121 /* Validate the cargo type. */
122 if (cargo >= NUM_CARGO && IsValidCargoType(cargo)) return { CMD_ERROR, VehicleID::Invalid(), 0, 0, {} };
123
124 const Engine *e = Engine::Get(eid);
126
127 /* Engines without valid cargo should not be available */
128 CargoType default_cargo = e->GetDefaultCargoType();
129 if (!IsValidCargoType(default_cargo)) return { CMD_ERROR, VehicleID::Invalid(), 0, 0, {} };
130
131 bool refitting = IsValidCargoType(cargo) && cargo != default_cargo;
132
133 /* Check whether the number of vehicles we need to build can be built according to pool space. */
134 uint num_vehicles;
135 switch (type) {
136 case VEH_TRAIN: num_vehicles = (e->VehInfo<RailVehicleInfo>().railveh_type == RAILVEH_MULTIHEAD ? 2 : 1) + CountArticulatedParts(eid); break;
137 case VEH_ROAD: num_vehicles = 1 + CountArticulatedParts(eid); break;
138 case VEH_SHIP: num_vehicles = 1; break;
139 case VEH_AIRCRAFT: num_vehicles = e->VehInfo<AircraftVehicleInfo>().subtype & AIR_CTOL ? 2 : 3; break;
140 default: NOT_REACHED(); // Safe due to IsDepotTile()
141 }
142 if (!Vehicle::CanAllocateItem(num_vehicles)) return { CommandCost(STR_ERROR_TOO_MANY_VEHICLES_IN_GAME), VehicleID::Invalid(), 0, 0, {} };
143
144 /* Check whether we can allocate a unit number. Autoreplace does not allocate
145 * an unit number as it will (always) reuse the one of the replaced vehicle
146 * and (train) wagons don't have an unit number in any scenario. */
147 UnitID unit_num = (flags.Test(DoCommandFlag::QueryCost) || flags.Test(DoCommandFlag::AutoReplace) || (type == VEH_TRAIN && e->VehInfo<RailVehicleInfo>().railveh_type == RAILVEH_WAGON)) ? 0 : GetFreeUnitNumber(type);
148 if (unit_num == UINT16_MAX) return { CommandCost(STR_ERROR_TOO_MANY_VEHICLES_IN_GAME), VehicleID::Invalid(), 0, 0, {} };
149
150 /* If we are refitting we need to temporarily purchase the vehicle to be able to
151 * test it. */
152 DoCommandFlags subflags = flags;
154
155 /* Vehicle construction needs random bits, so we have to save the random
156 * seeds to prevent desyncs. */
157 SavedRandomSeeds saved_seeds;
158 SaveRandomSeeds(&saved_seeds);
159
160 Vehicle *v = nullptr;
161 switch (type) {
162 case VEH_TRAIN: value.AddCost(CmdBuildRailVehicle(subflags, tile, e, &v)); break;
163 case VEH_ROAD: value.AddCost(CmdBuildRoadVehicle(subflags, tile, e, &v)); break;
164 case VEH_SHIP: value.AddCost(CmdBuildShip (subflags, tile, e, &v)); break;
165 case VEH_AIRCRAFT: value.AddCost(CmdBuildAircraft (subflags, tile, e, &v)); break;
166 default: NOT_REACHED(); // Safe due to IsDepotTile()
167 }
168
169 VehicleID veh_id = VehicleID::Invalid();
170 uint refitted_capacity = 0;
171 uint16_t refitted_mail_capacity = 0;
172 CargoArray cargo_capacities{};
173 if (value.Succeeded()) {
174 if (subflags.Test(DoCommandFlag::Execute)) {
175 v->unitnumber = unit_num;
176 v->value = value.GetCost();
177 veh_id = v->index;
178 }
179
180 if (refitting) {
181 /* Refit only one vehicle. If we purchased an engine, it may have gained free wagons. */
182 CommandCost cc;
183 std::tie(cc, refitted_capacity, refitted_mail_capacity, cargo_capacities) = CmdRefitVehicle(flags, v->index, cargo, 0, false, false, 1);
184 value.AddCost(std::move(cc));
185 } else {
186 /* Fill in non-refitted capacities */
187 if (e->type == VEH_TRAIN || e->type == VEH_ROAD) {
188 cargo_capacities = GetCapacityOfArticulatedParts(eid);
189 refitted_capacity = cargo_capacities[default_cargo];
190 refitted_mail_capacity = 0;
191 } else {
192 refitted_capacity = e->GetDisplayDefaultCapacity(&refitted_mail_capacity);
193 cargo_capacities[default_cargo] = refitted_capacity;
194 CargoType mail = GetCargoTypeByLabel(CT_MAIL);
195 if (IsValidCargoType(mail)) cargo_capacities[mail] = refitted_mail_capacity;
196 }
197 }
198
199 if (flags.Test(DoCommandFlag::Execute)) {
200 if (type == VEH_TRAIN && use_free_vehicles && !flags.Test(DoCommandFlag::AutoReplace) && Train::From(v)->IsEngine()) {
201 /* Move any free wagons to the new vehicle. */
203 }
204
208 if (IsLocalCompany()) {
209 InvalidateAutoreplaceWindow(v->engine_type, v->group_id); // updates the auto replace window (must be called before incrementing num_engines)
210 }
211 }
212
213 if (subflags.Test(DoCommandFlag::Execute)) {
216
217 if (v->IsPrimaryVehicle()) {
219 if (!subflags.Test(DoCommandFlag::AutoReplace)) OrderBackup::Restore(v, client_id);
220 }
221
222 Company::Get(v->owner)->freeunits[v->type].UseID(v->unitnumber);
223 }
224
225
226 /* If we are not in DoCommandFlag::Execute undo everything */
227 if (flags != subflags) {
228 Command<Commands::SellVehicle>::Do(DoCommandFlag::Execute, v->index, false, false, INVALID_CLIENT_ID);
229 }
230 }
231
232 /* Only restore if we actually did some refitting */
233 if (flags != subflags) RestoreRandomSeeds(saved_seeds);
234
235 return { value, veh_id, refitted_capacity, refitted_mail_capacity, cargo_capacities };
236}
237
247CommandCost CmdSellVehicle(DoCommandFlags flags, VehicleID v_id, bool sell_chain, bool backup_order, ClientID client_id)
248{
249 Vehicle *v = Vehicle::GetIfValid(v_id);
250 if (v == nullptr) return CMD_ERROR;
251
252 Vehicle *front = v->First();
253
254 CommandCost ret = CheckOwnership(front->owner);
255 if (ret.Failed()) return ret;
256
257 if (front->vehstatus.Test(VehState::Crashed)) return CommandCost(STR_ERROR_VEHICLE_IS_DESTROYED);
258
259 if (!front->IsStoppedInDepot()) return CommandCost(STR_ERROR_TRAIN_MUST_BE_STOPPED_INSIDE_DEPOT + front->type);
260
261 if (v->type == VEH_TRAIN) {
262 ret = CmdSellRailWagon(flags, v, sell_chain, backup_order, client_id);
263 } else {
265
266 if (flags.Test(DoCommandFlag::Execute)) {
267 if (front->IsPrimaryVehicle() && backup_order) OrderBackup::Backup(front, client_id);
268 delete front;
269 }
270 }
271
272 return ret;
273}
274
284static int GetRefitCostFactor(const Vehicle *v, EngineID engine_type, CargoType new_cargo_type, uint8_t new_subtype, bool *auto_refit_allowed)
285{
286 /* Prepare callback param with info about the new cargo type. */
287 const Engine *e = Engine::Get(engine_type);
288
289 /* Is this vehicle a NewGRF vehicle? */
290 if (e->GetGRF() != nullptr) {
291 const CargoSpec *cs = CargoSpec::Get(new_cargo_type);
292 uint32_t param1 = (cs->classes.base() << 16) | (new_subtype << 8) | e->GetGRF()->cargo_map[new_cargo_type];
293
294 uint16_t cb_res = GetVehicleCallback(CBID_VEHICLE_REFIT_COST, param1, 0, engine_type, v);
295 if (cb_res != CALLBACK_FAILED) {
296 *auto_refit_allowed = HasBit(cb_res, 14);
297 int factor = GB(cb_res, 0, 14);
298 if (factor >= 0x2000) factor -= 0x4000; // Treat as signed integer.
299 return factor;
300 }
301 }
302
303 *auto_refit_allowed = e->info.refit_cost == 0;
304 return (v == nullptr || v->cargo_type != new_cargo_type) ? e->info.refit_cost : 0;
305}
306
316static CommandCost GetRefitCost(const Vehicle *v, EngineID engine_type, CargoType new_cargo_type, uint8_t new_subtype, bool *auto_refit_allowed)
317{
318 ExpensesType expense_type;
319 const Engine *e = Engine::Get(engine_type);
320 Price base_price;
321 int cost_factor = GetRefitCostFactor(v, engine_type, new_cargo_type, new_subtype, auto_refit_allowed);
322 switch (e->type) {
323 case VEH_SHIP:
324 base_price = Price::BuildVehicleShip;
325 expense_type = EXPENSES_SHIP_RUN;
326 break;
327
328 case VEH_ROAD:
329 base_price = Price::BuildVehicleRoad;
330 expense_type = EXPENSES_ROADVEH_RUN;
331 break;
332
333 case VEH_AIRCRAFT:
334 base_price = Price::BuildVehicleAircraft;
335 expense_type = EXPENSES_AIRCRAFT_RUN;
336 break;
337
338 case VEH_TRAIN:
339 base_price = (e->VehInfo<RailVehicleInfo>().railveh_type == RAILVEH_WAGON) ? Price::BuildVehicleWagon : Price::BuildVehicleTrain;
340 cost_factor <<= 1;
341 expense_type = EXPENSES_TRAIN_RUN;
342 break;
343
344 default: NOT_REACHED();
345 }
346 if (cost_factor < 0) {
347 return CommandCost(expense_type, -GetPrice(base_price, -cost_factor, e->GetGRF(), -10));
348 } else {
349 return CommandCost(expense_type, GetPrice(base_price, cost_factor, e->GetGRF(), -10));
350 }
351}
352
360
373static std::tuple<CommandCost, uint, uint16_t, CargoArray> RefitVehicle(Vehicle *v, bool only_this, uint8_t num_vehicles, CargoType new_cargo_type, uint8_t new_subtype, DoCommandFlags flags, bool auto_refit)
374{
375 CommandCost cost(v->GetExpenseType(false));
376 uint total_capacity = 0;
377 uint total_mail_capacity = 0;
378 num_vehicles = num_vehicles == 0 ? UINT8_MAX : num_vehicles;
379 CargoArray cargo_capacities{};
380
381 VehicleSet vehicles_to_refit;
382 if (!only_this) {
383 GetVehicleSet(vehicles_to_refit, v, num_vehicles);
384 /* In this case, we need to check the whole chain. */
385 v = v->First();
386 }
387
388 std::vector<RefitResult> refit_result;
389
391 uint8_t actual_subtype = new_subtype;
392 for (; v != nullptr; v = (only_this ? nullptr : v->Next())) {
393 /* Reset actual_subtype for every new vehicle */
394 if (!v->IsArticulatedPart()) actual_subtype = new_subtype;
395
396 if (v->type == VEH_TRAIN && std::ranges::find(vehicles_to_refit, v->index) == vehicles_to_refit.end() && !only_this) continue;
397
398 const Engine *e = v->GetEngine();
399 if (!e->CanCarryCargo()) continue;
400
401 /* If the vehicle is not refittable, or does not allow automatic refitting,
402 * count its capacity nevertheless if the cargo matches */
403 bool refittable = HasBit(e->info.refit_mask, new_cargo_type) && (!auto_refit || e->info.misc_flags.Test(EngineMiscFlag::AutoRefit));
404 if (!refittable && v->cargo_type != new_cargo_type) {
405 uint amount = e->DetermineCapacity(v, nullptr);
406 if (amount > 0) cargo_capacities[v->cargo_type] += amount;
407 continue;
408 }
409
410 /* Determine best fitting subtype if requested */
411 if (actual_subtype == 0xFF) {
412 actual_subtype = GetBestFittingSubType(v, v, new_cargo_type);
413 }
414
415 /* Back up the vehicle's cargo type */
416 CargoType temp_cargo_type = v->cargo_type;
417 uint8_t temp_subtype = v->cargo_subtype;
418 if (refittable) {
419 v->cargo_type = new_cargo_type;
420 v->cargo_subtype = actual_subtype;
421 }
422
423 uint16_t mail_capacity = 0;
424 uint amount = e->DetermineCapacity(v, &mail_capacity);
425 total_capacity += amount;
426 /* mail_capacity will always be zero if the vehicle is not an aircraft. */
427 total_mail_capacity += mail_capacity;
428
429 cargo_capacities[new_cargo_type] += amount;
430 CargoType mail = GetCargoTypeByLabel(CT_MAIL);
431 if (IsValidCargoType(mail)) cargo_capacities[mail] += mail_capacity;
432
433 if (!refittable) continue;
434
435 /* Restore the original cargo type */
436 v->cargo_type = temp_cargo_type;
437 v->cargo_subtype = temp_subtype;
438
439 bool auto_refit_allowed;
440 CommandCost refit_cost = GetRefitCost(v, v->engine_type, new_cargo_type, actual_subtype, &auto_refit_allowed);
441 if (auto_refit && !flags.Test(DoCommandFlag::QueryCost) && !auto_refit_allowed) {
442 /* Sorry, auto-refitting not allowed, subtract the cargo amount again from the total.
443 * When querrying cost/capacity (for example in order refit GUI), we always assume 'allowed'.
444 * It is not predictable. */
445 total_capacity -= amount;
446 total_mail_capacity -= mail_capacity;
447
448 if (v->cargo_type == new_cargo_type) {
449 /* Add the old capacity nevertheless, if the cargo matches */
450 total_capacity += v->cargo_cap;
451 if (v->type == VEH_AIRCRAFT) total_mail_capacity += v->Next()->cargo_cap;
452 }
453 continue;
454 }
455 cost.AddCost(std::move(refit_cost));
456
457 /* Record the refitting.
458 * Do not execute the refitting immediately, so DetermineCapacity and GetRefitCost do the same in test and exec run.
459 * (weird NewGRFs)
460 * Note:
461 * - If the capacity of vehicles depends on other vehicles in the chain, the actual capacity is
462 * set after RefitVehicle() via ConsistChanged() and friends. The estimation via _returned_refit_capacity will be wrong.
463 * - We have to call the refit cost callback with the pre-refit configuration of the chain because we want refit and
464 * autorefit to behave the same, and we need its result for auto_refit_allowed.
465 */
466 refit_result.emplace_back(v, amount, mail_capacity, actual_subtype);
467 }
468
469 if (flags.Test(DoCommandFlag::Execute)) {
470 /* Store the result */
471 for (RefitResult &result : refit_result) {
472 Vehicle *u = result.v;
473 u->refit_cap = (u->cargo_type == new_cargo_type) ? std::min<uint16_t>(result.capacity, u->refit_cap) : 0;
474 if (u->cargo.TotalCount() > u->refit_cap) u->cargo.Truncate(u->cargo.TotalCount() - u->refit_cap);
475 u->cargo_type = new_cargo_type;
476 u->cargo_cap = result.capacity;
477 u->cargo_subtype = result.subtype;
478 if (u->type == VEH_AIRCRAFT) {
479 Vehicle *w = u->Next();
480 assert(w != nullptr);
481 w->refit_cap = std::min<uint16_t>(w->refit_cap, result.mail_capacity);
482 w->cargo_cap = result.mail_capacity;
483 if (w->cargo.TotalCount() > w->refit_cap) w->cargo.Truncate(w->cargo.TotalCount() - w->refit_cap);
484 }
485 }
486 }
487
488 refit_result.clear();
489 return { cost, total_capacity, total_mail_capacity, cargo_capacities };
490}
491
504std::tuple<CommandCost, uint, uint16_t, CargoArray> CmdRefitVehicle(DoCommandFlags flags, VehicleID veh_id, CargoType new_cargo_type, uint8_t new_subtype, bool auto_refit, bool only_this, uint8_t num_vehicles)
505{
506 Vehicle *v = Vehicle::GetIfValid(veh_id);
507 if (v == nullptr) return { CMD_ERROR, 0, 0, {} };
508
509 /* Don't allow disasters and sparks and such to be refitted.
510 * We cannot check for IsPrimaryVehicle as autoreplace also refits in free wagon chains. */
511 if (!IsCompanyBuildableVehicleType(v->type)) return { CMD_ERROR, 0, 0, {} };
512
513 Vehicle *front = v->First();
514
515 CommandCost ret = CheckOwnership(front->owner);
516 if (ret.Failed()) return { ret, 0, 0, {} };
517
518 bool free_wagon = v->type == VEH_TRAIN && Train::From(front)->IsFreeWagon(); // used by autoreplace/renew
519
520 /* Don't allow shadows and such to be refitted. */
521 if (v != front && (v->type == VEH_SHIP || v->type == VEH_AIRCRAFT)) return { CMD_ERROR, 0, 0, {} };
522
523 /* Allow auto-refitting only during loading and normal refitting only in a depot. */
524 if (!flags.Test(DoCommandFlag::QueryCost) && // used by the refit GUI, including the order refit GUI.
525 !free_wagon && // used by autoreplace/renew
526 (!auto_refit || !front->current_order.IsType(OT_LOADING)) && // refit inside stations
527 !front->IsStoppedInDepot()) { // refit inside depots
528 return { CommandCost(STR_ERROR_TRAIN_MUST_BE_STOPPED_INSIDE_DEPOT + front->type), 0, 0, {} };
529 }
530
531 if (front->vehstatus.Test(VehState::Crashed)) return { CommandCost(STR_ERROR_VEHICLE_IS_DESTROYED), 0, 0, {} };
532
533 /* Check cargo */
534 if (new_cargo_type >= NUM_CARGO) return { CMD_ERROR, 0, 0, {} };
535
536 /* For ships and aircraft there is always only one. */
537 only_this |= front->type == VEH_SHIP || front->type == VEH_AIRCRAFT;
538
539 auto [cost, refit_capacity, mail_capacity, cargo_capacities] = RefitVehicle(v, only_this, num_vehicles, new_cargo_type, new_subtype, flags, auto_refit);
540
541 if (flags.Test(DoCommandFlag::Execute)) {
542 /* Update the cached variables */
543 switch (v->type) {
544 case VEH_TRAIN:
545 Train::From(front)->ConsistChanged(auto_refit ? CCF_AUTOREFIT : CCF_REFIT);
546 break;
547 case VEH_ROAD:
548 RoadVehUpdateCache(RoadVehicle::From(front), auto_refit);
549 if (_settings_game.vehicle.roadveh_acceleration_model != AM_ORIGINAL) RoadVehicle::From(front)->CargoChanged();
550 break;
551
552 case VEH_SHIP:
555 break;
556
557 case VEH_AIRCRAFT:
560 break;
561
562 default: NOT_REACHED();
563 }
564 front->MarkDirty();
565
566 if (!free_wagon) {
569 }
571 } else {
572 /* Always invalidate the cache; querycost might have filled it. */
574 }
575
576 return { cost, refit_capacity, mail_capacity, cargo_capacities };
577}
578
586CommandCost CmdStartStopVehicle(DoCommandFlags flags, VehicleID veh_id, bool evaluate_startstop_cb)
587{
588 /* Disable the effect of evaluate_startstop_cb, when DoCommandFlag::AutoReplace is not set */
589 if (!flags.Test(DoCommandFlag::AutoReplace)) evaluate_startstop_cb = true;
590
591 Vehicle *v = Vehicle::GetIfValid(veh_id);
592 if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
593
595 if (ret.Failed()) return ret;
596
597 if (v->vehstatus.Test(VehState::Crashed)) return CommandCost(STR_ERROR_VEHICLE_IS_DESTROYED);
598
599 switch (v->type) {
600 case VEH_TRAIN:
601 if (v->vehstatus.Test(VehState::Stopped) && Train::From(v)->gcache.cached_power == 0) return CommandCost(STR_ERROR_TRAIN_START_NO_POWER);
602 break;
603
604 case VEH_SHIP:
605 case VEH_ROAD:
606 break;
607
608 case VEH_AIRCRAFT: {
609 Aircraft *a = Aircraft::From(v);
610 /* cannot stop airplane when in flight, or when taking off / landing */
611 if (a->state >= STARTTAKEOFF && a->state < TERM7) return CommandCost(STR_ERROR_AIRCRAFT_IS_IN_FLIGHT);
612 if (a->flags.Test(VehicleAirFlag::HelicopterDirectDescent)) return CommandCost(STR_ERROR_AIRCRAFT_IS_IN_FLIGHT);
613 break;
614 }
615
616 default: return CMD_ERROR;
617 }
618
619 if (evaluate_startstop_cb) {
620 /* Check if this vehicle can be started/stopped. Failure means 'allow'. */
621 std::array<int32_t, 1> regs100;
622 uint16_t callback = GetVehicleCallback(CBID_VEHICLE_START_STOP_CHECK, 0, 0, v->engine_type, v, regs100);
623 StringID error = STR_NULL;
624 if (callback != CALLBACK_FAILED) {
625 if (v->GetGRF()->grf_version < 8) {
626 /* 8 bit result 0xFF means 'allow' */
627 if (callback < 0x400 && GB(callback, 0, 8) != 0xFF) error = GetGRFStringID(v->GetGRFID(), GRFSTR_MISC_GRF_TEXT + callback);
628 } else {
629 if (callback < 0x400) {
630 error = GetGRFStringID(v->GetGRFID(), GRFSTR_MISC_GRF_TEXT + callback);
631 } else {
632 switch (callback) {
633 case 0x400: // allow
634 break;
635
636 case 0x40F:
637 error = GetGRFStringID(v->GetGRFID(), static_cast<GRFStringID>(regs100[0]));
638 break;
639
640 default: // unknown reason -> disallow
641 error = STR_ERROR_INCOMPATIBLE_RAIL_TYPES;
642 break;
643 }
644 }
645 }
646 }
647 if (error != STR_NULL) return CommandCost(error);
648 }
649
650 if (flags.Test(DoCommandFlag::Execute)) {
652
654 if (v->type != VEH_TRAIN) v->cur_speed = 0; // trains can stop 'slowly'
655
656 /* Unbunching data is no longer valid. */
658
659 v->MarkDirty();
664 }
665 return CommandCost();
666}
667
677CommandCost CmdMassStartStopVehicle(DoCommandFlags flags, TileIndex tile, bool do_start, bool vehicle_list_window, const VehicleListIdentifier &vli)
678{
679 VehicleList list;
680
681 if (!vli.Valid()) return CMD_ERROR;
683
684 if (vehicle_list_window) {
685 if (!GenerateVehicleSortList(&list, vli)) return CMD_ERROR;
686 } else {
687 if (!IsDepotTile(tile) || !IsTileOwner(tile, _current_company)) return CMD_ERROR;
688 /* Get the list of vehicles in the depot */
689 BuildDepotVehicleList(vli.vtype, tile, &list, nullptr);
690 }
691
692 for (const Vehicle *v : list) {
693 if (v->vehstatus.Test(VehState::Stopped) != do_start) continue;
694
695 if (!vehicle_list_window && !v->IsChainInDepot()) continue;
696
697 /* Just try and don't care if some vehicle's can't be stopped. */
698 Command<Commands::StartStopVehicle>::Do(flags, v->index, false);
699 }
700
701 return CommandCost();
702}
703
711CommandCost CmdDepotSellAllVehicles(DoCommandFlags flags, TileIndex tile, VehicleType vehicle_type)
712{
713 VehicleList list;
714
716
717 if (!IsCompanyBuildableVehicleType(vehicle_type)) return CMD_ERROR;
718 if (!IsDepotTile(tile) || !IsTileOwner(tile, _current_company)) return CMD_ERROR;
719
720 /* Get the list of vehicles in the depot */
721 BuildDepotVehicleList(vehicle_type, tile, &list, &list);
722
723 CommandCost last_error = CMD_ERROR;
724 bool had_success = false;
725 for (const Vehicle *v : list) {
726 CommandCost ret = Command<Commands::SellVehicle>::Do(flags, v->index, true, false, INVALID_CLIENT_ID);
727 if (ret.Succeeded()) {
728 cost.AddCost(ret.GetCost());
729 had_success = true;
730 } else {
731 last_error = std::move(ret);
732 }
733 }
734
735 return had_success ? cost : last_error;
736}
737
745CommandCost CmdDepotMassAutoReplace(DoCommandFlags flags, TileIndex tile, VehicleType vehicle_type)
746{
747 VehicleList list;
749
750 if (!IsCompanyBuildableVehicleType(vehicle_type)) return CMD_ERROR;
751 if (!IsDepotTile(tile) || !IsTileOwner(tile, _current_company)) return CMD_ERROR;
752
753 /* Get the list of vehicles in the depot */
754 BuildDepotVehicleList(vehicle_type, tile, &list, &list, true);
755
756 for (const Vehicle *v : list) {
757 /* Ensure that the vehicle completely in the depot */
758 if (!v->IsChainInDepot()) continue;
759
760 CommandCost ret = Command<Commands::AutoreplaceVehicle>::Do(flags, v->index);
761
762 if (ret.Succeeded()) cost.AddCost(ret.GetCost());
763 }
764 return cost;
765}
766
772bool IsUniqueVehicleName(const std::string &name)
773{
774 for (const Vehicle *v : Vehicle::Iterate()) {
775 if (!v->name.empty() && v->name == name) return false;
776 }
777
778 return true;
779}
780
786static void CloneVehicleName(const Vehicle *src, Vehicle *dst)
787{
788 std::string buf;
789
790 /* Find the position of the first digit in the last group of digits. */
791 size_t number_position;
792 for (number_position = src->name.length(); number_position > 0; number_position--) {
793 /* The design of UTF-8 lets this work simply without having to check
794 * for UTF-8 sequences. */
795 if (src->name[number_position - 1] < '0' || src->name[number_position - 1] > '9') break;
796 }
797
798 /* Format buffer and determine starting number. */
799 long num;
800 uint8_t padding = 0;
801 if (number_position == src->name.length()) {
802 /* No digit at the end, so start at number 2. */
803 buf = src->name;
804 buf += " ";
805 number_position = buf.length();
806 num = 2;
807 } else {
808 /* Found digits, parse them and start at the next number. */
809 buf = src->name.substr(0, number_position);
810
811 auto num_str = std::string_view(src->name).substr(number_position);
812 padding = (uint8_t)num_str.length();
813
814 [[maybe_unused]] auto err = std::from_chars(num_str.data(), num_str.data() + num_str.size(), num, 10).ec;
815 assert(err == std::errc());
816 num++;
817 }
818
819 /* Check if this name is already taken. */
820 for (int max_iterations = 1000; max_iterations > 0; max_iterations--, num++) {
821 std::string new_name = fmt::format("{}{:0{}}", buf, num, padding);
822
823 /* Check the name is unique. */
824 if (IsUniqueVehicleName(new_name)) {
825 dst->name = std::move(new_name);
826 break;
827 }
828 }
829
830 /* All done. If we didn't find a name, it'll just use its default. */
831}
832
841std::tuple<CommandCost, VehicleID> CmdCloneVehicle(DoCommandFlags flags, TileIndex tile, VehicleID veh_id, bool share_orders)
842{
844
845 Vehicle *v = Vehicle::GetIfValid(veh_id);
846 if (v == nullptr || !v->IsPrimaryVehicle()) return { CMD_ERROR, VehicleID::Invalid() };
847 Vehicle *v_front = v;
848 Vehicle *w = nullptr;
849 Vehicle *w_front = nullptr;
850 Vehicle *w_rear = nullptr;
851
852 /*
853 * v_front is the front engine in the original vehicle
854 * v is the car/vehicle of the original vehicle that is currently being copied
855 * w_front is the front engine of the cloned vehicle
856 * w is the car/vehicle currently being cloned
857 * w_rear is the rear end of the cloned train. It's used to add more cars and is only used by trains
858 */
859
861 if (ret.Failed()) return { ret, VehicleID::Invalid() };
862
863 /* Crashed trains can only be cloned before cleanup begins. */
864 if (v->type == VEH_TRAIN && (!v->IsFrontEngine() || Train::From(v)->crash_anim_pos >= 4400)) return { CommandCost(STR_ERROR_VEHICLE_IS_DESTROYED), VehicleID::Invalid() };
865
866 /* check that we can allocate enough vehicles */
867 if (!flags.Test(DoCommandFlag::Execute)) {
868 int veh_counter = 0;
869 do {
870 veh_counter++;
871 } while ((v = v->Next()) != nullptr);
872
873 if (!Vehicle::CanAllocateItem(veh_counter)) {
874 return { CommandCost(STR_ERROR_TOO_MANY_VEHICLES_IN_GAME), VehicleID::Invalid() };
875 }
876 }
877
878 v = v_front;
879
880 VehicleID new_veh_id = VehicleID::Invalid();
881 do {
882 if (v->type == VEH_TRAIN && Train::From(v)->IsRearDualheaded()) {
883 /* we build the rear ends of multiheaded trains with the front ones */
884 continue;
885 }
886
887 /* In case we're building a multi headed vehicle and the maximum number of
888 * vehicles is almost reached (e.g. max trains - 1) not all vehicles would
889 * be cloned. When the non-primary engines were build they were seen as
890 * 'new' vehicles whereas they would immediately be joined with a primary
891 * engine. This caused the vehicle to be not build as 'the limit' had been
892 * reached, resulting in partially build vehicles and such. */
893 DoCommandFlags build_flags = flags;
895
896 CommandCost cost;
897 std::tie(cost, new_veh_id, std::ignore, std::ignore, std::ignore) = Command<Commands::BuildVehicle>::Do(build_flags, tile, v->engine_type, false, INVALID_CARGO, INVALID_CLIENT_ID);
898
899 if (cost.Failed()) {
900 /* Can't build a part, then sell the stuff we already made; clear up the mess */
901 if (w_front != nullptr) Command<Commands::SellVehicle>::Do(flags, w_front->index, true, false, INVALID_CLIENT_ID);
902 return { cost, VehicleID::Invalid() };
903 }
904
905 total_cost.AddCost(cost.GetCost());
906
907 if (flags.Test(DoCommandFlag::Execute)) {
908 w = Vehicle::Get(new_veh_id);
909
910 if (v->type == VEH_TRAIN && Train::From(v)->flags.Test(VehicleRailFlag::Flipped)) {
911 /* Only copy the reverse state if neither old or new vehicle implements reverse-on-build probability callback. */
915 }
916 }
917
918 if (v->type == VEH_TRAIN && !v->IsFrontEngine()) {
919 /* this s a train car
920 * add this unit to the end of the train */
921 CommandCost result = Command<Commands::MoveRailVehicle>::Do(flags, w->index, w_rear->index, true);
922 if (result.Failed()) {
923 /* The train can't be joined to make the same consist as the original.
924 * Sell what we already made (clean up) and return an error. */
925 Command<Commands::SellVehicle>::Do(flags, w_front->index, true, false, INVALID_CLIENT_ID);
926 Command<Commands::SellVehicle>::Do(flags, w->index, true, false, INVALID_CLIENT_ID);
927 return { result, VehicleID::Invalid() }; // return error and the message returned from Commands::MoveRailVehicle
928 }
929 } else {
930 /* this is a front engine or not a train. */
931 w_front = w;
933 w->SetServiceIntervalIsCustom(v->ServiceIntervalIsCustom());
934 w->SetServiceIntervalIsPercent(v->ServiceIntervalIsPercent());
935 }
936 w_rear = w; // trains needs to know the last car in the train, so they can add more in next loop
937 }
938 } while (v->type == VEH_TRAIN && (v = v->GetNextVehicle()) != nullptr);
939
940 if (flags.Test(DoCommandFlag::Execute) && v_front->type == VEH_TRAIN) {
941 /* for trains this needs to be the front engine due to the callback function */
942 new_veh_id = w_front->index;
943 }
944
945 if (flags.Test(DoCommandFlag::Execute)) {
946 /* Cloned vehicles belong to the same group */
947 Command<Commands::AddVehicleToGroup>::Do(flags, v_front->group_id, w_front->index, false, VehicleListIdentifier{});
948 }
949
950
951 /* Take care of refitting. */
952 w = w_front;
953 v = v_front;
954
955 /* Both building and refitting are influenced by newgrf callbacks, which
956 * makes it impossible to accurately estimate the cloning costs. In
957 * particular, it is possible for engines of the same type to be built with
958 * different numbers of articulated parts, so when refitting we have to
959 * loop over real vehicles first, and then the articulated parts of those
960 * vehicles in a different loop. */
961 do {
962 do {
963 if (flags.Test(DoCommandFlag::Execute)) {
964 assert(w != nullptr);
965
966 /* Find out what's the best sub type */
967 uint8_t subtype = GetBestFittingSubType(v, w, v->cargo_type);
968 if (w->cargo_type != v->cargo_type || w->cargo_subtype != subtype) {
969 CommandCost cost = std::get<0>(Command<Commands::RefitVehicle>::Do(flags, w->index, v->cargo_type, subtype, false, true, 0));
970 if (cost.Succeeded()) total_cost.AddCost(cost.GetCost());
971 }
972
973 if (w->IsGroundVehicle() && w->HasArticulatedPart()) {
974 w = w->GetNextArticulatedPart();
975 } else {
976 break;
977 }
978 } else {
979 const Engine *e = v->GetEngine();
980 CargoType initial_cargo = (e->CanCarryCargo() ? e->GetDefaultCargoType() : INVALID_CARGO);
981
982 if (v->cargo_type != initial_cargo && IsValidCargoType(initial_cargo)) {
983 bool dummy;
984 total_cost.AddCost(GetRefitCost(nullptr, v->engine_type, v->cargo_type, v->cargo_subtype, &dummy));
985 }
986 }
987
988 if (v->IsGroundVehicle() && v->HasArticulatedPart()) {
989 v = v->GetNextArticulatedPart();
990 } else {
991 break;
992 }
993 } while (v != nullptr);
994
995 if (flags.Test(DoCommandFlag::Execute) && v->type == VEH_TRAIN) w = w->GetNextVehicle();
996 } while (v->type == VEH_TRAIN && (v = v->GetNextVehicle()) != nullptr);
997
998 if (flags.Test(DoCommandFlag::Execute)) {
999 /*
1000 * Set the orders of the vehicle. Cannot do it earlier as we need
1001 * the vehicle refitted before doing this, otherwise the moved
1002 * cargo types might not match (passenger vs non-passenger)
1003 */
1004 CommandCost result = Command<Commands::CloneOrder>::Do(flags, (share_orders ? CO_SHARE : CO_COPY), w_front->index, v_front->index);
1005 if (result.Failed()) {
1006 /* The vehicle has already been bought, so now it must be sold again. */
1007 Command<Commands::SellVehicle>::Do(flags, w_front->index, true, false, INVALID_CLIENT_ID);
1008 return { result, VehicleID::Invalid() };
1009 }
1010
1011 /* Now clone the vehicle's name, if it has one. */
1012 if (!v_front->name.empty()) CloneVehicleName(v_front, w_front);
1013
1014 /* Since we can't estimate the cost of cloning a vehicle accurately we must
1015 * check whether the company has enough money manually. */
1016 if (!CheckCompanyHasMoney(total_cost)) {
1017 /* The vehicle has already been bought, so now it must be sold again. */
1018 Command<Commands::SellVehicle>::Do(flags, w_front->index, true, false, INVALID_CLIENT_ID);
1019 return { total_cost, VehicleID::Invalid() };
1020 }
1021 }
1022
1023 return { total_cost, new_veh_id };
1024}
1025
1033static CommandCost SendAllVehiclesToDepot(DoCommandFlags flags, bool service, const VehicleListIdentifier &vli)
1034{
1035 VehicleList list;
1036
1037 if (!GenerateVehicleSortList(&list, vli)) return CMD_ERROR;
1038
1039 /* Send all the vehicles to a depot */
1040 bool had_success = false;
1041 for (uint i = 0; i < list.size(); i++) {
1042 const Vehicle *v = list[i];
1043 CommandCost ret = Command<Commands::SendVehicleToDepot>::Do(flags, v->index, (service ? DepotCommandFlag::Service : DepotCommandFlags{}) | DepotCommandFlag::DontCancel, {});
1044
1045 if (ret.Succeeded()) {
1046 had_success = true;
1047
1048 /* Return 0 if DoCommandFlag::Execute is not set this is a valid goto depot command)
1049 * In this case we know that at least one vehicle can be sent to a depot
1050 * and we will issue the command. We can now safely quit the loop, knowing
1051 * it will succeed at least once. With DoCommandFlag::Execute we really need to send them to the depot */
1052 if (!flags.Test(DoCommandFlag::Execute)) break;
1053 }
1054 }
1055
1056 return had_success ? CommandCost() : CMD_ERROR;
1057}
1058
1067CommandCost CmdSendVehicleToDepot(DoCommandFlags flags, VehicleID veh_id, DepotCommandFlags depot_cmd, const VehicleListIdentifier &vli)
1068{
1069 if (depot_cmd.Test(DepotCommandFlag::MassSend)) {
1070 /* Mass goto depot requested */
1071 if (!vli.Valid()) return CMD_ERROR;
1072 return SendAllVehiclesToDepot(flags, depot_cmd.Test(DepotCommandFlag::Service), vli);
1073 }
1074
1075 Vehicle *v = Vehicle::GetIfValid(veh_id);
1076 if (v == nullptr) return CMD_ERROR;
1077 if (!v->IsPrimaryVehicle()) return CMD_ERROR;
1078
1079 return v->SendToDepot(flags, depot_cmd);
1080}
1081
1089CommandCost CmdRenameVehicle(DoCommandFlags flags, VehicleID veh_id, const std::string &text)
1090{
1091 Vehicle *v = Vehicle::GetIfValid(veh_id);
1092 if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
1093
1095 if (ret.Failed()) return ret;
1096
1097 bool reset = text.empty();
1098
1099 if (!reset) {
1101 if (!flags.Test(DoCommandFlag::AutoReplace) && !IsUniqueVehicleName(text)) return CommandCost(STR_ERROR_NAME_MUST_BE_UNIQUE);
1102 }
1103
1104 if (flags.Test(DoCommandFlag::Execute)) {
1105 if (reset) {
1106 v->name.clear();
1107 } else {
1108 v->name = text;
1109 }
1112 }
1113
1114 return CommandCost();
1115}
1116
1117
1127CommandCost CmdChangeServiceInt(DoCommandFlags flags, VehicleID veh_id, uint16_t serv_int, bool is_custom, bool is_percent)
1128{
1129 Vehicle *v = Vehicle::GetIfValid(veh_id);
1130 if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
1131
1133 if (ret.Failed()) return ret;
1134
1135 const Company *company = Company::Get(v->owner);
1136 is_percent = is_custom ? is_percent : company->settings.vehicle.servint_ispercent;
1137
1138 if (is_custom) {
1139 if (serv_int != GetServiceIntervalClamped(serv_int, is_percent)) return CMD_ERROR;
1140 } else {
1141 serv_int = CompanyServiceInterval(company, v->type);
1142 }
1143
1144 if (flags.Test(DoCommandFlag::Execute)) {
1145 v->SetServiceInterval(serv_int);
1146 v->SetServiceIntervalIsCustom(is_custom);
1147 v->SetServiceIntervalIsPercent(is_percent);
1149 }
1150
1151 return CommandCost();
1152}
Base for aircraft.
@ HelicopterDirectDescent
The helicopter is descending directly at its destination (helipad or in front of hangar).
Definition aircraft.h:45
void UpdateAircraftCache(Aircraft *v, bool update_range=false)
Update cached values of an aircraft.
CommandCost CmdBuildAircraft(DoCommandFlags flags, TileIndex tile, const Engine *e, Vehicle **ret)
Build an aircraft.
Command definitions related to aircraft.
Various declarations for airports.
@ STARTTAKEOFF
Airplane has arrived at a runway for take-off.
Definition airport.h:74
@ TERM7
Heading for terminal 7.
Definition airport.h:82
CargoArray GetCapacityOfArticulatedParts(EngineID engine)
Get the capacity of the parts of a given engine.
uint CountArticulatedParts(EngineID engine_type)
Count the number of articulated parts of an engine.
Functions related to articulated vehicles.
Command definitions related to autoreplace.
void InvalidateAutoreplaceWindow(EngineID e, GroupID id_g)
Rebuild the left autoreplace list if an engine is removed or added.
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 bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
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:108
static const CargoType NUM_CARGO
Maximum number of cargo types in a game.
Definition cargo_type.h:73
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
constexpr Tstorage base() const noexcept
Retrieve the raw value behind this bit set.
constexpr Timpl & Flip(Tvalue_type value)
Flip the value-th bit.
constexpr Timpl & Set()
Set all bits.
Common return value for all commands.
bool Succeeded() const
Did this command succeed?
void AddCost(const Money &cost)
Adds the given cost to the cost of the command.
Money GetCost() const
The costs as made up to this moment.
bool Failed() const
Did this command fail?
Money GetCost() const
Return how much a new engine costs.
Definition engine.cpp:321
const GRFFile * GetGRF() const
Retrieve the NewGRF the engine is tied to.
uint DetermineCapacity(const Vehicle *v, uint16_t *mail_capacity=nullptr) const
Determines capacity of a given vehicle from scratch.
Definition engine.cpp:204
VehicleType type
Vehicle type, ie VEH_ROAD, VEH_TRAIN, etc.
Definition engine_base.h:62
uint GetDisplayDefaultCapacity(uint16_t *mail_capacity=nullptr) const
Determines the default cargo capacity of an engine for display purposes.
CargoType GetDefaultCargoType() const
Determines the default cargo type of an engine.
Definition engine_base.h:94
bool CanCarryCargo() const
Determines whether an engine can carry something.
Definition engine.cpp:171
uint Truncate(uint max_move=UINT_MAX)
Truncates the cargo in this list to the given amount.
uint TotalCount() const
Returns sum of cargo, including reserved cargo.
Functions related to commands.
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
@ QueryCost
query cost only, don't build.
@ Execute
execute the given command
@ AutoReplace
autoreplace/autorenew is in progress, this shall disable vehicle limits when building,...
Definition of stuff that is very close to a company, like the company struct itself.
int CompanyServiceInterval(const Company *c, VehicleType type)
Get the service interval for the given company and vehicle type.
bool CheckCompanyHasMoney(CommandCost &cost)
Verify whether the company can pay the bill.
CommandCost CheckOwnership(Owner owner, TileIndex tile)
Check whether the current owner owns something.
CompanyID _current_company
Company currently doing an action.
Functions related to companies.
bool IsLocalCompany()
Is the current company the local company?
Map related accessors for depots.
bool IsDepotTile(Tile tile)
Is the given tile a tile with a depot on it?
Definition depot_map.h:45
VehicleType GetDepotVehicleType(Tile t)
Get the type of vehicles that can use a depot.
Definition depot_map.h:81
bool do_start
flag for starting playback of next_file at next opportunity
Definition dmusic.cpp:171
Money GetPrice(Price index, uint cost_factor, const GRFFile *grf_file, int shift)
Determine a certain price.
Definition economy.cpp:940
ExpensesType
Types of expenses.
@ EXPENSES_ROADVEH_RUN
Running costs road vehicles.
@ EXPENSES_TRAIN_RUN
Running costs trains.
@ EXPENSES_AIRCRAFT_RUN
Running costs aircraft.
@ EXPENSES_SHIP_RUN
Running costs ships.
@ EXPENSES_NEW_VEHICLES
New vehicles.
Price
Enumeration of all base prices for use with Prices.
@ BuildVehicleWagon
Price for purchasing new wagons.
@ BuildVehicleTrain
Price for purchasing new train engines.
@ BuildVehicleShip
Price for purchasing new ships.
@ BuildVehicleAircraft
Price for purchasing new aircrafts.
@ BuildVehicleRoad
Price for purchasing new road vehicles.
bool IsEngineBuildable(EngineID engine, VehicleType type, CompanyID company)
Check if an engine is buildable.
Definition engine.cpp:1251
Functions related to engines.
@ AIR_CTOL
Conventional Take Off and Landing, i.e. planes.
@ AutoRefit
Automatic refitting is allowed.
PoolID< uint16_t, struct EngineIDTag, 64000, 0xFFFF > EngineID
Unique identification number of an engine.
Definition engine_type.h:26
@ RAILVEH_WAGON
simple wagon, not motorized
Definition engine_type.h:34
@ RAILVEH_MULTIHEAD
indicates a combination of two locomotives
Definition engine_type.h:33
Base class for groups and group functions.
Command definitions related to engine groups.
void MarkWholeScreenDirty()
This function mark the whole screen as dirty.
Definition gfx.cpp:1554
virtual void MarkDirty()
Marks the vehicles to be redrawn and updates cached variables.
ClientID
'Unique' identifier to be given to clients
@ INVALID_CLIENT_ID
Client is not part of anything.
Base for the NewGRF implementation.
@ CBID_VEHICLE_REFIT_COST
Called to determine the cost factor for refitting a vehicle.
@ CBID_VEHICLE_START_STOP_CHECK
Called when the company (or AI) tries to start or stop a vehicle.
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.
std::optional< bool > TestVehicleBuildProbability(Vehicle *v, BuildProbabilityType type)
Test for vehicle build probability type.
@ Reversed
Change the rail vehicle should be reversed when purchased.
StringID GetGRFStringID(uint32_t grfid, GRFStringID stringid)
Returns the index for this stringid associated with its grfID.
Header of Action 04 "universal holder" structure and functions.
StrongType::Typedef< uint32_t, struct GRFStringIDTag, StrongType::Compare, StrongType::Integer > GRFStringID
Type for GRF-internal string IDs.
static constexpr GRFStringID GRFSTR_MISC_GRF_TEXT
Miscellaneous GRF text range.
Functions related to news.
void DeleteVehicleNews(VehicleID vid, AdviceType advice_type=AdviceType::Invalid)
Delete news with a given advice type about a vehicle.
@ VehicleWaiting
The vehicle is waiting in the depot.
Definition news_type.h:60
Functions related to order backups.
uint16_t GetServiceIntervalClamped(int interval, bool ispercent)
Clamp the service interval to the correct min/max.
Command definitions related to orders.
Pseudo random number generator.
void SaveRandomSeeds(SavedRandomSeeds *storage)
Saves the current seeds.
void RestoreRandomSeeds(const SavedRandomSeeds &storage)
Restores previously saved seeds.
Road vehicle states.
void RoadVehUpdateCache(RoadVehicle *v, bool same_length=false)
Update the cache of a road vehicle.
CommandCost CmdBuildRoadVehicle(DoCommandFlags flags, TileIndex tile, const Engine *e, Vehicle **ret)
Build a road vehicle.
Command definitions related to road vehicles.
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
Base for ships.
CommandCost CmdBuildShip(DoCommandFlags flags, TileIndex tile, const Engine *e, Vehicle **ret)
Build a ship.
Definition ship_cmd.cpp:865
Command definitions related to ships.
Definition of base types and functions in a cross-platform compatible way.
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:351
Functions related to low-level strings.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
Information about a aircraft vehicle.
Aircraft, helicopters, rotors and their shadows belong to this class.
Definition aircraft.h:73
uint8_t state
State of the airport.
Definition aircraft.h:78
VehicleAirFlags flags
Aircraft flags.
Definition aircraft.h:82
std::string name
Name of vehicle.
uint16_t service_interval
The interval for (automatic) servicing; either in days or %.
void ResetDepotUnbunching()
Resets all the data used for depot unbunching.
VehicleType type
Type of vehicle.
Class for storing amounts of cargo.
Definition cargo_type.h:115
Specification of a cargo type.
Definition cargotype.h:74
CargoClasses classes
Classes of this cargo type.
Definition cargotype.h:81
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo type.
Definition cargotype.h:138
CompanySettings settings
settings specific for each company
VehicleDefaultSettings vehicle
default settings for vehicles
EngineMiscFlags misc_flags
Miscellaneous flags.
std::array< uint8_t, NUM_CARGO > cargo_map
Inverse cargo translation table (CargoType -> local ID).
Definition newgrf.h:139
void CargoChanged()
Recalculates the cached weight of a vehicle and its parts.
bool IsFreeWagon() const
Check if the vehicle is a free wagon (got no engine in front of it).
static void CountVehicle(const Vehicle *v, int delta)
Update num_vehicle when adding or removing a vehicle.
static void CountEngine(const Vehicle *v, int delta)
Update num_engines when adding/removing an engine.
static void UpdateAutoreplace(CompanyID company)
Update autoreplace_defined and autoreplace_finished of all statistics of a company.
static void Restore(Vehicle *v, uint32_t user)
Restore the data of this order to the given vehicle.
static void Backup(const Vehicle *v, uint32_t user)
Create an order backup for the given vehicle.
bool IsType(OrderType type) const
Check whether this order is of the given type.
Definition order_base.h:67
static Pool::IterateWrapper< Vehicle > Iterate(size_t from=0)
static Engine * Get(auto index)
static bool CanAllocateItem(size_t n=1)
static Vehicle * GetIfValid(auto index)
Information about a rail vehicle.
Definition engine_type.h:74
Helper structure for RefitVehicle().
uint capacity
New capacity of vehicle.
Vehicle * v
Vehicle to refit.
uint mail_capacity
New mail capacity of aircraft.
uint8_t subtype
cargo subtype to refit to
Stores the state of all random number generators.
void UpdateCache()
Update the caches of this ship.
Definition ship_cmd.cpp:231
static Train * From(Vehicle *v)
VehicleRailFlags flags
Which flags has this train currently set.
Definition train.h:98
void ConsistChanged(ConsistChangeFlags allowed_changes)
Recalculates the cached stuff of a train.
bool servint_ispercent
service intervals are in percents
The information about a vehicle list.
Definition vehiclelist.h:32
VehicleType vtype
The vehicle type associated with this list.
Definition vehiclelist.h:34
Vehicle data structure.
EngineID engine_type
The type of engine used for this vehicle.
const Engine * GetEngine() const
Retrieves the engine of the vehicle.
Definition vehicle.cpp:747
bool IsStoppedInDepot() const
Check whether the vehicle is in the depot and stopped.
virtual ExpensesType GetExpenseType(bool income) const
Sets the expense type associated to this vehicle type.
Vehicle * GetNextArticulatedPart() const
Get the next part of an articulated engine.
VehicleCargoList cargo
The cargo this vehicle is carrying.
uint16_t cargo_cap
total capacity
CommandCost SendToDepot(DoCommandFlags flags, DepotCommandFlags command)
Send this vehicle to the depot using the given command(s).
Definition vehicle.cpp:2598
bool HasArticulatedPart() const
Check if an engine has an articulated part.
Vehicle * GetNextVehicle() const
Get the next real (non-articulated part) vehicle in the consist.
GroupID group_id
Index of group Pool array.
bool IsGroundVehicle() const
Check if the vehicle is a ground vehicle.
VehStates vehstatus
Status.
bool IsArticulatedPart() const
Check if the vehicle is an articulated part of an engine.
CargoType cargo_type
type of cargo this vehicle is carrying
Vehicle * First() const
Get the first vehicle of this vehicle chain.
Order current_order
The current order (+ status, like: loading).
Vehicle * Next() const
Get the next vehicle of this vehicle.
const GRFFile * GetGRF() const
Retrieve the NewGRF the vehicle is tied to.
Definition vehicle.cpp:757
Money value
Value of the vehicle.
uint16_t refit_cap
Capacity left over from before last refit.
uint32_t GetGRFID() const
Retrieve the GRF ID of the NewGRF the vehicle is tied to.
Definition vehicle.cpp:767
virtual bool IsPrimaryVehicle() const
Whether this is the primary vehicle in the chain.
uint16_t cur_speed
current speed
uint8_t cargo_subtype
Used for livery refits (NewGRF variations).
bool IsFrontEngine() const
Check if the vehicle is a front engine.
TileIndex tile
Current tile index.
void InvalidateNewGRFCacheOfChain()
Invalidates cached NewGRF variables of all vehicles in the chain (after the current vehicle).
Owner owner
Which company owns the vehicle?
UnitID unitnumber
unit number, for display purposes only
bool IsTileOwner(Tile tile, Owner owner)
Checks if a tile belongs to the given owner.
Definition tile_map.h:214
StrongType::Typedef< uint32_t, struct TileIndexTag, StrongType::Compare, StrongType::Integer, StrongType::Compatible< int32_t >, StrongType::Compatible< int64_t > > TileIndex
The index/ID of a Tile.
Definition tile_type.h:92
Base for the train class.
void NormalizeTrainVehInDepot(const Train *u)
Move all free vehicles in the depot to the train.
@ Flipped
Reverse the visible direction of the vehicle.
Definition train.h:28
static constexpr ConsistChangeFlags CCF_REFIT
Valid changes for refitting in a depot.
Definition train.h:56
static constexpr ConsistChangeFlags CCF_AUTOREFIT
Valid changes for autorefitting in stations.
Definition train.h:55
CommandCost CmdBuildRailVehicle(DoCommandFlags flags, TileIndex tile, const Engine *e, Vehicle **ret)
Build a railroad vehicle.
CommandCost CmdSellRailWagon(DoCommandFlags flags, Vehicle *t, bool sell_chain, bool backup_order, ClientID user)
Sell a (single) train wagon/engine.
Command definitions related to trains.
uint16_t UnitID
Type for the company global vehicle unit number.
void GetVehicleSet(VehicleSet &set, Vehicle *v, uint8_t num_vehicles)
Calculates the set of vehicles that will be affected by a given selection.
Definition vehicle.cpp:3249
UnitID GetFreeUnitNumber(VehicleType type)
Get an unused unit number for a vehicle (if allowed).
Definition vehicle.cpp:1916
@ Crashed
Vehicle is crashed.
@ Stopped
Vehicle is stopped by the player.
CommandCost CmdMassStartStopVehicle(DoCommandFlags flags, TileIndex tile, bool do_start, bool vehicle_list_window, const VehicleListIdentifier &vli)
Starts or stops a lot of vehicles.
const StringID _veh_sell_all_msg_table[]
When can't sell all vehicles in depot.
static void CloneVehicleName(const Vehicle *src, Vehicle *dst)
Clone the custom name of a vehicle, adding or incrementing a number.
bool IsUniqueVehicleName(const std::string &name)
Test if a name is unique among vehicle names.
CommandCost CmdDepotSellAllVehicles(DoCommandFlags flags, TileIndex tile, VehicleType vehicle_type)
Sells all vehicles in a depot.
std::tuple< CommandCost, VehicleID > CmdCloneVehicle(DoCommandFlags flags, TileIndex tile, VehicleID veh_id, bool share_orders)
Clone a vehicle.
const StringID _veh_refit_msg_table[]
When can't refit such vehicle.
CommandCost CmdChangeServiceInt(DoCommandFlags flags, VehicleID veh_id, uint16_t serv_int, bool is_custom, bool is_percent)
Change the service interval of a vehicle.
static CommandCost GetRefitCost(const Vehicle *v, EngineID engine_type, CargoType new_cargo_type, uint8_t new_subtype, bool *auto_refit_allowed)
Learn the price of refitting a certain engine.
static int GetRefitCostFactor(const Vehicle *v, EngineID engine_type, CargoType new_cargo_type, uint8_t new_subtype, bool *auto_refit_allowed)
Helper to run the refit cost callback.
CommandCost CmdSellVehicle(DoCommandFlags flags, VehicleID v_id, bool sell_chain, bool backup_order, ClientID client_id)
Sell a vehicle.
const StringID _send_to_depot_msg_table[]
When can't send to depot such vehicle.
static std::tuple< CommandCost, uint, uint16_t, CargoArray > RefitVehicle(Vehicle *v, bool only_this, uint8_t num_vehicles, CargoType new_cargo_type, uint8_t new_subtype, DoCommandFlags flags, bool auto_refit)
Refits a vehicle (chain).
CommandCost CmdSendVehicleToDepot(DoCommandFlags flags, VehicleID veh_id, DepotCommandFlags depot_cmd, const VehicleListIdentifier &vli)
Send a vehicle to the depot.
static CommandCost SendAllVehiclesToDepot(DoCommandFlags flags, bool service, const VehicleListIdentifier &vli)
Send all vehicles of type to depots.
std::tuple< CommandCost, uint, uint16_t, CargoArray > CmdRefitVehicle(DoCommandFlags flags, VehicleID veh_id, CargoType new_cargo_type, uint8_t new_subtype, bool auto_refit, bool only_this, uint8_t num_vehicles)
Refits a vehicle to the specified cargo type.
CommandCost CmdRenameVehicle(DoCommandFlags flags, VehicleID veh_id, const std::string &text)
Give a custom name to your vehicle.
const StringID _veh_build_msg_table[]
When can't buy such vehicle.
CommandCost CmdStartStopVehicle(DoCommandFlags flags, VehicleID veh_id, bool evaluate_startstop_cb)
Start/Stop a vehicle.
CommandCost CmdDepotMassAutoReplace(DoCommandFlags flags, TileIndex tile, VehicleType vehicle_type)
Autoreplace all vehicles in the depot.
const StringID _veh_autoreplace_msg_table[]
When can't autoreplace such vehicle.
const StringID _veh_sell_msg_table[]
When can't sell such vehicle.
std::tuple< CommandCost, VehicleID, uint, uint16_t, CargoArray > CmdBuildVehicle(DoCommandFlags flags, TileIndex tile, EngineID eid, bool use_free_vehicles, CargoType cargo, ClientID client_id)
Build a vehicle.
Command definitions for vehicles.
Functions related to vehicles.
uint8_t GetBestFittingSubType(Vehicle *v_from, Vehicle *v_for, CargoType dest_cargo_type)
Get the best fitting subtype when 'cloning'/'replacing' v_from with v_for.
bool IsCompanyBuildableVehicleType(VehicleType type)
Is the given vehicle type buildable by a company?
WindowClass GetWindowClassForVehicleType(VehicleType vt)
Get WindowClass for vehicle list of given vehicle type.
Definition vehicle_gui.h:97
PoolID< uint32_t, struct VehicleIDTag, 0xFF000, 0xFFFFF > VehicleID
The type all our vehicle IDs have.
VehicleType
Available vehicle types.
@ VEH_ROAD
Road vehicle type.
@ VEH_AIRCRAFT
Aircraft vehicle type.
@ VEH_SHIP
Ship vehicle type.
@ VEH_TRAIN
Train vehicle type.
@ MassSend
Tells that it's a mass send to depot command (type in VLW flag).
@ DontCancel
Don't cancel current goto depot command if any.
@ Service
The vehicle will leave the depot right after arrival (service only).
static const uint MAX_LENGTH_VEHICLE_NAME_CHARS
The maximum length of a vehicle name in characters including '\0'.
@ WID_VV_START_STOP
Start or stop this vehicle, and show information about the current state.
bool GenerateVehicleSortList(VehicleList *list, const VehicleListIdentifier &vli)
Generate a list of vehicles based on window type.
void BuildDepotVehicleList(VehicleType type, TileIndex tile, VehicleList *engines, VehicleList *wagons, bool individual_wagons)
Generate a list of vehicles inside a depot.
Functions and type for generating vehicle lists.
std::vector< const Vehicle * > VehicleList
A list of vehicles.
Definition vehiclelist.h:68
void SetWindowClassesDirty(WindowClass cls)
Mark all windows of a particular class as dirty (in need of repainting).
Definition window.cpp:3229
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:3321
void SetWindowWidgetDirty(WindowClass cls, WindowNumber number, WidgetID widget_index)
Mark a particular widget in a particular window as dirty (in need of repainting).
Definition window.cpp:3215
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting).
Definition window.cpp:3199
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:3339
@ WC_VEHICLE_DEPOT
Depot view; Window numbers:
@ WC_VEHICLE_DETAILS
Vehicle details; Window numbers:
@ WC_COMPANY
Company view; Window numbers:
@ WC_VEHICLE_VIEW
Vehicle view; Window numbers: