OpenTTD Source 20241224-master-gf74b0cf984
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 <http://www.gnu.org/licenses/>.
6 */
7
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 <sstream>
41#include <iomanip>
42
43#include "table/strings.h"
44
45#include "safeguards.h"
46
47/* Tables used in vehicle_func.h to find the right error message for a certain vehicle type */
48const StringID _veh_build_msg_table[] = {
49 STR_ERROR_CAN_T_BUY_TRAIN,
50 STR_ERROR_CAN_T_BUY_ROAD_VEHICLE,
51 STR_ERROR_CAN_T_BUY_SHIP,
52 STR_ERROR_CAN_T_BUY_AIRCRAFT,
53};
54
55const StringID _veh_sell_msg_table[] = {
56 STR_ERROR_CAN_T_SELL_TRAIN,
57 STR_ERROR_CAN_T_SELL_ROAD_VEHICLE,
58 STR_ERROR_CAN_T_SELL_SHIP,
59 STR_ERROR_CAN_T_SELL_AIRCRAFT,
60};
61
62const StringID _veh_refit_msg_table[] = {
63 STR_ERROR_CAN_T_REFIT_TRAIN,
64 STR_ERROR_CAN_T_REFIT_ROAD_VEHICLE,
65 STR_ERROR_CAN_T_REFIT_SHIP,
66 STR_ERROR_CAN_T_REFIT_AIRCRAFT,
67};
68
69const StringID _send_to_depot_msg_table[] = {
70 STR_ERROR_CAN_T_SEND_TRAIN_TO_DEPOT,
71 STR_ERROR_CAN_T_SEND_ROAD_VEHICLE_TO_DEPOT,
72 STR_ERROR_CAN_T_SEND_SHIP_TO_DEPOT,
73 STR_ERROR_CAN_T_SEND_AIRCRAFT_TO_HANGAR,
74};
75
76
87std::tuple<CommandCost, VehicleID, uint, uint16_t, CargoArray> CmdBuildVehicle(DoCommandFlag flags, TileIndex tile, EngineID eid, bool use_free_vehicles, CargoID cargo, ClientID client_id)
88{
89 /* Elementary check for valid location. */
90 if (!IsDepotTile(tile) || !IsTileOwner(tile, _current_company)) return { CMD_ERROR, INVALID_VEHICLE, 0, 0, {} };
91
93
94 /* Validate the engine type. */
95 if (!IsEngineBuildable(eid, type, _current_company)) return { CommandCost(STR_ERROR_RAIL_VEHICLE_NOT_AVAILABLE + type), INVALID_VEHICLE, 0, 0, {} };
96
97 /* Validate the cargo type. */
98 if (cargo >= NUM_CARGO && IsValidCargoID(cargo)) return { CMD_ERROR, INVALID_VEHICLE, 0, 0, {} };
99
100 const Engine *e = Engine::Get(eid);
102
103 /* Engines without valid cargo should not be available */
104 CargoID default_cargo = e->GetDefaultCargoType();
105 if (!IsValidCargoID(default_cargo)) return { CMD_ERROR, INVALID_VEHICLE, 0, 0, {} };
106
107 bool refitting = IsValidCargoID(cargo) && cargo != default_cargo;
108
109 /* Check whether the number of vehicles we need to build can be built according to pool space. */
110 uint num_vehicles;
111 switch (type) {
112 case VEH_TRAIN: num_vehicles = (e->u.rail.railveh_type == RAILVEH_MULTIHEAD ? 2 : 1) + CountArticulatedParts(eid, false); break;
113 case VEH_ROAD: num_vehicles = 1 + CountArticulatedParts(eid, false); break;
114 case VEH_SHIP: num_vehicles = 1; break;
115 case VEH_AIRCRAFT: num_vehicles = e->u.air.subtype & AIR_CTOL ? 2 : 3; break;
116 default: NOT_REACHED(); // Safe due to IsDepotTile()
117 }
118 if (!Vehicle::CanAllocateItem(num_vehicles)) return { CommandCost(STR_ERROR_TOO_MANY_VEHICLES_IN_GAME), INVALID_VEHICLE, 0, 0, {} };
119
120 /* Check whether we can allocate a unit number. Autoreplace does not allocate
121 * an unit number as it will (always) reuse the one of the replaced vehicle
122 * and (train) wagons don't have an unit number in any scenario. */
123 UnitID unit_num = (flags & DC_QUERY_COST || flags & DC_AUTOREPLACE || (type == VEH_TRAIN && e->u.rail.railveh_type == RAILVEH_WAGON)) ? 0 : GetFreeUnitNumber(type);
124 if (unit_num == UINT16_MAX) return { CommandCost(STR_ERROR_TOO_MANY_VEHICLES_IN_GAME), INVALID_VEHICLE, 0, 0, {} };
125
126 /* If we are refitting we need to temporarily purchase the vehicle to be able to
127 * test it. */
128 DoCommandFlag subflags = flags;
129 if (refitting && !(flags & DC_EXEC)) subflags |= DC_EXEC | DC_AUTOREPLACE;
130
131 /* Vehicle construction needs random bits, so we have to save the random
132 * seeds to prevent desyncs. */
133 SavedRandomSeeds saved_seeds;
134 SaveRandomSeeds(&saved_seeds);
135
136 Vehicle *v = nullptr;
137 switch (type) {
138 case VEH_TRAIN: value.AddCost(CmdBuildRailVehicle(subflags, tile, e, &v)); break;
139 case VEH_ROAD: value.AddCost(CmdBuildRoadVehicle(subflags, tile, e, &v)); break;
140 case VEH_SHIP: value.AddCost(CmdBuildShip (subflags, tile, e, &v)); break;
141 case VEH_AIRCRAFT: value.AddCost(CmdBuildAircraft (subflags, tile, e, &v)); break;
142 default: NOT_REACHED(); // Safe due to IsDepotTile()
143 }
144
145 VehicleID veh_id = INVALID_VEHICLE;
146 uint refitted_capacity = 0;
147 uint16_t refitted_mail_capacity = 0;
148 CargoArray cargo_capacities{};
149 if (value.Succeeded()) {
150 if (subflags & DC_EXEC) {
151 v->unitnumber = unit_num;
152 v->value = value.GetCost();
153 veh_id = v->index;
154 }
155
156 if (refitting) {
157 /* Refit only one vehicle. If we purchased an engine, it may have gained free wagons. */
158 CommandCost cc;
159 std::tie(cc, refitted_capacity, refitted_mail_capacity, cargo_capacities) = CmdRefitVehicle(flags, v->index, cargo, 0, false, false, 1);
160 value.AddCost(cc);
161 } else {
162 /* Fill in non-refitted capacities */
163 if (e->type == VEH_TRAIN || e->type == VEH_ROAD) {
164 cargo_capacities = GetCapacityOfArticulatedParts(eid);
165 refitted_capacity = cargo_capacities[default_cargo];
166 refitted_mail_capacity = 0;
167 } else {
168 refitted_capacity = e->GetDisplayDefaultCapacity(&refitted_mail_capacity);
169 cargo_capacities[default_cargo] = refitted_capacity;
170 CargoID mail = GetCargoIDByLabel(CT_MAIL);
171 if (IsValidCargoID(mail)) cargo_capacities[mail] = refitted_mail_capacity;
172 }
173 }
174
175 if (flags & DC_EXEC) {
176 if (type == VEH_TRAIN && use_free_vehicles && !(flags & DC_AUTOREPLACE) && Train::From(v)->IsEngine()) {
177 /* Move any free wagons to the new vehicle. */
179 }
180
184 if (IsLocalCompany()) {
185 InvalidateAutoreplaceWindow(v->engine_type, v->group_id); // updates the auto replace window (must be called before incrementing num_engines)
186 }
187 }
188
189 if (subflags & DC_EXEC) {
192
193 if (v->IsPrimaryVehicle()) {
195 if (!(subflags & DC_AUTOREPLACE)) OrderBackup::Restore(v, client_id);
196 }
197
198 Company::Get(v->owner)->freeunits[v->type].UseID(v->unitnumber);
199 }
200
201
202 /* If we are not in DC_EXEC undo everything */
203 if (flags != subflags) {
205 }
206 }
207
208 /* Only restore if we actually did some refitting */
209 if (flags != subflags) RestoreRandomSeeds(saved_seeds);
210
211 return { value, veh_id, refitted_capacity, refitted_mail_capacity, cargo_capacities };
212}
213
223CommandCost CmdSellVehicle(DoCommandFlag flags, VehicleID v_id, bool sell_chain, bool backup_order, ClientID client_id)
224{
225 Vehicle *v = Vehicle::GetIfValid(v_id);
226 if (v == nullptr) return CMD_ERROR;
227
228 Vehicle *front = v->First();
229
230 CommandCost ret = CheckOwnership(front->owner);
231 if (ret.Failed()) return ret;
232
233 if (front->vehstatus & VS_CRASHED) return CommandCost(STR_ERROR_VEHICLE_IS_DESTROYED);
234
235 if (!front->IsStoppedInDepot()) return CommandCost(STR_ERROR_TRAIN_MUST_BE_STOPPED_INSIDE_DEPOT + front->type);
236
237 /* Can we actually make the order backup, i.e. are there enough orders? */
238 if (backup_order &&
239 front->orders != nullptr &&
240 !front->orders->IsShared() &&
242 /* Only happens in exceptional cases when there aren't enough orders anyhow.
243 * Thus it should be safe to just drop the orders in that case. */
244 backup_order = false;
245 }
246
247 if (v->type == VEH_TRAIN) {
248 ret = CmdSellRailWagon(flags, v, sell_chain, backup_order, client_id);
249 } else {
251
252 if (flags & DC_EXEC) {
253 if (front->IsPrimaryVehicle() && backup_order) OrderBackup::Backup(front, client_id);
254 delete front;
255 }
256 }
257
258 return ret;
259}
260
270static int GetRefitCostFactor(const Vehicle *v, EngineID engine_type, CargoID new_cid, uint8_t new_subtype, bool *auto_refit_allowed)
271{
272 /* Prepare callback param with info about the new cargo type. */
273 const Engine *e = Engine::Get(engine_type);
274
275 /* Is this vehicle a NewGRF vehicle? */
276 if (e->GetGRF() != nullptr) {
277 const CargoSpec *cs = CargoSpec::Get(new_cid);
278 uint32_t param1 = (cs->classes << 16) | (new_subtype << 8) | e->GetGRF()->cargo_map[new_cid];
279
280 uint16_t cb_res = GetVehicleCallback(CBID_VEHICLE_REFIT_COST, param1, 0, engine_type, v);
281 if (cb_res != CALLBACK_FAILED) {
282 *auto_refit_allowed = HasBit(cb_res, 14);
283 int factor = GB(cb_res, 0, 14);
284 if (factor >= 0x2000) factor -= 0x4000; // Treat as signed integer.
285 return factor;
286 }
287 }
288
289 *auto_refit_allowed = e->info.refit_cost == 0;
290 return (v == nullptr || v->cargo_type != new_cid) ? e->info.refit_cost : 0;
291}
292
302static CommandCost GetRefitCost(const Vehicle *v, EngineID engine_type, CargoID new_cid, uint8_t new_subtype, bool *auto_refit_allowed)
303{
304 ExpensesType expense_type;
305 const Engine *e = Engine::Get(engine_type);
306 Price base_price;
307 int cost_factor = GetRefitCostFactor(v, engine_type, new_cid, new_subtype, auto_refit_allowed);
308 switch (e->type) {
309 case VEH_SHIP:
310 base_price = PR_BUILD_VEHICLE_SHIP;
311 expense_type = EXPENSES_SHIP_RUN;
312 break;
313
314 case VEH_ROAD:
315 base_price = PR_BUILD_VEHICLE_ROAD;
316 expense_type = EXPENSES_ROADVEH_RUN;
317 break;
318
319 case VEH_AIRCRAFT:
320 base_price = PR_BUILD_VEHICLE_AIRCRAFT;
321 expense_type = EXPENSES_AIRCRAFT_RUN;
322 break;
323
324 case VEH_TRAIN:
325 base_price = (e->u.rail.railveh_type == RAILVEH_WAGON) ? PR_BUILD_VEHICLE_WAGON : PR_BUILD_VEHICLE_TRAIN;
326 cost_factor <<= 1;
327 expense_type = EXPENSES_TRAIN_RUN;
328 break;
329
330 default: NOT_REACHED();
331 }
332 if (cost_factor < 0) {
333 return CommandCost(expense_type, -GetPrice(base_price, -cost_factor, e->GetGRF(), -10));
334 } else {
335 return CommandCost(expense_type, GetPrice(base_price, cost_factor, e->GetGRF(), -10));
336 }
337}
338
346
359static std::tuple<CommandCost, uint, uint16_t, CargoArray> RefitVehicle(Vehicle *v, bool only_this, uint8_t num_vehicles, CargoID new_cid, uint8_t new_subtype, DoCommandFlag flags, bool auto_refit)
360{
361 CommandCost cost(v->GetExpenseType(false));
362 uint total_capacity = 0;
363 uint total_mail_capacity = 0;
364 num_vehicles = num_vehicles == 0 ? UINT8_MAX : num_vehicles;
365 CargoArray cargo_capacities{};
366
367 VehicleSet vehicles_to_refit;
368 if (!only_this) {
369 GetVehicleSet(vehicles_to_refit, v, num_vehicles);
370 /* In this case, we need to check the whole chain. */
371 v = v->First();
372 }
373
374 std::vector<RefitResult> refit_result;
375
377 uint8_t actual_subtype = new_subtype;
378 for (; v != nullptr; v = (only_this ? nullptr : v->Next())) {
379 /* Reset actual_subtype for every new vehicle */
380 if (!v->IsArticulatedPart()) actual_subtype = new_subtype;
381
382 if (v->type == VEH_TRAIN && std::ranges::find(vehicles_to_refit, v->index) == vehicles_to_refit.end() && !only_this) continue;
383
384 const Engine *e = v->GetEngine();
385 if (!e->CanCarryCargo()) continue;
386
387 /* If the vehicle is not refittable, or does not allow automatic refitting,
388 * count its capacity nevertheless if the cargo matches */
389 bool refittable = HasBit(e->info.refit_mask, new_cid) && (!auto_refit || HasBit(e->info.misc_flags, EF_AUTO_REFIT));
390 if (!refittable && v->cargo_type != new_cid) {
391 uint amount = e->DetermineCapacity(v, nullptr);
392 if (amount > 0) cargo_capacities[v->cargo_type] += amount;
393 continue;
394 }
395
396 /* Determine best fitting subtype if requested */
397 if (actual_subtype == 0xFF) {
398 actual_subtype = GetBestFittingSubType(v, v, new_cid);
399 }
400
401 /* Back up the vehicle's cargo type */
402 CargoID temp_cid = v->cargo_type;
403 uint8_t temp_subtype = v->cargo_subtype;
404 if (refittable) {
405 v->cargo_type = new_cid;
406 v->cargo_subtype = actual_subtype;
407 }
408
409 uint16_t mail_capacity = 0;
410 uint amount = e->DetermineCapacity(v, &mail_capacity);
411 total_capacity += amount;
412 /* mail_capacity will always be zero if the vehicle is not an aircraft. */
413 total_mail_capacity += mail_capacity;
414
415 cargo_capacities[new_cid] += amount;
416 CargoID mail = GetCargoIDByLabel(CT_MAIL);
417 if (IsValidCargoID(mail)) cargo_capacities[mail] += mail_capacity;
418
419 if (!refittable) continue;
420
421 /* Restore the original cargo type */
422 v->cargo_type = temp_cid;
423 v->cargo_subtype = temp_subtype;
424
425 bool auto_refit_allowed;
426 CommandCost refit_cost = GetRefitCost(v, v->engine_type, new_cid, actual_subtype, &auto_refit_allowed);
427 if (auto_refit && (flags & DC_QUERY_COST) == 0 && !auto_refit_allowed) {
428 /* Sorry, auto-refitting not allowed, subtract the cargo amount again from the total.
429 * When querrying cost/capacity (for example in order refit GUI), we always assume 'allowed'.
430 * It is not predictable. */
431 total_capacity -= amount;
432 total_mail_capacity -= mail_capacity;
433
434 if (v->cargo_type == new_cid) {
435 /* Add the old capacity nevertheless, if the cargo matches */
436 total_capacity += v->cargo_cap;
437 if (v->type == VEH_AIRCRAFT) total_mail_capacity += v->Next()->cargo_cap;
438 }
439 continue;
440 }
441 cost.AddCost(refit_cost);
442
443 /* Record the refitting.
444 * Do not execute the refitting immediately, so DetermineCapacity and GetRefitCost do the same in test and exec run.
445 * (weird NewGRFs)
446 * Note:
447 * - If the capacity of vehicles depends on other vehicles in the chain, the actual capacity is
448 * set after RefitVehicle() via ConsistChanged() and friends. The estimation via _returned_refit_capacity will be wrong.
449 * - We have to call the refit cost callback with the pre-refit configuration of the chain because we want refit and
450 * autorefit to behave the same, and we need its result for auto_refit_allowed.
451 */
452 refit_result.push_back({v, amount, mail_capacity, actual_subtype});
453 }
454
455 if (flags & DC_EXEC) {
456 /* Store the result */
457 for (RefitResult &result : refit_result) {
458 Vehicle *u = result.v;
459 u->refit_cap = (u->cargo_type == new_cid) ? std::min<uint16_t>(result.capacity, u->refit_cap) : 0;
460 if (u->cargo.TotalCount() > u->refit_cap) u->cargo.Truncate(u->cargo.TotalCount() - u->refit_cap);
461 u->cargo_type = new_cid;
462 u->cargo_cap = result.capacity;
463 u->cargo_subtype = result.subtype;
464 if (u->type == VEH_AIRCRAFT) {
465 Vehicle *w = u->Next();
466 assert(w != nullptr);
467 w->refit_cap = std::min<uint16_t>(w->refit_cap, result.mail_capacity);
468 w->cargo_cap = result.mail_capacity;
469 if (w->cargo.TotalCount() > w->refit_cap) w->cargo.Truncate(w->cargo.TotalCount() - w->refit_cap);
470 }
471 }
472 }
473
474 refit_result.clear();
475 return { cost, total_capacity, total_mail_capacity, cargo_capacities };
476}
477
490std::tuple<CommandCost, uint, uint16_t, CargoArray> CmdRefitVehicle(DoCommandFlag flags, VehicleID veh_id, CargoID new_cid, uint8_t new_subtype, bool auto_refit, bool only_this, uint8_t num_vehicles)
491{
492 Vehicle *v = Vehicle::GetIfValid(veh_id);
493 if (v == nullptr) return { CMD_ERROR, 0, 0, {} };
494
495 /* Don't allow disasters and sparks and such to be refitted.
496 * We cannot check for IsPrimaryVehicle as autoreplace also refits in free wagon chains. */
497 if (!IsCompanyBuildableVehicleType(v->type)) return { CMD_ERROR, 0, 0, {} };
498
499 Vehicle *front = v->First();
500
501 CommandCost ret = CheckOwnership(front->owner);
502 if (ret.Failed()) return { ret, 0, 0, {} };
503
504 bool free_wagon = v->type == VEH_TRAIN && Train::From(front)->IsFreeWagon(); // used by autoreplace/renew
505
506 /* Don't allow shadows and such to be refitted. */
507 if (v != front && (v->type == VEH_SHIP || v->type == VEH_AIRCRAFT)) return { CMD_ERROR, 0, 0, {} };
508
509 /* Allow auto-refitting only during loading and normal refitting only in a depot. */
510 if ((flags & DC_QUERY_COST) == 0 && // used by the refit GUI, including the order refit GUI.
511 !free_wagon && // used by autoreplace/renew
512 (!auto_refit || !front->current_order.IsType(OT_LOADING)) && // refit inside stations
513 !front->IsStoppedInDepot()) { // refit inside depots
514 return { CommandCost(STR_ERROR_TRAIN_MUST_BE_STOPPED_INSIDE_DEPOT + front->type), 0, 0, {} };
515 }
516
517 if (front->vehstatus & VS_CRASHED) return { CommandCost(STR_ERROR_VEHICLE_IS_DESTROYED), 0, 0, {} };
518
519 /* Check cargo */
520 if (new_cid >= NUM_CARGO) return { CMD_ERROR, 0, 0, {} };
521
522 /* For ships and aircraft there is always only one. */
523 only_this |= front->type == VEH_SHIP || front->type == VEH_AIRCRAFT;
524
525 auto [cost, refit_capacity, mail_capacity, cargo_capacities] = RefitVehicle(v, only_this, num_vehicles, new_cid, new_subtype, flags, auto_refit);
526
527 if (flags & DC_EXEC) {
528 /* Update the cached variables */
529 switch (v->type) {
530 case VEH_TRAIN:
531 Train::From(front)->ConsistChanged(auto_refit ? CCF_AUTOREFIT : CCF_REFIT);
532 break;
533 case VEH_ROAD:
534 RoadVehUpdateCache(RoadVehicle::From(front), auto_refit);
535 if (_settings_game.vehicle.roadveh_acceleration_model != AM_ORIGINAL) RoadVehicle::From(front)->CargoChanged();
536 break;
537
538 case VEH_SHIP:
541 break;
542
543 case VEH_AIRCRAFT:
546 break;
547
548 default: NOT_REACHED();
549 }
550 front->MarkDirty();
551
552 if (!free_wagon) {
555 }
557 } else {
558 /* Always invalidate the cache; querycost might have filled it. */
560 }
561
562 return { cost, refit_capacity, mail_capacity, cargo_capacities };
563}
564
572CommandCost CmdStartStopVehicle(DoCommandFlag flags, VehicleID veh_id, bool evaluate_startstop_cb)
573{
574 /* Disable the effect of p2 bit 0, when DC_AUTOREPLACE is not set */
575 if ((flags & DC_AUTOREPLACE) == 0) evaluate_startstop_cb = true;
576
577 Vehicle *v = Vehicle::GetIfValid(veh_id);
578 if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
579
581 if (ret.Failed()) return ret;
582
583 if (v->vehstatus & VS_CRASHED) return CommandCost(STR_ERROR_VEHICLE_IS_DESTROYED);
584
585 switch (v->type) {
586 case VEH_TRAIN:
587 if ((v->vehstatus & VS_STOPPED) && Train::From(v)->gcache.cached_power == 0) return CommandCost(STR_ERROR_TRAIN_START_NO_POWER);
588 break;
589
590 case VEH_SHIP:
591 case VEH_ROAD:
592 break;
593
594 case VEH_AIRCRAFT: {
595 Aircraft *a = Aircraft::From(v);
596 /* cannot stop airplane when in flight, or when taking off / landing */
597 if (a->state >= STARTTAKEOFF && a->state < TERM7) return CommandCost(STR_ERROR_AIRCRAFT_IS_IN_FLIGHT);
598 if (HasBit(a->flags, VAF_HELI_DIRECT_DESCENT)) return CommandCost(STR_ERROR_AIRCRAFT_IS_IN_FLIGHT);
599 break;
600 }
601
602 default: return CMD_ERROR;
603 }
604
605 if (evaluate_startstop_cb) {
606 /* Check if this vehicle can be started/stopped. Failure means 'allow'. */
607 uint16_t callback = GetVehicleCallback(CBID_VEHICLE_START_STOP_CHECK, 0, 0, v->engine_type, v);
608 StringID error = STR_NULL;
609 if (callback != CALLBACK_FAILED) {
610 if (v->GetGRF()->grf_version < 8) {
611 /* 8 bit result 0xFF means 'allow' */
612 if (callback < 0x400 && GB(callback, 0, 8) != 0xFF) error = GetGRFStringID(v->GetGRFID(), 0xD000 + callback);
613 } else {
614 if (callback < 0x400) {
615 error = GetGRFStringID(v->GetGRFID(), 0xD000 + callback);
616 } else {
617 switch (callback) {
618 case 0x400: // allow
619 break;
620
621 default: // unknown reason -> disallow
622 error = STR_ERROR_INCOMPATIBLE_RAIL_TYPES;
623 break;
624 }
625 }
626 }
627 }
628 if (error != STR_NULL) return CommandCost(error);
629 }
630
631 if (flags & DC_EXEC) {
632 if (v->IsStoppedInDepot() && (flags & DC_AUTOREPLACE) == 0) DeleteVehicleNews(veh_id, STR_NEWS_TRAIN_IS_WAITING + v->type);
633
634 v->vehstatus ^= VS_STOPPED;
635 if (v->type != VEH_TRAIN) v->cur_speed = 0; // trains can stop 'slowly'
636
637 /* Unbunching data is no longer valid. */
639
640 v->MarkDirty();
645 }
646 return CommandCost();
647}
648
658CommandCost CmdMassStartStopVehicle(DoCommandFlag flags, TileIndex tile, bool do_start, bool vehicle_list_window, const VehicleListIdentifier &vli)
659{
660 VehicleList list;
661
662 if (!vli.Valid()) return CMD_ERROR;
664
665 if (vehicle_list_window) {
666 if (!GenerateVehicleSortList(&list, vli)) return CMD_ERROR;
667 } else {
668 if (!IsDepotTile(tile) || !IsTileOwner(tile, _current_company)) return CMD_ERROR;
669 /* Get the list of vehicles in the depot */
670 BuildDepotVehicleList(vli.vtype, tile, &list, nullptr);
671 }
672
673 for (const Vehicle *v : list) {
674 if (!!(v->vehstatus & VS_STOPPED) != do_start) continue;
675
676 if (!vehicle_list_window && !v->IsChainInDepot()) continue;
677
678 /* Just try and don't care if some vehicle's can't be stopped. */
679 Command<CMD_START_STOP_VEHICLE>::Do(flags, v->index, false);
680 }
681
682 return CommandCost();
683}
684
693{
694 VehicleList list;
695
697
698 if (!IsCompanyBuildableVehicleType(vehicle_type)) return CMD_ERROR;
699 if (!IsDepotTile(tile) || !IsTileOwner(tile, _current_company)) return CMD_ERROR;
700
701 /* Get the list of vehicles in the depot */
702 BuildDepotVehicleList(vehicle_type, tile, &list, &list);
703
704 CommandCost last_error = CMD_ERROR;
705 bool had_success = false;
706 for (const Vehicle *v : list) {
707 CommandCost ret = Command<CMD_SELL_VEHICLE>::Do(flags, v->index, true, false, INVALID_CLIENT_ID);
708 if (ret.Succeeded()) {
709 cost.AddCost(ret);
710 had_success = true;
711 } else {
712 last_error = ret;
713 }
714 }
715
716 return had_success ? cost : last_error;
717}
718
727{
728 VehicleList list;
730
731 if (!IsCompanyBuildableVehicleType(vehicle_type)) return CMD_ERROR;
732 if (!IsDepotTile(tile) || !IsTileOwner(tile, _current_company)) return CMD_ERROR;
733
734 /* Get the list of vehicles in the depot */
735 BuildDepotVehicleList(vehicle_type, tile, &list, &list, true);
736
737 for (const Vehicle *v : list) {
738 /* Ensure that the vehicle completely in the depot */
739 if (!v->IsChainInDepot()) continue;
740
742
743 if (ret.Succeeded()) cost.AddCost(ret);
744 }
745 return cost;
746}
747
753bool IsUniqueVehicleName(const std::string &name)
754{
755 for (const Vehicle *v : Vehicle::Iterate()) {
756 if (!v->name.empty() && v->name == name) return false;
757 }
758
759 return true;
760}
761
767static void CloneVehicleName(const Vehicle *src, Vehicle *dst)
768{
769 std::string buf;
770
771 /* Find the position of the first digit in the last group of digits. */
772 size_t number_position;
773 for (number_position = src->name.length(); number_position > 0; number_position--) {
774 /* The design of UTF-8 lets this work simply without having to check
775 * for UTF-8 sequences. */
776 if (src->name[number_position - 1] < '0' || src->name[number_position - 1] > '9') break;
777 }
778
779 /* Format buffer and determine starting number. */
780 long num;
781 uint8_t padding = 0;
782 if (number_position == src->name.length()) {
783 /* No digit at the end, so start at number 2. */
784 buf = src->name;
785 buf += " ";
786 number_position = buf.length();
787 num = 2;
788 } else {
789 /* Found digits, parse them and start at the next number. */
790 buf = src->name.substr(0, number_position);
791
792 auto num_str = src->name.substr(number_position);
793 padding = (uint8_t)num_str.length();
794
795 std::istringstream iss(num_str);
796 iss >> num;
797 num++;
798 }
799
800 /* Check if this name is already taken. */
801 for (int max_iterations = 1000; max_iterations > 0; max_iterations--, num++) {
802 std::ostringstream oss;
803
804 /* Attach the number to the temporary name. */
805 oss << buf << std::setw(padding) << std::setfill('0') << std::internal << num;
806
807 /* Check the name is unique. */
808 auto new_name = oss.str();
809 if (IsUniqueVehicleName(new_name)) {
810 dst->name = new_name;
811 break;
812 }
813 }
814
815 /* All done. If we didn't find a name, it'll just use its default. */
816}
817
826std::tuple<CommandCost, VehicleID> CmdCloneVehicle(DoCommandFlag flags, TileIndex tile, VehicleID veh_id, bool share_orders)
827{
829
830 Vehicle *v = Vehicle::GetIfValid(veh_id);
831 if (v == nullptr || !v->IsPrimaryVehicle()) return { CMD_ERROR, INVALID_VEHICLE };
832 Vehicle *v_front = v;
833 Vehicle *w = nullptr;
834 Vehicle *w_front = nullptr;
835 Vehicle *w_rear = nullptr;
836
837 /*
838 * v_front is the front engine in the original vehicle
839 * v is the car/vehicle of the original vehicle that is currently being copied
840 * w_front is the front engine of the cloned vehicle
841 * w is the car/vehicle currently being cloned
842 * w_rear is the rear end of the cloned train. It's used to add more cars and is only used by trains
843 */
844
846 if (ret.Failed()) return { ret, INVALID_VEHICLE };
847
848 if (v->type == VEH_TRAIN && (!v->IsFrontEngine() || Train::From(v)->crash_anim_pos >= 4400)) return { CMD_ERROR, INVALID_VEHICLE };
849
850 /* check that we can allocate enough vehicles */
851 if (!(flags & DC_EXEC)) {
852 int veh_counter = 0;
853 do {
854 veh_counter++;
855 } while ((v = v->Next()) != nullptr);
856
857 if (!Vehicle::CanAllocateItem(veh_counter)) {
858 return { CommandCost(STR_ERROR_TOO_MANY_VEHICLES_IN_GAME), INVALID_VEHICLE };
859 }
860 }
861
862 v = v_front;
863
864 VehicleID new_veh_id = INVALID_VEHICLE;
865 do {
866 if (v->type == VEH_TRAIN && Train::From(v)->IsRearDualheaded()) {
867 /* we build the rear ends of multiheaded trains with the front ones */
868 continue;
869 }
870
871 /* In case we're building a multi headed vehicle and the maximum number of
872 * vehicles is almost reached (e.g. max trains - 1) not all vehicles would
873 * be cloned. When the non-primary engines were build they were seen as
874 * 'new' vehicles whereas they would immediately be joined with a primary
875 * engine. This caused the vehicle to be not build as 'the limit' had been
876 * reached, resulting in partially build vehicles and such. */
877 DoCommandFlag build_flags = flags;
878 if ((flags & DC_EXEC) && !v->IsPrimaryVehicle()) build_flags |= DC_AUTOREPLACE;
879
880 CommandCost cost;
881 std::tie(cost, new_veh_id, std::ignore, std::ignore, std::ignore) = Command<CMD_BUILD_VEHICLE>::Do(build_flags, tile, v->engine_type, false, INVALID_CARGO, INVALID_CLIENT_ID);
882
883 if (cost.Failed()) {
884 /* Can't build a part, then sell the stuff we already made; clear up the mess */
885 if (w_front != nullptr) Command<CMD_SELL_VEHICLE>::Do(flags, w_front->index, true, false, INVALID_CLIENT_ID);
886 return { cost, INVALID_VEHICLE };
887 }
888
889 total_cost.AddCost(cost);
890
891 if (flags & DC_EXEC) {
892 w = Vehicle::Get(new_veh_id);
893
894 if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION)) {
896 }
897
898 if (v->type == VEH_TRAIN && !v->IsFrontEngine()) {
899 /* this s a train car
900 * add this unit to the end of the train */
901 CommandCost result = Command<CMD_MOVE_RAIL_VEHICLE>::Do(flags, w->index, w_rear->index, true);
902 if (result.Failed()) {
903 /* The train can't be joined to make the same consist as the original.
904 * Sell what we already made (clean up) and return an error. */
905 Command<CMD_SELL_VEHICLE>::Do(flags, w_front->index, true, false, INVALID_CLIENT_ID);
907 return { result, INVALID_VEHICLE }; // return error and the message returned from CMD_MOVE_RAIL_VEHICLE
908 }
909 } else {
910 /* this is a front engine or not a train. */
911 w_front = w;
913 w->SetServiceIntervalIsCustom(v->ServiceIntervalIsCustom());
914 w->SetServiceIntervalIsPercent(v->ServiceIntervalIsPercent());
915 }
916 w_rear = w; // trains needs to know the last car in the train, so they can add more in next loop
917 }
918 } while (v->type == VEH_TRAIN && (v = v->GetNextVehicle()) != nullptr);
919
920 if ((flags & DC_EXEC) && v_front->type == VEH_TRAIN) {
921 /* for trains this needs to be the front engine due to the callback function */
922 new_veh_id = w_front->index;
923 }
924
925 if (flags & DC_EXEC) {
926 /* Cloned vehicles belong to the same group */
927 Command<CMD_ADD_VEHICLE_GROUP>::Do(flags, v_front->group_id, w_front->index, false, VehicleListIdentifier{});
928 }
929
930
931 /* Take care of refitting. */
932 w = w_front;
933 v = v_front;
934
935 /* Both building and refitting are influenced by newgrf callbacks, which
936 * makes it impossible to accurately estimate the cloning costs. In
937 * particular, it is possible for engines of the same type to be built with
938 * different numbers of articulated parts, so when refitting we have to
939 * loop over real vehicles first, and then the articulated parts of those
940 * vehicles in a different loop. */
941 do {
942 do {
943 if (flags & DC_EXEC) {
944 assert(w != nullptr);
945
946 /* Find out what's the best sub type */
947 uint8_t subtype = GetBestFittingSubType(v, w, v->cargo_type);
948 if (w->cargo_type != v->cargo_type || w->cargo_subtype != subtype) {
949 CommandCost cost = std::get<0>(Command<CMD_REFIT_VEHICLE>::Do(flags, w->index, v->cargo_type, subtype, false, true, 0));
950 if (cost.Succeeded()) total_cost.AddCost(cost);
951 }
952
953 if (w->IsGroundVehicle() && w->HasArticulatedPart()) {
954 w = w->GetNextArticulatedPart();
955 } else {
956 break;
957 }
958 } else {
959 const Engine *e = v->GetEngine();
960 CargoID initial_cargo = (e->CanCarryCargo() ? e->GetDefaultCargoType() : INVALID_CARGO);
961
962 if (v->cargo_type != initial_cargo && IsValidCargoID(initial_cargo)) {
963 bool dummy;
964 total_cost.AddCost(GetRefitCost(nullptr, v->engine_type, v->cargo_type, v->cargo_subtype, &dummy));
965 }
966 }
967
968 if (v->IsGroundVehicle() && v->HasArticulatedPart()) {
969 v = v->GetNextArticulatedPart();
970 } else {
971 break;
972 }
973 } while (v != nullptr);
974
975 if ((flags & DC_EXEC) && v->type == VEH_TRAIN) w = w->GetNextVehicle();
976 } while (v->type == VEH_TRAIN && (v = v->GetNextVehicle()) != nullptr);
977
978 if (flags & DC_EXEC) {
979 /*
980 * Set the orders of the vehicle. Cannot do it earlier as we need
981 * the vehicle refitted before doing this, otherwise the moved
982 * cargo types might not match (passenger vs non-passenger)
983 */
984 CommandCost result = Command<CMD_CLONE_ORDER>::Do(flags, (share_orders ? CO_SHARE : CO_COPY), w_front->index, v_front->index);
985 if (result.Failed()) {
986 /* The vehicle has already been bought, so now it must be sold again. */
987 Command<CMD_SELL_VEHICLE>::Do(flags, w_front->index, true, false, INVALID_CLIENT_ID);
988 return { result, INVALID_VEHICLE };
989 }
990
991 /* Now clone the vehicle's name, if it has one. */
992 if (!v_front->name.empty()) CloneVehicleName(v_front, w_front);
993
994 /* Since we can't estimate the cost of cloning a vehicle accurately we must
995 * check whether the company has enough money manually. */
996 if (!CheckCompanyHasMoney(total_cost)) {
997 /* The vehicle has already been bought, so now it must be sold again. */
998 Command<CMD_SELL_VEHICLE>::Do(flags, w_front->index, true, false, INVALID_CLIENT_ID);
999 return { total_cost, INVALID_VEHICLE };
1000 }
1001 }
1002
1003 return { total_cost, new_veh_id };
1004}
1005
1014{
1015 VehicleList list;
1016
1017 if (!GenerateVehicleSortList(&list, vli)) return CMD_ERROR;
1018
1019 /* Send all the vehicles to a depot */
1020 bool had_success = false;
1021 for (uint i = 0; i < list.size(); i++) {
1022 const Vehicle *v = list[i];
1024
1025 if (ret.Succeeded()) {
1026 had_success = true;
1027
1028 /* Return 0 if DC_EXEC is not set this is a valid goto depot command)
1029 * In this case we know that at least one vehicle can be sent to a depot
1030 * and we will issue the command. We can now safely quit the loop, knowing
1031 * it will succeed at least once. With DC_EXEC we really need to send them to the depot */
1032 if (!(flags & DC_EXEC)) break;
1033 }
1034 }
1035
1036 return had_success ? CommandCost() : CMD_ERROR;
1037}
1038
1048{
1049 if (HasFlag(depot_cmd, DepotCommand::MassSend)) {
1050 /* Mass goto depot requested */
1051 if (!vli.Valid()) return CMD_ERROR;
1052 return SendAllVehiclesToDepot(flags, HasFlag(depot_cmd, DepotCommand::Service), vli);
1053 }
1054
1055 Vehicle *v = Vehicle::GetIfValid(veh_id);
1056 if (v == nullptr) return CMD_ERROR;
1057 if (!v->IsPrimaryVehicle()) return CMD_ERROR;
1058
1059 return v->SendToDepot(flags, depot_cmd);
1060}
1061
1069CommandCost CmdRenameVehicle(DoCommandFlag flags, VehicleID veh_id, const std::string &text)
1070{
1071 Vehicle *v = Vehicle::GetIfValid(veh_id);
1072 if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
1073
1075 if (ret.Failed()) return ret;
1076
1077 bool reset = text.empty();
1078
1079 if (!reset) {
1081 if (!(flags & DC_AUTOREPLACE) && !IsUniqueVehicleName(text)) return CommandCost(STR_ERROR_NAME_MUST_BE_UNIQUE);
1082 }
1083
1084 if (flags & DC_EXEC) {
1085 if (reset) {
1086 v->name.clear();
1087 } else {
1088 v->name = text;
1089 }
1092 }
1093
1094 return CommandCost();
1095}
1096
1097
1107CommandCost CmdChangeServiceInt(DoCommandFlag flags, VehicleID veh_id, uint16_t serv_int, bool is_custom, bool is_percent)
1108{
1109 Vehicle *v = Vehicle::GetIfValid(veh_id);
1110 if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
1111
1113 if (ret.Failed()) return ret;
1114
1115 const Company *company = Company::Get(v->owner);
1116 is_percent = is_custom ? is_percent : company->settings.vehicle.servint_ispercent;
1117
1118 if (is_custom) {
1119 if (serv_int != GetServiceIntervalClamped(serv_int, is_percent)) return CMD_ERROR;
1120 } else {
1121 serv_int = CompanyServiceInterval(company, v->type);
1122 }
1123
1124 if (flags & DC_EXEC) {
1125 v->SetServiceInterval(serv_int);
1126 v->SetServiceIntervalIsCustom(is_custom);
1127 v->SetServiceIntervalIsPercent(is_percent);
1129 }
1130
1131 return CommandCost();
1132}
Base for aircraft.
@ VAF_HELI_DIRECT_DESCENT
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(DoCommandFlag 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:72
@ TERM7
Heading for terminal 7.
Definition airport.h:80
CargoArray GetCapacityOfArticulatedParts(EngineID engine)
Get the capacity of the parts of a given engine.
uint CountArticulatedParts(EngineID engine_type, bool purchase_window)
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.
debug_inline constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
debug_inline static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
uint8_t CargoID
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:22
bool IsValidCargoID(CargoID t)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:107
static const CargoID NUM_CARGO
Maximum number of cargo types in a game.
Definition cargo_type.h:74
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?
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.
DoCommandFlag
List of flags for a command.
@ DC_AUTOREPLACE
autoreplace/autorenew is in progress, this shall disable vehicle limits when building,...
@ DC_QUERY_COST
query cost only, don't build.
@ DC_EXEC
execute the given command
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:41
VehicleType GetDepotVehicleType(Tile t)
Get the type of vehicles that can use a depot.
Definition depot_map.h:65
bool do_start
flag for starting playback of next_file at next opportunity
Definition dmusic.cpp:122
Money GetPrice(Price index, uint cost_factor, const GRFFile *grf_file, int shift)
Determine a certain price.
Definition economy.cpp:966
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.
bool IsEngineBuildable(EngineID engine, VehicleType type, CompanyID company)
Check if an engine is buildable.
Definition engine.cpp:1254
Functions related to engines.
uint16_t EngineID
Unique identification number of an engine.
Definition engine_type.h:21
@ AIR_CTOL
Conventional Take Off and Landing, i.e. planes.
Definition engine_type.h:95
@ EF_AUTO_REFIT
Automatic refitting is allowed.
@ RAILVEH_WAGON
simple wagon, not motorized
Definition engine_type.h:29
@ RAILVEH_MULTIHEAD
indicates a combination of two locomotives
Definition engine_type.h:28
debug_inline constexpr bool HasFlag(const T x, const T y)
Checks if a value in a bitset enum is set.
Definition enum_type.hpp:58
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:1529
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)
Evaluate a newgrf callback for vehicles.
StringID GetGRFStringID(uint32_t grfid, StringID stringid)
Returns the index for this stringid associated with its grfID.
Header of Action 04 "universal holder" structure and functions.
Functions related to news.
void DeleteVehicleNews(VehicleID vid, StringID news)
Delete a news item type about a vehicle.
Definition news_gui.cpp:998
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(DoCommandFlag 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:57
Base for ships.
CommandCost CmdBuildShip(DoCommandFlag flags, TileIndex tile, const Engine *e, Vehicle **ret)
Build a ship.
Definition ship_cmd.cpp:895
Command definitions related to ships.
Definition of base types and functions in a cross-platform compatible way.
size_t Utf8StringLength(const char *s)
Get the length of an UTF-8 encoded string in number of characters and thus not the number of bytes th...
Definition string.cpp:359
Functions related to low-level strings.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
uint8_t subtype
Type of aircraft.
Aircraft, helicopters, rotors and their shadows belong to this class.
Definition aircraft.h:72
uint8_t state
State of the airport.
Definition aircraft.h:77
uint8_t flags
Aircraft flags.
Definition aircraft.h:81
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:114
Specification of a cargo type.
Definition cargotype.h:76
CargoClasses classes
Classes of this cargo type.
Definition cargotype.h:83
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo ID.
Definition cargotype.h:139
CompanySettings settings
settings specific for each company
VehicleDefaultSettings vehicle
default settings for vehicles
uint8_t misc_flags
Miscellaneous flags.
CargoID GetDefaultCargoType() const
Determines the default cargo type of an engine.
Money GetCost() const
Return how much a new engine costs.
Definition engine.cpp:318
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:201
VehicleType type
Vehicle type, ie VEH_ROAD, VEH_TRAIN, etc.
Definition engine_base.h:60
uint GetDisplayDefaultCapacity(uint16_t *mail_capacity=nullptr) const
Determines the default cargo capacity of an engine for display purposes.
bool CanCarryCargo() const
Determines whether an engine can carry something.
Definition engine.cpp:168
std::array< uint8_t, NUM_CARGO > cargo_map
Inverse cargo translation table (CargoID -> local ID)
Definition newgrf.h:130
VehicleSettings vehicle
options for vehicles
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.
VehicleOrderID GetNumOrders() const
Get number of orders in the order list.
Definition order_base.h:319
bool IsShared() const
Is this a shared order list?
Definition order_base.h:338
bool IsType(OrderType type) const
Check whether this order is of the given type.
Definition order_base.h:70
Tindex index
Index of this pool item.
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
static Titem * GetIfValid(size_t index)
Returns Titem with given index.
static bool CanAllocateItem(size_t n=1)
Helper functions so we can use PoolItem::Function() instead of _poolitem_pool.Function()
static Titem * Get(size_t index)
Returns Titem with given index.
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:232
static T * From(Vehicle *v)
Converts a Vehicle to SpecializedVehicle with type checking.
bool servint_ispercent
service intervals are in percents
The information about a vehicle list.
Definition vehiclelist.h:28
VehicleType vtype
The vehicle type associated with this list.
Definition vehiclelist.h:30
uint8_t roadveh_acceleration_model
realistic acceleration for road vehicles
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
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.
CommandCost SendToDepot(DoCommandFlag flags, DepotCommand command)
Send this vehicle to the depot using the given command(s).
Definition vehicle.cpp:2583
bool IsArticulatedPart() const
Check if the vehicle is an articulated part of an engine.
debug_inline bool IsFrontEngine() const
Check if the vehicle is a front engine.
Vehicle * First() const
Get the first vehicle of this vehicle chain.
Order current_order
The current order (+ status, like: loading)
CargoID cargo_type
type of cargo this vehicle is carrying
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
OrderList * orders
Pointer to the order list for this vehicle.
Money value
Value of the vehicle.
uint16_t refit_cap
Capacity left over from before last refit.
uint8_t vehstatus
Status.
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)
debug_inline bool IsGroundVehicle() const
Check if the vehicle is a ground vehicle.
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
Base for the train class.
@ VRF_REVERSE_DIRECTION
Reverse the visible direction of the vehicle.
Definition train.h:28
void NormalizeTrainVehInDepot(const Train *u)
Move all free vehicles in the depot to the train.
@ CCF_AUTOREFIT
Valid changes for autorefitting in stations.
Definition train.h:50
@ CCF_REFIT
Valid changes for refitting in a depot.
Definition train.h:51
CommandCost CmdBuildRailVehicle(DoCommandFlag flags, TileIndex tile, const Engine *e, Vehicle **ret)
Build a railroad vehicle.
CommandCost CmdSellRailWagon(DoCommandFlag 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:3218
UnitID GetFreeUnitNumber(VehicleType type)
Get an unused unit number for a vehicle (if allowed).
Definition vehicle.cpp:1895
@ VS_STOPPED
Vehicle is stopped by the player.
@ VS_CRASHED
Vehicle is crashed.
CommandCost CmdSendVehicleToDepot(DoCommandFlag flags, VehicleID veh_id, DepotCommand depot_cmd, const VehicleListIdentifier &vli)
Send a vehicle to the depot.
static void CloneVehicleName(const Vehicle *src, Vehicle *dst)
Clone the custom name of a vehicle, adding or incrementing a number.
static int GetRefitCostFactor(const Vehicle *v, EngineID engine_type, CargoID new_cid, uint8_t new_subtype, bool *auto_refit_allowed)
Helper to run the refit cost callback.
bool IsUniqueVehicleName(const std::string &name)
Test if a name is unique among vehicle names.
std::tuple< CommandCost, VehicleID > CmdCloneVehicle(DoCommandFlag flags, TileIndex tile, VehicleID veh_id, bool share_orders)
Clone a vehicle.
static std::tuple< CommandCost, uint, uint16_t, CargoArray > RefitVehicle(Vehicle *v, bool only_this, uint8_t num_vehicles, CargoID new_cid, uint8_t new_subtype, DoCommandFlag flags, bool auto_refit)
Refits a vehicle (chain).
CommandCost CmdSellVehicle(DoCommandFlag flags, VehicleID v_id, bool sell_chain, bool backup_order, ClientID client_id)
Sell a vehicle.
static CommandCost SendAllVehiclesToDepot(DoCommandFlag flags, bool service, const VehicleListIdentifier &vli)
Send all vehicles of type to depots.
CommandCost CmdRenameVehicle(DoCommandFlag flags, VehicleID veh_id, const std::string &text)
Give a custom name to your vehicle.
static CommandCost GetRefitCost(const Vehicle *v, EngineID engine_type, CargoID new_cid, uint8_t new_subtype, bool *auto_refit_allowed)
Learn the price of refitting a certain engine.
std::tuple< CommandCost, VehicleID, uint, uint16_t, CargoArray > CmdBuildVehicle(DoCommandFlag flags, TileIndex tile, EngineID eid, bool use_free_vehicles, CargoID cargo, ClientID client_id)
Build a vehicle.
CommandCost CmdStartStopVehicle(DoCommandFlag flags, VehicleID veh_id, bool evaluate_startstop_cb)
Start/Stop a vehicle.
std::tuple< CommandCost, uint, uint16_t, CargoArray > CmdRefitVehicle(DoCommandFlag flags, VehicleID veh_id, CargoID new_cid, uint8_t new_subtype, bool auto_refit, bool only_this, uint8_t num_vehicles)
Refits a vehicle to the specified cargo type.
CommandCost CmdDepotSellAllVehicles(DoCommandFlag flags, TileIndex tile, VehicleType vehicle_type)
Sells all vehicles in a depot.
CommandCost CmdDepotMassAutoReplace(DoCommandFlag flags, TileIndex tile, VehicleType vehicle_type)
Autoreplace all vehicles in the depot.
CommandCost CmdChangeServiceInt(DoCommandFlag flags, VehicleID veh_id, uint16_t serv_int, bool is_custom, bool is_percent)
Change the service interval of a vehicle.
CommandCost CmdMassStartStopVehicle(DoCommandFlag flags, TileIndex tile, bool do_start, bool vehicle_list_window, const VehicleListIdentifier &vli)
Starts or stops a lot of vehicles.
Command definitions for vehicles.
Functions related to vehicles.
uint8_t GetBestFittingSubType(Vehicle *v_from, Vehicle *v_for, CargoID 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
VehicleType
Available vehicle types.
@ VEH_ROAD
Road vehicle type.
@ VEH_AIRCRAFT
Aircraft vehicle type.
@ VEH_SHIP
Ship vehicle type.
@ VEH_TRAIN
Train vehicle type.
uint32_t VehicleID
The type all our vehicle IDs have.
static const uint MAX_LENGTH_VEHICLE_NAME_CHARS
The maximum length of a vehicle name in characters including '\0'.
static const VehicleID INVALID_VEHICLE
Constant representing a non-existing vehicle.
DepotCommand
Flags for goto depot commands.
@ None
No special flags.
@ 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)
@ 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:54
void SetWindowClassesDirty(WindowClass cls)
Mark all windows of a particular class as dirty (in need of repainting)
Definition window.cpp:3127
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:3219
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:3114
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting)
Definition window.cpp:3101
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:3236
@ 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: