OpenTTD Source 20260108-master-g8ba1860eaa
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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
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
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()) continue;
51 Group *pg = Group::GetIfValid(g->parent);
52 if (pg == nullptr || pg->owner != g->owner || pg->vehicle_type != g->vehicle_type) {
53 /* Due to a bug, groups which should have been deleted could be left with an invalid parent.
54 * Keep the group but clear the invalid parent so that the game is recoverable. */
55 Debug(misc, 2, "Group {} has invalid parent {}", g->index, g->parent);
56 g->parent = GroupID::Invalid();
57 } else {
58 pg->children.insert(g->index);
59 }
60 }
61}
62
69{
70 auto found = this->num_engines.find(engine);
71 if (found != std::end(this->num_engines)) return found->second;
72 return 0;
73}
74
83{
84 if (Group::IsValidID(id_g)) {
85 Group *g = Group::Get(id_g);
86 assert(g->owner == company);
87 assert(g->vehicle_type == type);
88 return g->statistics;
89 }
90
91 if (IsDefaultGroupID(id_g)) return Company::Get(company)->group_default[type];
92 if (IsAllGroupID(id_g)) return Company::Get(company)->group_all[type];
93
94 NOT_REACHED();
95}
96
103{
104 return GroupStatistics::Get(v->owner, v->group_id, v->type);
105}
106
113{
115}
116
121{
122 /* Set up the engine count for all companies */
123 for (Company *c : Company::Iterate()) {
124 for (VehicleType type = VEH_BEGIN; type < VEH_COMPANY_END; type++) {
125 c->group_all[type].Clear();
126 c->group_default[type].Clear();
127 }
128 }
129
130 /* Recalculate */
131 for (Group *g : Group::Iterate()) {
132 g->statistics.Clear();
133 }
134
135 for (const Vehicle *v : Vehicle::Iterate()) {
136 if (!v->IsEngineCountable()) continue;
137
139 if (v->IsPrimaryVehicle()) GroupStatistics::CountVehicle(v, 1);
140 }
141
142 for (const Company *c : Company::Iterate()) {
144 }
145}
146
152/* static */ void GroupStatistics::CountVehicle(const Vehicle *v, int delta)
153{
154 assert(delta == 1 || delta == -1);
155
158
159 stats_all.num_vehicle += delta;
160 stats_all.profit_last_year += v->GetDisplayProfitLastYear() * delta;
161 stats.num_vehicle += delta;
162 stats.profit_last_year += v->GetDisplayProfitLastYear() * delta;
163
165 stats_all.num_vehicle_min_age += delta;
166 stats_all.profit_last_year_min_age += v->GetDisplayProfitLastYear() * delta;
167 stats.num_vehicle_min_age += delta;
169 }
170}
171
177/* static */ void GroupStatistics::CountEngine(const Vehicle *v, int delta)
178{
179 assert(delta == 1 || delta == -1);
182}
183
195
209
214{
215 /* Set up the engine count for all companies */
216 for (Company *c : Company::Iterate()) {
217 for (VehicleType type = VEH_BEGIN; type < VEH_COMPANY_END; type++) {
218 c->group_all[type].ClearProfits();
219 c->group_default[type].ClearProfits();
220 }
221 }
222
223 /* Recalculate */
224 for (Group *g : Group::Iterate()) {
225 g->statistics.ClearProfits();
226 }
227
228 for (const Vehicle *v : Vehicle::Iterate()) {
229 if (v->IsPrimaryVehicle()) {
232 }
233 }
234}
235
241{
242 /* Set up the engine count for all companies */
243 Company *c = Company::Get(company);
244 for (VehicleType type = VEH_BEGIN; type < VEH_COMPANY_END; type++) {
245 c->group_all[type].ClearAutoreplace();
246 c->group_default[type].ClearAutoreplace();
247 }
248
249 /* Recalculate */
250 for (Group *g : Group::Iterate()) {
251 if (g->owner != company) continue;
252 g->statistics.ClearAutoreplace();
253 }
254
255 for (EngineRenewList erl = c->engine_renew_list; erl != nullptr; erl = erl->next) {
256 const Engine *e = Engine::Get(erl->from);
257 GroupStatistics &stats = GroupStatistics::Get(company, erl->group_id, e->type);
258 if (!stats.autoreplace_defined) {
259 stats.autoreplace_defined = true;
260 stats.autoreplace_finished = true;
261 }
262 if (GetGroupNumEngines(company, erl->group_id, erl->from) > 0) stats.autoreplace_finished = false;
263 }
264}
265
273static inline void UpdateNumEngineGroup(const Vehicle *v, GroupID old_g, GroupID new_g)
274{
275 if (old_g != new_g) {
276 /* Decrease the num engines in the old group */
278
279 /* Increase the num engines in the new group */
281 }
282}
283
284
285const Livery *GetParentLivery(const Group *g)
286{
287 if (g->parent == GroupID::Invalid()) {
288 const Company *c = Company::Get(g->owner);
289 return &c->livery[LS_DEFAULT];
290 }
291
292 const Group *pg = Group::Get(g->parent);
293 return &pg->livery;
294}
295
296
302static void PropagateChildLivery(const Group *g, bool reset_cache)
303{
304 if (reset_cache) {
305 /* Company colour data is indirectly cached. */
306 for (Vehicle *v : Vehicle::Iterate()) {
307 if (v->group_id == g->index && (!v->IsGroundVehicle() || v->IsFrontEngine())) {
308 for (Vehicle *u = v; u != nullptr; u = u->Next()) {
309 u->colourmap = PAL_NONE;
310 u->InvalidateNewGRFCache();
311 }
312 }
313 }
314 }
315
316 for (const GroupID &childgroup : g->children) {
317 Group *cg = Group::Get(childgroup);
320 PropagateChildLivery(cg, reset_cache);
321 }
322}
323
330{
331 for (Group *g : Group::Iterate()) {
332 if (g->owner == c->index && g->parent == GroupID::Invalid()) {
333 if (!g->livery.in_use.Test(Livery::Flag::Primary)) g->livery.colour1 = c->livery[LS_DEFAULT].colour1;
334 if (!g->livery.in_use.Test(Livery::Flag::Secondary)) g->livery.colour2 = c->livery[LS_DEFAULT].colour2;
335 PropagateChildLivery(g, false);
336 }
337 }
338}
339
340
348std::tuple<CommandCost, GroupID> CmdCreateGroup(DoCommandFlags flags, VehicleType vt, GroupID parent_group)
349{
350 if (!IsCompanyBuildableVehicleType(vt)) return { CMD_ERROR, GroupID::Invalid() };
351
352 if (!Group::CanAllocateItem()) return { CMD_ERROR, GroupID::Invalid() };
353
354 Group *pg = Group::GetIfValid(parent_group);
355 if (pg != nullptr) {
356 if (pg->owner != _current_company) return { CMD_ERROR, GroupID::Invalid() };
357 if (pg->vehicle_type != vt) return { CMD_ERROR, GroupID::Invalid() };
358 }
359
360 if (flags.Test(DoCommandFlag::Execute)) {
362
363 Company *c = Company::Get(g->owner);
364 g->number = c->freegroups.UseID(c->freegroups.NextID());
365 if (pg == nullptr) {
366 g->livery.colour1 = c->livery[LS_DEFAULT].colour1;
367 g->livery.colour2 = c->livery[LS_DEFAULT].colour2;
369 } else {
370 g->parent = pg->index;
371 g->livery.colour1 = pg->livery.colour1;
372 g->livery.colour2 = pg->livery.colour2;
373 g->flags = pg->flags;
374 pg->children.insert(g->index);
375 }
376
379
380 return { CommandCost(), g->index };
381 }
382
383 return { CommandCost(), GroupID::Invalid()};
384}
385
386
394{
395 Group *g = Group::GetIfValid(group_id);
396 if (g == nullptr || g->owner != _current_company) return CMD_ERROR;
397
398 /* Remove all vehicles from the group */
400
401 /* Delete sub-groups, using a copy to avoid invalid iteration. */
402 FlatSet<GroupID> children = g->children;
403 for (const GroupID &childgroup : children) {
404 Command<CMD_DELETE_GROUP>::Do(flags, childgroup);
405 }
406
407 if (flags.Test(DoCommandFlag::Execute)) {
408 /* Update backupped orders if needed */
410
411 if (g->owner < MAX_COMPANIES) {
412 Company *c = Company::Get(g->owner);
413
414 /* If we set an autoreplace for the group we delete, remove it. */
415 for (const EngineRenew *er : EngineRenew::Iterate()) {
416 if (er->group_id == g->index) RemoveEngineReplacementForCompany(c, er->from, g->index, flags);
417 }
418
419 c->freegroups.ReleaseID(g->number);
420 }
421
422 if (g->parent != GroupID::Invalid()) {
423 Group *pg = Group::Get(g->parent);
424 pg->children.erase(g->index);
425 }
426
428
429 /* Delete the Replace Vehicle Windows */
431 delete g;
432
435 }
436
437 return CommandCost();
438}
439
449CommandCost CmdAlterGroup(DoCommandFlags flags, AlterGroupMode mode, GroupID group_id, GroupID parent_id, const std::string &text)
450{
451 Group *g = Group::GetIfValid(group_id);
452 if (g == nullptr || g->owner != _current_company) return CMD_ERROR;
453
454 if (mode == AlterGroupMode::Rename) {
455 /* Rename group */
456 bool reset = text.empty();
457
458 if (!reset) {
460 }
461
462 if (flags.Test(DoCommandFlag::Execute)) {
463 /* Assign the new one */
464 if (reset) {
465 g->name.clear();
466 } else {
467 g->name = text;
468 }
469 }
470 } else if (mode == AlterGroupMode::SetParent) {
471 /* Do nothing if the parent group isn't actually changed. */
472 if (g->parent == parent_id) return CommandCost();
473
474 /* Set group parent */
475 const Group *pg = Group::GetIfValid(parent_id);
476
477 if (pg != nullptr) {
478 if (pg->owner != _current_company) return CMD_ERROR;
479 if (pg->vehicle_type != g->vehicle_type) return CMD_ERROR;
480
481 /* Ensure request parent isn't child of group.
482 * This is the only place that infinite loops are prevented. */
483 if (GroupIsInGroup(pg->index, g->index)) return CommandCost(STR_ERROR_GROUP_CAN_T_SET_PARENT_RECURSION);
484 }
485
486 if (flags.Test(DoCommandFlag::Execute)) {
487 if (g->parent != GroupID::Invalid()) Group::Get(g->parent)->children.erase(g->index);
488 g->parent = (pg == nullptr) ? GroupID::Invalid() : pg->index;
489 if (g->parent != GroupID::Invalid()) Group::Get(g->parent)->children.insert(g->index);
490
492
493 if (!g->livery.in_use.All({Livery::Flag::Primary, Livery::Flag::Secondary})) {
494 /* Update livery with new parent's colours if either colour is default. */
495 const Livery *livery = GetParentLivery(g);
498
499 PropagateChildLivery(g, true);
501 }
502 }
503 } else {
504 return CMD_ERROR;
505 }
506
507 if (flags.Test(DoCommandFlag::Execute)) {
513 }
514
515 return CommandCost();
516}
517
518
524static void AddVehicleToGroup(Vehicle *v, GroupID new_g)
525{
527
528 switch (v->type) {
529 default: NOT_REACHED();
530 case VEH_TRAIN:
531 SetTrainGroupID(Train::From(v), new_g);
532 break;
533
534 case VEH_ROAD:
535 case VEH_SHIP:
536 case VEH_AIRCRAFT:
537 if (v->IsEngineCountable()) UpdateNumEngineGroup(v, v->group_id, new_g);
538 v->group_id = new_g;
539 for (Vehicle *u = v; u != nullptr; u = u->Next()) {
540 u->colourmap = PAL_NONE;
541 u->InvalidateNewGRFCache();
542 u->UpdateViewport(true);
543 }
544 break;
545 }
546
549
551}
552
561std::tuple<CommandCost, GroupID> CmdAddVehicleGroup(DoCommandFlags flags, GroupID group_id, VehicleID veh_id, bool add_shared, const VehicleListIdentifier &vli)
562{
563 GroupID new_g = group_id;
564 if (!Group::IsValidID(new_g) && !IsDefaultGroupID(new_g) && new_g != NEW_GROUP) return { CMD_ERROR, GroupID::Invalid() };
565
566 VehicleList list;
567 if (veh_id == VehicleID::Invalid() && vli.Valid()) {
568 if (!GenerateVehicleSortList(&list, vli) || list.empty()) return { CMD_ERROR, GroupID::Invalid() };
569 } else {
570 const Vehicle *v = Vehicle::GetIfValid(veh_id);
571 if (v == nullptr) return { CMD_ERROR, GroupID::Invalid() };
572 list.push_back(v);
573 }
574
575 VehicleType vtype = list.front()->type;
576 for (const Vehicle *v : list) {
577 if (v->owner != _current_company || !v->IsPrimaryVehicle()) return { CMD_ERROR, GroupID::Invalid() };
578 }
579
580 if (Group::IsValidID(new_g)) {
581 const Group *g = Group::Get(new_g);
582 if (g->owner != _current_company || g->vehicle_type != vtype) return { CMD_ERROR, GroupID::Invalid() };
583 }
584
585 if (new_g == NEW_GROUP) {
586 /* Create new group. */
587 auto [ret, new_group_id] = CmdCreateGroup(flags, vtype, GroupID::Invalid());
588 if (ret.Failed()) return { ret, new_group_id };
589
590 new_g = new_group_id;
591 }
592
593 if (flags.Test(DoCommandFlag::Execute)) {
594 for (const Vehicle *vc : list) {
595 /* VehicleList is const but we need to modify the vehicle. */
596 Vehicle *v = Vehicle::Get(vc->index);
597 AddVehicleToGroup(v, new_g);
598
599 if (add_shared) {
600 /* Add vehicles in the shared order list as well. */
601 for (Vehicle *v2 = v->FirstShared(); v2 != nullptr; v2 = v2->NextShared()) {
602 if (v2->group_id != new_g) AddVehicleToGroup(v2, new_g);
603 }
604 }
605
607 }
608
610
611 /* Update the Replace Vehicle Windows */
614 }
615
616 return { CommandCost(), new_g };
617}
618
627{
628 if (!Group::IsValidID(id_g) || !IsCompanyBuildableVehicleType(type)) return CMD_ERROR;
629
630 if (flags.Test(DoCommandFlag::Execute)) {
631 /* Find the first front engine which belong to the group id_g
632 * then add all shared vehicles of this front engine to the group id_g */
633 for (const Vehicle *v : Vehicle::Iterate()) {
634 if (v->type == type && v->IsPrimaryVehicle()) {
635 if (v->group_id != id_g) continue;
636
637 /* For each shared vehicles add it to the group */
638 for (Vehicle *v2 = v->FirstShared(); v2 != nullptr; v2 = v2->NextShared()) {
639 if (v2->group_id != id_g) Command<CMD_ADD_VEHICLE_GROUP>::Do(flags, id_g, v2->index, false, VehicleListIdentifier{});
640 }
641 }
642 }
643
645 }
646
647 return CommandCost();
648}
649
650
658{
659 const Group *g = Group::GetIfValid(group_id);
660
661 if (g == nullptr || g->owner != _current_company) return CMD_ERROR;
662
663 if (flags.Test(DoCommandFlag::Execute)) {
664 /* Find each Vehicle that belongs to the group old_g and add it to the default group */
665 for (const Vehicle *v : Vehicle::Iterate()) {
666 if (v->IsPrimaryVehicle()) {
667 if (v->group_id != group_id) continue;
668
669 /* Add The Vehicle to the default group */
671 }
672 }
673
675 }
676
677 return CommandCost();
678}
679
687CommandCost CmdSetGroupLivery(DoCommandFlags flags, GroupID group_id, bool primary, Colours colour)
688{
689 Group *g = Group::GetIfValid(group_id);
690
691 if (g == nullptr || g->owner != _current_company) return CMD_ERROR;
692
693 if (colour >= COLOUR_END && colour != INVALID_COLOUR) return CMD_ERROR;
694
695 if (flags.Test(DoCommandFlag::Execute)) {
696 if (primary) {
697 g->livery.in_use.Set(Livery::Flag::Primary, colour != INVALID_COLOUR);
698 if (colour == INVALID_COLOUR) colour = GetParentLivery(g)->colour1;
699 g->livery.colour1 = colour;
700 } else {
701 g->livery.in_use.Set(Livery::Flag::Secondary, colour != INVALID_COLOUR);
702 if (colour == INVALID_COLOUR) colour = GetParentLivery(g)->colour2;
703 g->livery.colour2 = colour;
704 }
705
706 PropagateChildLivery(g, true);
708 }
709
710 return CommandCost();
711}
712
718static void SetGroupFlag(Group *g, GroupFlag flag, bool set, bool children)
719{
720 if (set) {
721 g->flags.Set(flag);
722 } else {
723 g->flags.Reset(flag);
724 }
725
726 if (!children) return;
727
728 for (const GroupID &childgroup : g->children) {
729 SetGroupFlag(Group::Get(childgroup), flag, set, true);
730 }
731}
732
742CommandCost CmdSetGroupFlag(DoCommandFlags flags, GroupID group_id, GroupFlag flag, bool value, bool recursive)
743{
744 Group *g = Group::GetIfValid(group_id);
745 if (g == nullptr || g->owner != _current_company) return CMD_ERROR;
746
748
749 if (flags.Test(DoCommandFlag::Execute)) {
750 SetGroupFlag(g, flag, value, recursive);
751
754 }
755
756 return CommandCost();
757}
758
766{
767 if (!Group::IsValidID(new_g) && !IsDefaultGroupID(new_g)) return;
768
769 assert(v->IsFrontEngine() || IsDefaultGroupID(new_g));
770
771 for (Vehicle *u = v; u != nullptr; u = u->Next()) {
772 if (u->IsEngineCountable()) UpdateNumEngineGroup(u, u->group_id, new_g);
773
774 u->group_id = new_g;
775 u->colourmap = PAL_NONE;
776 u->InvalidateNewGRFCache();
777 u->UpdateViewport(true);
778 }
779
780 /* Update the Replace Vehicle Windows */
783}
784
785
794{
795 assert(v->IsFrontEngine() || v->IsFreeWagon());
796
798 for (Vehicle *u = v; u != nullptr; u = u->Next()) {
799 if (u->IsEngineCountable()) UpdateNumEngineGroup(u, u->group_id, new_g);
800
801 u->group_id = new_g;
802 u->colourmap = PAL_NONE;
803 u->InvalidateNewGRFCache();
804 }
805
806 /* Update the Replace Vehicle Windows */
809}
810
820{
821 uint count = 0;
822
823 if (const Group *g = Group::GetIfValid(id_g); g != nullptr) {
824 for (const GroupID &childgroup : g->children) {
825 count += GetGroupNumEngines(company, childgroup, id_e);
826 }
827 }
828
829 return count + GroupStatistics::Get(company, id_g, Engine::Get(id_e)->type).GetNumEngines(id_e);
830}
831
841{
842 uint count = 0;
843
844 if (const Group *g = Group::GetIfValid(id_g); g != nullptr) {
845 for (const GroupID &childgroup : g->children) {
846 count += GetGroupNumVehicle(company, childgroup, type);
847 }
848 }
849
850 return count + GroupStatistics::Get(company, id_g, type).num_vehicle;
851}
852
862{
863 uint count = 0;
864
865 if (const Group *g = Group::GetIfValid(id_g); g != nullptr) {
866 for (const GroupID &childgroup : g->children) {
867 count += GetGroupNumVehicleMinAge(company, childgroup, type);
868 }
869 }
870
871 return count + GroupStatistics::Get(company, id_g, type).num_vehicle_min_age;
872}
873
883{
884 Money sum = 0;
885
886 if (const Group *g = Group::GetIfValid(id_g); g != nullptr) {
887 for (const GroupID &childgroup : g->children) {
888 sum += GetGroupProfitLastYearMinAge(company, childgroup, type);
889 }
890 }
891
892 return sum + GroupStatistics::Get(company, id_g, type).profit_last_year_min_age;
893}
894
895void RemoveAllGroupsForCompany(const CompanyID company)
896{
897 for (Group *g : Group::Iterate()) {
898 if (company == g->owner) delete g;
899 }
900}
901
902
909bool GroupIsInGroup(GroupID search, GroupID group)
910{
911 if (!Group::IsValidID(search)) return search == group;
912
913 do {
914 if (search == group) return true;
915 search = Group::Get(search)->parent;
916 } while (search != GroupID::Invalid());
917
918 return false;
919}
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.
constexpr bool All(const Timpl &other) const
Test if all of the values are set.
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.
VehicleType type
Vehicle type, ie VEH_ROAD, VEH_TRAIN, etc.
Definition engine_base.h:62
Enum-as-bit-set wrapper.
Flat set implementation that uses a sorted vector for storage.
UnitID UseID(UnitID index)
Use a unit number.
Definition vehicle.cpp:1845
void ReleaseID(UnitID index)
Release a unit number.
Definition vehicle.cpp:1862
UnitID NextID() const
Find first unused unit number.
Definition vehicle.cpp:1830
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.
#define Debug(category, level, format_string,...)
Output a line of debugging information.
Definition debug.h:37
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:1549
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:349
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.
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:68
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_GROUP 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:82
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:79
Flags in_use
Livery flags.
Definition livery.h:86
Colours colour2
Second colour, for vehicles with 2CC support.
Definition livery.h:88
Colours colour1
First colour, for all vehicles.
Definition livery.h:87
@ Primary
Primary colour is set.
@ Secondary
Secondary colour is set.
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 T * Create(Targs &&... args)
Creates a new T-object in the associated pool.
static Titem * Get(auto 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 bool IsValidID(auto index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
const Tindex index
Index of this pool item.
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:686
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.
bool IsFrontEngine() const
Check if the vehicle is a front engine.
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
@ Clear
Plain water.
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:1195
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:3300
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting)
Definition window.cpp:3178
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:3318
@ 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: