OpenTTD Source 20260218-master-g2123fca5ea
company_cmd.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
10#include "stdafx.h"
11#include "company_base.h"
12#include "company_func.h"
13#include "company_gui.h"
14#include "core/backup_type.hpp"
15#include "town.h"
16#include "news_func.h"
17#include "command_func.h"
18#include "network/network.h"
22#include "ai/ai.hpp"
23#include "ai/ai_instance.hpp"
24#include "ai/ai_config.hpp"
26#include "window_func.h"
27#include "strings_func.h"
28#include "sound_func.h"
29#include "rail.h"
30#include "core/pool_func.hpp"
32#include "settings_func.h"
33#include "vehicle_base.h"
34#include "vehicle_func.h"
35#include "smallmap_gui.h"
36#include "game/game.hpp"
37#include "goal_base.h"
38#include "story_base.h"
39#include "company_cmd.h"
40#include "timer/timer.h"
43#include "timer/timer_window.h"
44
46
47#include "table/strings.h"
48#include "table/company_face.h"
49
50#include "safeguards.h"
51
52void ClearEnginesHiddenFlagOfCompany(CompanyID cid);
53void UpdateObjectColours(const Company *c);
54
55CompanyID _local_company;
60
61CompanyPool _company_pool("Company");
63
64
70Company::Company(CompanyID index, StringID name_1, bool is_ai) : CompanyPool::PoolItem<&_company_pool>(index)
71{
72 this->name_1 = name_1;
73 this->is_ai = is_ai;
74 this->terraform_limit = (uint32_t)_settings_game.construction.terraform_frame_burst << 16;
75 this->clear_limit = (uint32_t)_settings_game.construction.clear_frame_burst << 16;
76 this->tree_limit = (uint32_t)_settings_game.construction.tree_frame_burst << 16;
77 this->build_object_limit = (uint32_t)_settings_game.construction.build_object_frame_burst << 16;
78
79 InvalidateWindowData(WC_PERFORMANCE_DETAIL, 0, CompanyID::Invalid());
80}
81
84{
85 if (CleaningPool()) return;
86
88}
89
95{
100 /* If the currently shown error message has this company in it, then close it. */
102}
103
109{
110 if (this->max_loan == COMPANY_MAX_LOAN_DEFAULT) return _economy.max_loan;
111 return this->max_loan;
112}
113
120void SetLocalCompany(CompanyID new_company)
121{
122 /* company could also be COMPANY_SPECTATOR or OWNER_NONE */
123 assert(Company::IsValidID(new_company) || new_company == COMPANY_SPECTATOR || new_company == OWNER_NONE);
124
125 /* If actually changing to another company, several windows need closing */
126 bool switching_company = _local_company != new_company;
127
128 /* Delete the chat window, if you were team chatting. */
130
131 assert(IsLocalCompany());
132
133 _current_company = _local_company = new_company;
134
135 if (switching_company) {
138 /* Delete any construction windows... */
140 }
141
142 /* ... and redraw the whole screen. */
147 ResetVehicleColourMap();
148}
149
156{
157 if (!Company::IsValidID(company)) return GetColourGradient(COLOUR_WHITE, SHADE_NORMAL).ToTextColour();
158 return GetColourGradient(_company_colours[company], SHADE_NORMAL).ToTextColour();
159}
160
166PaletteID GetCompanyPalette(CompanyID company)
167{
168 return GetColourPalette(_company_colours[company]);
169}
170
177void DrawCompanyIcon(CompanyID c, int x, int y)
178{
179 DrawSprite(SPR_COMPANY_ICON, GetCompanyPalette(c), x, y);
180}
181
189{
190 if (cmf.style >= GetNumCompanyManagerFaceStyles()) return false;
191
192 /* Test if each enabled part is valid. */
193 FaceVars vars = GetCompanyManagerFaceVars(cmf.style);
194 for (uint var : SetBitIterator(GetActiveFaceVars(cmf, vars))) {
195 if (!vars[var].IsValid(cmf)) return false;
196 }
197
198 return true;
199}
200
202
209{
210 CompanyID cid = company->index;
212}
213
217static const IntervalTimer<TimerWindow> invalidate_company_windows_interval(std::chrono::milliseconds(1), [](auto) {
218 for (CompanyID cid : _dirty_company_finances) {
221 if (w != nullptr) {
227 }
229 }
231});
232
240Money GetAvailableMoney(CompanyID company)
241{
242 if (_settings_game.difficulty.infinite_money) return INT64_MAX;
243 if (!Company::IsValidID(company)) return INT64_MAX;
244 return Company::Get(company)->money;
245}
246
258
266{
267 if (cost.GetCost() <= 0) return true;
268 if (_settings_game.difficulty.infinite_money) return true;
269
271 if (c != nullptr && cost.GetCost() > c->money) {
272 cost.MakeError(STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY);
273 if (IsLocalCompany()) {
274 cost.SetEncodedMessage(GetEncodedString(STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY, cost.GetCost()));
275 }
276 return false;
277 }
278 return true;
279}
280
286static void SubtractMoneyFromCompany(Company *c, const CommandCost &cost)
287{
288 if (cost.GetCost() == 0) return;
289 assert(cost.GetExpensesType() != INVALID_EXPENSES);
290
291 c->money -= cost.GetCost();
292 c->yearly_expenses[0][cost.GetExpensesType()] += cost.GetCost();
293
298 c->cur_economy.income -= cost.GetCost();
299 } else if (HasBit(1 << EXPENSES_TRAIN_RUN |
302 1 << EXPENSES_SHIP_RUN |
303 1 << EXPENSES_PROPERTY |
305 c->cur_economy.expenses -= cost.GetCost();
306 }
307
309}
310
316void SubtractMoneyFromCompany(CompanyID company, const CommandCost &cost)
317{
318 Company *c = Company::GetIfValid(company);
319 if (c != nullptr) SubtractMoneyFromCompany(c, cost);
320}
321
327void SubtractMoneyFromCompanyFract(CompanyID company, const CommandCost &cst)
328{
329 Company *c = Company::Get(company);
330 uint8_t m = c->money_fraction;
331 Money cost = cst.GetCost();
332
333 c->money_fraction = m - (uint8_t)cost;
334 cost >>= 8;
335 if (c->money_fraction > m) cost++;
336 if (cost != 0) SubtractMoneyFromCompany(c, CommandCost(cst.GetExpensesType(), cost));
337}
338
339static constexpr void UpdateLandscapingLimit(uint32_t &limit, uint64_t per_64k_frames, uint64_t burst)
340{
341 limit = static_cast<uint32_t>(std::min<uint64_t>(limit + per_64k_frames, burst << 16));
342}
343
346{
347 for (Company *c : Company::Iterate()) {
348 UpdateLandscapingLimit(c->terraform_limit, _settings_game.construction.terraform_per_64k_frames, _settings_game.construction.terraform_frame_burst);
349 UpdateLandscapingLimit(c->clear_limit, _settings_game.construction.clear_per_64k_frames, _settings_game.construction.clear_frame_burst);
350 UpdateLandscapingLimit(c->tree_limit, _settings_game.construction.tree_per_64k_frames, _settings_game.construction.tree_frame_burst);
351 UpdateLandscapingLimit(c->build_object_limit, _settings_game.construction.build_object_per_64k_frames, _settings_game.construction.build_object_frame_burst);
352 }
353}
354
362std::array<StringParameter, 2> GetParamsForOwnedBy(Owner owner, TileIndex tile)
363{
364 if (owner == OWNER_TOWN) {
365 assert(tile != 0);
366 const Town *t = ClosestTownFromTile(tile, UINT_MAX);
367 return {STR_TOWN_NAME, t->index};
368 }
369
370 if (!Company::IsValidID(owner)) {
371 return {STR_COMPANY_SOMEONE, std::monostate{}};
372 }
373
374 return {STR_COMPANY_NAME, owner};
375}
376
386{
387 assert(owner < OWNER_END);
388 assert(owner != OWNER_TOWN || tile != 0);
389
390 if (owner == _current_company) return CommandCost();
391
392 CommandCost error{STR_ERROR_OWNED_BY};
393 if (IsLocalCompany()) {
394 auto params = GetParamsForOwnedBy(owner, tile);
395 error.SetEncodedMessage(GetEncodedStringWithArgs(STR_ERROR_OWNED_BY, params));
396 if (owner != OWNER_TOWN) error.SetErrorOwner(owner);
397 }
398 return error;
399}
400
409{
410 return CheckOwnership(GetTileOwner(tile), tile);
411}
412
418{
419 if (c->name_1 != STR_SV_UNNAMED) return;
420 if (c->last_build_coordinate == 0) return;
421
423
424 StringID str;
425 uint32_t strp;
426 std::string name;
427 if (t->name.empty() && IsInsideMM(t->townnametype, SPECSTR_TOWNNAME_START, SPECSTR_TOWNNAME_END)) {
428 str = t->townnametype - SPECSTR_TOWNNAME_START + SPECSTR_COMPANY_NAME_START;
429 strp = t->townnameparts;
430
431verify_name:;
432 /* No companies must have this name already */
433 for (const Company *cc : Company::Iterate()) {
434 if (cc->name_1 == str && cc->name_2 == strp) goto bad_town_name;
435 }
436
437 name = GetString(str, strp);
438 if (Utf8StringLength(name) >= MAX_LENGTH_COMPANY_NAME_CHARS) goto bad_town_name;
439
440set_name:;
441 c->name_1 = str;
442 c->name_2 = strp;
443
445 AI::BroadcastNewEvent(new ScriptEventCompanyRenamed(c->index, name));
446 Game::NewEvent(new ScriptEventCompanyRenamed(c->index, name));
447
448 if (c->is_ai) {
449 auto cni = std::make_unique<CompanyNewsInformation>(STR_NEWS_COMPANY_LAUNCH_TITLE, c);
450 EncodedString headline = GetEncodedString(STR_NEWS_COMPANY_LAUNCH_DESCRIPTION, cni->company_name, t->index);
451 AddNewsItem(std::move(headline),
453 }
454 return;
455 }
456bad_town_name:;
457
459 str = SPECSTR_ANDCO_NAME;
460 strp = c->president_name_2;
461 name = GetString(str, strp);
462 goto set_name;
463 } else {
464 str = SPECSTR_ANDCO_NAME;
465 strp = Random();
466 goto verify_name;
467 }
468}
469
471static const uint8_t _colour_sort[COLOUR_END] = {2, 2, 3, 2, 3, 2, 3, 2, 3, 2, 2, 2, 3, 1, 1, 1};
473static const Colours _similar_colour[COLOUR_END][2] = {
474 { COLOUR_BLUE, COLOUR_LIGHT_BLUE }, // COLOUR_DARK_BLUE
475 { COLOUR_GREEN, COLOUR_DARK_GREEN }, // COLOUR_PALE_GREEN
476 { INVALID_COLOUR, INVALID_COLOUR }, // COLOUR_PINK
477 { COLOUR_ORANGE, INVALID_COLOUR }, // COLOUR_YELLOW
478 { INVALID_COLOUR, INVALID_COLOUR }, // COLOUR_RED
479 { COLOUR_DARK_BLUE, COLOUR_BLUE }, // COLOUR_LIGHT_BLUE
480 { COLOUR_PALE_GREEN, COLOUR_DARK_GREEN }, // COLOUR_GREEN
481 { COLOUR_PALE_GREEN, COLOUR_GREEN }, // COLOUR_DARK_GREEN
482 { COLOUR_DARK_BLUE, COLOUR_LIGHT_BLUE }, // COLOUR_BLUE
483 { COLOUR_BROWN, COLOUR_ORANGE }, // COLOUR_CREAM
484 { COLOUR_PURPLE, INVALID_COLOUR }, // COLOUR_MAUVE
485 { COLOUR_MAUVE, INVALID_COLOUR }, // COLOUR_PURPLE
486 { COLOUR_YELLOW, COLOUR_CREAM }, // COLOUR_ORANGE
487 { COLOUR_CREAM, INVALID_COLOUR }, // COLOUR_BROWN
488 { COLOUR_WHITE, INVALID_COLOUR }, // COLOUR_GREY
489 { COLOUR_GREY, INVALID_COLOUR }, // COLOUR_WHITE
490};
491
496static Colours GenerateCompanyColour()
497{
498 Colours colours[COLOUR_END];
499
500 /* Initialize array */
501 for (uint i = 0; i < COLOUR_END; i++) colours[i] = static_cast<Colours>(i);
502
503 /* And randomize it */
504 for (uint i = 0; i < 100; i++) {
505 uint r = Random();
506 std::swap(colours[GB(r, 0, 4)], colours[GB(r, 4, 4)]);
507 }
508
509 /* Bubble sort it according to the values in table 1 */
510 for (uint i = 0; i < COLOUR_END; i++) {
511 for (uint j = 1; j < COLOUR_END; j++) {
512 if (_colour_sort[colours[j - 1]] < _colour_sort[colours[j]]) {
513 std::swap(colours[j - 1], colours[j]);
514 }
515 }
516 }
517
518 /* Move the colours that look similar to each company's colour to the side */
519 for (const Company *c : Company::Iterate()) {
520 Colours pcolour = c->colour;
521
522 for (uint i = 0; i < COLOUR_END; i++) {
523 if (colours[i] == pcolour) {
524 colours[i] = INVALID_COLOUR;
525 break;
526 }
527 }
528
529 for (uint j = 0; j < 2; j++) {
530 Colours similar = _similar_colour[pcolour][j];
531 if (similar == INVALID_COLOUR) break;
532
533 for (uint i = 1; i < COLOUR_END; i++) {
534 if (colours[i - 1] == similar) std::swap(colours[i - 1], colours[i]);
535 }
536 }
537 }
538
539 /* Return the first available colour */
540 for (uint i = 0; i < COLOUR_END; i++) {
541 if (colours[i] != INVALID_COLOUR) return colours[i];
542 }
543
544 NOT_REACHED();
545}
546
552{
553 for (;;) {
554restart:;
555 c->president_name_2 = Random();
557
558 /* Reserve space for extra unicode character. We need to do this to be able
559 * to detect too long president name. */
560 std::string name = GetString(STR_PRESIDENT_NAME, c->index);
562
563 for (const Company *cc : Company::Iterate()) {
564 if (c != cc) {
565 std::string other_name = GetString(STR_PRESIDENT_NAME, cc->index);
566 if (name == other_name) goto restart;
567 }
568 }
569 return;
570 }
571}
572
579{
580 for (LiveryScheme scheme = LS_BEGIN; scheme < LS_END; scheme++) {
581 c->livery[scheme].in_use.Reset();
582 c->livery[scheme].colour1 = c->colour;
583 c->livery[scheme].colour2 = c->colour;
584 }
585
586 for (Group *g : Group::Iterate()) {
587 if (g->owner == c->index) {
588 g->livery.in_use.Reset();
589 g->livery.colour1 = c->colour;
590 g->livery.colour2 = c->colour;
591 }
592 }
593}
594
602Company *DoStartupNewCompany(bool is_ai, CompanyID company = CompanyID::Invalid())
603{
604 if (!Company::CanAllocateItem()) return nullptr;
605
606 /* we have to generate colour before this company is valid */
607 Colours colour = GenerateCompanyColour();
608
609 Company *c;
610 if (company == CompanyID::Invalid()) {
611 c = Company::Create(STR_SV_UNNAMED, is_ai);
612 } else {
613 if (Company::IsValidID(company)) return nullptr;
614 c = Company::CreateAtIndex(company, STR_SV_UNNAMED, is_ai);
615 }
616
617 c->colour = colour;
618
620 _company_colours[c->index] = c->colour;
621
622 /* Scale the initial loan based on the inflation rounded down to the loan interval. The maximum loan has already been inflation adjusted. */
623 c->money = c->current_loan = std::min<int64_t>((INITIAL_LOAN * _economy.inflation_prices >> 16) / LOAN_INTERVAL * LOAN_INTERVAL, _economy.max_loan);
624
629
630 /* If starting a player company in singleplayer and a favourite company manager face is selected, choose it. Otherwise, use a random face.
631 * In a network game, we'll choose the favourite face later in CmdCompanyCtrl to sync it to all clients. */
632 bool randomise_face = true;
633 if (!_company_manager_face.empty() && !is_ai && !_networking) {
635 if (cmf.has_value()) {
636 randomise_face = false;
637 c->face = std::move(*cmf);
638 }
639 }
640 if (randomise_face) RandomiseCompanyManagerFace(c->face, _random);
641
644
646
652
653 if (is_ai && (!_networking || _network_server)) AI::StartNew(c->index);
654
655 AI::BroadcastNewEvent(new ScriptEventCompanyNew(c->index), c->index);
656 Game::NewEvent(new ScriptEventCompanyNew(c->index));
657
658 return c;
659}
660
663 if (_game_mode == GM_MENU || !AI::CanStartNew()) return;
664 if (_networking && Company::GetNumItems() >= _settings_client.network.max_companies) return;
665 if (_settings_game.difficulty.competitors_interval == 0) return;
666
667 /* count number of competitors */
668 uint8_t n = 0;
669 for (const Company *c : Company::Iterate()) {
670 if (c->is_ai) n++;
671 }
672
673 if (n >= _settings_game.difficulty.max_no_competitors) return;
674
675 /* Send a command to all clients to start up a new AI.
676 * Works fine for Multiplayer and Singleplayer */
677 Command<Commands::CompanyControl>::Post(CompanyCtrlAction::NewAI, CompanyID::Invalid(), CompanyRemoveReason::None, INVALID_CLIENT_ID);
678});
679
682{
683 /* Ensure the timeout is aborted, so it doesn't fire based on information of the last game. */
685}
686
692
699bool CheckTakeoverVehicleLimit(CompanyID cbig, CompanyID csmall)
700{
701 const Company *c1 = Company::Get(cbig);
702 const Company *c2 = Company::Get(csmall);
703
704 /* Do the combined vehicle counts stay within the limits? */
705 return c1->group_all[VEH_TRAIN].num_vehicle + c2->group_all[VEH_TRAIN].num_vehicle <= _settings_game.vehicle.max_trains &&
706 c1->group_all[VEH_ROAD].num_vehicle + c2->group_all[VEH_ROAD].num_vehicle <= _settings_game.vehicle.max_roadveh &&
707 c1->group_all[VEH_SHIP].num_vehicle + c2->group_all[VEH_SHIP].num_vehicle <= _settings_game.vehicle.max_ships &&
708 c1->group_all[VEH_AIRCRAFT].num_vehicle + c2->group_all[VEH_AIRCRAFT].num_vehicle <= _settings_game.vehicle.max_aircraft;
709}
710
721{
722 /* Amount of time out for each company to take over a company;
723 * Timeout is a quarter (3 months of 30 days) divided over the
724 * number of companies. The minimum number of days in a quarter
725 * is 90: 31 in January, 28 in February and 31 in March.
726 * Note that the company going bankrupt can't buy itself. */
727 static const int TAKE_OVER_TIMEOUT = 3 * 30 * Ticks::DAY_TICKS / (MAX_COMPANIES - 1);
728
729 assert(c->bankrupt_asked.Any());
730
731 /* We're currently asking some company to buy 'us' */
732 if (c->bankrupt_timeout != 0) {
733 c->bankrupt_timeout -= MAX_COMPANIES;
734 if (c->bankrupt_timeout > 0) return;
735 c->bankrupt_timeout = 0;
736
737 return;
738 }
739
740 /* Did we ask everyone for bankruptcy? If so, bail out. */
741 if (c->bankrupt_asked.All()) return;
742
743 Company *best = nullptr;
744 int32_t best_performance = -1;
745
746 /* Ask the company with the highest performance history first */
747 for (Company *c2 : Company::Iterate()) {
748 if (c2->bankrupt_asked.None() && // Don't ask companies going bankrupt themselves
749 !c->bankrupt_asked.Test(c2->index) &&
750 best_performance < c2->old_economy[1].performance_history &&
751 CheckTakeoverVehicleLimit(c2->index, c->index)) {
752 best_performance = c2->old_economy[1].performance_history;
753 best = c2;
754 }
755 }
756
757 /* Asked all companies? */
758 if (best_performance == -1) {
759 c->bankrupt_asked.Set();
760 return;
761 }
762
763 c->bankrupt_asked.Set(best->index);
764
765 c->bankrupt_timeout = TAKE_OVER_TIMEOUT;
766
767 AI::NewEvent(best->index, new ScriptEventCompanyAskMerger(c->index, c->bankrupt_value));
768 if (IsInteractiveCompany(best->index)) {
769 ShowBuyCompanyDialog(c->index, false);
770 }
771}
772
775{
776 if (_game_mode == GM_EDITOR) return;
777
779 if (c != nullptr) {
780 if (c->name_1 != 0) GenerateCompanyName(c);
782 }
783
784 if (_new_competitor_timeout.HasFired() && _game_mode != GM_MENU && AI::CanStartNew()) {
785 int32_t timeout = _settings_game.difficulty.competitors_interval * 60 * Ticks::TICKS_PER_SECOND;
786 /* If the interval is zero, start as many competitors as needed then check every ~10 minutes if a company went bankrupt and needs replacing. */
787 if (timeout == 0) {
788 /* count number of competitors */
789 uint8_t num_ais = 0;
790 for (const Company *cc : Company::Iterate()) {
791 if (cc->is_ai) num_ais++;
792 }
793
794 size_t num_companies = Company::GetNumItems();
795 for (auto i = 0; i < _settings_game.difficulty.max_no_competitors; i++) {
796 if (_networking && num_companies++ >= _settings_client.network.max_companies) break;
797 if (num_ais++ >= _settings_game.difficulty.max_no_competitors) break;
798 Command<Commands::CompanyControl>::Post(CompanyCtrlAction::NewAI, CompanyID::Invalid(), {}, INVALID_CLIENT_ID);
799 }
800 timeout = 10 * 60 * Ticks::TICKS_PER_SECOND;
801 }
802 /* Randomize a bit when the AI is actually going to start; ranges from 87.5% .. 112.5% of indicated value. */
803 timeout += ScriptObject::GetRandomizer(OWNER_NONE).Next(timeout / 4) - timeout / 8;
804
805 _new_competitor_timeout.Reset({ TimerGameTick::Priority::CompetitorTimeout, static_cast<uint>(std::max(1, timeout)) });
806 }
807
808 _cur_company_tick_index = (_cur_company_tick_index + 1) % MAX_COMPANIES;
809}
810
815static const IntervalTimer<TimerGameEconomy> _economy_companies_yearly({TimerGameEconomy::Trigger::Year, TimerGameEconomy::Priority::Company}, [](auto)
816{
817 /* Copy statistics */
818 for (Company *c : Company::Iterate()) {
819 /* Move expenses to previous years. */
820 std::rotate(std::rbegin(c->yearly_expenses), std::rbegin(c->yearly_expenses) + 1, std::rend(c->yearly_expenses));
821 c->yearly_expenses[0].fill(0);
823 }
824
825 if (_settings_client.gui.show_finances && _local_company != COMPANY_SPECTATOR) {
828 if (c->num_valid_stat_ent > 5 && c->old_economy[0].performance_history < c->old_economy[4].performance_history) {
829 if (_settings_client.sound.new_year) SndPlayFx(SND_01_BAD_YEAR);
830 } else {
831 if (_settings_client.sound.new_year) SndPlayFx(SND_00_GOOD_YEAR);
832 }
833 }
834});
835
843{
844 this->company_name = GetString(STR_COMPANY_NAME, c->index);
845
846 if (other != nullptr) {
847 this->other_company_name = GetString(STR_COMPANY_NAME, other->index);
848 c = other;
849 }
850
851 this->president_name = GetString(STR_PRESIDENT_NAME_MANAGER, c->index);
852
853 this->title = title;
854 this->colour = c->colour;
855 this->face = c->face;
856
857}
858
863void CompanyAdminUpdate(const Company *company)
864{
866}
867
873void CompanyAdminRemove(CompanyID company_id, CompanyRemoveReason reason)
874{
876}
877
887CommandCost CmdCompanyCtrl(DoCommandFlags flags, CompanyCtrlAction cca, CompanyID company_id, CompanyRemoveReason reason, ClientID client_id)
888{
890
891 switch (cca) {
892 case CompanyCtrlAction::New: { // Create a new company
893 /* This command is only executed in a multiplayer game */
894 if (!_networking) return CMD_ERROR;
895
896 /* Has the network client a correct ClientID? */
897 if (!flags.Test(DoCommandFlag::Execute)) return CommandCost();
898
900
901 /* Delete multiplayer progress bar */
903
904 Company *c = DoStartupNewCompany(false);
905
906 /* A new company could not be created, revert to being a spectator */
907 if (c == nullptr) {
908 /* We check for "ci != nullptr" as a client could have left by
909 * the time we execute this command. */
910 if (_network_server && ci != nullptr) {
913 }
914 break;
915 }
916
919
920 /* This is the client (or non-dedicated server) who wants a new company */
921 if (client_id == _network_own_client_id) {
923 SetLocalCompany(c->index);
924
925 /*
926 * If a favourite company manager face is selected, choose it. Otherwise, use a random face.
927 * Because this needs to be synchronised over the network, only the client knows
928 * its configuration and we are currently in the execution of a command, we have
929 * to circumvent the normal ::Post logic for commands and just send the command.
930 */
931 if (!_company_manager_face.empty()) {
933 if (cmf.has_value()) {
934 Command<Commands::SetCompanyManagerFace>::SendNet(STR_NULL, c->index, cmf->style, cmf->bits);
935 }
936 }
937
938 /* Now that we have a new company, broadcast our company settings to
939 * all clients so everything is in sync */
941
943 }
944 break;
945 }
946
947 case CompanyCtrlAction::NewAI: { // Make a new AI company
948 if (company_id != CompanyID::Invalid() && company_id >= MAX_COMPANIES) return CMD_ERROR;
949
950 /* For network games, company deletion is delayed. */
951 if (!_networking && company_id != CompanyID::Invalid() && Company::IsValidID(company_id)) return CMD_ERROR;
952
953 if (!flags.Test(DoCommandFlag::Execute)) return CommandCost();
954
955 /* For network game, just assume deletion happened. */
956 assert(company_id == CompanyID::Invalid() || !Company::IsValidID(company_id));
957
958 Company *c = DoStartupNewCompany(true, company_id);
959 if (c != nullptr) {
961 NetworkServerNewCompany(c, nullptr);
962 }
963 break;
964 }
965
966 case CompanyCtrlAction::Delete: { // Delete a company
967 if (reason >= CompanyRemoveReason::End) return CMD_ERROR;
968
969 /* We can't delete the last existing company in singleplayer mode. */
970 if (!_networking && Company::GetNumItems() == 1) return CMD_ERROR;
971
972 Company *c = Company::GetIfValid(company_id);
973 if (c == nullptr) return CMD_ERROR;
974
975 if (!flags.Test(DoCommandFlag::Execute)) return CommandCost();
976
977 /* Show the bankrupt news */
978 auto cni = std::make_unique<CompanyNewsInformation>(STR_NEWS_COMPANY_BANKRUPT_TITLE, c);
979 EncodedString headline = GetEncodedString(STR_NEWS_COMPANY_BANKRUPT_DESCRIPTION, cni->company_name);
980 AddCompanyNewsItem(std::move(headline), std::move(cni));
981
982 /* Remove the company */
984 if (c->is_ai) AI::Stop(c->index);
985
986 CompanyID c_index = c->index;
987 delete c;
988 AI::BroadcastNewEvent(new ScriptEventCompanyBankrupt(c_index));
989 Game::NewEvent(new ScriptEventCompanyBankrupt(c_index));
990 CompanyAdminRemove(c_index, (CompanyRemoveReason)reason);
991
994
995 break;
996 }
997
998 default: return CMD_ERROR;
999 }
1000
1004
1005 return CommandCost();
1006}
1007
1008static bool ExecuteAllowListCtrlAction(CompanyAllowListCtrlAction action, Company *c, const std::string &public_key)
1009{
1010 switch (action) {
1012 return c->allow_list.Add(public_key);
1013
1015 return c->allow_list.Remove(public_key);
1016
1018 if (c->allow_any) return false;
1019 c->allow_any = true;
1020 return true;
1021
1023 if (!c->allow_any) return false;
1024 c->allow_any = false;
1025 return true;
1026
1027 default:
1028 NOT_REACHED();
1029 }
1030}
1031
1039CommandCost CmdCompanyAllowListCtrl(DoCommandFlags flags, CompanyAllowListCtrlAction action, const std::string &public_key)
1040{
1042 if (c == nullptr) return CMD_ERROR;
1043
1044 switch (action) {
1047 /* The public key length includes the '\0'. */
1048 if (public_key.size() != NETWORK_PUBLIC_KEY_LENGTH - 1) return CMD_ERROR;
1049 break;
1050
1053 if (public_key.size() != 0) return CMD_ERROR;
1054 break;
1055
1056 default:
1057 return CMD_ERROR;
1058 }
1059
1060 if (flags.Test(DoCommandFlag::Execute)) {
1061 if (ExecuteAllowListCtrlAction(action, c, public_key)) {
1064 }
1065 }
1066
1067 return CommandCost();
1068}
1069
1077CommandCost CmdSetCompanyManagerFace(DoCommandFlags flags, uint style, uint32_t bits)
1078{
1079 CompanyManagerFace tmp_face{style, bits, {}};
1080 if (!IsValidCompanyManagerFace(tmp_face)) return CMD_ERROR;
1081
1082 if (flags.Test(DoCommandFlag::Execute)) {
1084 SetCompanyManagerFaceStyle(cmf, style);
1085 cmf.bits = tmp_face.bits;
1086
1088 }
1089 return CommandCost();
1090}
1091
1098{
1099 for (int i = 1; i < LS_END; i++) {
1100 if (!c->livery[i].in_use.Test(Livery::Flag::Primary)) c->livery[i].colour1 = c->livery[LS_DEFAULT].colour1;
1101 if (!c->livery[i].in_use.Test(Livery::Flag::Secondary)) c->livery[i].colour2 = c->livery[LS_DEFAULT].colour2;
1102 }
1104}
1105
1114CommandCost CmdSetCompanyColour(DoCommandFlags flags, LiveryScheme scheme, bool primary, Colours colour)
1115{
1116 if (scheme >= LS_END || (colour >= COLOUR_END && colour != INVALID_COLOUR)) return CMD_ERROR;
1117
1118 /* Default scheme can't be reset to invalid. */
1119 if (scheme == LS_DEFAULT && colour == INVALID_COLOUR) return CMD_ERROR;
1120
1122
1123 /* Ensure no two companies have the same primary colour */
1124 if (scheme == LS_DEFAULT && primary) {
1125 for (const Company *cc : Company::Iterate()) {
1126 if (cc != c && cc->colour == colour) return CMD_ERROR;
1127 }
1128 }
1129
1130 if (flags.Test(DoCommandFlag::Execute)) {
1131 if (primary) {
1132 if (scheme != LS_DEFAULT) c->livery[scheme].in_use.Set(Livery::Flag::Primary, colour != INVALID_COLOUR);
1133 if (colour == INVALID_COLOUR) colour = c->livery[LS_DEFAULT].colour1;
1134 c->livery[scheme].colour1 = colour;
1135
1136 /* If setting the first colour of the default scheme, adjust the
1137 * original and cached company colours too. */
1138 if (scheme == LS_DEFAULT) {
1141 c->colour = colour;
1143 }
1144 } else {
1145 if (scheme != LS_DEFAULT) c->livery[scheme].in_use.Set(Livery::Flag::Secondary, colour != INVALID_COLOUR);
1146 if (colour == INVALID_COLOUR) colour = c->livery[LS_DEFAULT].colour2;
1147 c->livery[scheme].colour2 = colour;
1148
1149 if (scheme == LS_DEFAULT) {
1151 }
1152 }
1153
1154 if (c->livery[scheme].in_use.Any({Livery::Flag::Primary, Livery::Flag::Secondary})) {
1155 /* If enabling a scheme, set the default scheme to be in use too */
1156 c->livery[LS_DEFAULT].in_use.Set(Livery::Flag::Primary);
1157 } else {
1158 /* Else loop through all schemes to see if any are left enabled.
1159 * If not, disable the default scheme too. */
1160 c->livery[LS_DEFAULT].in_use.Reset({Livery::Flag::Primary, Livery::Flag::Secondary});
1161 for (scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
1162 if (c->livery[scheme].in_use.Any({Livery::Flag::Primary, Livery::Flag::Secondary})) {
1163 c->livery[LS_DEFAULT].in_use.Set(Livery::Flag::Primary);
1164 break;
1165 }
1166 }
1167 }
1168
1169 ResetVehicleColourMap();
1171
1172 /* All graph related to companies use the company colour. */
1179 /* The smallmap owner view also stores the company colours. */
1182
1183 /* Company colour data is indirectly cached. */
1184 for (Vehicle *v : Vehicle::Iterate()) {
1185 if (v->owner == _current_company) v->InvalidateNewGRFCache();
1186 }
1187
1189 }
1190 return CommandCost();
1191}
1192
1198static bool IsUniqueCompanyName(const std::string &name)
1199{
1200 for (const Company *c : Company::Iterate()) {
1201 if (!c->name.empty() && c->name == name) return false;
1202 }
1203
1204 return true;
1205}
1206
1213CommandCost CmdRenameCompany(DoCommandFlags flags, const std::string &text)
1214{
1215 bool reset = text.empty();
1216
1217 if (!reset) {
1219 if (!IsUniqueCompanyName(text)) return CommandCost(STR_ERROR_NAME_MUST_BE_UNIQUE);
1220 }
1221
1222 if (flags.Test(DoCommandFlag::Execute)) {
1224 if (reset) {
1225 c->name.clear();
1226 } else {
1227 c->name = text;
1228 }
1229
1233
1234 std::string new_name = GetString(STR_COMPANY_NAME, c->index);
1235 AI::BroadcastNewEvent(new ScriptEventCompanyRenamed(c->index, new_name));
1236 Game::NewEvent(new ScriptEventCompanyRenamed(c->index, new_name));
1237 }
1238
1239 return CommandCost();
1240}
1241
1247static bool IsUniquePresidentName(const std::string &name)
1248{
1249 for (const Company *c : Company::Iterate()) {
1250 if (!c->president_name.empty() && c->president_name == name) return false;
1251 }
1252
1253 return true;
1254}
1255
1262CommandCost CmdRenamePresident(DoCommandFlags flags, const std::string &text)
1263{
1264 bool reset = text.empty();
1265
1266 if (!reset) {
1268 if (!IsUniquePresidentName(text)) return CommandCost(STR_ERROR_NAME_MUST_BE_UNIQUE);
1269 }
1270
1271 if (flags.Test(DoCommandFlag::Execute)) {
1273
1274 if (reset) {
1275 c->president_name.clear();
1276 } else {
1277 c->president_name = text;
1278
1279 if (c->name_1 == STR_SV_UNNAMED && c->name.empty()) {
1280 Command<Commands::RenameCompany>::Do(DoCommandFlag::Execute, text + " Transport");
1281 }
1282 }
1283
1287
1288 std::string new_name = GetString(STR_PRESIDENT_NAME, c->index);
1289 AI::BroadcastNewEvent(new ScriptEventPresidentRenamed(c->index, new_name));
1290 Game::NewEvent(new ScriptEventPresidentRenamed(c->index, new_name));
1291 }
1292
1293 return CommandCost();
1294}
1295
1303{
1304 const VehicleDefaultSettings *vds = (c == nullptr) ? &_settings_client.company.vehicle : &c->settings.vehicle;
1305 switch (type) {
1306 default: NOT_REACHED();
1307 case VEH_TRAIN: return vds->servint_trains;
1308 case VEH_ROAD: return vds->servint_roadveh;
1309 case VEH_AIRCRAFT: return vds->servint_aircraft;
1310 case VEH_SHIP: return vds->servint_ships;
1311 }
1312}
1313
1320{
1321 uint32_t total = 0;
1322 for (RoadType rt : GetMaskForRoadTramType(rtt)) {
1323 total += this->road[rt];
1324 }
1325 return total;
1326}
1327
1338CommandCost CmdGiveMoney(DoCommandFlags flags, Money money, CompanyID dest_company)
1339{
1340 if (!_settings_game.economy.give_money) return CMD_ERROR;
1341
1343 CommandCost amount(EXPENSES_OTHER, std::min<Money>(money, 20000000LL));
1344
1345 /* You can only transfer funds that is in excess of your loan */
1346 if (c->money - c->current_loan < amount.GetCost() || amount.GetCost() < 0) return CommandCost(STR_ERROR_INSUFFICIENT_FUNDS);
1347 if (!Company::IsValidID(dest_company)) return CMD_ERROR;
1348
1349 if (flags.Test(DoCommandFlag::Execute)) {
1350 /* Add money to company */
1352
1353 if (_networking) {
1354 std::string dest_company_name = GetString(STR_COMPANY_NAME, dest_company);
1355 std::string from_company_name = GetString(STR_COMPANY_NAME, _current_company);
1356
1357 NetworkTextMessage(NETWORK_ACTION_GIVE_MONEY, GetDrawStringCompanyColour(_current_company), false, from_company_name, dest_company_name, amount.GetCost());
1358 }
1359 }
1360
1361 /* Subtract money from local-company */
1362 return amount;
1363}
1364
1375{
1376 for (Company *c : Company::Iterate()) {
1377 if (Company::IsHumanID(c->index)) {
1378 return c->index;
1379 }
1380 }
1381
1383 for (CompanyID c = CompanyID::Begin(); c < MAX_COMPANIES; ++c) {
1384 if (!Company::IsValidID(c)) {
1385 return c;
1386 }
1387 }
1388 }
1389
1390 return CompanyID::Begin();
1391}
1392
1393static std::vector<FaceSpec> _faces;
1394
1399{
1400 _faces.clear();
1401 _faces.assign(std::begin(_original_faces), std::end(_original_faces));
1402}
1403
1409{
1410 return static_cast<uint>(std::size(_faces));
1411}
1412
1418const FaceSpec *GetCompanyManagerFaceSpec(uint style_index)
1419{
1420 if (style_index < GetNumCompanyManagerFaceStyles()) return &_faces[style_index];
1421 return nullptr;
1422}
1423
1429std::optional<uint> FindCompanyManagerFaceLabel(std::string_view label)
1430{
1431 auto it = std::ranges::find(_faces, label, &FaceSpec::label);
1432 if (it == std::end(_faces)) return std::nullopt;
1433
1434 return static_cast<uint>(std::distance(std::begin(_faces), it));
1435}
1436
1442FaceVars GetCompanyManagerFaceVars(uint style)
1443{
1444 const FaceSpec *spec = GetCompanyManagerFaceSpec(style);
1445 if (spec == nullptr) return {};
1446 return spec->GetFaceVars();
1447}
1448
1456{
1457 const FaceSpec *spec = GetCompanyManagerFaceSpec(style);
1458 assert(spec != nullptr);
1459
1460 cmf.style = style;
1461 cmf.style_label = spec->label;
1462}
1463
1475
1483uint32_t MaskCompanyManagerFaceBits(const CompanyManagerFace &cmf, FaceVars vars)
1484{
1485 CompanyManagerFace face{};
1486
1487 for (auto var : SetBitIterator(GetActiveFaceVars(cmf, vars))) {
1488 vars[var].SetBits(face, vars[var].GetBits(cmf));
1489 }
1490
1491 return face.bits;
1492}
1493
1500{
1501 uint32_t masked_face_bits = MaskCompanyManagerFaceBits(cmf, GetCompanyManagerFaceVars(cmf.style));
1502 return fmt::format("{}:{}", cmf.style_label, masked_face_bits);
1503}
1504
1510std::optional<CompanyManagerFace> ParseCompanyManagerFaceCode(std::string_view str)
1511{
1512 if (str.empty()) return std::nullopt;
1513
1515 StringConsumer consumer{str};
1516 if (consumer.FindChar(':') != StringConsumer::npos) {
1517 auto label = consumer.ReadUntilChar(':', StringConsumer::SKIP_ONE_SEPARATOR);
1518
1519 /* Read numeric part and ensure it's valid. */
1520 auto bits = consumer.TryReadIntegerBase<uint32_t>(10, true);
1521 if (!bits.has_value() || consumer.AnyBytesLeft()) return std::nullopt;
1522
1523 /* Ensure style label is valid. */
1524 auto style = FindCompanyManagerFaceLabel(label);
1525 if (!style.has_value()) return std::nullopt;
1526
1527 SetCompanyManagerFaceStyle(cmf, *style);
1528 cmf.bits = *bits;
1529 } else {
1530 /* No ':' included, treat as numeric-only. This allows old-style codes to be entered. */
1531 auto bits = ParseInteger(str, 10, true);
1532 if (!bits.has_value()) return std::nullopt;
1533
1534 /* Old codes use bits 0..1 to represent face style. These map directly to the default face styles. */
1535 SetCompanyManagerFaceStyle(cmf, GB(*bits, 0, 2));
1536 cmf.bits = *bits;
1537 }
1538
1539 /* Force the face bits to be valid. */
1540 FaceVars vars = GetCompanyManagerFaceVars(cmf.style);
1542 cmf.bits = MaskCompanyManagerFaceBits(cmf, vars);
1543
1544 return cmf;
1545}
Base functions for all AIs.
AIConfig stores the configuration settings of every AI.
The AIInstance tracks an AI.
Class for backupping variables and making sure they are restored later.
static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
static void BroadcastNewEvent(ScriptEvent *event, CompanyID skip_company=CompanyID::Invalid())
Broadcast a new event to all active AIs.
Definition ai_core.cpp:255
static bool CanStartNew()
Is it possible to start a new AI company?
Definition ai_core.cpp:30
static void StartNew(CompanyID company)
Start a new AI company.
Definition ai_core.cpp:36
static void Stop(CompanyID company)
Stop a company to be controlled by an AI.
Definition ai_core.cpp:107
static void NewEvent(CompanyID company, ScriptEvent *event)
Queue a new event for an AI.
Definition ai_core.cpp:235
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 & Set()
Set all bits.
constexpr bool Any(const Timpl &other) const
Test if any of the given values are set.
Common return value for all commands.
ExpensesType GetExpensesType() const
The expense type of the cost.
void MakeError(StringID message)
Makes this CommandCost behave like an error command.
Money GetCost() const
The costs as made up to this moment.
void SetEncodedMessage(EncodedString &&message)
Set the encoded message string.
void SetErrorOwner(Owner owner)
Set the 'owner' (the originator) of this error message.
Container for an encoded string, created by GetEncodedString.
static void NewEvent(class ScriptEvent *event)
Queue a new event for the game script.
An interval timer will fire every interval, and will continue to fire until it is deleted.
Definition timer.h:76
bool Add(std::string_view key)
Add the given key to the authorized keys, when it is not already contained.
Definition network.cpp:189
bool Remove(std::string_view key)
Remove the given key from the authorized keys, when it is exists.
Definition network.cpp:205
Parse data from a string / buffer.
std::optional< T > TryReadIntegerBase(int base, bool clamp=false)
Try to read and parse an integer in number 'base', and then advance the reader.
std::string_view ReadUntilChar(char c, SeparatorUsage sep)
Read data until the first occurrence of 8-bit char 'c', and advance reader.
size_type FindChar(char c) const
Find first occurrence of 8-bit char 'c'.
@ SKIP_ONE_SEPARATOR
Read and discard one separator, do not include it in the result.
bool AnyBytesLeft() const noexcept
Check whether any bytes left to read.
static constexpr size_type npos
Special value for "end of data".
static constexpr TimerGameTick::Ticks DAY_TICKS
1 day is 74 ticks; TimerGameCalendar::date_fract used to be uint16_t and incremented by 885.
static constexpr TimerGameTick::Ticks TICKS_PER_SECOND
Estimation of how many ticks fit in a single second.
A timeout timer will fire once after the interval.
Definition timer.h:116
static Year year
Current year, starting at 0.
static Year year
Current year, starting at 0.
@ CompetitorTimeout
Considering starting a new competitor/AI.
A sort-of mixin that implements 'at(pos)' and 'operator[](pos)' only for a specific type.
Functions related to commands.
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
@ Execute
execute the given command
Definition of stuff that is very close to a company, like the company struct itself.
uint _cur_company_tick_index
used to generate a name for one company that doesn't have a name yet per tick
void ClearEnginesHiddenFlagOfCompany(CompanyID cid)
Clear the 'hidden' flag for all engines of a new company.
Definition engine.cpp:1009
void UpdateObjectColours(const Company *c)
Updates the colour of the object whenever a company changes.
std::optional< CompanyManagerFace > ParseCompanyManagerFaceCode(std::string_view str)
Parse a face code into a company manager face.
static void GenerateCompanyName(Company *c)
Generate the name of a company from the last build coordinate.
static const IntervalTimer< TimerGameEconomy > _economy_companies_yearly({TimerGameEconomy::Trigger::Year, TimerGameEconomy::Priority::Company}, [](auto) { for(Company *c :Company::Iterate()) { std::rotate(std::rbegin(c->yearly_expenses), std::rbegin(c->yearly_expenses)+1, std::rend(c->yearly_expenses));c->yearly_expenses[0].fill(0);InvalidateWindowData(WC_FINANCES, c->index);} if(_settings_client.gui.show_finances &&_local_company !=COMPANY_SPECTATOR) { ShowCompanyFinances(_local_company);Company *c=Company::Get(_local_company);if(c->num_valid_stat_ent > 5 &&c->old_economy[0].performance_history< c->old_economy[4].performance_history) { if(_settings_client.sound.new_year) SndPlayFx(SND_01_BAD_YEAR);} else { if(_settings_client.sound.new_year) SndPlayFx(SND_00_GOOD_YEAR);} } })
A year has passed, update the economic data of all companies, and perhaps show the financial overview...
static bool IsValidCompanyManagerFace(CompanyManagerFace cmf)
Checks whether a company manager's face is a valid encoding.
const FaceSpec * GetCompanyManagerFaceSpec(uint style_index)
Get the definition of a company manager face style.
void OnTick_Companies()
Called every tick for updating some company info.
std::array< StringParameter, 2 > GetParamsForOwnedBy(Owner owner, TileIndex tile)
Get the right StringParameters for STR_ERROR_OWNED_BY.
FaceVars GetCompanyManagerFaceVars(uint style)
Get the face variables for a face style.
TimeoutTimer< TimerGameTick > _new_competitor_timeout({ TimerGameTick::Priority::CompetitorTimeout, 0 }, []() { if(_game_mode==GM_MENU||!AI::CanStartNew()) return;if(_networking &&Company::GetNumItems() >=_settings_client.network.max_companies) return;if(_settings_game.difficulty.competitors_interval==0) return;uint8_t n=0;for(const Company *c :Company::Iterate()) { if(c->is_ai) n++;} if(n >=_settings_game.difficulty.max_no_competitors) return;Command< Commands::CompanyControl >::Post(CompanyCtrlAction::NewAI, CompanyID::Invalid(), CompanyRemoveReason::None, INVALID_CLIENT_ID);})
Start a new competitor company if possible.
CommandCost CmdCompanyAllowListCtrl(DoCommandFlags flags, CompanyAllowListCtrlAction action, const std::string &public_key)
Add or remove the given public key to the allow list of this company.
void RandomiseCompanyManagerFace(CompanyManagerFace &cmf, Randomizer &randomizer)
Completely randomise a company manager face, including style.
void ResetFaces()
Reset company manager face styles to default.
Company * DoStartupNewCompany(bool is_ai, CompanyID company=CompanyID::Invalid())
Create a new company and sets all company variables default values.
void DrawCompanyIcon(CompanyID c, int x, int y)
Draw the icon of a company.
uint32_t MaskCompanyManagerFaceBits(const CompanyManagerFace &cmf, FaceVars vars)
Mask company manager face bits to ensure they are all within range.
std::string _company_manager_face
for company manager face storage in openttd.cfg
static Colours GenerateCompanyColour()
Generate a company colour.
static void GeneratePresidentName(Company *c)
Generate a random president name of a company.
static const Colours _similar_colour[COLOUR_END][2]
Similar colours, so we can try to prevent same coloured companies.
TypedIndexContainer< std::array< Colours, MAX_COMPANIES >, CompanyID > _company_colours
NOSAVE: can be determined from company structs.
void ResetCompanyLivery(Company *c)
Reset the livery schemes to the company's primary colour.
void UpdateCompanyLiveries(Company *c)
Update liveries for a company.
CommandCost CheckTileOwnership(TileIndex tile)
Check whether the current owner owns the stuff on the given tile.
CommandCost CmdSetCompanyColour(DoCommandFlags flags, LiveryScheme scheme, bool primary, Colours colour)
Change the company's company-colour.
CommandCost CmdCompanyCtrl(DoCommandFlags flags, CompanyCtrlAction cca, CompanyID company_id, CompanyRemoveReason reason, ClientID client_id)
Control the companies: add, delete, etc.
static std::vector< FaceSpec > _faces
All company manager face styles.
void InvalidateCompanyWindows(const Company *company)
Mark all finance windows owned by a company as needing a refresh.
int CompanyServiceInterval(const Company *c, VehicleType type)
Get the service interval for the given company and vehicle type.
PaletteID GetCompanyPalette(CompanyID company)
Get the palette for recolouring with a company colour.
void SetCompanyManagerFaceStyle(CompanyManagerFace &cmf, uint style)
Set a company face style.
bool CheckCompanyHasMoney(CommandCost &cost)
Verify whether the company can pay the bill.
static void SubtractMoneyFromCompany(Company *c, const CommandCost &cost)
Deduct costs of a command from the money of a company.
CompanyID GetFirstPlayableCompanyID()
Get the index of the first available company.
static CompanyMask _dirty_company_finances
Bitmask of company finances that should be marked dirty.
TextColour GetDrawStringCompanyColour(CompanyID company)
Get the colour for DrawString-subroutines which matches the colour of the company.
CommandCost CmdSetCompanyManagerFace(DoCommandFlags flags, uint style, uint32_t bits)
Change the company manager's face.
Money GetAvailableMoneyForCommand()
This functions returns the money which can be used to execute a command.
void CompanyAdminUpdate(const Company *company)
Called whenever company related information changes in order to notify admins.
std::optional< uint > FindCompanyManagerFaceLabel(std::string_view label)
Find a company manager face style by label.
CommandCost CheckOwnership(Owner owner, TileIndex tile)
Check whether the current owner owns something.
void CompanyAdminRemove(CompanyID company_id, CompanyRemoveReason reason)
Called whenever a company is removed in order to notify admins.
CommandCost CmdRenamePresident(DoCommandFlags flags, const std::string &text)
Change the name of the president.
CompanyPool _company_pool("Company")
Pool of companies.
uint GetNumCompanyManagerFaceStyles()
Get the number of company manager face styles.
std::string FormatCompanyManagerFaceCode(const CompanyManagerFace &cmf)
Get a face code representation of a company manager face.
Money GetAvailableMoney(CompanyID company)
Get the amount of money that a company has available, or INT64_MAX if there is no such valid company.
void UpdateLandscapingLimits()
Update the landscaping limits per company.
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
void InitializeCompanies()
Initialize the pool of companies.
void StartupCompanies()
Start of a new game.
bool CheckTakeoverVehicleLimit(CompanyID cbig, CompanyID csmall)
Can company cbig buy company csmall without exceeding vehicle limits?
static bool IsUniqueCompanyName(const std::string &name)
Is the given name in use as name of a company?
void SetLocalCompany(CompanyID new_company)
Sets the local company and updates the settings that are set on a per-company basis to reflect the co...
static bool IsUniquePresidentName(const std::string &name)
Is the given name in use as president name of a company?
CompanyID _current_company
Company currently doing an action.
CommandCost CmdGiveMoney(DoCommandFlags flags, Money money, CompanyID dest_company)
Transfer funds (money) from one company to another.
static void HandleBankruptcyTakeover(Company *c)
Handle the bankruptcy take over of a company.
CommandCost CmdRenameCompany(DoCommandFlags flags, const std::string &text)
Change the name of the company.
void SubtractMoneyFromCompanyFract(CompanyID company, const CommandCost &cst)
Subtract money from a company, including the money fraction.
static const IntervalTimer< TimerWindow > invalidate_company_windows_interval(std::chrono::milliseconds(1), [](auto) { for(CompanyID cid :_dirty_company_finances) { if(cid==_local_company) SetWindowWidgetDirty(WC_STATUS_BAR, 0, WID_S_RIGHT);Window *w=FindWindowById(WC_FINANCES, cid);if(w !=nullptr) { w->SetWidgetDirty(WID_CF_EXPS_PRICE3);w->SetWidgetDirty(WID_CF_OWN_VALUE);w->SetWidgetDirty(WID_CF_LOAN_VALUE);w->SetWidgetDirty(WID_CF_BALANCE_VALUE);w->SetWidgetDirty(WID_CF_MAXLOAN_VALUE);} SetWindowWidgetDirty(WC_COMPANY, cid, WID_C_DESC_COMPANY_VALUE);} _dirty_company_finances.Reset();})
Refresh all company finance windows previously marked dirty.
static const uint8_t _colour_sort[COLOUR_END]
Sorting weights for the company colours.
Command definitions related to companies.
This file contains all definitions for default company faces.
static FaceSpec _original_faces[]
Original face styles.
Functions related to companies.
bool IsInteractiveCompany(CompanyID company)
Is the user representing company?
void ChangeOwnershipOfCompanyItems(Owner old_owner, Owner new_owner)
Change the ownership of all the items of a company.
Definition economy.cpp:322
void ShowBuyCompanyDialog(CompanyID company, bool hostile_takeover)
Show the query to buy another company.
bool IsLocalCompany()
Is the current company the local company?
void ShowCompanyFinances(CompanyID company)
Open the finances window of a company.
GUI Functions related to companies.
void CloseCompanyWindows(CompanyID company)
Close all windows of a company.
Definition window.cpp:1225
Functionality related to the company manager's face.
void RandomiseCompanyManagerFaceBits(CompanyManagerFace &cmf, FaceVars vars, Randomizer &randomizer)
Make a random new face without changing the face style.
uint64_t GetActiveFaceVars(const CompanyManagerFace &cmf, FaceVars vars)
Get a bitmask of currently active face variables.
void ScaleAllCompanyManagerFaceBits(CompanyManagerFace &cmf, FaceVars vars)
Scales all company manager's face bits to the correct scope.
static const uint MAX_LENGTH_PRESIDENT_NAME_CHARS
The maximum length of a president name in characters including '\0'.
static const uint MAX_LENGTH_COMPANY_NAME_CHARS
The maximum length of a company name in characters including '\0'.
CompanyCtrlAction
The action to do with Commands::CompanyControl.
@ New
Create a new company.
@ NewAI
Create a new AI company.
@ Delete
Delete a company.
static constexpr CompanyID COMPANY_SPECTATOR
The client is spectating.
static constexpr Owner OWNER_END
Last + 1 owner.
CompanyAllowListCtrlAction
The action to do with Commands::CompanyAllowListControl.
@ RemoveKey
Remove a public key.
@ AddKey
Create a public key.
@ AllowListed
Allow only listed keys to join the company.
@ AllowAny
Allow joining the company without a key.
static constexpr Owner OWNER_TOWN
A town owns the tile, or a town is expanding.
static constexpr Owner OWNER_NONE
The tile has no ownership.
static constexpr Owner INVALID_OWNER
An invalid owner.
CompanyRemoveReason
The reason why the company was removed.
@ None
Dummy reason for actions that don't need one.
@ End
Sentinel for end.
@ WID_CF_OWN_VALUE
Own funds, not including loan.
@ WID_CF_LOAN_VALUE
Loan.
@ WID_CF_BALANCE_VALUE
Bank balance value.
@ WID_CF_EXPS_PRICE3
Column for year Y expenses.
@ WID_CF_MAXLOAN_VALUE
Max loan widget.
@ WID_C_DESC_COMPANY_VALUE
Company value.
@ WID_C_PRESIDENT_NAME
Button to change president name.
@ WID_C_COMPANY_NAME
Button to change company name.
static const uint NETWORK_PUBLIC_KEY_LENGTH
The maximum length of the hexadecimal encoded public keys, in bytes including '\0'.
Definition config.h:99
@ EXPENSES_ROADVEH_RUN
Running costs road vehicles.
@ EXPENSES_TRAIN_RUN
Running costs trains.
@ EXPENSES_AIRCRAFT_REVENUE
Revenue from aircraft.
@ EXPENSES_AIRCRAFT_RUN
Running costs aircraft.
@ EXPENSES_ROADVEH_REVENUE
Revenue from road vehicles.
@ EXPENSES_PROPERTY
Property costs.
@ EXPENSES_OTHER
Other expenses.
@ EXPENSES_SHIP_REVENUE
Revenue from ships.
@ EXPENSES_LOAN_INTEREST
Interest payments over the loan.
@ EXPENSES_TRAIN_REVENUE
Revenue from trains.
@ EXPENSES_SHIP_RUN
Running costs ships.
@ INVALID_EXPENSES
Invalid expense type.
static const int LOAN_INTERVAL
The "steps" in loan size, in British Pounds!
static const int64_t INITIAL_LOAN
The size of loan for a new company, in British Pounds!
Base functions for all Games.
void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub, ZoomLevel zoom)
Draw a sprite, not in a viewport.
Definition gfx.cpp:1038
uint32_t PaletteID
The number of the palette.
Definition gfx_type.h:18
TextColour
Colour of the strings, see _string_colourmap in table/string_colours.h or docs/ottd-colourtext-palett...
Definition gfx_type.h:307
Goal base class.
void UpdateCompanyGroupLiveries(const Company *c)
Update group liveries for a company.
void MarkWholeScreenDirty()
This function mark the whole screen as dirty.
Definition gfx.cpp:1554
LiveryScheme
List of different livery schemes.
Definition livery.h:22
constexpr bool IsInsideMM(const size_t x, const size_t min, const size_t max) noexcept
Checks if a value is in an interval.
bool _networking
are we in networking mode?
Definition network.cpp:66
bool _network_server
network-server is active
Definition network.cpp:67
ClientID _network_own_client_id
Our client identifier.
Definition network.cpp:71
Basic functions/variables used all over the place.
void NetworkAdminCompanyUpdate(const Company *company)
Notify the admin network of company updates.
void NetworkAdminCompanyNew(const Company *company)
Notify the admin network of a new company.
void NetworkAdminCompanyRemove(CompanyID company_id, AdminCompanyRemoveReason bcrr)
Notify the admin network of a company to be removed (including the reason why).
Server part of the admin network protocol.
Base core network types and some helper functions to access them.
Network functions used by other parts of OpenTTD.
void NetworkServerNewCompany(const Company *company, NetworkClientInfo *ci)
Perform all the server specific administration of a new company.
void NetworkUpdateClientInfo(ClientID client_id)
Send updated client info of a particular client.
@ DESTTYPE_TEAM
Send message/notice to everyone playing the same company (Team).
ClientID
'Unique' identifier to be given to clients
@ INVALID_CLIENT_ID
Client is not part of anything.
Functions related to news.
void AddNewsItem(EncodedString &&headline, NewsType type, NewsStyle style, NewsFlags flags, NewsReference ref1={}, NewsReference ref2={}, std::unique_ptr< NewsAllocatedData > &&data=nullptr, AdviceType advice_type=AdviceType::Invalid)
Add a new newsitem to be shown.
Definition news_gui.cpp:914
@ CompanyInfo
Company info (new companies, bankruptcy messages).
Definition news_type.h:34
@ Company
Company news item. (Newspaper with face).
Definition news_type.h:82
PixelColour GetColourGradient(Colours colour, ColourShade shade)
Get colour gradient palette index.
Definition palette.cpp:388
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.
RailTypes GetCompanyRailTypes(CompanyID company, bool introduces)
Get the rail types the given company can build.
Definition rail.cpp:135
Rail specific functions.
Randomizer _random
Random used in the game state calculations.
RoadTypes GetCompanyRoadTypes(CompanyID company, bool introduces)
Get the road types the given company can build.
Definition road.cpp:210
RoadTypes GetMaskForRoadTramType(RoadTramType rtt)
Get the mask for road types of the given RoadTramType.
Definition road.h:183
RoadTramType
The different types of road type.
Definition road_type.h:37
RoadType
The different roadtypes we support.
Definition road_type.h:23
A number of safeguards to prevent using unsafe methods.
void SyncCompanySettings()
Sync all company settings in a multiplayer game.
void SetDefaultCompanySettings(CompanyID cid)
Set the company settings for a new company to their default values.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition settings.cpp:61
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:60
Functions related to setting/changing the settings.
void BuildOwnerLegend()
Completes the array for the owned property legend.
Smallmap GUI functions.
Functions related to sound.
@ SND_01_BAD_YEAR
40 == 0x28 New year: performance declined
Definition sound_type.h:88
@ SND_00_GOOD_YEAR
39 == 0x27 New year: performance improved
Definition sound_type.h:87
static PaletteID GetColourPalette(Colours colour)
Get recolour palette for a colour.
Definition sprite.h:217
Types related to the statusbar widgets.
@ WID_S_RIGHT
Right part; bank balance.
Definition of base types and functions in a cross-platform compatible way.
StoryPage base class.
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
Parse strings.
static std::optional< T > ParseInteger(std::string_view arg, int base=10, bool clamp=false)
Change a string into its number representation.
EncodedString GetEncodedStringWithArgs(StringID str, std::span< const StringParameter > params)
Encode a string with its parameters into an encoded string.
Definition strings.cpp:102
EncodedString GetEncodedString(StringID str)
Encode a string with no parameters into an encoded string.
Definition strings.cpp:90
std::string GetString(StringID string)
Resolve the given StringID into a std::string with formatting but no parameters.
Definition strings.cpp:424
Functions related to OTTD's strings.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
static constexpr StringID SPECSTR_COMPANY_NAME_START
Special strings for company names on the form "TownName transport".
static constexpr StringID SPECSTR_ANDCO_NAME
Special string for Surname & Co company names.
static constexpr StringID SPECSTR_PRESIDENT_NAME
Special string for the president's name.
static constexpr StringID SPECSTR_TOWNNAME_START
Special strings for town names.
Money income
The amount of income.
Money expenses
The amount of expenses.
uint32_t GetRoadTramTotal(RoadTramType rtt) const
Get total sum of all owned road bits.
std::array< uint32_t, ROADTYPE_END > road
Count of company owned track bits for each road type.
uint32_t bits
Company manager face bits, meaning is dependent on style.
uint style
Company manager face style.
std::string style_label
Face style label.
CompanyManagerFace face
The face of the president.
Definition news_type.h:168
Colours colour
The colour related to the company.
Definition news_type.h:169
CompanyNewsInformation(StringID title, const struct Company *c, const struct Company *other=nullptr)
Fill the CompanyNewsInformation struct with the required data.
std::string president_name
The name of the president.
Definition news_type.h:164
std::string company_name
The name of the company.
Definition news_type.h:163
std::string other_company_name
The name of the company taking over this one.
Definition news_type.h:165
uint32_t clear_limit
Amount of tiles we can (still) clear (times 65536).
CompanyMask bankrupt_asked
which companies were asked about buying it?
std::string president_name
Name of the president if the user changed it.
int16_t bankrupt_timeout
If bigger than 0, amount of time to wait for an answer on an offer to buy this company.
CompanySettings settings
settings specific for each company
NetworkAuthorizedKeys allow_list
Public keys of clients that are allowed to join this company.
bool allow_any
Set if anyone is allowed to join this company.
uint32_t build_object_limit
Amount of tiles we can (still) build objects on (times 65536). Also applies to buying land and placin...
uint32_t name_2
Parameter of name_1.
uint8_t money_fraction
Fraction of money of the company, too small to represent in money.
bool is_ai
If true, the company is (also) controlled by the computer (a NoAI program).
uint32_t president_name_2
Parameter of president_name_1.
StringID name_1
Name of the company if the user did not change it.
Money current_loan
Amount of money borrowed from the bank.
TimerGameCalendar::Year inaugurated_year_calendar
Calendar year of starting the company. Used to display proper Inauguration year while in wallclock mo...
uint32_t terraform_limit
Amount of tileheights we can (still) terraform (times 65536).
TimerGameEconomy::Year inaugurated_year
Economy year of starting the company.
CompanyEconomyEntry cur_economy
Economic data of the company of this quarter.
Colours colour
Company colour.
uint32_t tree_limit
Amount of trees we can (still) plant (times 65536).
std::array< CompanyEconomyEntry, MAX_HISTORY_QUARTERS > old_economy
Economic data of the company of the last MAX_HISTORY_QUARTERS quarters.
CompanyManagerFace face
Face description of the president.
Money max_loan
Max allowed amount of the loan or COMPANY_MAX_LOAN_DEFAULT.
std::array< Expenses, 3 > yearly_expenses
Expenses of the company for the last three years.
TileIndex last_build_coordinate
Coordinate of the last build thing by this company.
StringID president_name_1
Name of the president if the user did not change it.
std::string name
Name of the company if the user changed it.
Money money
Money owned by the company.
uint8_t num_valid_stat_ent
Number of valid statistical entries in old_economy.
VehicleDefaultSettings vehicle
default settings for vehicles
Money GetMaxLoan() const
Calculate the max allowed loan for this company.
static bool IsHumanID(auto index)
Is this company a company not controlled by a NoAI program?
std::array< GroupStatistics, VEH_COMPANY_END > group_all
NOSAVE: Statistics for the ALL_GROUP group.
RoadTypes avail_roadtypes
Road types available to this company.
~Company()
Destructor.
RailTypes avail_railtypes
Rail types available to this company.
static void PostDestructor(size_t index)
Invalidating some stuff after removing item from the pool.
Company(CompanyID index, StringID name_1={}, bool is_ai=false)
Constructor.
Group data.
Definition group.h:74
@ Primary
Primary colour is set.
Definition livery.h:82
@ Secondary
Secondary colour is set.
Definition livery.h:83
Container for all information known about a client.
static NetworkClientInfo * GetByClientID(ClientID client_id)
Return the CI given it's client-identifier.
Definition network.cpp:117
CompanyID client_playas
As which company is this client playing (CompanyID).
ClientID client_id
Client identifier (same as ClientState->client_id).
static Pool::IterateWrapper< Company > Iterate(size_t from=0)
static T * CreateAtIndex(CompanyID index, Targs &&... args)
static Company * Get(auto index)
static bool CanAllocateItem(size_t n=1)
static T * Create(Targs &&... args)
static Company * GetIfValid(auto index)
Structure to encapsulate the pseudo random number generators.
uint32_t Next()
Generate the next pseudo random number.
Iterable ensemble of each set bit in a value.
Town data structure.
Definition town.h:63
std::string name
Custom town name. If empty, the town was not renamed and uses the generated name.
Definition town.h:72
Default settings for vehicles.
uint16_t servint_aircraft
service interval for aircraft
uint16_t servint_roadveh
service interval for road vehicles
uint16_t servint_ships
service interval for ships
uint16_t servint_trains
service interval for trains
Vehicle data structure.
Data structure for an opened window.
Definition window_gui.h:274
void SetWidgetDirty(WidgetID widget_index) const
Invalidate a widget, i.e.
Definition window.cpp:557
AdminCompanyRemoveReason
Reasons for removing a company - communicated to admins.
Definition tcp_admin.h:105
Owner GetTileOwner(Tile tile)
Returns the owner of a tile.
Definition tile_map.h:178
StrongType::Typedef< uint32_t, struct TileIndexTag, StrongType::Compare, StrongType::Integer, StrongType::Compatible< int32_t >, StrongType::Compatible< int64_t > > TileIndex
The index/ID of a Tile.
Definition tile_type.h:92
Definition of Interval and OneShot timers.
Definition of the game-economy-timer.
Definition of the tick-based game-timer.
Definition of the Window system.
Base of the town class.
Town * ClosestTownFromTile(TileIndex tile, uint threshold)
Return the town closest (in distance or ownership) to a given tile, within a given threshold.
Base class for all vehicles.
Functions related to vehicles.
VehicleType
Available vehicle types.
@ VEH_ROAD
Road vehicle type.
@ VEH_AIRCRAFT
Aircraft vehicle type.
@ VEH_SHIP
Ship vehicle type.
@ VEH_TRAIN
Train vehicle type.
void CloseConstructionWindows()
Close all windows that are used for construction of vehicle etc.
Definition window.cpp:3394
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:1196
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:3307
Window * FindWindowById(WindowClass cls, WindowNumber number)
Find a window by its class and window number.
Definition window.cpp:1153
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:3201
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting).
Definition window.cpp:3185
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:3325
Window functions not directly related to making/drawing windows.
@ WN_NETWORK_STATUS_WINDOW_JOIN
Network join status.
Definition window_type.h:44
@ WC_PERFORMANCE_HISTORY
Performance history graph; Window numbers:
@ WC_COMPANY_LEAGUE
Company league window; Window numbers:
@ WC_SIGN_LIST
Sign list; Window numbers:
@ WC_PERFORMANCE_DETAIL
Performance detail window; Window numbers:
@ WC_COMPANY_COLOUR
Company colour selection; Window numbers:
@ WC_GRAPH_LEGEND
Legend for graphs; Window numbers:
@ WC_LINKGRAPH_LEGEND
Linkgraph legend; Window numbers:
@ WC_STATUS_BAR
Statusbar (at the bottom of your screen); Window numbers:
Definition window_type.h:69
@ WC_SEND_NETWORK_MSG
Chatbox; Window numbers:
@ WC_ERRMSG
Error message; Window numbers:
@ WC_SCRIPT_SETTINGS
Script settings; Window numbers:
@ WC_SCRIPT_LIST
Scripts list; Window numbers:
@ WC_GOALS_LIST
Goals list; Window numbers:
@ WC_OPERATING_PROFIT
Operating profit graph; Window numbers:
@ WC_CLIENT_LIST
Client list; Window numbers:
@ WC_GAME_OPTIONS
Game options window; Window numbers:
@ WC_FINANCES
Finances of a company; Window numbers:
@ WC_INCOME_GRAPH
Income graph; Window numbers:
@ WC_SMALLMAP
Small map; Window numbers:
@ WC_DELIVERED_CARGO
Delivered cargo graph; Window numbers:
@ WC_COMPANY_VALUE
Company value graph; Window numbers:
@ WC_MAIN_TOOLBAR
Main toolbar (the long bar at the top); Window numbers:
Definition window_type.h:63
@ WC_COMPANY
Company view; Window numbers:
@ WC_NETWORK_STATUS_WINDOW
Network status window; Window numbers:
@ WC_VEHICLE_VIEW
Vehicle view; Window numbers: