OpenTTD Source 20260731-master-g77ba2b244a
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
43
44#include "table/strings.h"
45
46#include "safeguards.h"
47
55 STR_ERROR_CAN_T_BUY_TRAIN,
56 STR_ERROR_CAN_T_BUY_ROAD_VEHICLE,
57 STR_ERROR_CAN_T_BUY_SHIP,
58 STR_ERROR_CAN_T_BUY_AIRCRAFT,
59};
60
63 STR_ERROR_CAN_T_SELL_TRAIN,
64 STR_ERROR_CAN_T_SELL_ROAD_VEHICLE,
65 STR_ERROR_CAN_T_SELL_SHIP,
66 STR_ERROR_CAN_T_SELL_AIRCRAFT,
67};
68
71 STR_ERROR_CAN_T_SELL_ALL_TRAIN,
72 STR_ERROR_CAN_T_SELL_ALL_ROAD_VEHICLE,
73 STR_ERROR_CAN_T_SELL_ALL_SHIP,
74 STR_ERROR_CAN_T_SELL_ALL_AIRCRAFT,
75};
76
79 STR_ERROR_CAN_T_AUTOREPLACE_TRAIN,
80 STR_ERROR_CAN_T_AUTOREPLACE_ROAD_VEHICLE,
81 STR_ERROR_CAN_T_AUTOREPLACE_SHIP,
82 STR_ERROR_CAN_T_AUTOREPLACE_AIRCRAFT,
83};
84
87 STR_ERROR_CAN_T_REFIT_TRAIN,
88 STR_ERROR_CAN_T_REFIT_ROAD_VEHICLE,
89 STR_ERROR_CAN_T_REFIT_SHIP,
90 STR_ERROR_CAN_T_REFIT_AIRCRAFT,
91};
92
95 STR_ERROR_CAN_T_SEND_TRAIN_TO_DEPOT,
96 STR_ERROR_CAN_T_SEND_ROAD_VEHICLE_TO_DEPOT,
97 STR_ERROR_CAN_T_SEND_SHIP_TO_DEPOT,
98 STR_ERROR_CAN_T_SEND_AIRCRAFT_TO_HANGAR,
99};
100
101
102
113std::tuple<CommandCost, VehicleID, uint, uint16_t, CargoArray> CmdBuildVehicle(DoCommandFlags flags, TileIndex tile, EngineID eid, bool use_free_vehicles, CargoType cargo, ClientID client_id)
114{
115 /* Elementary check for valid location. */
116 if (!IsDepotTile(tile) || !IsTileOwner(tile, _current_company)) return { CMD_ERROR, VehicleID::Invalid(), 0, 0, {} };
117
118 VehicleType type = GetDepotVehicleType(tile);
119
120 /* Validate the engine type. */
121 if (!IsEngineBuildable(eid, type, _current_company)) return { CommandCost(STR_ERROR_RAIL_VEHICLE_NOT_AVAILABLE + to_underlying(type)), VehicleID::Invalid(), 0, 0, {} };
122
123 /* Validate the cargo type. */
124 if (cargo >= NUM_CARGO && IsValidCargoType(cargo)) return { CMD_ERROR, VehicleID::Invalid(), 0, 0, {} };
125
126 const Engine *e = Engine::Get(eid);
128
129 /* Engines without valid cargo should not be available */
130 CargoType default_cargo = e->GetDefaultCargoType();
131 if (!IsValidCargoType(default_cargo)) return { CMD_ERROR, VehicleID::Invalid(), 0, 0, {} };
132
133 bool refitting = IsValidCargoType(cargo) && cargo != default_cargo;
134
135 /* Check whether the number of vehicles we need to build can be built according to pool space. */
136 uint num_vehicles;
137 switch (type) {
138 case VehicleType::Train: num_vehicles = (e->VehInfo<RailVehicleInfo>().railveh_type == RailVehicleType::Multihead ? 2 : 1) + CountArticulatedParts(eid); break;
139 case VehicleType::Road: num_vehicles = 1 + CountArticulatedParts(eid); break;
140 case VehicleType::Ship: num_vehicles = 1; break;
141 case VehicleType::Aircraft: num_vehicles = e->VehInfo<AircraftVehicleInfo>().subtype & AIR_CTOL ? 2 : 3; break;
142 default: NOT_REACHED(); // Safe due to IsDepotTile()
143 }
144 if (!Vehicle::CanAllocateItem(num_vehicles)) return { CommandCost(STR_ERROR_TOO_MANY_VEHICLES_IN_GAME), VehicleID::Invalid(), 0, 0, {} };
145
146 /* Check whether we can allocate a unit number. Autoreplace does not allocate
147 * an unit number as it will (always) reuse the one of the replaced vehicle
148 * and (train) wagons don't have an unit number in any scenario. */
150 if (unit_num == UINT16_MAX) return { CommandCost(STR_ERROR_TOO_MANY_VEHICLES_IN_GAME), VehicleID::Invalid(), 0, 0, {} };
151
152 /* If we are refitting we need to temporarily purchase the vehicle to be able to
153 * test it. */
154 DoCommandFlags subflags = flags;
156
157 /* Vehicle construction needs random bits, so we have to save the random
158 * seeds to prevent desyncs. */
159 SavedRandomSeeds saved_seeds;
160 SaveRandomSeeds(&saved_seeds);
161
162 Vehicle *v = nullptr;
163 switch (type) {
164 case VehicleType::Train: value.AddCost(CmdBuildRailVehicle(subflags, tile, e, &v)); break;
165 case VehicleType::Road: value.AddCost(CmdBuildRoadVehicle(subflags, tile, e, &v)); break;
166 case VehicleType::Ship: value.AddCost(CmdBuildShip (subflags, tile, e, &v)); break;
167 case VehicleType::Aircraft: value.AddCost(CmdBuildAircraft (subflags, tile, e, &v)); break;
168 default: NOT_REACHED(); // Safe due to IsDepotTile()
169 }
170
171 VehicleID veh_id = VehicleID::Invalid();
172 uint refitted_capacity = 0;
173 uint16_t refitted_mail_capacity = 0;
174 CargoArray cargo_capacities{};
175 if (value.Succeeded()) {
176 if (subflags.Test(DoCommandFlag::Execute)) {
177 v->unitnumber = unit_num;
178 v->value = value.GetCost();
179 veh_id = v->index;
180 }
181
182 if (refitting) {
183 /* Refit only one vehicle. If we purchased an engine, it may have gained free wagons. */
184 CommandCost cc;
185 std::tie(cc, refitted_capacity, refitted_mail_capacity, cargo_capacities) = CmdRefitVehicle(flags, v->index, cargo, 0, false, false, 1);
186 value.AddCost(std::move(cc));
187 } else {
188 /* Fill in non-refitted capacities */
189 if (e->type == VehicleType::Train || e->type == VehicleType::Road) {
190 cargo_capacities = GetCapacityOfArticulatedParts(eid);
191 refitted_capacity = cargo_capacities[default_cargo];
192 refitted_mail_capacity = 0;
193 } else {
194 refitted_capacity = e->GetDisplayDefaultCapacity(&refitted_mail_capacity);
195 cargo_capacities[default_cargo] = refitted_capacity;
196 CargoType mail = GetCargoTypeByLabel(CT_MAIL);
197 if (IsValidCargoType(mail)) cargo_capacities[mail] = refitted_mail_capacity;
198 }
199 }
200
201 if (flags.Test(DoCommandFlag::Execute)) {
202 if (type == VehicleType::Train && use_free_vehicles && !flags.Test(DoCommandFlag::AutoReplace) && Train::From(v)->IsEngine()) {
203 /* Move any free wagons to the new vehicle. */
205 }
206
207 InvalidateWindowData(WindowClass::VehicleDepot, v->tile);
209 SetWindowDirty(WindowClass::Company, _current_company);
210 if (IsLocalCompany()) {
211 InvalidateAutoreplaceWindow(v->engine_type, v->group_id); // updates the auto replace window (must be called before incrementing num_engines)
212 }
213 }
214
215 if (subflags.Test(DoCommandFlag::Execute)) {
218
219 if (v->IsPrimaryVehicle()) {
221 if (!subflags.Test(DoCommandFlag::AutoReplace)) OrderBackup::Restore(v, client_id);
222 }
223
224 Company::Get(v->owner)->freeunits[v->type].UseID(v->unitnumber);
225 }
226
227
228 /* If we are not in DoCommandFlag::Execute undo everything */
229 if (flags != subflags) {
230 Command<Commands::SellVehicle>::Do(DoCommandFlag::Execute, v->index, false, false, ClientID::Invalid);
231 }
232 }
233
234 /* Only restore if we actually did some refitting */
235 if (flags != subflags) RestoreRandomSeeds(saved_seeds);
236
237 return { value, veh_id, refitted_capacity, refitted_mail_capacity, cargo_capacities };
238}
239
249CommandCost CmdSellVehicle(DoCommandFlags flags, VehicleID v_id, bool sell_chain, bool backup_order, ClientID client_id)
250{
251 Vehicle *v = Vehicle::GetIfValid(v_id);
252 if (v == nullptr || !IsCompanyBuildableVehicleType(v)) return CMD_ERROR;
253
254 Vehicle *front = v->First();
255
256 CommandCost ret = CheckOwnership(front->owner);
257 if (ret.Failed()) return ret;
258
259 if (front->vehstatus.Test(VehState::Crashed)) return CommandCost(STR_ERROR_VEHICLE_IS_DESTROYED);
260
261 if (!front->IsStoppedInDepot()) return CommandCost(STR_ERROR_TRAIN_MUST_BE_STOPPED_INSIDE_DEPOT + to_underlying(front->type));
262
263 if (v->type == VehicleType::Train) {
264 ret = CmdSellRailWagon(flags, v, sell_chain, backup_order, client_id);
265 } else {
267
268 if (flags.Test(DoCommandFlag::Execute)) {
269 if (front->IsPrimaryVehicle() && backup_order) OrderBackup::Backup(front, client_id);
270 delete front;
271 }
272 }
273
274 return ret;
275}
276
286static int GetRefitCostFactor(const Vehicle *v, EngineID engine_type, CargoType new_cargo_type, uint8_t new_subtype, bool *auto_refit_allowed)
287{
288 /* Prepare callback param with info about the new cargo type. */
289 const Engine *e = Engine::Get(engine_type);
290
291 /* Is this vehicle a NewGRF vehicle? */
292 if (e->GetGRF() != nullptr) {
293 const CargoSpec *cs = CargoSpec::Get(new_cargo_type);
294 uint32_t param1 = (cs->classes.base() << 16) | (new_subtype << 8) | e->GetGRF()->cargo_map[new_cargo_type];
295
296 uint16_t cb_res = GetVehicleCallback(CBID_VEHICLE_REFIT_COST, param1, 0, engine_type, v);
297 if (cb_res != CALLBACK_FAILED) {
298 *auto_refit_allowed = HasBit(cb_res, 14);
299 int factor = GB(cb_res, 0, 14);
300 if (factor >= 0x2000) factor -= 0x4000; // Treat as signed integer.
301 return factor;
302 }
303 }
304
305 *auto_refit_allowed = e->info.refit_cost == 0;
306 return (v == nullptr || v->cargo_type != new_cargo_type) ? e->info.refit_cost : 0;
307}
308
318static CommandCost GetRefitCost(const Vehicle *v, EngineID engine_type, CargoType new_cargo_type, uint8_t new_subtype, bool *auto_refit_allowed)
319{
320 ExpensesType expense_type;
321 const Engine *e = Engine::Get(engine_type);
322 Price base_price;
323 int cost_factor = GetRefitCostFactor(v, engine_type, new_cargo_type, new_subtype, auto_refit_allowed);
324 switch (e->type) {
326 base_price = Price::BuildVehicleShip;
327 expense_type = ExpensesType::ShipRun;
328 break;
329
331 base_price = Price::BuildVehicleRoad;
332 expense_type = ExpensesType::RoadVehRun;
333 break;
334
336 base_price = Price::BuildVehicleAircraft;
337 expense_type = ExpensesType::AircraftRun;
338 break;
339
342 cost_factor <<= 1;
343 expense_type = ExpensesType::TrainRun;
344 break;
345
346 default: NOT_REACHED();
347 }
348 if (cost_factor < 0) {
349 return CommandCost(expense_type, -GetPrice(base_price, -cost_factor, e->GetGRF(), -10));
350 } else {
351 return CommandCost(expense_type, GetPrice(base_price, cost_factor, e->GetGRF(), -10));
352 }
353}
354
362
375static 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)
376{
377 CommandCost cost(v->GetExpenseType(false));
378 uint total_capacity = 0;
379 uint total_mail_capacity = 0;
380 num_vehicles = num_vehicles == 0 ? UINT8_MAX : num_vehicles;
381 CargoArray cargo_capacities{};
382
383 VehicleSet vehicles_to_refit;
384 if (!only_this) {
385 GetVehicleSet(vehicles_to_refit, v, num_vehicles);
386 /* In this case, we need to check the whole chain. */
387 v = v->First();
388 }
389
390 std::vector<RefitResult> refit_result;
391
393 uint8_t actual_subtype = new_subtype;
394 for (; v != nullptr; v = (only_this ? nullptr : v->Next())) {
395 /* Reset actual_subtype for every new vehicle */
396 if (!v->IsArticulatedPart()) actual_subtype = new_subtype;
397
398 if (v->type == VehicleType::Train && std::ranges::find(vehicles_to_refit, v->index) == vehicles_to_refit.end() && !only_this) continue;
399
400 const Engine *e = v->GetEngine();
401 if (!e->CanCarryCargo()) continue;
402
403 /* If the vehicle is not refittable, or does not allow automatic refitting,
404 * count its capacity nevertheless if the cargo matches */
405 bool refittable = e->info.refit_mask.Test(new_cargo_type) && (!auto_refit || e->info.misc_flags.Test(EngineMiscFlag::AutoRefit));
406 if (!refittable && v->cargo_type != new_cargo_type) {
407 uint amount = e->DetermineCapacity(v, nullptr);
408 if (amount > 0) cargo_capacities[v->cargo_type] += amount;
409 continue;
410 }
411
412 /* Determine best fitting subtype if requested */
413 if (actual_subtype == 0xFF) {
414 actual_subtype = GetBestFittingSubType(v, v, new_cargo_type);
415 }
416
417 /* Back up the vehicle's cargo type */
418 CargoType temp_cargo_type = v->cargo_type;
419 uint8_t temp_subtype = v->cargo_subtype;
420 if (refittable) {
421 v->cargo_type = new_cargo_type;
422 v->cargo_subtype = actual_subtype;
423 }
424
425 uint16_t mail_capacity = 0;
426 uint amount = e->DetermineCapacity(v, &mail_capacity);
427 total_capacity += amount;
428 /* mail_capacity will always be zero if the vehicle is not an aircraft. */
429 total_mail_capacity += mail_capacity;
430
431 cargo_capacities[new_cargo_type] += amount;
432 CargoType mail = GetCargoTypeByLabel(CT_MAIL);
433 if (IsValidCargoType(mail)) cargo_capacities[mail] += mail_capacity;
434
435 if (!refittable) continue;
436
437 /* Restore the original cargo type */
438 v->cargo_type = temp_cargo_type;
439 v->cargo_subtype = temp_subtype;
440
441 bool auto_refit_allowed;
442 CommandCost refit_cost = GetRefitCost(v, v->engine_type, new_cargo_type, actual_subtype, &auto_refit_allowed);
443 if (auto_refit && !flags.Test(DoCommandFlag::QueryCost) && !auto_refit_allowed) {
444 /* Sorry, auto-refitting not allowed, subtract the cargo amount again from the total.
445 * When querying cost/capacity (for example in order refit GUI), we always assume 'allowed'.
446 * It is not predictable. */
447 total_capacity -= amount;
448 total_mail_capacity -= mail_capacity;
449
450 if (v->cargo_type == new_cargo_type) {
451 /* Add the old capacity nevertheless, if the cargo matches */
452 total_capacity += v->cargo_cap;
453 if (v->type == VehicleType::Aircraft) total_mail_capacity += v->Next()->cargo_cap;
454 }
455 continue;
456 }
457 cost.AddCost(std::move(refit_cost));
458
459 /* Record the refitting.
460 * Do not execute the refitting immediately, so DetermineCapacity and GetRefitCost do the same in test and exec run.
461 * (weird NewGRFs)
462 * Note:
463 * - If the capacity of vehicles depends on other vehicles in the chain, the actual capacity is
464 * set after RefitVehicle() via ConsistChanged() and friends. The estimation via _returned_refit_capacity will be wrong.
465 * - We have to call the refit cost callback with the pre-refit configuration of the chain because we want refit and
466 * autorefit to behave the same, and we need its result for auto_refit_allowed.
467 */
468 refit_result.emplace_back(v, amount, mail_capacity, actual_subtype);
469 }
470
471 if (flags.Test(DoCommandFlag::Execute)) {
472 /* Store the result */
473 for (RefitResult &result : refit_result) {
474 Vehicle *u = result.v;
475 u->refit_cap = (u->cargo_type == new_cargo_type) ? std::min<uint16_t>(result.capacity, u->refit_cap) : 0;
476 if (u->cargo.TotalCount() > u->refit_cap) u->cargo.Truncate(u->cargo.TotalCount() - u->refit_cap);
477 u->cargo_type = new_cargo_type;
478 u->cargo_cap = result.capacity;
479 u->cargo_subtype = result.subtype;
480 if (u->type == VehicleType::Aircraft) {
481 Vehicle *w = u->Next();
482 assert(w != nullptr);
483 w->refit_cap = std::min<uint16_t>(w->refit_cap, result.mail_capacity);
484 w->cargo_cap = result.mail_capacity;
485 if (w->cargo.TotalCount() > w->refit_cap) w->cargo.Truncate(w->cargo.TotalCount() - w->refit_cap);
486 }
487 }
488 }
489
490 refit_result.clear();
491 return { cost, total_capacity, total_mail_capacity, cargo_capacities };
492}
493
506std::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)
507{
508 Vehicle *v = Vehicle::GetIfValid(veh_id);
509 if (v == nullptr || !IsCompanyBuildableVehicleType(v)) return { CMD_ERROR, 0, 0, {} };
510
511 Vehicle *front = v->First();
512
513 CommandCost ret = CheckOwnership(front->owner);
514 if (ret.Failed()) return { ret, 0, 0, {} };
515
516 bool free_wagon = v->type == VehicleType::Train && Train::From(front)->IsFreeWagon(); // used by autoreplace/renew
517
518 /* Don't allow shadows and such to be refitted. */
519 if (v != front && (v->type == VehicleType::Ship || v->type == VehicleType::Aircraft)) return { CMD_ERROR, 0, 0, {} };
520
521 /* Allow auto-refitting only during loading and normal refitting only in a depot. */
522 if (!flags.Test(DoCommandFlag::QueryCost) && // used by the refit GUI, including the order refit GUI.
523 !free_wagon && // used by autoreplace/renew
524 (!auto_refit || !front->current_order.IsType(OT_LOADING)) && // refit inside stations
525 !front->IsStoppedInDepot()) { // refit inside depots
526 return { CommandCost(STR_ERROR_TRAIN_MUST_BE_STOPPED_INSIDE_DEPOT + to_underlying(front->type)), 0, 0, {} };
527 }
528
529 if (front->vehstatus.Test(VehState::Crashed)) return { CommandCost(STR_ERROR_VEHICLE_IS_DESTROYED), 0, 0, {} };
530
531 /* Check cargo */
532 if (new_cargo_type >= NUM_CARGO) return { CMD_ERROR, 0, 0, {} };
533
534 /* For ships and aircraft there is always only one. */
535 only_this |= front->type == VehicleType::Ship || front->type == VehicleType::Aircraft;
536
537 auto [cost, refit_capacity, mail_capacity, cargo_capacities] = RefitVehicle(v, only_this, num_vehicles, new_cargo_type, new_subtype, flags, auto_refit);
538
539 if (flags.Test(DoCommandFlag::Execute)) {
540 /* Update the cached variables */
541 switch (v->type) {
543 Train::From(front)->ConsistChanged(auto_refit ? CCF_AUTOREFIT : CCF_REFIT);
544 break;
546 RoadVehUpdateCache(RoadVehicle::From(front), auto_refit);
547 if (_settings_game.vehicle.roadveh_acceleration_model != AccelerationModel::Original) RoadVehicle::From(front)->CargoChanged();
548 break;
549
553 break;
554
558 break;
559
560 default: NOT_REACHED();
561 }
562 front->MarkDirty();
563
564 if (!free_wagon) {
565 InvalidateWindowData(WindowClass::VehicleDetails, front->index);
567 }
568 SetWindowDirty(WindowClass::VehicleDepot, front->tile);
569 } else {
570 /* Always invalidate the cache; querycost might have filled it. */
572 }
573
574 return { cost, refit_capacity, mail_capacity, cargo_capacities };
575}
576
584CommandCost CmdStartStopVehicle(DoCommandFlags flags, VehicleID veh_id, bool evaluate_startstop_cb)
585{
586 /* Disable the effect of evaluate_startstop_cb, when DoCommandFlag::AutoReplace is not set */
587 if (!flags.Test(DoCommandFlag::AutoReplace)) evaluate_startstop_cb = true;
588
589 Vehicle *v = Vehicle::GetIfValid(veh_id);
590 if (v == nullptr || !IsCompanyBuildableVehicleType(v) || !v->IsPrimaryVehicle()) return CMD_ERROR;
591
593 if (ret.Failed()) return ret;
594
595 if (v->vehstatus.Test(VehState::Crashed)) return CommandCost(STR_ERROR_VEHICLE_IS_DESTROYED);
596
597 switch (v->type) {
599 if (v->vehstatus.Test(VehState::Stopped) && Train::From(v)->gcache.cached_power == 0) return CommandCost(STR_ERROR_TRAIN_START_NO_POWER);
600 break;
601
604 break;
605
607 Aircraft *a = Aircraft::From(v);
608 /* cannot stop airplane when in flight, or when taking off / landing */
609 if (a->state >= STARTTAKEOFF && a->state < TERM7) return CommandCost(STR_ERROR_AIRCRAFT_IS_IN_FLIGHT);
610 if (a->flags.Test(VehicleAirFlag::HelicopterDirectDescent)) return CommandCost(STR_ERROR_AIRCRAFT_IS_IN_FLIGHT);
611 break;
612 }
613
614 default: return CMD_ERROR;
615 }
616
617 if (evaluate_startstop_cb) {
618 /* Check if this vehicle can be started/stopped. Failure means 'allow'. */
619 std::array<int32_t, 1> regs100;
620 uint16_t callback = GetVehicleCallback(CBID_VEHICLE_START_STOP_CHECK, 0, 0, v->engine_type, v, regs100);
621 StringID error = STR_NULL;
622 if (callback != CALLBACK_FAILED) {
623 if (v->GetGRF()->grf_version < 8) {
624 /* 8 bit result 0xFF means 'allow' */
625 if (callback < 0x400 && GB(callback, 0, 8) != 0xFF) error = GetGRFStringID(v->GetGRFID(), GRFSTR_MISC_GRF_TEXT + callback);
626 } else {
627 if (callback < 0x400) {
628 error = GetGRFStringID(v->GetGRFID(), GRFSTR_MISC_GRF_TEXT + callback);
629 } else {
630 switch (callback) {
631 case 0x400: // allow
632 break;
633
634 case 0x40F:
635 error = GetGRFStringID(v->GetGRFID(), static_cast<GRFStringID>(regs100[0]));
636 break;
637
638 default: // unknown reason -> disallow
639 error = STR_ERROR_INCOMPATIBLE_RAIL_TYPES;
640 break;
641 }
642 }
643 }
644 }
645 if (error != STR_NULL) return CommandCost(error);
646 }
647
648 if (flags.Test(DoCommandFlag::Execute)) {
650
652 if (v->type != VehicleType::Train) v->cur_speed = 0; // trains can stop 'slowly'
653
654 /* Unbunching data is no longer valid. */
656
657 v->MarkDirty();
658 SetWindowWidgetDirty(WindowClass::VehicleView, v->index, WID_VV_START_STOP);
659 SetWindowDirty(WindowClass::VehicleDepot, v->GetMovingFront()->tile);
661 InvalidateWindowData(WindowClass::VehicleView, v->index);
662 }
663 return CommandCost();
664}
665
675CommandCost CmdMassStartStopVehicle(DoCommandFlags flags, TileIndex tile, bool do_start, bool vehicle_list_window, const VehicleListIdentifier &vli)
676{
677 VehicleList list;
678
679 if (!vli.Valid()) return CMD_ERROR;
681
682 if (vehicle_list_window) {
683 if (!GenerateVehicleSortList(&list, vli)) return CMD_ERROR;
684 } else {
685 if (!IsDepotTile(tile) || !IsTileOwner(tile, _current_company)) return CMD_ERROR;
686 /* Get the list of vehicles in the depot */
687 BuildDepotVehicleList(vli.vtype, tile, &list, nullptr);
688 }
689
690 for (const Vehicle *v : list) {
691 if (v->vehstatus.Test(VehState::Stopped) != do_start) continue;
692
693 if (!vehicle_list_window && !v->IsChainInDepot()) continue;
694
695 /* Just try and don't care if some vehicle's can't be stopped. */
696 Command<Commands::StartStopVehicle>::Do(flags, v->index, false);
697 }
698
699 return CommandCost();
700}
701
710{
711 VehicleList list;
712
714
715 if (!IsCompanyBuildableVehicleType(vehicle_type)) return CMD_ERROR;
716 if (!IsDepotTile(tile) || !IsTileOwner(tile, _current_company)) return CMD_ERROR;
717
718 /* Get the list of vehicles in the depot */
719 BuildDepotVehicleList(vehicle_type, tile, &list, &list);
720
721 CommandCost last_error = CMD_ERROR;
722 bool had_success = false;
723 for (const Vehicle *v : list) {
724 CommandCost ret = Command<Commands::SellVehicle>::Do(flags, v->index, true, false, ClientID::Invalid);
725 if (ret.Succeeded()) {
726 cost.AddCost(ret.GetCost());
727 had_success = true;
728 } else {
729 last_error = std::move(ret);
730 }
731 }
732
733 return had_success ? cost : last_error;
734}
735
744{
745 VehicleList list;
747
748 if (!IsCompanyBuildableVehicleType(vehicle_type)) return CMD_ERROR;
749 if (!IsDepotTile(tile) || !IsTileOwner(tile, _current_company)) return CMD_ERROR;
750
751 /* Get the list of vehicles in the depot */
752 BuildDepotVehicleList(vehicle_type, tile, &list, &list, true);
753
754 for (const Vehicle *v : list) {
755 /* Ensure that the vehicle completely in the depot */
756 if (!v->IsChainInDepot()) continue;
757
758 CommandCost ret = Command<Commands::AutoreplaceVehicle>::Do(flags, v->index);
759
760 if (ret.Succeeded()) cost.AddCost(ret.GetCost());
761 }
762 return cost;
763}
764
770bool IsUniqueVehicleName(const std::string &name)
771{
772 for (const Vehicle *v : Vehicle::Iterate()) {
773 if (!v->name.empty() && v->name == name) return false;
774 }
775
776 return true;
777}
778
784static void CloneVehicleName(const Vehicle *src, Vehicle *dst)
785{
786 std::string buf;
787
788 /* Find the position of the first digit in the last group of digits. */
789 size_t number_position;
790 for (number_position = src->name.length(); number_position > 0; number_position--) {
791 /* The design of UTF-8 lets this work simply without having to check
792 * for UTF-8 sequences. */
793 if (src->name[number_position - 1] < '0' || src->name[number_position - 1] > '9') break;
794 }
795
796 /* Format buffer and determine starting number. */
797 long num;
798 uint8_t padding = 0;
799 if (number_position == src->name.length()) {
800 /* No digit at the end, so start at number 2. */
801 buf = src->name;
802 buf += " ";
803 number_position = buf.length();
804 num = 2;
805 } else {
806 /* Found digits, parse them and start at the next number. */
807 buf = src->name.substr(0, number_position);
808
809 auto num_str = std::string_view(src->name).substr(number_position);
810 padding = (uint8_t)num_str.length();
811
812 [[maybe_unused]] auto err = std::from_chars(num_str.data(), num_str.data() + num_str.size(), num, 10).ec;
813 assert(err == std::errc());
814 num++;
815 }
816
817 /* Check if this name is already taken. */
818 for (int max_iterations = 1000; max_iterations > 0; max_iterations--, num++) {
819 std::string new_name = fmt::format("{}{:0{}}", buf, num, padding);
820
821 /* Check the name is unique. */
822 if (IsUniqueVehicleName(new_name)) {
823 dst->name = std::move(new_name);
824 break;
825 }
826 }
827
828 /* All done. If we didn't find a name, it'll just use its default. */
829}
830
839std::tuple<CommandCost, VehicleID> CmdCloneVehicle(DoCommandFlags flags, TileIndex tile, VehicleID veh_id, bool share_orders)
840{
842
843 Vehicle *v = Vehicle::GetIfValid(veh_id);
844 if (v == nullptr || !IsCompanyBuildableVehicleType(v) || !v->IsPrimaryVehicle()) return { CMD_ERROR, VehicleID::Invalid() };
845 Vehicle *v_front = v;
846 Vehicle *w = nullptr;
847 Vehicle *w_front = nullptr;
848 Vehicle *w_rear = nullptr;
849
850 /*
851 * v_front is the front engine in the original vehicle
852 * v is the car/vehicle of the original vehicle that is currently being copied
853 * w_front is the front engine of the cloned vehicle
854 * w is the car/vehicle currently being cloned
855 * w_rear is the rear end of the cloned train. It's used to add more cars and is only used by trains
856 */
857
859 if (ret.Failed()) return { ret, VehicleID::Invalid() };
860
861 /* Crashed trains can only be cloned before cleanup begins. */
862 if (v->type == VehicleType::Train && (!v->IsFrontEngine() || Train::From(v)->crash_anim_pos >= 4400)) return { CommandCost(STR_ERROR_VEHICLE_IS_DESTROYED), VehicleID::Invalid() };
863
864 /* check that we can allocate enough vehicles */
865 if (!flags.Test(DoCommandFlag::Execute)) {
866 int veh_counter = 0;
867 do {
868 veh_counter++;
869 } while ((v = v->Next()) != nullptr);
870
871 if (!Vehicle::CanAllocateItem(veh_counter)) {
872 return { CommandCost(STR_ERROR_TOO_MANY_VEHICLES_IN_GAME), VehicleID::Invalid() };
873 }
874 }
875
876 v = v_front;
877
878 VehicleID new_veh_id = VehicleID::Invalid();
879 do {
880 if (v->type == VehicleType::Train && Train::From(v)->IsRearDualheaded()) {
881 /* we build the rear ends of multiheaded trains with the front ones */
882 continue;
883 }
884
885 /* In case we're building a multi headed vehicle and the maximum number of
886 * vehicles is almost reached (e.g. max trains - 1) not all vehicles would
887 * be cloned. When the non-primary engines were build they were seen as
888 * 'new' vehicles whereas they would immediately be joined with a primary
889 * engine. This caused the vehicle to be not build as 'the limit' had been
890 * reached, resulting in partially build vehicles and such. */
891 DoCommandFlags build_flags = flags;
893
894 CommandCost cost;
895 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, ClientID::Invalid);
896
897 if (cost.Failed()) {
898 /* Can't build a part, then sell the stuff we already made; clear up the mess */
899 if (w_front != nullptr) Command<Commands::SellVehicle>::Do(flags, w_front->index, true, false, ClientID::Invalid);
900 return { cost, VehicleID::Invalid() };
901 }
902
903 total_cost.AddCost(cost.GetCost());
904
905 if (flags.Test(DoCommandFlag::Execute)) {
906 w = Vehicle::Get(new_veh_id);
907
908 if (v->type == VehicleType::Train && Train::From(v)->flags.Test(VehicleRailFlag::Flipped)) {
909 /* Only copy the reverse state if neither old or new vehicle implements reverse-on-build probability callback. */
913 }
914 }
915
916 if (v->type == VehicleType::Train && !v->IsFrontEngine()) {
917 /* this s a train car
918 * add this unit to the end of the train */
919 CommandCost result = Command<Commands::MoveRailVehicle>::Do(flags, w->index, w_rear->index, true);
920 if (result.Failed()) {
921 /* The train can't be joined to make the same consist as the original.
922 * Sell what we already made (clean up) and return an error. */
923 Command<Commands::SellVehicle>::Do(flags, w_front->index, true, false, ClientID::Invalid);
924 Command<Commands::SellVehicle>::Do(flags, w->index, true, false, ClientID::Invalid);
925 return { result, VehicleID::Invalid() }; // return error and the message returned from Commands::MoveRailVehicle
926 }
927 } else {
928 /* this is a front engine or not a train. */
929 w_front = w;
931 w->SetServiceIntervalIsCustom(v->ServiceIntervalIsCustom());
932 w->SetServiceIntervalIsPercent(v->ServiceIntervalIsPercent());
933 }
934 w_rear = w; // trains needs to know the last car in the train, so they can add more in next loop
935 }
936 } while (v->type == VehicleType::Train && (v = v->GetNextVehicle()) != nullptr);
937
938 if (flags.Test(DoCommandFlag::Execute) && v_front->type == VehicleType::Train) {
939 /* for trains this needs to be the front engine due to the callback function */
940 new_veh_id = w_front->index;
941 }
942
943 if (flags.Test(DoCommandFlag::Execute)) {
944 /* Cloned vehicles belong to the same group */
945 Command<Commands::AddVehicleToGroup>::Do(flags, v_front->group_id, w_front->index, false, VehicleListIdentifier{});
946 }
947
948
949 /* Take care of refitting. */
950 w = w_front;
951 v = v_front;
952
953 /* Both building and refitting are influenced by newgrf callbacks, which
954 * makes it impossible to accurately estimate the cloning costs. In
955 * particular, it is possible for engines of the same type to be built with
956 * different numbers of articulated parts, so when refitting we have to
957 * loop over real vehicles first, and then the articulated parts of those
958 * vehicles in a different loop. */
959 do {
960 do {
961 if (flags.Test(DoCommandFlag::Execute)) {
962 assert(w != nullptr);
963
964 /* Find out what's the best sub type */
965 uint8_t subtype = GetBestFittingSubType(v, w, v->cargo_type);
966 if (w->cargo_type != v->cargo_type || w->cargo_subtype != subtype) {
967 CommandCost cost = ExtractCommandCost(Command<Commands::RefitVehicle>::Do(flags, w->index, v->cargo_type, subtype, false, true, 0));
968 if (cost.Succeeded()) total_cost.AddCost(cost.GetCost());
969 }
970
971 if (w->IsGroundVehicle() && w->HasArticulatedPart()) {
972 w = w->GetNextArticulatedPart();
973 } else {
974 break;
975 }
976 } else {
977 const Engine *e = v->GetEngine();
978 CargoType initial_cargo = (e->CanCarryCargo() ? e->GetDefaultCargoType() : INVALID_CARGO);
979
980 if (v->cargo_type != initial_cargo && IsValidCargoType(initial_cargo)) {
981 bool dummy;
982 total_cost.AddCost(GetRefitCost(nullptr, v->engine_type, v->cargo_type, v->cargo_subtype, &dummy));
983 }
984 }
985
986 if (v->IsGroundVehicle() && v->HasArticulatedPart()) {
987 v = v->GetNextArticulatedPart();
988 } else {
989 break;
990 }
991 } while (v != nullptr);
992
994 } while (v->type == VehicleType::Train && (v = v->GetNextVehicle()) != nullptr);
995
996 if (flags.Test(DoCommandFlag::Execute)) {
997 /*
998 * Set the orders of the vehicle. Cannot do it earlier as we need
999 * the vehicle refitted before doing this, otherwise the moved
1000 * cargo types might not match (passenger vs non-passenger)
1001 */
1002 CommandCost result = Command<Commands::CloneOrder>::Do(flags, (share_orders ? CO_SHARE : CO_COPY), w_front->index, v_front->index);
1003 if (result.Failed()) {
1004 /* The vehicle has already been bought, so now it must be sold again. */
1005 Command<Commands::SellVehicle>::Do(flags, w_front->index, true, false, ClientID::Invalid);
1006 return { result, VehicleID::Invalid() };
1007 }
1008
1009 /* Now clone the vehicle's name, if it has one. */
1010 if (!v_front->name.empty()) CloneVehicleName(v_front, w_front);
1011
1012 /* Since we can't estimate the cost of cloning a vehicle accurately we must
1013 * check whether the company has enough money manually. */
1014 if (!CheckCompanyHasMoney(total_cost)) {
1015 /* The vehicle has already been bought, so now it must be sold again. */
1016 Command<Commands::SellVehicle>::Do(flags, w_front->index, true, false, ClientID::Invalid);
1017 return { total_cost, VehicleID::Invalid() };
1018 }
1019 }
1020
1021 return { total_cost, new_veh_id };
1022}
1023
1032{
1033 VehicleList list;
1034
1035 if (!GenerateVehicleSortList(&list, vli)) return CMD_ERROR;
1036
1037 /* Send all the vehicles to a depot */
1038 bool had_success = false;
1039 for (uint i = 0; i < list.size(); i++) {
1040 const Vehicle *v = list[i];
1041 CommandCost ret = Command<Commands::SendVehicleToDepot>::Do(flags, v->index, (service ? DepotCommandFlag::Service : DepotCommandFlags{}) | DepotCommandFlag::DontCancel, {});
1042
1043 if (ret.Succeeded()) {
1044 had_success = true;
1045
1046 /* Return 0 if DoCommandFlag::Execute is not set this is a valid goto depot command)
1047 * In this case we know that at least one vehicle can be sent to a depot
1048 * and we will issue the command. We can now safely quit the loop, knowing
1049 * it will succeed at least once. With DoCommandFlag::Execute we really need to send them to the depot */
1050 if (!flags.Test(DoCommandFlag::Execute)) break;
1051 }
1052 }
1053
1054 return had_success ? CommandCost() : CMD_ERROR;
1055}
1056
1066{
1067 if (depot_cmd.Test(DepotCommandFlag::MassSend)) {
1068 /* Mass goto depot requested */
1069 if (!vli.Valid()) return CMD_ERROR;
1070 return SendAllVehiclesToDepot(flags, depot_cmd.Test(DepotCommandFlag::Service), vli);
1071 }
1072
1073 Vehicle *v = Vehicle::GetIfValid(veh_id);
1074 if (v == nullptr || !IsCompanyBuildableVehicleType(v)) return CMD_ERROR;
1075 if (!v->IsPrimaryVehicle()) return CMD_ERROR;
1076
1077 return v->SendToDepot(flags, depot_cmd);
1078}
1079
1087CommandCost CmdRenameVehicle(DoCommandFlags flags, VehicleID veh_id, const std::string &text)
1088{
1089 Vehicle *v = Vehicle::GetIfValid(veh_id);
1090 if (v == nullptr || !IsCompanyBuildableVehicleType(v) || !v->IsPrimaryVehicle()) return CMD_ERROR;
1091
1093 if (ret.Failed()) return ret;
1094
1095 bool reset = text.empty();
1096
1097 if (!reset) {
1099 if (!flags.Test(DoCommandFlag::AutoReplace) && !IsUniqueVehicleName(text)) return CommandCost(STR_ERROR_NAME_MUST_BE_UNIQUE);
1100 }
1101
1102 if (flags.Test(DoCommandFlag::Execute)) {
1103 if (reset) {
1104 v->name.clear();
1105 } else {
1106 v->name = text;
1107 }
1110 }
1111
1112 return CommandCost();
1113}
1114
1115
1125CommandCost CmdChangeServiceInt(DoCommandFlags flags, VehicleID veh_id, uint16_t serv_int, bool is_custom, bool is_percent)
1126{
1127 Vehicle *v = Vehicle::GetIfValid(veh_id);
1128 if (v == nullptr || !IsCompanyBuildableVehicleType(v) || !v->IsPrimaryVehicle()) return CMD_ERROR;
1129
1131 if (ret.Failed()) return ret;
1132
1133 const Company *company = Company::Get(v->owner);
1134 is_percent = is_custom ? is_percent : company->settings.vehicle.servint_ispercent;
1135
1136 if (is_custom) {
1137 if (serv_int != GetServiceIntervalClamped(serv_int, is_percent)) return CMD_ERROR;
1138 } else {
1139 serv_int = CompanyServiceInterval(company, v->type);
1140 }
1141
1142 if (flags.Test(DoCommandFlag::Execute)) {
1143 v->SetServiceInterval(serv_int);
1144 v->SetServiceIntervalIsCustom(is_custom);
1145 v->SetServiceIntervalIsPercent(is_percent);
1146 SetWindowDirty(WindowClass::VehicleDetails, v->index);
1147 }
1148
1149 return CommandCost();
1150}
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:75
@ TERM7
Heading for terminal 7.
Definition airport.h:83
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.
bool IsValidCargoType(CargoType cargo)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:110
static constexpr CargoType NUM_CARGO
Maximum number of cargo types in a game.
Definition cargo_type.h:75
CargoType
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:22
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()
Flip all bits.
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:344
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:227
VehicleType type
Vehicle type, ie VehicleType::Road, VehicleType::Train, etc.
Definition engine_base.h:64
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:96
bool CanCarryCargo() const
Determines whether an engine can carry something.
Definition engine.cpp:194
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.
CommandCost & ExtractCommandCost(Tret &ret)
Extract the CommandCost from a command proc result.
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,...
EnumBitSet< DoCommandFlag, uint16_t > DoCommandFlags
Bitset of DoCommandFlag elements.
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:937
ExpensesType
Types of expenses.
@ TrainRun
Running costs trains.
@ NewVehicles
New vehicles.
@ AircraftRun
Running costs aircraft.
@ RoadVehRun
Running costs road vehicles.
@ ShipRun
Running costs ships.
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:1284
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
@ Multihead
indicates a combination of two locomotives
Definition engine_type.h:33
@ Wagon
simple wagon, not motorized
Definition engine_type.h:34
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23).
Definition enum_type.hpp:21
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:1553
virtual void MarkDirty()
Marks the vehicles to be redrawn and updates cached variables.
ClientID
'Unique' identifier to be given to clients
@ Invalid
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(GrfID 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:815
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.
StrongType::Typedef< uint32_t, struct StringIDTag, StrongType::Compare, StrongType::Integer > 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:75
uint8_t state
State of the airport.
Definition aircraft.h:80
VehicleAirFlags flags
Aircraft flags.
Definition aircraft.h:84
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:118
Specification of a cargo type.
Definition cargotype.h:77
CargoClasses classes
Classes of this cargo type.
Definition cargotype.h:84
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo type.
Definition cargotype.h:141
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:146
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 Backup(const Vehicle *v, ClientID user)
Create an order backup for the given vehicle.
static void Restore(Vehicle *v, ClientID user)
Restore the data of this order to 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
RailVehicleType railveh_type
Type of rail vehicle.
Definition engine_type.h:76
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:233
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:749
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:2602
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:759
Vehicle * GetMovingFront() const
Get the moving front of the vehicle chain.
Money value
Value of the vehicle.
uint16_t refit_cap
Capacity left over from before last refit.
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
GrfID GetGRFID() const
Retrieve the GRF ID of the NewGRF the vehicle is tied to.
Definition vehicle.cpp:769
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:3272
UnitID GetFreeUnitNumber(VehicleType type)
Get an unused unit number for a vehicle (if allowed).
Definition vehicle.cpp:1921
@ 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.
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.
CommandCost CmdChangeServiceInt(DoCommandFlags flags, VehicleID veh_id, uint16_t serv_int, bool is_custom, bool is_percent)
Change the service interval of a vehicle.
VehicleTypeIndexArray< const StringID > _veh_autoreplace_msg_table
When can't autoreplace such vehicle.
VehicleTypeIndexArray< const StringID > _veh_build_msg_table
When can't buy such 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.
VehicleTypeIndexArray< const StringID > _veh_sell_msg_table
When can't sell such vehicle.
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.
VehicleTypeIndexArray< const StringID > _veh_sell_all_msg_table
When can't sell all vehicles in depot.
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.
VehicleTypeIndexArray< const StringID > _send_to_depot_msg_table
When can't send to depot 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.
VehicleTypeIndexArray< const StringID > _veh_refit_msg_table
When can't refit 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
EnumBitSet< DepotCommandFlag, uint8_t > DepotCommandFlags
Bitset of DepotCommandFlag elements.
PoolID< uint32_t, struct VehicleIDTag, 0xFF000, 0xFFFFF > VehicleID
The type all our vehicle IDs have.
VehicleType
Available vehicle types.
@ Ship
Ship vehicle type.
@ Aircraft
Aircraft vehicle type.
@ Road
Road vehicle type.
@ 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).
@ Original
Original acceleration model.
EnumIndexArray< T, VehicleType, Tend > VehicleTypeIndexArray
Array with VehicleType as index.
static const uint MAX_LENGTH_VEHICLE_NAME_CHARS
The maximum length of a vehicle name in characters including '\0'.
Types related to the vehicle widgets.
@ 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:3226
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:3318
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:3212
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting).
Definition window.cpp:3196
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:3336