OpenTTD Source 20250524-master-gc366e6a48e
group_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 "command_func.h"
12#include "train.h"
13#include "vehiclelist.h"
14#include "vehicle_func.h"
15#include "autoreplace_base.h"
16#include "autoreplace_func.h"
17#include "string_func.h"
18#include "company_func.h"
19#include "core/pool_func.hpp"
20#include "order_backup.h"
21#include "group_cmd.h"
22
23#include "table/strings.h"
24
25#include "safeguards.h"
26
27GroupPool _group_pool("Group");
29
30
33void GroupStatistics::Clear()
34{
35 this->num_vehicle = 0;
36 this->profit_last_year = 0;
37 this->num_vehicle_min_age = 0;
38 this->profit_last_year_min_age = 0;
39
40 /* This is also called when NewGRF change. So the number of engines might have changed. Reset. */
41 this->num_engines.clear();
42}
43
48{
49 for (Group *g : Group::Iterate()) {
50 if (g->parent != GroupID::Invalid()) Group::Get(g->parent)->children.insert(g->index);
51 }
52}
53
60{
61 auto found = this->num_engines.find(engine);
62 if (found != std::end(this->num_engines)) return found->second;
63 return 0;
64}
65
74{
75 if (Group::IsValidID(id_g)) {
76 Group *g = Group::Get(id_g);
77 assert(g->owner == company);
78 assert(g->vehicle_type == type);
79 return g->statistics;
80 }
81
82 if (IsDefaultGroupID(id_g)) return Company::Get(company)->group_default[type];
83 if (IsAllGroupID(id_g)) return Company::Get(company)->group_all[type];
84
85 NOT_REACHED();
86}
87
94{
95 return GroupStatistics::Get(v->owner, v->group_id, v->type);
96}
97
104{
106}
107
112{
113 /* Set up the engine count for all companies */
114 for (Company *c : Company::Iterate()) {
115 for (VehicleType type = VEH_BEGIN; type < VEH_COMPANY_END; type++) {
116 c->group_all[type].Clear();
117 c->group_default[type].Clear();
118 }
119 }
120
121 /* Recalculate */
122 for (Group *g : Group::Iterate()) {
123 g->statistics.Clear();
124 }
125
126 for (const Vehicle *v : Vehicle::Iterate()) {
127 if (!v->IsEngineCountable()) continue;
128
130 if (v->IsPrimaryVehicle()) GroupStatistics::CountVehicle(v, 1);
131 }
132
133 for (const Company *c : Company::Iterate()) {
135 }
136}
137
143/* static */ void GroupStatistics::CountVehicle(const Vehicle *v, int delta)
144{
145 assert(delta == 1 || delta == -1);
146
149
150 stats_all.num_vehicle += delta;
151 stats_all.profit_last_year += v->GetDisplayProfitLastYear() * delta;
152 stats.num_vehicle += delta;
153 stats.profit_last_year += v->GetDisplayProfitLastYear() * delta;
154
156 stats_all.num_vehicle_min_age += delta;
157 stats_all.profit_last_year_min_age += v->GetDisplayProfitLastYear() * delta;
158 stats.num_vehicle_min_age += delta;
160 }
161}
162
168/* static */ void GroupStatistics::CountEngine(const Vehicle *v, int delta)
169{
170 assert(delta == 1 || delta == -1);
173}
174
186
200
205{
206 /* Set up the engine count for all companies */
207 for (Company *c : Company::Iterate()) {
208 for (VehicleType type = VEH_BEGIN; type < VEH_COMPANY_END; type++) {
209 c->group_all[type].ClearProfits();
210 c->group_default[type].ClearProfits();
211 }
212 }
213
214 /* Recalculate */
215 for (Group *g : Group::Iterate()) {
216 g->statistics.ClearProfits();
217 }
218
219 for (const Vehicle *v : Vehicle::Iterate()) {
220 if (v->IsPrimaryVehicle()) {
223 }
224 }
225}
226
232{
233 /* Set up the engine count for all companies */
234 Company *c = Company::Get(company);
235 for (VehicleType type = VEH_BEGIN; type < VEH_COMPANY_END; type++) {
236 c->group_all[type].ClearAutoreplace();
237 c->group_default[type].ClearAutoreplace();
238 }
239
240 /* Recalculate */
241 for (Group *g : Group::Iterate()) {
242 if (g->owner != company) continue;
243 g->statistics.ClearAutoreplace();
244 }
245
246 for (EngineRenewList erl = c->engine_renew_list; erl != nullptr; erl = erl->next) {
247 const Engine *e = Engine::Get(erl->from);
248 GroupStatistics &stats = GroupStatistics::Get(company, erl->group_id, e->type);
249 if (!stats.autoreplace_defined) {
250 stats.autoreplace_defined = true;
251 stats.autoreplace_finished = true;
252 }
253 if (GetGroupNumEngines(company, erl->group_id, erl->from) > 0) stats.autoreplace_finished = false;
254 }
255}
256
264static inline void UpdateNumEngineGroup(const Vehicle *v, GroupID old_g, GroupID new_g)
265{
266 if (old_g != new_g) {
267 /* Decrease the num engines in the old group */
269
270 /* Increase the num engines in the new group */
272 }
273}
274
275
276const Livery *GetParentLivery(const Group *g)
277{
278 if (g->parent == GroupID::Invalid()) {
279 const Company *c = Company::Get(g->owner);
280 return &c->livery[LS_DEFAULT];
281 }
282
283 const Group *pg = Group::Get(g->parent);
284 return &pg->livery;
285}
286
287
293static void PropagateChildLivery(const Group *g, bool reset_cache)
294{
295 if (reset_cache) {
296 /* Company colour data is indirectly cached. */
297 for (Vehicle *v : Vehicle::Iterate()) {
298 if (v->group_id == g->index && (!v->IsGroundVehicle() || v->IsFrontEngine())) {
299 for (Vehicle *u = v; u != nullptr; u = u->Next()) {
300 u->colourmap = PAL_NONE;
301 u->InvalidateNewGRFCache();
302 }
303 }
304 }
305 }
306
307 for (const GroupID &childgroup : g->children) {
308 Group *cg = Group::Get(childgroup);
309 if (!HasBit(cg->livery.in_use, 0)) cg->livery.colour1 = g->livery.colour1;
310 if (!HasBit(cg->livery.in_use, 1)) cg->livery.colour2 = g->livery.colour2;
311 PropagateChildLivery(cg, reset_cache);
312 }
313}
314
321{
322 for (Group *g : Group::Iterate()) {
323 if (g->owner == c->index && g->parent == GroupID::Invalid()) {
324 if (!HasBit(g->livery.in_use, 0)) g->livery.colour1 = c->livery[LS_DEFAULT].colour1;
325 if (!HasBit(g->livery.in_use, 1)) g->livery.colour2 = c->livery[LS_DEFAULT].colour2;
326 PropagateChildLivery(g, false);
327 }
328 }
329}
330
331
339std::tuple<CommandCost, GroupID> CmdCreateGroup(DoCommandFlags flags, VehicleType vt, GroupID parent_group)
340{
341 if (!IsCompanyBuildableVehicleType(vt)) return { CMD_ERROR, GroupID::Invalid() };
342
343 if (!Group::CanAllocateItem()) return { CMD_ERROR, GroupID::Invalid() };
344
345 Group *pg = Group::GetIfValid(parent_group);
346 if (pg != nullptr) {
347 if (pg->owner != _current_company) return { CMD_ERROR, GroupID::Invalid() };
348 if (pg->vehicle_type != vt) return { CMD_ERROR, GroupID::Invalid() };
349 }
350
351 if (flags.Test(DoCommandFlag::Execute)) {
352 Group *g = new Group(_current_company, vt);
353
354 Company *c = Company::Get(g->owner);
355 g->number = c->freegroups.UseID(c->freegroups.NextID());
356 if (pg == nullptr) {
357 g->livery.colour1 = c->livery[LS_DEFAULT].colour1;
358 g->livery.colour2 = c->livery[LS_DEFAULT].colour2;
360 } else {
361 g->parent = pg->index;
362 g->livery.colour1 = pg->livery.colour1;
363 g->livery.colour2 = pg->livery.colour2;
364 g->flags = pg->flags;
365 pg->children.insert(g->index);
366 }
367
370
371 return { CommandCost(), g->index };
372 }
373
374 return { CommandCost(), GroupID::Invalid()};
375}
376
377
385{
386 Group *g = Group::GetIfValid(group_id);
387 if (g == nullptr || g->owner != _current_company) return CMD_ERROR;
388
389 /* Remove all vehicles from the group */
391
392 /* Delete sub-groups */
393 for (const GroupID &childgroup : g->children) {
394 Command<CMD_DELETE_GROUP>::Do(flags, childgroup);
395 }
396
397 if (flags.Test(DoCommandFlag::Execute)) {
398 /* Update backupped orders if needed */
400
401 if (g->owner < MAX_COMPANIES) {
402 Company *c = Company::Get(g->owner);
403
404 /* If we set an autoreplace for the group we delete, remove it. */
405 for (EngineRenew *er : EngineRenew::Iterate()) {
406 if (er->group_id == g->index) RemoveEngineReplacementForCompany(c, er->from, g->index, flags);
407 }
408
409 c->freegroups.ReleaseID(g->number);
410 }
411
412 if (g->parent != GroupID::Invalid()) {
413 Group *pg = Group::Get(g->parent);
414 pg->children.erase(g->index);
415 }
416
418
419 /* Delete the Replace Vehicle Windows */
421 delete g;
422
425 }
426
427 return CommandCost();
428}
429
439CommandCost CmdAlterGroup(DoCommandFlags flags, AlterGroupMode mode, GroupID group_id, GroupID parent_id, const std::string &text)
440{
441 Group *g = Group::GetIfValid(group_id);
442 if (g == nullptr || g->owner != _current_company) return CMD_ERROR;
443
444 if (mode == AlterGroupMode::Rename) {
445 /* Rename group */
446 bool reset = text.empty();
447
448 if (!reset) {
450 }
451
452 if (flags.Test(DoCommandFlag::Execute)) {
453 /* Assign the new one */
454 if (reset) {
455 g->name.clear();
456 } else {
457 g->name = text;
458 }
459 }
460 } else if (mode == AlterGroupMode::SetParent) {
461 /* Do nothing if the parent group isn't actually changed. */
462 if (g->parent == parent_id) return CommandCost();
463
464 /* Set group parent */
465 const Group *pg = Group::GetIfValid(parent_id);
466
467 if (pg != nullptr) {
468 if (pg->owner != _current_company) return CMD_ERROR;
469 if (pg->vehicle_type != g->vehicle_type) return CMD_ERROR;
470
471 /* Ensure request parent isn't child of group.
472 * This is the only place that infinite loops are prevented. */
473 if (GroupIsInGroup(pg->index, g->index)) return CommandCost(STR_ERROR_GROUP_CAN_T_SET_PARENT_RECURSION);
474 }
475
476 if (flags.Test(DoCommandFlag::Execute)) {
477 if (g->parent != GroupID::Invalid()) Group::Get(g->parent)->children.erase(g->index);
478 g->parent = (pg == nullptr) ? GroupID::Invalid() : pg->index;
479 if (g->parent != GroupID::Invalid()) Group::Get(g->parent)->children.insert(g->index);
480
482
483 if (!HasBit(g->livery.in_use, 0) || !HasBit(g->livery.in_use, 1)) {
484 /* Update livery with new parent's colours if either colour is default. */
485 const Livery *livery = GetParentLivery(g);
486 if (!HasBit(g->livery.in_use, 0)) g->livery.colour1 = livery->colour1;
487 if (!HasBit(g->livery.in_use, 1)) g->livery.colour2 = livery->colour2;
488
489 PropagateChildLivery(g, true);
491 }
492 }
493 } else {
494 return CMD_ERROR;
495 }
496
497 if (flags.Test(DoCommandFlag::Execute)) {
503 }
504
505 return CommandCost();
506}
507
508
514static void AddVehicleToGroup(Vehicle *v, GroupID new_g)
515{
517
518 switch (v->type) {
519 default: NOT_REACHED();
520 case VEH_TRAIN:
521 SetTrainGroupID(Train::From(v), new_g);
522 break;
523
524 case VEH_ROAD:
525 case VEH_SHIP:
526 case VEH_AIRCRAFT:
527 if (v->IsEngineCountable()) UpdateNumEngineGroup(v, v->group_id, new_g);
528 v->group_id = new_g;
529 for (Vehicle *u = v; u != nullptr; u = u->Next()) {
530 u->colourmap = PAL_NONE;
531 u->InvalidateNewGRFCache();
532 u->UpdateViewport(true);
533 }
534 break;
535 }
536
539
541}
542
551std::tuple<CommandCost, GroupID> CmdAddVehicleGroup(DoCommandFlags flags, GroupID group_id, VehicleID veh_id, bool add_shared, const VehicleListIdentifier &vli)
552{
553 GroupID new_g = group_id;
554 if (!Group::IsValidID(new_g) && !IsDefaultGroupID(new_g) && new_g != NEW_GROUP) return { CMD_ERROR, GroupID::Invalid() };
555
556 VehicleList list;
557 if (veh_id == VehicleID::Invalid() && vli.Valid()) {
558 if (!GenerateVehicleSortList(&list, vli) || list.empty()) return { CMD_ERROR, GroupID::Invalid() };
559 } else {
560 Vehicle *v = Vehicle::GetIfValid(veh_id);
561 if (v == nullptr) return { CMD_ERROR, GroupID::Invalid() };
562 list.push_back(v);
563 }
564
565 VehicleType vtype = list.front()->type;
566 for (const Vehicle *v : list) {
567 if (v->owner != _current_company || !v->IsPrimaryVehicle()) return { CMD_ERROR, GroupID::Invalid() };
568 }
569
570 if (Group::IsValidID(new_g)) {
571 Group *g = Group::Get(new_g);
572 if (g->owner != _current_company || g->vehicle_type != vtype) return { CMD_ERROR, GroupID::Invalid() };
573 }
574
575 if (new_g == NEW_GROUP) {
576 /* Create new group. */
577 auto [ret, new_group_id] = CmdCreateGroup(flags, vtype, GroupID::Invalid());
578 if (ret.Failed()) return { ret, new_group_id };
579
580 new_g = new_group_id;
581 }
582
583 if (flags.Test(DoCommandFlag::Execute)) {
584 for (const Vehicle *vc : list) {
585 /* VehicleList is const but we need to modify the vehicle. */
586 Vehicle *v = Vehicle::Get(vc->index);
587 AddVehicleToGroup(v, new_g);
588
589 if (add_shared) {
590 /* Add vehicles in the shared order list as well. */
591 for (Vehicle *v2 = v->FirstShared(); v2 != nullptr; v2 = v2->NextShared()) {
592 if (v2->group_id != new_g) AddVehicleToGroup(v2, new_g);
593 }
594 }
595
597 }
598
600
601 /* Update the Replace Vehicle Windows */
604 }
605
606 return { CommandCost(), new_g };
607}
608
617{
618 if (!Group::IsValidID(id_g) || !IsCompanyBuildableVehicleType(type)) return CMD_ERROR;
619
620 if (flags.Test(DoCommandFlag::Execute)) {
621 /* Find the first front engine which belong to the group id_g
622 * then add all shared vehicles of this front engine to the group id_g */
623 for (const Vehicle *v : Vehicle::Iterate()) {
624 if (v->type == type && v->IsPrimaryVehicle()) {
625 if (v->group_id != id_g) continue;
626
627 /* For each shared vehicles add it to the group */
628 for (Vehicle *v2 = v->FirstShared(); v2 != nullptr; v2 = v2->NextShared()) {
629 if (v2->group_id != id_g) Command<CMD_ADD_VEHICLE_GROUP>::Do(flags, id_g, v2->index, false, VehicleListIdentifier{});
630 }
631 }
632 }
633
635 }
636
637 return CommandCost();
638}
639
640
648{
649 Group *g = Group::GetIfValid(group_id);
650
651 if (g == nullptr || g->owner != _current_company) return CMD_ERROR;
652
653 if (flags.Test(DoCommandFlag::Execute)) {
654 /* Find each Vehicle that belongs to the group old_g and add it to the default group */
655 for (const Vehicle *v : Vehicle::Iterate()) {
656 if (v->IsPrimaryVehicle()) {
657 if (v->group_id != group_id) continue;
658
659 /* Add The Vehicle to the default group */
661 }
662 }
663
665 }
666
667 return CommandCost();
668}
669
677CommandCost CmdSetGroupLivery(DoCommandFlags flags, GroupID group_id, bool primary, Colours colour)
678{
679 Group *g = Group::GetIfValid(group_id);
680
681 if (g == nullptr || g->owner != _current_company) return CMD_ERROR;
682
683 if (colour >= COLOUR_END && colour != INVALID_COLOUR) return CMD_ERROR;
684
685 if (flags.Test(DoCommandFlag::Execute)) {
686 if (primary) {
687 AssignBit(g->livery.in_use, 0, colour != INVALID_COLOUR);
688 if (colour == INVALID_COLOUR) colour = GetParentLivery(g)->colour1;
689 g->livery.colour1 = colour;
690 } else {
691 AssignBit(g->livery.in_use, 1, colour != INVALID_COLOUR);
692 if (colour == INVALID_COLOUR) colour = GetParentLivery(g)->colour2;
693 g->livery.colour2 = colour;
694 }
695
696 PropagateChildLivery(g, true);
698 }
699
700 return CommandCost();
701}
702
708static void SetGroupFlag(Group *g, GroupFlag flag, bool set, bool children)
709{
710 if (set) {
711 g->flags.Set(flag);
712 } else {
713 g->flags.Reset(flag);
714 }
715
716 if (!children) return;
717
718 for (const GroupID &childgroup : g->children) {
719 SetGroupFlag(Group::Get(childgroup), flag, set, true);
720 }
721}
722
732CommandCost CmdSetGroupFlag(DoCommandFlags flags, GroupID group_id, GroupFlag flag, bool value, bool recursive)
733{
734 Group *g = Group::GetIfValid(group_id);
735 if (g == nullptr || g->owner != _current_company) return CMD_ERROR;
736
738
739 if (flags.Test(DoCommandFlag::Execute)) {
740 SetGroupFlag(g, flag, value, recursive);
741
744 }
745
746 return CommandCost();
747}
748
756{
757 if (!Group::IsValidID(new_g) && !IsDefaultGroupID(new_g)) return;
758
759 assert(v->IsFrontEngine() || IsDefaultGroupID(new_g));
760
761 for (Vehicle *u = v; u != nullptr; u = u->Next()) {
762 if (u->IsEngineCountable()) UpdateNumEngineGroup(u, u->group_id, new_g);
763
764 u->group_id = new_g;
765 u->colourmap = PAL_NONE;
766 u->InvalidateNewGRFCache();
767 u->UpdateViewport(true);
768 }
769
770 /* Update the Replace Vehicle Windows */
773}
774
775
784{
785 assert(v->IsFrontEngine() || v->IsFreeWagon());
786
788 for (Vehicle *u = v; u != nullptr; u = u->Next()) {
789 if (u->IsEngineCountable()) UpdateNumEngineGroup(u, u->group_id, new_g);
790
791 u->group_id = new_g;
792 u->colourmap = PAL_NONE;
793 u->InvalidateNewGRFCache();
794 }
795
796 /* Update the Replace Vehicle Windows */
799}
800
810{
811 uint count = 0;
812
813 if (Group *g = Group::GetIfValid(id_g); g != nullptr) {
814 for (const GroupID &childgroup : g->children) {
815 count += GetGroupNumEngines(company, childgroup, id_e);
816 }
817 }
818
819 return count + GroupStatistics::Get(company, id_g, Engine::Get(id_e)->type).GetNumEngines(id_e);
820}
821
831{
832 uint count = 0;
833
834 if (Group *g = Group::GetIfValid(id_g); g != nullptr) {
835 for (const GroupID &childgroup : g->children) {
836 count += GetGroupNumVehicle(company, childgroup, type);
837 }
838 }
839
840 return count + GroupStatistics::Get(company, id_g, type).num_vehicle;
841}
842
852{
853 uint count = 0;
854
855 if (Group *g = Group::GetIfValid(id_g); g != nullptr) {
856 for (const GroupID &childgroup : g->children) {
857 count += GetGroupNumVehicleMinAge(company, childgroup, type);
858 }
859 }
860
861 return count + GroupStatistics::Get(company, id_g, type).num_vehicle_min_age;
862}
863
873{
874 Money sum = 0;
875
876 if (Group *g = Group::GetIfValid(id_g); g != nullptr) {
877 for (const GroupID &childgroup : g->children) {
878 sum += GetGroupProfitLastYearMinAge(company, childgroup, type);
879 }
880 }
881
882 return sum + GroupStatistics::Get(company, id_g, type).profit_last_year_min_age;
883}
884
885void RemoveAllGroupsForCompany(const CompanyID company)
886{
887 for (Group *g : Group::Iterate()) {
888 if (company == g->owner) delete g;
889 }
890}
891
892
899bool GroupIsInGroup(GroupID search, GroupID group)
900{
901 if (!Group::IsValidID(search)) return search == group;
902
903 do {
904 if (search == group) return true;
905 search = Group::Get(search)->parent;
906 } while (search != GroupID::Invalid());
907
908 return false;
909}
Base class for autoreplaces/autorenews.
Functions related to autoreplacing.
CommandCost RemoveEngineReplacementForCompany(Company *c, EngineID engine, GroupID group, DoCommandFlags flags)
Remove an engine replacement for the company.
debug_inline constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr T AssignBit(T &x, const uint8_t y, bool value)
Assigns a bit in a variable.
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
constexpr Timpl & Reset()
Reset all bits.
constexpr Timpl & Set()
Set all bits.
Common return value for all commands.
Enum-as-bit-set wrapper.
UnitID UseID(UnitID index)
Use a unit number.
Definition vehicle.cpp:1833
void ReleaseID(UnitID index)
Release a unit number.
Definition vehicle.cpp:1850
UnitID NextID() const
Find first unused unit number.
Definition vehicle.cpp:1818
Functions related to commands.
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
@ Execute
execute the given command
CompanyID _current_company
Company currently doing an action.
Functions related to companies.
GroupFlag
Definition group.h:66
@ ReplaceProtection
If set, the global autoreplace has no effect on the group.
@ ReplaceWagonRemoval
If set, autoreplace will perform wagon removal on vehicles in this group.
uint GetGroupNumEngines(CompanyID company, GroupID id_g, EngineID id_e)
Get the number of engines with EngineID id_e in the group with GroupID id_g and its sub-groups.
GroupPool _group_pool
Pool of groups.
bool IsAllGroupID(GroupID id_g)
Checks if a GroupID stands for all vehicles of a company.
Definition group.h:103
Money GetGroupProfitLastYearMinAge(CompanyID company, GroupID id_g, VehicleType type)
Get last year's profit of vehicles above minimum age for the group with GroupID id_g and its sub-grou...
CommandCost CmdAddSharedVehicleGroup(DoCommandFlags flags, GroupID id_g, VehicleType type)
Add all shared vehicles of all vehicles from a group.
CommandCost CmdSetGroupFlag(DoCommandFlags flags, GroupID group_id, GroupFlag flag, bool value, bool recursive)
(Un)set group flag from a group
std::tuple< CommandCost, GroupID > CmdCreateGroup(DoCommandFlags flags, VehicleType vt, GroupID parent_group)
Create a new vehicle group.
static void SetGroupFlag(Group *g, GroupFlag flag, bool set, bool children)
Set group flag for a group and its sub-groups.
void UpdateCompanyGroupLiveries(const Company *c)
Update group liveries for a company.
CommandCost CmdAlterGroup(DoCommandFlags flags, AlterGroupMode mode, GroupID group_id, GroupID parent_id, const std::string &text)
Alter a group.
void SetTrainGroupID(Train *v, GroupID new_g)
Affect the groupID of a train to new_g.
void UpdateGroupChildren()
Update children list for each group.
Definition group_cmd.cpp:47
CommandCost CmdSetGroupLivery(DoCommandFlags flags, GroupID group_id, bool primary, Colours colour)
Set the livery for a vehicle group.
CommandCost CmdRemoveAllVehiclesGroup(DoCommandFlags flags, GroupID group_id)
Remove all vehicles from a group.
void UpdateTrainGroupID(Train *v)
Recalculates the groupID of a train.
CommandCost CmdDeleteGroup(DoCommandFlags flags, GroupID group_id)
Add all vehicles in the given group to the default group and then deletes the group.
uint GetGroupNumEngines(CompanyID company, GroupID id_g, EngineID id_e)
Get the number of engines with EngineID id_e in the group with GroupID id_g and its sub-groups.
static void UpdateNumEngineGroup(const Vehicle *v, GroupID old_g, GroupID new_g)
Update the num engines of a groupID.
std::tuple< CommandCost, GroupID > CmdAddVehicleGroup(DoCommandFlags flags, GroupID group_id, VehicleID veh_id, bool add_shared, const VehicleListIdentifier &vli)
Add a vehicle to a group.
static void AddVehicleToGroup(Vehicle *v, GroupID new_g)
Do add a vehicle to a group.
static void PropagateChildLivery(const Group *g, bool reset_cache)
Propagate a livery change to a group's children, and optionally update cached vehicle colourmaps.
uint GetGroupNumVehicle(CompanyID company, GroupID id_g, VehicleType type)
Get the number of vehicles in the group with GroupID id_g and its sub-groups.
uint GetGroupNumVehicleMinAge(CompanyID company, GroupID id_g, VehicleType type)
Get the number of vehicles above profit minimum age in the group with GroupID id_g and its sub-groups...
bool GroupIsInGroup(GroupID search, GroupID group)
Test if GroupID group is a descendant of (or is) GroupID search.
Command definitions related to engine groups.
AlterGroupMode
Action for CmdAlterGroup.
Definition group_cmd.h:23
@ Rename
Change group name.
@ SetParent
Change group parent.
void MarkWholeScreenDirty()
This function mark the whole screen as dirty.
Definition gfx.cpp:1535
static constexpr GroupID DEFAULT_GROUP
Ungrouped vehicles are in this group.
Definition group_type.h:18
static constexpr GroupID ALL_GROUP
All vehicles are in this group.
Definition group_type.h:17
static constexpr GroupID NEW_GROUP
Sentinel for a to-be-created group.
Definition group_type.h:16
static const uint MAX_LENGTH_GROUP_NAME_CHARS
The maximum length of a group name in characters including '\0'.
Definition group_type.h:20
Functions related to order backups.
Some methods of Pool are placed here in order to reduce compilation time and binary size.
#define INSTANTIATE_POOL_METHODS(name)
Force instantiation of pool methods so we don't get linker errors.
A number of safeguards to prevent using unsafe methods.
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:347
Functions related to low-level strings.
VehicleType type
Type of vehicle.
CompanySettings settings
settings specific for each company
EngineRenewList engine_renew_list
Engine renewals of this company.
bool renew_keep_length
sell some wagons if after autoreplace the train is longer than before
std::array< GroupStatistics, VEH_COMPANY_END > group_default
NOSAVE: Statistics for the DEFAULT_GROUP group.
std::array< GroupStatistics, VEH_COMPANY_END > group_all
NOSAVE: Statistics for the ALL_GROUP group.
Struct to store engine replacements.
VehicleType type
Vehicle type, ie VEH_ROAD, VEH_TRAIN, etc.
Definition engine_base.h:61
bool IsFreeWagon() const
Check if the vehicle is a free wagon (got no engine in front of it).
Statistics and caches on the vehicles in a group.
Definition group.h:25
static void CountVehicle(const Vehicle *v, int delta)
Update num_vehicle when adding or removing a vehicle.
static void AddProfitLastYear(const Vehicle *v)
Add a vehicle's last year profit to the profit sum of its group.
static void VehicleReachedMinAge(const Vehicle *v)
Add a vehicle to the profit sum of its group.
uint16_t GetNumEngines(EngineID engine) const
Get number of vehicles of a specific engine ID.
Definition group_cmd.cpp:59
Money profit_last_year
Sum of profits for all vehicles.
Definition group.h:26
static GroupStatistics & GetAllGroup(const Vehicle *v)
Returns the GroupStatistic for the ALL_GROUPO of a vehicle type.
static void UpdateAfterLoad()
Update all caches after loading a game, changing NewGRF, etc.
static void CountEngine(const Vehicle *v, int delta)
Update num_engines when adding/removing an engine.
uint16_t num_vehicle
Number of vehicles.
Definition group.h:29
Money profit_last_year_min_age
Sum of profits for vehicles considered for profit statistics.
Definition group.h:27
static void UpdateAutoreplace(CompanyID company)
Update autoreplace_defined and autoreplace_finished of all statistics of a company.
static void UpdateProfits()
Recompute the profits for all groups.
bool autoreplace_defined
Are any autoreplace rules set?
Definition group.h:31
static GroupStatistics & Get(CompanyID company, GroupID id_g, VehicleType type)
Returns the GroupStatistics for a specific group.
Definition group_cmd.cpp:73
bool autoreplace_finished
Have all autoreplacement finished?
Definition group.h:32
std::map< EngineID, uint16_t > num_engines
Caches the number of engines of each type the company owns.
Definition group.h:28
uint16_t num_vehicle_min_age
Number of vehicles considered for profit statistics;.
Definition group.h:30
Group data.
Definition group.h:73
GroupFlags flags
Group flags.
Definition group.h:78
Livery livery
Custom colour scheme for vehicles in this group.
Definition group.h:79
GroupID parent
Parent group.
Definition group.h:85
GroupStatistics statistics
NOSAVE: Statistics and caches on the vehicles in the group.
Definition group.h:80
VehicleType vehicle_type
Vehicle type of the group.
Definition group.h:76
std::string name
Group Name.
Definition group.h:74
uint16_t number
Per-company group number.
Definition group.h:86
Owner owner
Group Owner.
Definition group.h:75
FlatSet< GroupID > children
NOSAVE: child groups belonging to this group.
Definition group.h:82
Information about a particular livery.
Definition livery.h:78
Colours colour2
Second colour, for vehicles with 2CC support.
Definition livery.h:81
Colours colour1
First colour, for all vehicles.
Definition livery.h:80
uint8_t in_use
Bit 0 set if this livery should override the default livery first colour, Bit 1 for the second colour...
Definition livery.h:79
static void ClearGroup(GroupID group)
Clear the group of all backups having this group ID.
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
static Titem * Get(auto index)
Returns Titem with given index.
Tindex index
Index of this pool item.
static bool CanAllocateItem(size_t n=1)
Helper functions so we can use PoolItem::Function() instead of _poolitem_pool.Function()
static bool IsValidID(auto index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
static Titem * GetIfValid(auto index)
Returns Titem with given index.
Base class for all pools.
T * Next() const
Get next vehicle in the chain.
static T * From(Vehicle *v)
Converts a Vehicle to SpecializedVehicle with type checking.
'Train' is either a loco or a wagon.
Definition train.h:91
The information about a vehicle list.
Definition vehiclelist.h:32
WindowNumber ToWindowNumber() const
Pack a VehicleListIdentifier in 32 bits so it can be used as unique WindowNumber.
Vehicle data structure.
EngineID engine_type
The type of engine used for this vehicle.
TimerGameEconomy::Date economy_age
Age in economy days.
GroupID group_id
Index of group Pool array.
bool IsEngineCountable() const
Check if a vehicle is counted in num_engines in each company struct.
Definition vehicle.cpp:685
debug_inline bool IsFrontEngine() const
Check if the vehicle is a front engine.
Vehicle * Next() const
Get the next vehicle of this vehicle.
Vehicle * NextShared() const
Get the next vehicle of the shared vehicle chain.
Money GetDisplayProfitLastYear() const
Gets the profit vehicle had last year.
Vehicle * FirstShared() const
Get the first vehicle of this vehicle chain.
TileIndex tile
Current tile index.
Owner owner
Which company owns the vehicle?
Base for the train class.
Functions related to vehicles.
static const TimerGameEconomy::Date VEHICLE_PROFIT_MIN_AGE
Only vehicles older than this have a meaningful profit.
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.
@ VEH_COMPANY_END
Last company-ownable type.
bool GenerateVehicleSortList(VehicleList *list, const VehicleListIdentifier &vli)
Generate a list of vehicles based on window type.
Functions and type for generating vehicle lists.
std::vector< const Vehicle * > VehicleList
A list of vehicles.
Definition vehiclelist.h:68
@ VL_GROUP_LIST
Index is the group.
Definition vehiclelist.h:27
void CloseWindowById(WindowClass cls, WindowNumber number, bool force, int data)
Close a window by its class and window number (if it is open).
Definition window.cpp:1182
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:3265
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting)
Definition window.cpp:3147
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:3282
@ WC_COMPANY_COLOUR
Company colour selection; Window numbers:
@ WC_VEHICLE_DEPOT
Depot view; Window numbers:
@ WC_REPLACE_VEHICLE
Replace vehicle window; Window numbers:
@ WC_VEHICLE_DETAILS
Vehicle details; Window numbers:
@ WC_VEHICLE_VIEW
Vehicle view; Window numbers: