Merge remote-tracking branch 'upstream/master' into 13.0

This commit is contained in:
Pavel Stupnikov
2022-11-26 22:16:25 +04:00
508 changed files with 14617 additions and 9750 deletions
+77 -64
View File
@@ -14,7 +14,6 @@
#include "core/backup_type.hpp"
#include "town.h"
#include "news_func.h"
#include "cmd_helper.h"
#include "command_func.h"
#include "network/network.h"
#include "network/network_func.h"
@@ -36,6 +35,7 @@
#include "goal_base.h"
#include "story_base.h"
#include "widgets/statusbar_widget.h"
#include "company_cmd.h"
#include "table/strings.h"
#include "cargo_type.h"
@@ -67,11 +67,12 @@ Company::Company(uint16 name_1, bool is_ai)
this->name_1 = name_1;
this->location_of_HQ = INVALID_TILE;
this->is_ai = is_ai;
this->terraform_limit = (uint32)_settings_game.construction.terraform_frame_burst << 16;
this->clear_limit = (uint32)_settings_game.construction.clear_frame_burst << 16;
this->tree_limit = (uint32)_settings_game.construction.tree_frame_burst << 16;
this->terraform_limit = (uint32)_settings_game.construction.terraform_frame_burst << 16;
this->clear_limit = (uint32)_settings_game.construction.clear_frame_burst << 16;
this->tree_limit = (uint32)_settings_game.construction.tree_frame_burst << 16;
this->build_object_limit = (uint32)_settings_game.construction.build_object_frame_burst << 16;
for (uint j = 0; j < 4; j++) this->share_owners[j] = INVALID_OWNER;
std::fill(this->share_owners.begin(), this->share_owners.end(), INVALID_OWNER);
InvalidateWindowData(WC_PERFORMANCE_DETAIL, 0, INVALID_COMPANY);
InvalidateWindowClassesData(WC_WATCH_COMPANY, 0);
InvalidateWindowClassesData(WC_WATCH_COMPANYA, 1);
@@ -228,17 +229,17 @@ static void SubtractMoneyFromAnyCompany(Company *c, const CommandCost &cost)
c->money -= cost.GetCost();
c->yearly_expenses[0][cost.GetExpensesType()] += cost.GetCost();
if (HasBit(1 << EXPENSES_TRAIN_INC |
1 << EXPENSES_ROADVEH_INC |
1 << EXPENSES_AIRCRAFT_INC |
1 << EXPENSES_SHIP_INC, cost.GetExpensesType())) {
if (HasBit(1 << EXPENSES_TRAIN_REVENUE |
1 << EXPENSES_ROADVEH_REVENUE |
1 << EXPENSES_AIRCRAFT_REVENUE |
1 << EXPENSES_SHIP_REVENUE, cost.GetExpensesType())) {
c->cur_economy.income -= cost.GetCost();
} else if (HasBit(1 << EXPENSES_TRAIN_RUN |
1 << EXPENSES_ROADVEH_RUN |
1 << EXPENSES_AIRCRAFT_RUN |
1 << EXPENSES_SHIP_RUN |
1 << EXPENSES_PROPERTY |
1 << EXPENSES_LOAN_INT, cost.GetExpensesType())) {
1 << EXPENSES_LOAN_INTEREST, cost.GetExpensesType())) {
c->cur_economy.expenses -= cost.GetCost();
}
@@ -276,9 +277,10 @@ void SubtractMoneyFromCompanyFract(CompanyID company, const CommandCost &cst)
void UpdateLandscapingLimits()
{
for (Company *c : Company::Iterate()) {
c->terraform_limit = std::min<uint64>((uint64)c->terraform_limit + _settings_game.construction.terraform_per_64k_frames, (uint64)_settings_game.construction.terraform_frame_burst << 16);
c->clear_limit = std::min<uint64>((uint64)c->clear_limit + _settings_game.construction.clear_per_64k_frames, (uint64)_settings_game.construction.clear_frame_burst << 16);
c->tree_limit = std::min<uint64>((uint64)c->tree_limit + _settings_game.construction.tree_per_64k_frames, (uint64)_settings_game.construction.tree_frame_burst << 16);
c->terraform_limit = std::min<uint64>((uint64)c->terraform_limit + _settings_game.construction.terraform_per_64k_frames, (uint64)_settings_game.construction.terraform_frame_burst << 16);
c->clear_limit = std::min<uint64>((uint64)c->clear_limit + _settings_game.construction.clear_per_64k_frames, (uint64)_settings_game.construction.clear_frame_burst << 16);
c->tree_limit = std::min<uint64>((uint64)c->tree_limit + _settings_game.construction.tree_per_64k_frames, (uint64)_settings_game.construction.tree_frame_burst << 16);
c->build_object_limit = std::min<uint64>((uint64)c->build_object_limit + _settings_game.construction.build_object_per_64k_frames, (uint64)_settings_game.construction.build_object_frame_burst << 16);
}
}
@@ -566,12 +568,19 @@ Company *DoStartupNewCompany(bool is_ai, CompanyID company = INVALID_COMPANY)
c->money = c->current_loan = (std::min<int64>(INITIAL_LOAN, _economy.max_loan) * _economy.inflation_prices >> 16) / 50000 * 50000;
c->share_owners[0] = c->share_owners[1] = c->share_owners[2] = c->share_owners[3] = INVALID_OWNER;
std::fill(c->share_owners.begin(), c->share_owners.end(), INVALID_OWNER);
c->avail_railtypes = GetCompanyRailtypes(c->index);
c->avail_roadtypes = GetCompanyRoadTypes(c->index);
c->inaugurated_year = _cur_year;
RandomCompanyManagerFaceBits(c->face, (GenderEthnicity)Random(), false, false); // create a random company manager face
/* If starting a player company in singleplayer and a favorite company manager face is selected, choose it. Otherwise, use a random face.
* In a network game, we'll choose the favorite face later in CmdCompanyCtrl to sync it to all clients, but we choose it here for the first (host) company. */
if (_company_manager_face != 0 && !is_ai) {
c->face = _company_manager_face;
} else {
RandomCompanyManagerFaceBits(c->face, (GenderEthnicity)Random(), false, false);
}
SetDefaultCompanySettings(c->index);
ClearEnginesHiddenFlagOfCompany(c->index);
@@ -612,7 +621,7 @@ static bool MaybeStartNewCompany()
if (n < (uint)_settings_game.difficulty.max_no_competitors) {
/* Send a command to all clients to start up a new AI.
* Works fine for Multiplayer and Singleplayer */
return DoCommandP(0, CCA_NEW_AI | INVALID_COMPANY << 16, 0, CMD_COMPANY_CTRL);
return Command<CMD_COMPANY_CTRL>::Post(CCA_NEW_AI, INVALID_COMPANY, CRR_NONE, INVALID_CLIENT_ID );
}
return false;
@@ -803,22 +812,17 @@ void CompanyAdminRemove(CompanyID company_id, CompanyRemoveReason reason)
/**
* Control the companies: add, delete, etc.
* @param tile unused
* @param flags operation to perform
* @param p1 various functionality
* - bits 0..15: CompanyCtrlAction
* - bits 16..23: CompanyID
* - bits 24..31: CompanyRemoveReason (with CCA_DELETE)
* @param p2 ClientID
* @param text unused
* @param cca action to perform
* @param company_id company to perform the action on
* @param client_id ClientID
* @return the cost of this operation or an error
*/
CommandCost CmdCompanyCtrl(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const std::string &text)
CommandCost CmdCompanyCtrl(DoCommandFlag flags, CompanyCtrlAction cca, CompanyID company_id, CompanyRemoveReason reason, ClientID client_id)
{
InvalidateWindowData(WC_COMPANY_LEAGUE, 0, 0);
CompanyID company_id = (CompanyID)GB(p1, 16, 8);
switch ((CompanyCtrlAction)GB(p1, 0, 16)) {
switch (cca) {
case CCA_NEW: { // Create a new company
/* This command is only executed in a multiplayer game */
if (!_networking && !citymania::IsReplayingCommands()) return CMD_ERROR;
@@ -826,7 +830,6 @@ CommandCost CmdCompanyCtrl(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
/* Has the network client a correct ClientIndex? */
if (!(flags & DC_EXEC)) return CommandCost();
ClientID client_id = (ClientID)p2;
NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id);
/* Delete multiplayer progress bar */
@@ -853,6 +856,10 @@ CommandCost CmdCompanyCtrl(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
NetworkChangeCompanyPassword(_local_company, _settings_client.network.default_company_pass);
}
/* In network games, we need to try setting the company manager face here to sync it to all clients.
* If a favorite company manager face is selected, choose it. Otherwise, use a random face. */
if (_company_manager_face != 0) Command<CMD_SET_COMPANY_MANAGER_FACE>::SendNet(STR_NULL, c->index, _company_manager_face);
/* Now that we have a new company, broadcast our company settings to
* all clients so everything is in sync */
SyncCompanySettings();
@@ -882,7 +889,6 @@ CommandCost CmdCompanyCtrl(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
}
case CCA_DELETE: { // Delete a company
CompanyRemoveReason reason = (CompanyRemoveReason)GB(p1, 24, 8);
if (reason >= CRR_END) return CMD_ERROR;
/* We can't delete the last existing company in singleplayer mode. */
@@ -931,17 +937,12 @@ CommandCost CmdCompanyCtrl(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
/**
* Change the company manager's face.
* @param tile unused
* @param flags operation to perform
* @param p1 unused
* @param p2 face bitmasked
* @param text unused
* @param cmf face bitmasked
* @return the cost of this operation or an error
*/
CommandCost CmdSetCompanyManagerFace(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const std::string &text)
CommandCost CmdSetCompanyManagerFace(DoCommandFlag flags, CompanyManagerFace cmf)
{
CompanyManagerFace cmf = (CompanyManagerFace)p2;
if (!IsValidCompanyManagerFace(cmf)) return CMD_ERROR;
if (flags & DC_EXEC) {
@@ -953,21 +954,14 @@ CommandCost CmdSetCompanyManagerFace(TileIndex tile, DoCommandFlag flags, uint32
/**
* Change the company's company-colour
* @param tile unused
* @param flags operation to perform
* @param p1 bitstuffed:
* p1 bits 0-7 scheme to set
* p1 bit 8 set first/second colour
* @param p2 new colour for vehicles, property, etc.
* @param text unused
* @param scheme scheme to set
* @param primary set first/second colour
* @param colour new colour for vehicles, property, etc.
* @return the cost of this operation or an error
*/
CommandCost CmdSetCompanyColour(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const std::string &text)
CommandCost CmdSetCompanyColour(DoCommandFlag flags, LiveryScheme scheme, bool primary, Colours colour)
{
Colours colour = Extract<Colours, 0, 8>(p2);
LiveryScheme scheme = Extract<LiveryScheme, 0, 8>(p1);
bool second = HasBit(p1, 8);
if (scheme >= LS_END || (colour >= COLOUR_END && colour != INVALID_COLOUR)) return CMD_ERROR;
/* Default scheme can't be reset to invalid. */
@@ -976,14 +970,14 @@ CommandCost CmdSetCompanyColour(TileIndex tile, DoCommandFlag flags, uint32 p1,
Company *c = Company::Get(_current_company);
/* Ensure no two companies have the same primary colour */
if (scheme == LS_DEFAULT && !second) {
if (scheme == LS_DEFAULT && primary) {
for (const Company *cc : Company::Iterate()) {
if (cc != c && cc->colour == colour) return CMD_ERROR;
}
}
if (flags & DC_EXEC) {
if (!second) {
if (primary) {
if (scheme != LS_DEFAULT) SB(c->livery[scheme].in_use, 0, 1, colour != INVALID_COLOUR);
if (colour == INVALID_COLOUR) colour = (Colours)c->livery[LS_DEFAULT].colour1;
c->livery[scheme].colour1 = colour;
@@ -1066,14 +1060,11 @@ static bool IsUniqueCompanyName(const std::string &name)
/**
* Change the name of the company.
* @param tile unused
* @param flags operation to perform
* @param p1 unused
* @param p2 unused
* @param text the new name or an empty string when resetting to the default
* @return the cost of this operation or an error
*/
CommandCost CmdRenameCompany(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const std::string &text)
CommandCost CmdRenameCompany(DoCommandFlag flags, const std::string &text)
{
bool reset = text.empty();
@@ -1113,14 +1104,11 @@ static bool IsUniquePresidentName(const std::string &name)
/**
* Change the name of the president.
* @param tile unused
* @param flags operation to perform
* @param p1 unused
* @param p2 unused
* @param text the new name or an empty string when resetting to the default
* @return the cost of this operation or an error
*/
CommandCost CmdRenamePresident(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const std::string &text)
CommandCost CmdRenamePresident(DoCommandFlag flags, const std::string &text)
{
bool reset = text.empty();
@@ -1138,7 +1126,7 @@ CommandCost CmdRenamePresident(TileIndex tile, DoCommandFlag flags, uint32 p1, u
c->president_name = text;
if (c->name_1 == STR_SV_UNNAMED && c->name.empty()) {
DoCommand(0, 0, 0, DC_EXEC, CMD_RENAME_COMPANY, text + " Transport");
Command<CMD_RENAME_COMPANY>::Do(DC_EXEC, text + " Transport");
}
}
@@ -1198,20 +1186,17 @@ uint32 CompanyInfrastructure::GetTramTotal() const
* To prevent abuse in multiplayer games you can only send money to other
* companies if you have paid off your loan (either explicitly, or implicitly
* given the fact that you have more money than loan).
* @param tile unused
* @param flags operation to perform
* @param p1 the amount of money to transfer; max 20.000.000
* @param p2 the company to transfer the money to
* @param text unused
* @param money the amount of money to transfer; max 20.000.000
* @param dest_company the company to transfer the money to
* @return the cost of this operation or an error
*/
CommandCost CmdGiveMoney(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const std::string &text)
CommandCost CmdGiveMoney(DoCommandFlag flags, uint32 money, CompanyID dest_company)
{
if (!_settings_game.economy.give_money) return CMD_ERROR;
const Company *c = Company::Get(_current_company);
CommandCost amount(EXPENSES_OTHER, std::min<Money>(p1, 20000000LL));
CompanyID dest_company = (CompanyID)p2;
CommandCost amount(EXPENSES_OTHER, std::min<Money>(money, 20000000LL));
/* You can only transfer funds that is in excess of your loan */
if (c->money - c->current_loan < amount.GetCost() || amount.GetCost() < 0) return_cmd_error(STR_ERROR_INSUFFICIENT_FUNDS);
@@ -1237,3 +1222,31 @@ CommandCost CmdGiveMoney(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
/* Subtract money from local-company */
return amount;
}
/**
* Get the index of the first available company. It attempts,
* from first to last, and as soon as the attempt succeeds,
* to get the index of the company:
* 1st - get the first existing human company.
* 2nd - get the first non-existing company.
* 3rd - get COMPANY_FIRST.
* @return the index of the first available company.
*/
CompanyID GetFirstPlayableCompanyID()
{
for (Company *c : Company::Iterate()) {
if (Company::IsHumanID(c->index)) {
return c->index;
}
}
if (Company::CanAllocateItem()) {
for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
if (!Company::IsValidID(c)) {
return c;
}
}
}
return COMPANY_FIRST;
}