2009-08-21 20:21:05 +00:00
|
|
|
/*
|
|
|
|
* This file is part of OpenTTD.
|
|
|
|
* 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.
|
|
|
|
* 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.
|
|
|
|
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2008-09-30 20:39:50 +00:00
|
|
|
/** @file company_cmd.cpp Handling of companies. */
|
2008-05-06 15:11:33 +00:00
|
|
|
|
2004-08-09 17:04:08 +00:00
|
|
|
#include "stdafx.h"
|
2010-08-01 14:43:39 +00:00
|
|
|
#include "company_base.h"
|
2008-09-30 20:51:04 +00:00
|
|
|
#include "company_func.h"
|
|
|
|
#include "company_gui.h"
|
2021-01-05 17:06:48 +00:00
|
|
|
#include "core/backup_type.hpp"
|
2004-08-09 17:04:08 +00:00
|
|
|
#include "town.h"
|
2008-03-28 08:53:36 +00:00
|
|
|
#include "news_func.h"
|
2010-04-17 13:31:41 +00:00
|
|
|
#include "cmd_helper.h"
|
2007-12-21 21:50:46 +00:00
|
|
|
#include "command_func.h"
|
2012-01-03 21:47:01 +00:00
|
|
|
#include "network/network.h"
|
|
|
|
#include "network/network_func.h"
|
2008-12-23 11:06:52 +00:00
|
|
|
#include "network/network_base.h"
|
2010-10-17 17:37:45 +00:00
|
|
|
#include "network/network_admin.h"
|
2009-01-12 17:11:45 +00:00
|
|
|
#include "ai/ai.hpp"
|
2008-09-30 20:51:04 +00:00
|
|
|
#include "company_manager_face.h"
|
2007-12-19 19:44:29 +00:00
|
|
|
#include "window_func.h"
|
2007-12-21 19:49:27 +00:00
|
|
|
#include "strings_func.h"
|
2007-12-26 13:50:40 +00:00
|
|
|
#include "date_func.h"
|
2007-12-29 09:24:26 +00:00
|
|
|
#include "sound_func.h"
|
2008-01-09 21:05:03 +00:00
|
|
|
#include "rail.h"
|
2009-05-22 15:13:50 +00:00
|
|
|
#include "core/pool_func.hpp"
|
2009-05-26 13:29:01 +00:00
|
|
|
#include "settings_func.h"
|
2010-01-05 17:11:56 +00:00
|
|
|
#include "vehicle_base.h"
|
|
|
|
#include "vehicle_func.h"
|
2011-01-04 20:57:11 +00:00
|
|
|
#include "smallmap_gui.h"
|
2011-12-19 20:59:36 +00:00
|
|
|
#include "game/game.hpp"
|
2013-09-13 12:45:25 +00:00
|
|
|
#include "goal_base.h"
|
|
|
|
#include "story_base.h"
|
2021-02-18 11:29:30 +00:00
|
|
|
#include "widgets/statusbar_widget.h"
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2012-01-03 21:47:01 +00:00
|
|
|
#include "table/strings.h"
|
2008-01-13 01:21:35 +00:00
|
|
|
|
2014-04-23 20:13:33 +00:00
|
|
|
#include "safeguards.h"
|
|
|
|
|
2014-09-07 16:12:58 +00:00
|
|
|
void ClearEnginesHiddenFlagOfCompany(CompanyID cid);
|
|
|
|
|
2019-04-22 08:10:04 +00:00
|
|
|
CompanyID _local_company; ///< Company controlled by the human player at this client. Can also be #COMPANY_SPECTATOR.
|
|
|
|
CompanyID _current_company; ///< Company currently doing an action.
|
2010-08-01 17:45:53 +00:00
|
|
|
Colours _company_colours[MAX_COMPANIES]; ///< NOSAVE: can be determined from company structs.
|
2008-09-30 20:39:50 +00:00
|
|
|
CompanyManagerFace _company_manager_face; ///< for company manager face storage in openttd.cfg
|
2009-02-25 21:45:14 +00:00
|
|
|
uint _next_competitor_start; ///< the number of ticks before the next AI is started
|
|
|
|
uint _cur_company_tick_index; ///< used to generate a name for one company that doesn't have a name yet per tick
|
2008-01-12 14:10:35 +00:00
|
|
|
|
2010-08-01 17:45:53 +00:00
|
|
|
CompanyPool _company_pool("Company"); ///< Pool of companies.
|
2009-05-22 15:13:50 +00:00
|
|
|
INSTANTIATE_POOL_METHODS(Company)
|
2008-07-18 16:40:29 +00:00
|
|
|
|
2010-08-02 20:32:39 +00:00
|
|
|
/**
|
|
|
|
* Constructor.
|
|
|
|
* @param name_1 Name of the company.
|
|
|
|
* @param is_ai A computer program is running for this company.
|
|
|
|
*/
|
2010-06-13 14:15:11 +00:00
|
|
|
Company::Company(uint16 name_1, bool is_ai)
|
2008-07-18 16:40:29 +00:00
|
|
|
{
|
2010-06-13 14:15:11 +00:00
|
|
|
this->name_1 = name_1;
|
|
|
|
this->location_of_HQ = INVALID_TILE;
|
|
|
|
this->is_ai = is_ai;
|
2021-03-01 14:15:50 +00:00
|
|
|
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;
|
2011-01-04 22:50:09 +00:00
|
|
|
|
2008-09-30 20:39:50 +00:00
|
|
|
for (uint j = 0; j < 4; j++) this->share_owners[j] = COMPANY_SPECTATOR;
|
2009-09-03 11:56:29 +00:00
|
|
|
InvalidateWindowData(WC_PERFORMANCE_DETAIL, 0, INVALID_COMPANY);
|
2008-07-18 16:40:29 +00:00
|
|
|
}
|
|
|
|
|
2010-08-02 20:32:39 +00:00
|
|
|
/** Destructor. */
|
2008-09-30 20:39:50 +00:00
|
|
|
Company::~Company()
|
2008-07-18 16:40:29 +00:00
|
|
|
{
|
|
|
|
if (CleaningPool()) return;
|
|
|
|
|
2008-09-30 20:39:50 +00:00
|
|
|
DeleteCompanyWindows(this->index);
|
2009-09-08 12:27:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Invalidating some stuff after removing item from the pool.
|
|
|
|
* @param index index of deleted item
|
|
|
|
*/
|
|
|
|
void Company::PostDestructor(size_t index)
|
|
|
|
{
|
2009-09-09 12:41:51 +00:00
|
|
|
InvalidateWindowData(WC_GRAPH_LEGEND, 0, (int)index);
|
|
|
|
InvalidateWindowData(WC_PERFORMANCE_DETAIL, 0, (int)index);
|
2009-11-15 23:22:07 +00:00
|
|
|
InvalidateWindowData(WC_COMPANY_LEAGUE, 0, 0);
|
2013-05-19 14:43:23 +00:00
|
|
|
InvalidateWindowData(WC_LINKGRAPH_LEGEND, 0);
|
2010-07-31 21:02:56 +00:00
|
|
|
/* If the currently shown error message has this company in it, then close it. */
|
2010-03-06 16:26:09 +00:00
|
|
|
InvalidateWindowData(WC_ERRMSG, 0);
|
2008-07-18 16:40:29 +00:00
|
|
|
}
|
|
|
|
|
2006-12-26 12:56:48 +00:00
|
|
|
/**
|
2009-02-08 12:25:13 +00:00
|
|
|
* Sets the local company and updates the settings that are set on a
|
2008-09-30 20:39:50 +00:00
|
|
|
* per-company basis to reflect the core's state in the GUI.
|
|
|
|
* @param new_company the new company
|
2009-05-17 01:00:56 +00:00
|
|
|
* @pre Company::IsValidID(new_company) || new_company == COMPANY_SPECTATOR || new_company == OWNER_NONE
|
2006-12-26 12:56:48 +00:00
|
|
|
*/
|
2008-09-30 20:39:50 +00:00
|
|
|
void SetLocalCompany(CompanyID new_company)
|
2006-12-26 12:56:48 +00:00
|
|
|
{
|
2008-09-30 20:39:50 +00:00
|
|
|
/* company could also be COMPANY_SPECTATOR or OWNER_NONE */
|
2009-05-17 01:00:56 +00:00
|
|
|
assert(Company::IsValidID(new_company) || new_company == COMPANY_SPECTATOR || new_company == OWNER_NONE);
|
2006-12-26 12:56:48 +00:00
|
|
|
|
2019-09-08 08:26:09 +00:00
|
|
|
/* If actually changing to another company, several windows need closing */
|
|
|
|
bool switching_company = _local_company != new_company;
|
|
|
|
|
2009-10-07 17:36:33 +00:00
|
|
|
/* Delete the chat window, if you were team chatting. */
|
2019-09-08 08:26:09 +00:00
|
|
|
if (switching_company) InvalidateWindowData(WC_SEND_NETWORK_MSG, DESTTYPE_TEAM, _local_company);
|
2009-10-07 17:36:33 +00:00
|
|
|
|
2010-07-31 21:43:07 +00:00
|
|
|
assert(IsLocalCompany());
|
2010-06-05 13:32:42 +00:00
|
|
|
|
|
|
|
_current_company = _local_company = new_company;
|
2006-12-26 12:56:48 +00:00
|
|
|
|
2009-02-04 16:59:41 +00:00
|
|
|
/* Delete any construction windows... */
|
2019-09-08 08:26:09 +00:00
|
|
|
if (switching_company) DeleteConstructionWindows();
|
2009-02-04 16:59:41 +00:00
|
|
|
|
|
|
|
/* ... and redraw the whole screen. */
|
|
|
|
MarkWholeScreenDirty();
|
2012-01-03 10:27:14 +00:00
|
|
|
InvalidateWindowClassesData(WC_SIGN_LIST, -1);
|
2021-02-20 23:32:45 +00:00
|
|
|
InvalidateWindowClassesData(WC_GOALS_LIST);
|
2006-12-26 12:56:48 +00:00
|
|
|
}
|
|
|
|
|
2010-08-01 17:45:53 +00:00
|
|
|
/**
|
|
|
|
* Get the colour for DrawString-subroutines which matches the colour of the company.
|
|
|
|
* @param company Company to get the colour of.
|
|
|
|
* @return Colour of \a company.
|
|
|
|
*/
|
2011-01-03 11:55:08 +00:00
|
|
|
TextColour GetDrawStringCompanyColour(CompanyID company)
|
2006-08-28 06:21:48 +00:00
|
|
|
{
|
2011-01-03 11:55:08 +00:00
|
|
|
if (!Company::IsValidID(company)) return (TextColour)_colour_gradient[COLOUR_WHITE][4] | TC_IS_PALETTE_COLOUR;
|
|
|
|
return (TextColour)_colour_gradient[_company_colours[company]][4] | TC_IS_PALETTE_COLOUR;
|
2006-08-28 06:21:48 +00:00
|
|
|
}
|
|
|
|
|
2010-08-01 17:45:53 +00:00
|
|
|
/**
|
|
|
|
* Draw the icon of a company.
|
|
|
|
* @param c Company that needs its icon drawn.
|
|
|
|
* @param x Horizontal coordinate of the icon.
|
|
|
|
* @param y Vertical coordinate of the icon.
|
|
|
|
*/
|
2008-10-07 20:57:41 +00:00
|
|
|
void DrawCompanyIcon(CompanyID c, int x, int y)
|
2007-01-21 11:49:18 +00:00
|
|
|
{
|
2009-11-02 16:07:09 +00:00
|
|
|
DrawSprite(SPR_COMPANY_ICON, COMPANY_SPRITE_COLOUR(c), x, y);
|
2007-01-21 11:49:18 +00:00
|
|
|
}
|
|
|
|
|
2007-03-02 01:17:11 +00:00
|
|
|
/**
|
2008-09-30 20:39:50 +00:00
|
|
|
* Checks whether a company manager's face is a valid encoding.
|
2007-03-02 01:17:11 +00:00
|
|
|
* Unused bits are not enforced to be 0.
|
2008-09-30 20:39:50 +00:00
|
|
|
* @param cmf the fact to check
|
2007-03-02 01:17:11 +00:00
|
|
|
* @return true if and only if the face is valid
|
|
|
|
*/
|
2010-08-29 15:58:43 +00:00
|
|
|
static bool IsValidCompanyManagerFace(CompanyManagerFace cmf)
|
2007-03-02 01:17:11 +00:00
|
|
|
{
|
2008-09-30 20:39:50 +00:00
|
|
|
if (!AreCompanyManagerFaceBitsValid(cmf, CMFV_GEN_ETHN, GE_WM)) return false;
|
|
|
|
|
|
|
|
GenderEthnicity ge = (GenderEthnicity)GetCompanyManagerFaceBits(cmf, CMFV_GEN_ETHN, GE_WM);
|
|
|
|
bool has_moustache = !HasBit(ge, GENDER_FEMALE) && GetCompanyManagerFaceBits(cmf, CMFV_HAS_MOUSTACHE, ge) != 0;
|
|
|
|
bool has_tie_earring = !HasBit(ge, GENDER_FEMALE) || GetCompanyManagerFaceBits(cmf, CMFV_HAS_TIE_EARRING, ge) != 0;
|
|
|
|
bool has_glasses = GetCompanyManagerFaceBits(cmf, CMFV_HAS_GLASSES, ge) != 0;
|
|
|
|
|
|
|
|
if (!AreCompanyManagerFaceBitsValid(cmf, CMFV_EYE_COLOUR, ge)) return false;
|
|
|
|
for (CompanyManagerFaceVariable cmfv = CMFV_CHEEKS; cmfv < CMFV_END; cmfv++) {
|
|
|
|
switch (cmfv) {
|
|
|
|
case CMFV_MOUSTACHE: if (!has_moustache) continue; break;
|
2017-08-13 18:38:42 +00:00
|
|
|
case CMFV_LIPS:
|
2008-09-30 20:39:50 +00:00
|
|
|
case CMFV_NOSE: if (has_moustache) continue; break;
|
|
|
|
case CMFV_TIE_EARRING: if (!has_tie_earring) continue; break;
|
|
|
|
case CMFV_GLASSES: if (!has_glasses) continue; break;
|
2007-03-02 01:17:11 +00:00
|
|
|
default: break;
|
|
|
|
}
|
2008-09-30 20:39:50 +00:00
|
|
|
if (!AreCompanyManagerFaceBitsValid(cmf, cmfv, ge)) return false;
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
2007-02-24 14:53:32 +00:00
|
|
|
|
2007-03-02 01:17:11 +00:00
|
|
|
return true;
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
|
2010-08-01 17:45:53 +00:00
|
|
|
/**
|
|
|
|
* Refresh all windows owned by a company.
|
|
|
|
* @param company Company that changed, and needs its windows refreshed.
|
|
|
|
*/
|
2008-09-30 20:39:50 +00:00
|
|
|
void InvalidateCompanyWindows(const Company *company)
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
2008-09-30 20:39:50 +00:00
|
|
|
CompanyID cid = company->index;
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2021-02-18 11:29:30 +00:00
|
|
|
if (cid == _local_company) SetWindowWidgetDirty(WC_STATUS_BAR, 0, WID_S_RIGHT);
|
2009-09-13 19:15:59 +00:00
|
|
|
SetWindowDirty(WC_FINANCES, cid);
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
|
2010-03-14 12:39:24 +00:00
|
|
|
/**
|
|
|
|
* Verify whether the company can pay the bill.
|
2018-10-28 02:17:36 +00:00
|
|
|
* @param[in,out] cost Money to pay, is changed to an error if the company does not have enough money.
|
2010-03-14 12:39:24 +00:00
|
|
|
* @return Function returns \c true if the company has enough money, else it returns \c false.
|
|
|
|
*/
|
2010-01-11 20:21:56 +00:00
|
|
|
bool CheckCompanyHasMoney(CommandCost &cost)
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
2007-06-18 19:53:50 +00:00
|
|
|
if (cost.GetCost() > 0) {
|
2009-05-18 16:21:28 +00:00
|
|
|
const Company *c = Company::GetIfValid(_current_company);
|
2019-04-10 21:07:06 +00:00
|
|
|
if (c != nullptr && cost.GetCost() > c->money) {
|
2007-06-21 17:25:17 +00:00
|
|
|
SetDParam(0, cost.GetCost());
|
2010-01-11 20:21:56 +00:00
|
|
|
cost.MakeError(STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY);
|
2004-08-09 17:04:08 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-08-01 17:45:53 +00:00
|
|
|
/**
|
|
|
|
* Deduct costs of a command from the money of a company.
|
|
|
|
* @param c Company to pay the bill.
|
|
|
|
* @param cost Money to pay.
|
|
|
|
*/
|
2020-02-17 01:57:22 +00:00
|
|
|
static void SubtractMoneyFromAnyCompany(Company *c, const CommandCost &cost)
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
2008-01-09 16:55:48 +00:00
|
|
|
if (cost.GetCost() == 0) return;
|
|
|
|
assert(cost.GetExpensesType() != INVALID_EXPENSES);
|
2004-09-11 09:55:19 +00:00
|
|
|
|
2008-09-30 20:39:50 +00:00
|
|
|
c->money -= cost.GetCost();
|
|
|
|
c->yearly_expenses[0][cost.GetExpensesType()] += cost.GetCost();
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2007-11-19 21:02:30 +00:00
|
|
|
if (HasBit(1 << EXPENSES_TRAIN_INC |
|
2007-06-10 09:37:09 +00:00
|
|
|
1 << EXPENSES_ROADVEH_INC |
|
|
|
|
1 << EXPENSES_AIRCRAFT_INC |
|
2008-01-09 16:55:48 +00:00
|
|
|
1 << EXPENSES_SHIP_INC, cost.GetExpensesType())) {
|
2008-09-30 20:39:50 +00:00
|
|
|
c->cur_economy.income -= cost.GetCost();
|
2007-11-19 21:02:30 +00:00
|
|
|
} else if (HasBit(1 << EXPENSES_TRAIN_RUN |
|
2007-06-10 09:37:09 +00:00
|
|
|
1 << EXPENSES_ROADVEH_RUN |
|
|
|
|
1 << EXPENSES_AIRCRAFT_RUN |
|
|
|
|
1 << EXPENSES_SHIP_RUN |
|
|
|
|
1 << EXPENSES_PROPERTY |
|
2008-01-09 16:55:48 +00:00
|
|
|
1 << EXPENSES_LOAN_INT, cost.GetExpensesType())) {
|
2008-09-30 20:39:50 +00:00
|
|
|
c->cur_economy.expenses -= cost.GetCost();
|
2006-06-27 21:25:53 +00:00
|
|
|
}
|
2004-09-11 09:55:19 +00:00
|
|
|
|
2008-09-30 20:39:50 +00:00
|
|
|
InvalidateCompanyWindows(c);
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
|
2010-08-01 17:45:53 +00:00
|
|
|
/**
|
|
|
|
* Subtract money from the #_current_company, if the company is valid.
|
|
|
|
* @param cost Money to pay.
|
|
|
|
*/
|
2020-02-17 01:57:22 +00:00
|
|
|
void SubtractMoneyFromCompany(const CommandCost &cost)
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
2009-05-18 16:21:28 +00:00
|
|
|
Company *c = Company::GetIfValid(_current_company);
|
2019-04-10 21:07:06 +00:00
|
|
|
if (c != nullptr) SubtractMoneyFromAnyCompany(c, cost);
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
|
2010-08-01 17:45:53 +00:00
|
|
|
/**
|
|
|
|
* Subtract money from a company, including the money fraction.
|
|
|
|
* @param company Company paying the bill.
|
|
|
|
* @param cst Cost of a command.
|
|
|
|
*/
|
2020-02-17 01:57:22 +00:00
|
|
|
void SubtractMoneyFromCompanyFract(CompanyID company, const CommandCost &cst)
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
2009-05-16 23:34:14 +00:00
|
|
|
Company *c = Company::Get(company);
|
2008-09-30 20:39:50 +00:00
|
|
|
byte m = c->money_fraction;
|
2007-06-18 21:44:47 +00:00
|
|
|
Money cost = cst.GetCost();
|
2006-06-27 21:25:53 +00:00
|
|
|
|
2008-09-30 20:39:50 +00:00
|
|
|
c->money_fraction = m - (byte)cost;
|
2004-08-09 17:04:08 +00:00
|
|
|
cost >>= 8;
|
2008-09-30 20:39:50 +00:00
|
|
|
if (c->money_fraction > m) cost++;
|
|
|
|
if (cost != 0) SubtractMoneyFromAnyCompany(c, CommandCost(cst.GetExpensesType(), cost));
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
|
2011-01-04 22:50:09 +00:00
|
|
|
/** Update the landscaping limits per company. */
|
|
|
|
void UpdateLandscapingLimits()
|
|
|
|
{
|
2019-12-14 16:22:38 +00:00
|
|
|
for (Company *c : Company::Iterate()) {
|
2021-03-01 14:16:26 +00:00
|
|
|
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);
|
2011-01-04 22:50:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-04 11:35:12 +00:00
|
|
|
/**
|
|
|
|
* Set the right DParams to get the name of an owner.
|
|
|
|
* @param owner the owner to get the name of.
|
|
|
|
* @param tile optional tile to get the right town.
|
|
|
|
* @pre if tile == 0, then owner can't be OWNER_TOWN.
|
|
|
|
*/
|
2006-10-14 22:22:48 +00:00
|
|
|
void GetNameOfOwner(Owner owner, TileIndex tile)
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
2004-12-02 22:53:07 +00:00
|
|
|
SetDParam(2, owner);
|
2004-09-11 09:55:19 +00:00
|
|
|
|
2004-08-09 17:04:08 +00:00
|
|
|
if (owner != OWNER_TOWN) {
|
2009-05-17 01:00:56 +00:00
|
|
|
if (!Company::IsValidID(owner)) {
|
2009-04-21 23:40:56 +00:00
|
|
|
SetDParam(0, STR_COMPANY_SOMEONE);
|
2006-06-27 21:25:53 +00:00
|
|
|
} else {
|
2007-06-25 13:30:38 +00:00
|
|
|
SetDParam(0, STR_COMPANY_NAME);
|
2008-09-30 20:39:50 +00:00
|
|
|
SetDParam(1, owner);
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
} else {
|
2010-01-04 11:35:12 +00:00
|
|
|
assert(tile != 0);
|
2008-10-14 18:38:51 +00:00
|
|
|
const Town *t = ClosestTownFromTile(tile, UINT_MAX);
|
2006-06-27 21:25:53 +00:00
|
|
|
|
2009-07-20 11:21:57 +00:00
|
|
|
SetDParam(0, STR_TOWN_NAME);
|
2005-07-15 18:30:13 +00:00
|
|
|
SetDParam(1, t->index);
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-01-04 11:35:12 +00:00
|
|
|
/**
|
|
|
|
* Check whether the current owner owns something.
|
|
|
|
* If that isn't the case an appropriate error will be given.
|
|
|
|
* @param owner the owner of the thing to check.
|
|
|
|
* @param tile optional tile to get the right town.
|
|
|
|
* @pre if tile == 0 then the owner can't be OWNER_TOWN.
|
2010-03-13 17:11:28 +00:00
|
|
|
* @return A succeeded command iff it's owned by the current company, else a failed command.
|
2010-01-04 11:35:12 +00:00
|
|
|
*/
|
2010-03-13 17:11:28 +00:00
|
|
|
CommandCost CheckOwnership(Owner owner, TileIndex tile)
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
2006-10-14 22:22:48 +00:00
|
|
|
assert(owner < OWNER_END);
|
2010-01-04 11:35:12 +00:00
|
|
|
assert(owner != OWNER_TOWN || tile != 0);
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2010-03-13 17:11:28 +00:00
|
|
|
if (owner == _current_company) return CommandCost();
|
|
|
|
|
2010-01-04 11:35:12 +00:00
|
|
|
GetNameOfOwner(owner, tile);
|
2010-03-13 17:11:28 +00:00
|
|
|
return_cmd_error(STR_ERROR_OWNED_BY);
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
|
2010-01-04 11:35:12 +00:00
|
|
|
/**
|
|
|
|
* Check whether the current owner owns the stuff on
|
|
|
|
* the given tile. If that isn't the case an
|
|
|
|
* appropriate error will be given.
|
|
|
|
* @param tile the tile to check.
|
2010-03-07 20:44:05 +00:00
|
|
|
* @return A succeeded command iff it's owned by the current company, else a failed command.
|
2010-01-04 11:35:12 +00:00
|
|
|
*/
|
2010-03-07 20:44:05 +00:00
|
|
|
CommandCost CheckTileOwnership(TileIndex tile)
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
2006-10-14 22:22:48 +00:00
|
|
|
Owner owner = GetTileOwner(tile);
|
2005-06-04 11:56:32 +00:00
|
|
|
|
2006-10-14 22:22:48 +00:00
|
|
|
assert(owner < OWNER_END);
|
2005-06-04 11:56:32 +00:00
|
|
|
|
2010-03-07 20:44:05 +00:00
|
|
|
if (owner == _current_company) return CommandCost();
|
2004-09-11 09:55:19 +00:00
|
|
|
|
2008-09-30 20:39:50 +00:00
|
|
|
/* no need to get the name of the owner unless we're the local company (saves some time) */
|
|
|
|
if (IsLocalCompany()) GetNameOfOwner(owner, tile);
|
2010-03-07 20:44:05 +00:00
|
|
|
return_cmd_error(STR_ERROR_OWNED_BY);
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
|
2010-08-01 17:45:53 +00:00
|
|
|
/**
|
|
|
|
* Generate the name of a company from the last build coordinate.
|
|
|
|
* @param c Company to give a name.
|
|
|
|
*/
|
2008-09-30 20:39:50 +00:00
|
|
|
static void GenerateCompanyName(Company *c)
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
2009-09-22 12:42:56 +00:00
|
|
|
/* Reserve space for extra unicode character. We need to do this to be able
|
|
|
|
* to detect too long company name. */
|
2010-12-05 22:24:50 +00:00
|
|
|
char buffer[(MAX_LENGTH_COMPANY_NAME_CHARS + 1) * MAX_CHAR_LENGTH];
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2008-09-30 20:39:50 +00:00
|
|
|
if (c->name_1 != STR_SV_UNNAMED) return;
|
2010-08-02 20:19:10 +00:00
|
|
|
if (c->last_build_coordinate == 0) return;
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2010-08-02 20:19:10 +00:00
|
|
|
Town *t = ClosestTownFromTile(c->last_build_coordinate, UINT_MAX);
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2010-08-02 20:19:10 +00:00
|
|
|
StringID str;
|
|
|
|
uint32 strp;
|
2020-05-17 21:31:59 +00:00
|
|
|
if (t->name.empty() && IsInsideMM(t->townnametype, SPECSTR_TOWNNAME_START, SPECSTR_TOWNNAME_LAST + 1)) {
|
2011-09-23 19:27:15 +00:00
|
|
|
str = t->townnametype - SPECSTR_TOWNNAME_START + SPECSTR_COMPANY_NAME_START;
|
2004-08-09 17:04:08 +00:00
|
|
|
strp = t->townnameparts;
|
|
|
|
|
|
|
|
verify_name:;
|
2008-09-30 20:39:50 +00:00
|
|
|
/* No companies must have this name already */
|
2019-12-14 16:22:38 +00:00
|
|
|
for (const Company *cc : Company::Iterate()) {
|
2008-09-30 20:39:50 +00:00
|
|
|
if (cc->name_1 == str && cc->name_2 == strp) goto bad_town_name;
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
|
2006-10-21 23:31:34 +00:00
|
|
|
GetString(buffer, str, lastof(buffer));
|
2010-12-05 22:24:50 +00:00
|
|
|
if (Utf8StringLength(buffer) >= MAX_LENGTH_COMPANY_NAME_CHARS) goto bad_town_name;
|
2004-08-09 17:04:08 +00:00
|
|
|
|
|
|
|
set_name:;
|
2008-09-30 20:39:50 +00:00
|
|
|
c->name_1 = str;
|
|
|
|
c->name_2 = strp;
|
2004-08-09 17:04:08 +00:00
|
|
|
|
|
|
|
MarkWholeScreenDirty();
|
|
|
|
|
2009-06-10 22:05:01 +00:00
|
|
|
if (c->is_ai) {
|
2008-07-18 16:26:51 +00:00
|
|
|
CompanyNewsInformation *cni = MallocT<CompanyNewsInformation>(1);
|
2008-09-30 20:39:50 +00:00
|
|
|
cni->FillData(c);
|
2009-04-21 23:40:56 +00:00
|
|
|
SetDParam(0, STR_NEWS_COMPANY_LAUNCH_TITLE);
|
|
|
|
SetDParam(1, STR_NEWS_COMPANY_LAUNCH_DESCRIPTION);
|
2008-07-18 16:26:51 +00:00
|
|
|
SetDParamStr(2, cni->company_name);
|
2008-05-13 10:17:04 +00:00
|
|
|
SetDParam(3, t->index);
|
2012-05-26 14:16:03 +00:00
|
|
|
AddNewsItem(STR_MESSAGE_NEWS_FORMAT, NT_COMPANY_INFO, NF_COMPANY, NR_TILE, c->last_build_coordinate, NR_NONE, UINT32_MAX, cni);
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
bad_town_name:;
|
2004-09-11 09:55:19 +00:00
|
|
|
|
2008-09-30 20:39:50 +00:00
|
|
|
if (c->president_name_1 == SPECSTR_PRESIDENT_NAME) {
|
2004-08-09 17:04:08 +00:00
|
|
|
str = SPECSTR_ANDCO_NAME;
|
2008-09-30 20:39:50 +00:00
|
|
|
strp = c->president_name_2;
|
2004-09-11 09:55:19 +00:00
|
|
|
goto set_name;
|
2004-08-09 17:04:08 +00:00
|
|
|
} else {
|
|
|
|
str = SPECSTR_ANDCO_NAME;
|
|
|
|
strp = Random();
|
|
|
|
goto verify_name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-02 20:59:54 +00:00
|
|
|
/** Sorting weights for the company colours. */
|
2008-04-24 11:11:50 +00:00
|
|
|
static const byte _colour_sort[COLOUR_END] = {2, 2, 3, 2, 3, 2, 3, 2, 3, 2, 2, 2, 3, 1, 1, 1};
|
2011-05-02 20:59:54 +00:00
|
|
|
/** Similar colours, so we can try to prevent same coloured companies. */
|
2008-04-24 11:11:50 +00:00
|
|
|
static const Colours _similar_colour[COLOUR_END][2] = {
|
|
|
|
{ COLOUR_BLUE, COLOUR_LIGHT_BLUE }, // COLOUR_DARK_BLUE
|
|
|
|
{ COLOUR_GREEN, COLOUR_DARK_GREEN }, // COLOUR_PALE_GREEN
|
|
|
|
{ INVALID_COLOUR, INVALID_COLOUR }, // COLOUR_PINK
|
|
|
|
{ COLOUR_ORANGE, INVALID_COLOUR }, // COLOUR_YELLOW
|
|
|
|
{ INVALID_COLOUR, INVALID_COLOUR }, // COLOUR_RED
|
|
|
|
{ COLOUR_DARK_BLUE, COLOUR_BLUE }, // COLOUR_LIGHT_BLUE
|
|
|
|
{ COLOUR_PALE_GREEN, COLOUR_DARK_GREEN }, // COLOUR_GREEN
|
|
|
|
{ COLOUR_PALE_GREEN, COLOUR_GREEN }, // COLOUR_DARK_GREEN
|
2008-08-23 12:29:41 +00:00
|
|
|
{ COLOUR_DARK_BLUE, COLOUR_LIGHT_BLUE }, // COLOUR_BLUE
|
2008-04-24 11:11:50 +00:00
|
|
|
{ COLOUR_BROWN, COLOUR_ORANGE }, // COLOUR_CREAM
|
|
|
|
{ COLOUR_PURPLE, INVALID_COLOUR }, // COLOUR_MAUVE
|
|
|
|
{ COLOUR_MAUVE, INVALID_COLOUR }, // COLOUR_PURPLE
|
|
|
|
{ COLOUR_YELLOW, COLOUR_CREAM }, // COLOUR_ORANGE
|
|
|
|
{ COLOUR_CREAM, INVALID_COLOUR }, // COLOUR_BROWN
|
|
|
|
{ COLOUR_WHITE, INVALID_COLOUR }, // COLOUR_GREY
|
|
|
|
{ COLOUR_GREY, INVALID_COLOUR }, // COLOUR_WHITE
|
|
|
|
};
|
|
|
|
|
2010-08-01 17:45:53 +00:00
|
|
|
/**
|
|
|
|
* Generate a company colour.
|
|
|
|
* @return Generated company colour.
|
|
|
|
*/
|
2009-01-27 01:15:29 +00:00
|
|
|
static Colours GenerateCompanyColour()
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
2008-04-24 11:11:50 +00:00
|
|
|
Colours colours[COLOUR_END];
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2007-03-21 17:42:43 +00:00
|
|
|
/* Initialize array */
|
2008-04-24 11:11:50 +00:00
|
|
|
for (uint i = 0; i < COLOUR_END; i++) colours[i] = (Colours)i;
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2007-03-21 17:42:43 +00:00
|
|
|
/* And randomize it */
|
2008-04-24 11:11:50 +00:00
|
|
|
for (uint i = 0; i < 100; i++) {
|
|
|
|
uint r = Random();
|
|
|
|
Swap(colours[GB(r, 0, 4)], colours[GB(r, 4, 4)]);
|
|
|
|
}
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2007-03-21 17:42:43 +00:00
|
|
|
/* Bubble sort it according to the values in table 1 */
|
2008-04-24 11:11:50 +00:00
|
|
|
for (uint i = 0; i < COLOUR_END; i++) {
|
|
|
|
for (uint j = 1; j < COLOUR_END; j++) {
|
|
|
|
if (_colour_sort[colours[j - 1]] < _colour_sort[colours[j]]) {
|
|
|
|
Swap(colours[j - 1], colours[j]);
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
}
|
2011-01-15 15:36:58 +00:00
|
|
|
}
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2009-02-09 02:57:15 +00:00
|
|
|
/* Move the colours that look similar to each company's colour to the side */
|
2019-12-14 16:22:38 +00:00
|
|
|
for (const Company *c : Company::Iterate()) {
|
2008-09-30 20:39:50 +00:00
|
|
|
Colours pcolour = (Colours)c->colour;
|
2008-04-24 11:11:50 +00:00
|
|
|
|
|
|
|
for (uint i = 0; i < COLOUR_END; i++) {
|
|
|
|
if (colours[i] == pcolour) {
|
|
|
|
colours[i] = INVALID_COLOUR;
|
|
|
|
break;
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
2008-04-24 11:11:50 +00:00
|
|
|
}
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2008-04-24 11:11:50 +00:00
|
|
|
for (uint j = 0; j < 2; j++) {
|
|
|
|
Colours similar = _similar_colour[pcolour][j];
|
|
|
|
if (similar == INVALID_COLOUR) break;
|
|
|
|
|
|
|
|
for (uint i = 1; i < COLOUR_END; i++) {
|
|
|
|
if (colours[i - 1] == similar) Swap(colours[i - 1], colours[i]);
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-09 02:57:15 +00:00
|
|
|
/* Return the first available colour */
|
2008-04-24 11:11:50 +00:00
|
|
|
for (uint i = 0; i < COLOUR_END; i++) {
|
|
|
|
if (colours[i] != INVALID_COLOUR) return colours[i];
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
2008-04-24 11:11:50 +00:00
|
|
|
|
|
|
|
NOT_REACHED();
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
|
2010-08-01 17:45:53 +00:00
|
|
|
/**
|
|
|
|
* Generate a random president name of a company.
|
|
|
|
* @param c Company that needs a new president name.
|
|
|
|
*/
|
2008-09-30 20:39:50 +00:00
|
|
|
static void GeneratePresidentName(Company *c)
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
2006-02-01 07:36:15 +00:00
|
|
|
for (;;) {
|
2004-08-09 17:04:08 +00:00
|
|
|
restart:;
|
2008-09-30 20:39:50 +00:00
|
|
|
c->president_name_2 = Random();
|
|
|
|
c->president_name_1 = SPECSTR_PRESIDENT_NAME;
|
2004-09-11 09:55:19 +00:00
|
|
|
|
2009-09-22 12:42:56 +00:00
|
|
|
/* Reserve space for extra unicode character. We need to do this to be able
|
|
|
|
* to detect too long president name. */
|
2010-12-05 22:23:50 +00:00
|
|
|
char buffer[(MAX_LENGTH_PRESIDENT_NAME_CHARS + 1) * MAX_CHAR_LENGTH];
|
2008-09-30 20:39:50 +00:00
|
|
|
SetDParam(0, c->index);
|
2008-09-30 21:18:28 +00:00
|
|
|
GetString(buffer, STR_PRESIDENT_NAME, lastof(buffer));
|
2010-12-05 22:23:50 +00:00
|
|
|
if (Utf8StringLength(buffer) >= MAX_LENGTH_PRESIDENT_NAME_CHARS) continue;
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2019-12-14 16:22:38 +00:00
|
|
|
for (const Company *cc : Company::Iterate()) {
|
2008-09-30 20:39:50 +00:00
|
|
|
if (c != cc) {
|
2009-09-22 12:42:56 +00:00
|
|
|
/* Reserve extra space so even overlength president names can be compared. */
|
2010-12-05 22:23:50 +00:00
|
|
|
char buffer2[(MAX_LENGTH_PRESIDENT_NAME_CHARS + 1) * MAX_CHAR_LENGTH];
|
2008-09-30 20:39:50 +00:00
|
|
|
SetDParam(0, cc->index);
|
2008-09-30 21:18:28 +00:00
|
|
|
GetString(buffer2, STR_PRESIDENT_NAME, lastof(buffer2));
|
2009-01-26 22:27:11 +00:00
|
|
|
if (strcmp(buffer2, buffer) == 0) goto restart;
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-18 22:31:06 +00:00
|
|
|
/**
|
|
|
|
* Reset the livery schemes to the company's primary colour.
|
|
|
|
* This is used on loading games without livery information and on new company start up.
|
|
|
|
* @param c Company to reset.
|
|
|
|
*/
|
2008-09-30 20:39:50 +00:00
|
|
|
void ResetCompanyLivery(Company *c)
|
2006-09-15 12:27:00 +00:00
|
|
|
{
|
2007-01-10 18:56:51 +00:00
|
|
|
for (LiveryScheme scheme = LS_BEGIN; scheme < LS_END; scheme++) {
|
2019-01-31 13:57:44 +00:00
|
|
|
c->livery[scheme].in_use = 0;
|
2008-09-30 20:39:50 +00:00
|
|
|
c->livery[scheme].colour1 = c->colour;
|
|
|
|
c->livery[scheme].colour2 = c->colour;
|
2006-09-15 12:27:00 +00:00
|
|
|
}
|
2019-01-31 13:57:44 +00:00
|
|
|
|
2019-12-16 17:01:57 +00:00
|
|
|
for (Group *g : Group::Iterate()) {
|
2019-01-31 13:57:44 +00:00
|
|
|
if (g->owner == c->index) {
|
|
|
|
g->livery.in_use = 0;
|
|
|
|
g->livery.colour1 = c->colour;
|
|
|
|
g->livery.colour2 = c->colour;
|
|
|
|
}
|
|
|
|
}
|
2006-09-15 12:27:00 +00:00
|
|
|
}
|
|
|
|
|
2007-10-15 19:59:27 +00:00
|
|
|
/**
|
2008-09-30 20:39:50 +00:00
|
|
|
* Create a new company and sets all company variables default values
|
2007-10-15 19:59:27 +00:00
|
|
|
*
|
2010-07-31 21:02:56 +00:00
|
|
|
* @param is_ai is an AI company?
|
2009-08-28 15:23:11 +00:00
|
|
|
* @param company CompanyID to use for the new company
|
2008-09-30 20:39:50 +00:00
|
|
|
* @return the company struct
|
2007-10-15 19:59:27 +00:00
|
|
|
*/
|
2009-08-28 15:23:11 +00:00
|
|
|
Company *DoStartupNewCompany(bool is_ai, CompanyID company = INVALID_COMPANY)
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
2019-04-10 21:07:06 +00:00
|
|
|
if (!Company::CanAllocateItem()) return nullptr;
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2009-01-27 01:15:29 +00:00
|
|
|
/* we have to generate colour before this company is valid */
|
|
|
|
Colours colour = GenerateCompanyColour();
|
|
|
|
|
2009-08-28 15:23:11 +00:00
|
|
|
Company *c;
|
|
|
|
if (company == INVALID_COMPANY) {
|
|
|
|
c = new Company(STR_SV_UNNAMED, is_ai);
|
|
|
|
} else {
|
2019-04-10 21:07:06 +00:00
|
|
|
if (Company::IsValidID(company)) return nullptr;
|
2009-08-28 15:23:11 +00:00
|
|
|
c = new (company) Company(STR_SV_UNNAMED, is_ai);
|
|
|
|
}
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2009-01-27 01:15:29 +00:00
|
|
|
c->colour = colour;
|
|
|
|
|
2008-09-30 20:39:50 +00:00
|
|
|
ResetCompanyLivery(c);
|
2009-02-09 01:06:23 +00:00
|
|
|
_company_colours[c->index] = (Colours)c->colour;
|
2004-09-11 09:55:19 +00:00
|
|
|
|
2021-01-08 10:16:18 +00:00
|
|
|
c->money = c->current_loan = (std::min<int64>(INITIAL_LOAN, _economy.max_loan) * _economy.inflation_prices >> 16) / 50000 * 50000;
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2008-09-30 20:39:50 +00:00
|
|
|
c->share_owners[0] = c->share_owners[1] = c->share_owners[2] = c->share_owners[3] = INVALID_OWNER;
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2008-09-30 20:39:50 +00:00
|
|
|
c->avail_railtypes = GetCompanyRailtypes(c->index);
|
2019-04-06 06:46:15 +00:00
|
|
|
c->avail_roadtypes = GetCompanyRoadTypes(c->index);
|
2008-09-30 20:39:50 +00:00
|
|
|
c->inaugurated_year = _cur_year;
|
2013-06-27 20:20:13 +00:00
|
|
|
RandomCompanyManagerFaceBits(c->face, (GenderEthnicity)Random(), false, false); // create a random company manager face
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2009-05-26 23:14:02 +00:00
|
|
|
SetDefaultCompanySettings(c->index);
|
2014-09-07 16:12:58 +00:00
|
|
|
ClearEnginesHiddenFlagOfCompany(c->index);
|
2009-05-16 00:16:43 +00:00
|
|
|
|
2008-09-30 20:39:50 +00:00
|
|
|
GeneratePresidentName(c);
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2009-09-13 19:15:59 +00:00
|
|
|
SetWindowDirty(WC_GRAPH_LEGEND, 0);
|
2021-04-18 07:54:47 +00:00
|
|
|
InvalidateWindowData(WC_CLIENT_LIST, 0);
|
2013-05-19 14:43:23 +00:00
|
|
|
InvalidateWindowData(WC_LINKGRAPH_LEGEND, 0);
|
2011-01-04 20:57:11 +00:00
|
|
|
BuildOwnerLegend();
|
|
|
|
InvalidateWindowData(WC_SMALLMAP, 0, 1);
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2009-01-12 17:11:45 +00:00
|
|
|
if (is_ai && (!_networking || _network_server)) AI::StartNew(c->index);
|
2005-09-07 15:10:11 +00:00
|
|
|
|
2011-12-02 23:40:24 +00:00
|
|
|
AI::BroadcastNewEvent(new ScriptEventCompanyNew(c->index), c->index);
|
2011-12-19 20:59:36 +00:00
|
|
|
Game::NewEvent(new ScriptEventCompanyNew(c->index));
|
2011-12-02 23:40:24 +00:00
|
|
|
|
2008-09-30 20:39:50 +00:00
|
|
|
return c;
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
|
2010-08-01 17:45:53 +00:00
|
|
|
/** Start the next competitor now. */
|
2008-09-30 20:39:50 +00:00
|
|
|
void StartupCompanies()
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
2009-01-13 16:53:03 +00:00
|
|
|
_next_competitor_start = 0;
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
|
2010-08-01 17:45:53 +00:00
|
|
|
/** Start a new competitor company if possible. */
|
2019-01-31 14:35:13 +00:00
|
|
|
static bool MaybeStartNewCompany()
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
2019-01-31 14:35:13 +00:00
|
|
|
if (_networking && Company::GetNumItems() >= _settings_client.network.max_companies) return false;
|
2009-01-31 17:56:06 +00:00
|
|
|
|
2007-03-21 17:42:43 +00:00
|
|
|
/* count number of competitors */
|
2009-01-31 17:56:06 +00:00
|
|
|
uint n = 0;
|
2019-12-14 16:22:38 +00:00
|
|
|
for (const Company *c : Company::Iterate()) {
|
2008-09-30 20:39:50 +00:00
|
|
|
if (c->is_ai) n++;
|
2005-09-07 15:10:11 +00:00
|
|
|
}
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2009-01-13 16:53:03 +00:00
|
|
|
if (n < (uint)_settings_game.difficulty.max_no_competitors) {
|
2006-06-10 08:37:41 +00:00
|
|
|
/* Send a command to all clients to start up a new AI.
|
|
|
|
* Works fine for Multiplayer and Singleplayer */
|
2019-02-04 17:06:19 +00:00
|
|
|
return DoCommandP(0, CCA_NEW_AI | INVALID_COMPANY << 16, 0, CMD_COMPANY_CTRL);
|
2006-06-10 08:37:41 +00:00
|
|
|
}
|
2019-01-31 14:35:13 +00:00
|
|
|
|
|
|
|
return false;
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
|
2010-08-01 17:45:53 +00:00
|
|
|
/** Initialize the pool of companies. */
|
2008-09-30 20:39:50 +00:00
|
|
|
void InitializeCompanies()
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
2008-09-30 20:39:50 +00:00
|
|
|
_cur_company_tick_index = 0;
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
|
2010-08-06 20:26:01 +00:00
|
|
|
/**
|
|
|
|
* May company \a cbig buy company \a csmall?
|
|
|
|
* @param cbig Company buying \a csmall.
|
|
|
|
* @param csmall Company getting bought.
|
|
|
|
* @return Return \c true if it is allowed.
|
|
|
|
*/
|
|
|
|
bool MayCompanyTakeOver(CompanyID cbig, CompanyID csmall)
|
|
|
|
{
|
2011-10-03 17:24:31 +00:00
|
|
|
const Company *c1 = Company::Get(cbig);
|
|
|
|
const Company *c2 = Company::Get(csmall);
|
2010-08-06 20:26:01 +00:00
|
|
|
|
|
|
|
/* Do the combined vehicle counts stay within the limits? */
|
2011-10-03 17:24:31 +00:00
|
|
|
return c1->group_all[VEH_TRAIN].num_vehicle + c2->group_all[VEH_TRAIN].num_vehicle <= _settings_game.vehicle.max_trains &&
|
|
|
|
c1->group_all[VEH_ROAD].num_vehicle + c2->group_all[VEH_ROAD].num_vehicle <= _settings_game.vehicle.max_roadveh &&
|
|
|
|
c1->group_all[VEH_SHIP].num_vehicle + c2->group_all[VEH_SHIP].num_vehicle <= _settings_game.vehicle.max_ships &&
|
|
|
|
c1->group_all[VEH_AIRCRAFT].num_vehicle + c2->group_all[VEH_AIRCRAFT].num_vehicle <= _settings_game.vehicle.max_aircraft;
|
2010-08-06 20:26:01 +00:00
|
|
|
}
|
|
|
|
|
2009-09-01 12:57:04 +00:00
|
|
|
/**
|
|
|
|
* Handle the bankruptcy take over of a company.
|
|
|
|
* Companies going bankrupt will ask the other companies in order of their
|
|
|
|
* performance rating, so better performing companies get the 'do you want to
|
|
|
|
* merge with Y' question earlier. The question will then stay till either the
|
|
|
|
* company has gone bankrupt or got merged with a company.
|
|
|
|
*
|
|
|
|
* @param c the company that is going bankrupt.
|
|
|
|
*/
|
|
|
|
static void HandleBankruptcyTakeover(Company *c)
|
|
|
|
{
|
|
|
|
/* Amount of time out for each company to take over a company;
|
|
|
|
* Timeout is a quarter (3 months of 30 days) divided over the
|
|
|
|
* number of companies. The minimum number of days in a quarter
|
|
|
|
* is 90: 31 in January, 28 in February and 31 in March.
|
|
|
|
* Note that the company going bankrupt can't buy itself. */
|
|
|
|
static const int TAKE_OVER_TIMEOUT = 3 * 30 * DAY_TICKS / (MAX_COMPANIES - 1);
|
|
|
|
|
|
|
|
assert(c->bankrupt_asked != 0);
|
|
|
|
|
|
|
|
/* We're currently asking some company to buy 'us' */
|
|
|
|
if (c->bankrupt_timeout != 0) {
|
|
|
|
c->bankrupt_timeout -= MAX_COMPANIES;
|
|
|
|
if (c->bankrupt_timeout > 0) return;
|
|
|
|
c->bankrupt_timeout = 0;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Did we ask everyone for bankruptcy? If so, bail out. */
|
|
|
|
if (c->bankrupt_asked == MAX_UVALUE(CompanyMask)) return;
|
|
|
|
|
2019-12-14 16:22:38 +00:00
|
|
|
Company *best = nullptr;
|
2009-09-01 12:57:04 +00:00
|
|
|
int32 best_performance = -1;
|
|
|
|
|
|
|
|
/* Ask the company with the highest performance history first */
|
2019-12-14 16:22:38 +00:00
|
|
|
for (Company *c2 : Company::Iterate()) {
|
2009-09-01 12:57:04 +00:00
|
|
|
if (c2->bankrupt_asked == 0 && // Don't ask companies going bankrupt themselves
|
|
|
|
!HasBit(c->bankrupt_asked, c2->index) &&
|
2010-08-06 20:26:01 +00:00
|
|
|
best_performance < c2->old_economy[1].performance_history &&
|
|
|
|
MayCompanyTakeOver(c2->index, c->index)) {
|
2009-09-01 12:57:04 +00:00
|
|
|
best_performance = c2->old_economy[1].performance_history;
|
|
|
|
best = c2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Asked all companies? */
|
|
|
|
if (best_performance == -1) {
|
|
|
|
c->bankrupt_asked = MAX_UVALUE(CompanyMask);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
SetBit(c->bankrupt_asked, best->index);
|
|
|
|
|
2010-04-14 20:26:34 +00:00
|
|
|
c->bankrupt_timeout = TAKE_OVER_TIMEOUT;
|
2009-09-01 12:57:04 +00:00
|
|
|
if (best->is_ai) {
|
2011-11-29 23:15:35 +00:00
|
|
|
AI::NewEvent(best->index, new ScriptEventCompanyAskMerger(c->index, ClampToI32(c->bankrupt_value)));
|
2010-04-14 20:26:34 +00:00
|
|
|
} else if (IsInteractiveCompany(best->index)) {
|
|
|
|
ShowBuyCompanyDialog(c->index);
|
2009-09-01 12:57:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-02 20:59:54 +00:00
|
|
|
/** Called every tick for updating some company info. */
|
2008-09-30 20:39:50 +00:00
|
|
|
void OnTick_Companies()
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
2006-06-10 08:37:41 +00:00
|
|
|
if (_game_mode == GM_EDITOR) return;
|
2004-09-11 09:55:19 +00:00
|
|
|
|
2009-05-18 16:21:28 +00:00
|
|
|
Company *c = Company::GetIfValid(_cur_company_tick_index);
|
2019-04-10 21:07:06 +00:00
|
|
|
if (c != nullptr) {
|
2009-09-01 12:57:04 +00:00
|
|
|
if (c->name_1 != 0) GenerateCompanyName(c);
|
|
|
|
if (c->bankrupt_asked != 0) HandleBankruptcyTakeover(c);
|
2009-01-13 16:53:03 +00:00
|
|
|
}
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2009-01-13 16:53:03 +00:00
|
|
|
if (_next_competitor_start == 0) {
|
2019-01-31 14:35:13 +00:00
|
|
|
/* AI::GetStartNextTime() can return 0. */
|
2021-01-08 10:16:18 +00:00
|
|
|
_next_competitor_start = std::max(1, AI::GetStartNextTime() * DAY_TICKS);
|
2009-01-13 16:53:03 +00:00
|
|
|
}
|
|
|
|
|
2019-01-31 14:35:13 +00:00
|
|
|
if (_game_mode != GM_MENU && AI::CanStartNew() && --_next_competitor_start == 0) {
|
|
|
|
/* Allow multiple AIs to possibly start in the same tick. */
|
|
|
|
do {
|
|
|
|
if (!MaybeStartNewCompany()) break;
|
2019-02-04 17:19:21 +00:00
|
|
|
|
|
|
|
/* In networking mode, we can only send a command to start but it
|
|
|
|
* didn't execute yet, so we cannot loop. */
|
|
|
|
if (_networking) break;
|
2019-01-31 14:35:13 +00:00
|
|
|
} while (AI::GetStartNextTime() == 0);
|
2008-07-18 16:40:29 +00:00
|
|
|
}
|
|
|
|
|
2008-09-30 20:39:50 +00:00
|
|
|
_cur_company_tick_index = (_cur_company_tick_index + 1) % MAX_COMPANIES;
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
|
2010-08-01 17:45:53 +00:00
|
|
|
/**
|
|
|
|
* A year has passed, update the economic data of all companies, and perhaps show the
|
|
|
|
* financial overview window of the local company.
|
|
|
|
*/
|
2008-09-30 20:39:50 +00:00
|
|
|
void CompaniesYearlyLoop()
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
2007-03-21 17:42:43 +00:00
|
|
|
/* Copy statistics */
|
2019-12-14 16:22:38 +00:00
|
|
|
for (Company *c : Company::Iterate()) {
|
2008-09-30 20:39:50 +00:00
|
|
|
memmove(&c->yearly_expenses[1], &c->yearly_expenses[0], sizeof(c->yearly_expenses) - sizeof(c->yearly_expenses[0]));
|
|
|
|
memset(&c->yearly_expenses[0], 0, sizeof(c->yearly_expenses[0]));
|
2009-09-13 19:15:59 +00:00
|
|
|
SetWindowDirty(WC_FINANCES, c->index);
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
|
2008-09-30 20:39:50 +00:00
|
|
|
if (_settings_client.gui.show_finances && _local_company != COMPANY_SPECTATOR) {
|
|
|
|
ShowCompanyFinances(_local_company);
|
2019-12-14 16:22:38 +00:00
|
|
|
Company *c = Company::Get(_local_company);
|
2008-09-30 20:39:50 +00:00
|
|
|
if (c->num_valid_stat_ent > 5 && c->old_economy[0].performance_history < c->old_economy[4].performance_history) {
|
2012-12-23 21:09:09 +00:00
|
|
|
if (_settings_client.sound.new_year) SndPlayFx(SND_01_BAD_YEAR);
|
2004-08-09 17:04:08 +00:00
|
|
|
} else {
|
2012-12-23 21:09:09 +00:00
|
|
|
if (_settings_client.sound.new_year) SndPlayFx(SND_00_GOOD_YEAR);
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-07-18 16:26:51 +00:00
|
|
|
/**
|
|
|
|
* Fill the CompanyNewsInformation struct with the required data.
|
2009-08-09 15:58:34 +00:00
|
|
|
* @param c the current company.
|
2019-04-10 21:07:06 +00:00
|
|
|
* @param other the other company (use \c nullptr if not relevant).
|
2008-07-18 16:26:51 +00:00
|
|
|
*/
|
2008-09-30 20:39:50 +00:00
|
|
|
void CompanyNewsInformation::FillData(const Company *c, const Company *other)
|
2008-07-18 16:26:51 +00:00
|
|
|
{
|
2008-09-30 20:39:50 +00:00
|
|
|
SetDParam(0, c->index);
|
2008-07-18 16:26:51 +00:00
|
|
|
GetString(this->company_name, STR_COMPANY_NAME, lastof(this->company_name));
|
|
|
|
|
2019-04-10 21:07:06 +00:00
|
|
|
if (other == nullptr) {
|
2008-07-18 16:26:51 +00:00
|
|
|
*this->other_company_name = '\0';
|
|
|
|
} else {
|
|
|
|
SetDParam(0, other->index);
|
|
|
|
GetString(this->other_company_name, STR_COMPANY_NAME, lastof(this->other_company_name));
|
2008-09-30 20:39:50 +00:00
|
|
|
c = other;
|
2008-07-18 16:26:51 +00:00
|
|
|
}
|
|
|
|
|
2008-09-30 20:39:50 +00:00
|
|
|
SetDParam(0, c->index);
|
2009-04-21 23:40:56 +00:00
|
|
|
GetString(this->president_name, STR_PRESIDENT_NAME_MANAGER, lastof(this->president_name));
|
2008-07-18 16:26:51 +00:00
|
|
|
|
2008-09-30 20:39:50 +00:00
|
|
|
this->colour = c->colour;
|
|
|
|
this->face = c->face;
|
2008-07-18 16:26:51 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2010-10-17 17:37:45 +00:00
|
|
|
/**
|
|
|
|
* Called whenever company related information changes in order to notify admins.
|
|
|
|
* @param company The company data changed of.
|
|
|
|
*/
|
|
|
|
void CompanyAdminUpdate(const Company *company)
|
|
|
|
{
|
|
|
|
if (_network_server) NetworkAdminCompanyUpdate(company);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2011-10-15 20:42:32 +00:00
|
|
|
* Called whenever a company is removed in order to notify admins.
|
|
|
|
* @param company_id The company that was removed.
|
|
|
|
* @param reason The reason the company was removed.
|
2010-10-17 17:37:45 +00:00
|
|
|
*/
|
2011-10-15 20:42:32 +00:00
|
|
|
void CompanyAdminRemove(CompanyID company_id, CompanyRemoveReason reason)
|
2010-10-17 17:37:45 +00:00
|
|
|
{
|
2011-10-15 20:42:32 +00:00
|
|
|
if (_network_server) NetworkAdminCompanyRemove(company_id, (AdminCompanyRemoveReason)reason);
|
2010-10-17 17:37:45 +00:00
|
|
|
}
|
|
|
|
|
2010-08-01 19:22:34 +00:00
|
|
|
/**
|
|
|
|
* Control the companies: add, delete, etc.
|
2006-04-10 07:15:58 +00:00
|
|
|
* @param tile unused
|
2007-04-17 21:09:38 +00:00
|
|
|
* @param flags operation to perform
|
2005-05-12 23:46:01 +00:00
|
|
|
* @param p1 various functionality
|
2019-02-04 17:06:19 +00:00
|
|
|
* - bits 0..15: CompanyCtrlAction
|
2019-04-05 13:11:52 +00:00
|
|
|
* - bits 16..23: CompanyID
|
|
|
|
* - bits 24..31: CompanyRemoveReason (with CCA_DELETE)
|
|
|
|
* @param p2 ClientID
|
2009-09-18 14:23:58 +00:00
|
|
|
* @param text unused
|
|
|
|
* @return the cost of this operation or an error
|
2005-05-12 23:46:01 +00:00
|
|
|
*/
|
2009-02-09 21:20:05 +00:00
|
|
|
CommandCost CmdCompanyCtrl(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
2008-06-15 15:48:33 +00:00
|
|
|
InvalidateWindowData(WC_COMPANY_LEAGUE, 0, 0);
|
2010-08-18 17:06:45 +00:00
|
|
|
CompanyID company_id = (CompanyID)GB(p1, 16, 8);
|
2008-06-15 15:48:33 +00:00
|
|
|
|
2019-02-04 17:06:19 +00:00
|
|
|
switch ((CompanyCtrlAction)GB(p1, 0, 16)) {
|
|
|
|
case CCA_NEW: { // Create a new company
|
2008-09-30 20:39:50 +00:00
|
|
|
/* This command is only executed in a multiplayer game */
|
|
|
|
if (!_networking) return CMD_ERROR;
|
2008-07-17 15:16:11 +00:00
|
|
|
|
2008-12-22 12:59:31 +00:00
|
|
|
/* Has the network client a correct ClientIndex? */
|
2008-09-30 20:39:50 +00:00
|
|
|
if (!(flags & DC_EXEC)) return CommandCost();
|
2019-02-10 22:34:55 +00:00
|
|
|
|
|
|
|
ClientID client_id = (ClientID)p2;
|
2011-04-22 15:54:16 +00:00
|
|
|
NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id);
|
2008-09-30 20:39:50 +00:00
|
|
|
|
|
|
|
/* Delete multiplayer progress bar */
|
2011-12-19 20:50:21 +00:00
|
|
|
DeleteWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN);
|
2008-09-30 20:39:50 +00:00
|
|
|
|
|
|
|
Company *c = DoStartupNewCompany(false);
|
|
|
|
|
|
|
|
/* A new company could not be created, revert to being a spectator */
|
2019-04-10 21:07:06 +00:00
|
|
|
if (c == nullptr) {
|
Fix: [Network] don't desync if client leaves before you finish downloading map
When you are downloading a map, all the commands are queued up
for you. Clients joining/leaving is done by the network protocol,
and as such are processed immediately. This means that by the
time you are processing the commands, a client that triggered
it, might already have left.
So, all commands that do something with ClientID, shouldn't
error on an invalid ClientID when DC_EXEC is set, but
gracefully handle the command anyway, to make sure the
game-state is kept in sync with all the clients that did
execute the DoCommand while the now-gone client was still
there.
Additionally, in the small chance a client disconnects between
the server validating a DoCommand and the command being
executed, also just process the command as if the client was
still there. Otherwise, lag or latency can cause clients that
did not receive the disconnect yet to desync.
2021-02-27 10:01:57 +00:00
|
|
|
/* We check for "ci != nullptr" as a client could have left by
|
|
|
|
* the time we execute this command. */
|
|
|
|
if (_network_server && ci != nullptr) {
|
2008-09-30 20:39:50 +00:00
|
|
|
ci->client_playas = COMPANY_SPECTATOR;
|
2008-12-22 12:59:31 +00:00
|
|
|
NetworkUpdateClientInfo(ci->client_id);
|
2008-09-30 20:39:50 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-01-23 22:18:06 +00:00
|
|
|
/* This is the client (or non-dedicated server) who wants a new company */
|
2010-08-18 17:06:45 +00:00
|
|
|
if (client_id == _network_own_client_id) {
|
2008-09-30 20:39:50 +00:00
|
|
|
assert(_local_company == COMPANY_SPECTATOR);
|
|
|
|
SetLocalCompany(c->index);
|
|
|
|
if (!StrEmpty(_settings_client.network.default_company_pass)) {
|
2011-01-19 16:47:40 +00:00
|
|
|
NetworkChangeCompanyPassword(_local_company, _settings_client.network.default_company_pass);
|
2008-09-30 20:39:50 +00:00
|
|
|
}
|
2006-11-10 17:52:51 +00:00
|
|
|
|
2009-05-26 13:29:01 +00:00
|
|
|
/* Now that we have a new company, broadcast our company settings to
|
2009-03-14 18:16:29 +00:00
|
|
|
* all clients so everything is in sync */
|
2009-05-26 13:29:01 +00:00
|
|
|
SyncCompanySettings();
|
2006-11-10 17:52:51 +00:00
|
|
|
|
2008-09-30 20:39:50 +00:00
|
|
|
MarkWholeScreenDirty();
|
|
|
|
}
|
2004-12-15 21:13:52 +00:00
|
|
|
|
2014-05-11 12:52:21 +00:00
|
|
|
NetworkServerNewCompany(c, ci);
|
2010-08-01 18:53:30 +00:00
|
|
|
break;
|
|
|
|
}
|
2005-05-12 23:46:01 +00:00
|
|
|
|
2019-02-04 17:06:19 +00:00
|
|
|
case CCA_NEW_AI: { // Make a new AI company
|
2021-01-18 14:31:07 +00:00
|
|
|
if (company_id != INVALID_COMPANY && company_id >= MAX_COMPANIES) return CMD_ERROR;
|
|
|
|
|
|
|
|
/* For network games, company deletion is delayed. */
|
|
|
|
if (!_networking && company_id != INVALID_COMPANY && Company::IsValidID(company_id)) return CMD_ERROR;
|
|
|
|
|
2008-09-30 20:39:50 +00:00
|
|
|
if (!(flags & DC_EXEC)) return CommandCost();
|
2005-05-12 23:46:01 +00:00
|
|
|
|
2021-01-18 14:31:07 +00:00
|
|
|
/* For network game, just assume deletion happened. */
|
|
|
|
assert(company_id == INVALID_COMPANY || !Company::IsValidID(company_id));
|
|
|
|
|
2014-05-11 12:52:21 +00:00
|
|
|
Company *c = DoStartupNewCompany(true, company_id);
|
2019-04-10 21:07:06 +00:00
|
|
|
if (c != nullptr) NetworkServerNewCompany(c, nullptr);
|
2008-09-30 20:39:50 +00:00
|
|
|
break;
|
2014-05-11 12:52:21 +00:00
|
|
|
}
|
2005-05-12 23:46:01 +00:00
|
|
|
|
2019-02-04 17:06:19 +00:00
|
|
|
case CCA_DELETE: { // Delete a company
|
2019-04-05 13:11:52 +00:00
|
|
|
CompanyRemoveReason reason = (CompanyRemoveReason)GB(p1, 24, 8);
|
2011-10-15 20:42:32 +00:00
|
|
|
if (reason >= CRR_END) return CMD_ERROR;
|
|
|
|
|
2021-01-22 15:24:29 +00:00
|
|
|
/* We can't delete the last existing company in singleplayer mode. */
|
2021-01-18 14:31:07 +00:00
|
|
|
if (!_networking && Company::GetNumItems() == 1) return CMD_ERROR;
|
|
|
|
|
2010-08-18 17:06:45 +00:00
|
|
|
Company *c = Company::GetIfValid(company_id);
|
2019-04-10 21:07:06 +00:00
|
|
|
if (c == nullptr) return CMD_ERROR;
|
2005-05-12 23:46:01 +00:00
|
|
|
|
2008-09-30 20:39:50 +00:00
|
|
|
if (!(flags & DC_EXEC)) return CommandCost();
|
2005-05-12 23:46:01 +00:00
|
|
|
|
2009-01-12 17:11:45 +00:00
|
|
|
/* Delete any open window of the company */
|
|
|
|
DeleteCompanyWindows(c->index);
|
|
|
|
CompanyNewsInformation *cni = MallocT<CompanyNewsInformation>(1);
|
|
|
|
cni->FillData(c);
|
2008-07-18 16:26:51 +00:00
|
|
|
|
2009-01-12 17:11:45 +00:00
|
|
|
/* Show the bankrupt news */
|
2009-04-21 23:40:56 +00:00
|
|
|
SetDParam(0, STR_NEWS_COMPANY_BANKRUPT_TITLE);
|
|
|
|
SetDParam(1, STR_NEWS_COMPANY_BANKRUPT_DESCRIPTION);
|
2009-01-12 17:11:45 +00:00
|
|
|
SetDParamStr(2, cni->company_name);
|
2012-05-26 14:15:46 +00:00
|
|
|
AddCompanyNewsItem(STR_MESSAGE_NEWS_FORMAT, cni);
|
2004-12-16 11:36:57 +00:00
|
|
|
|
2009-01-12 17:11:45 +00:00
|
|
|
/* Remove the company */
|
|
|
|
ChangeOwnershipOfCompanyItems(c->index, INVALID_OWNER);
|
2009-06-10 22:05:01 +00:00
|
|
|
if (c->is_ai) AI::Stop(c->index);
|
2008-07-18 16:40:29 +00:00
|
|
|
|
2009-01-12 17:11:45 +00:00
|
|
|
CompanyID c_index = c->index;
|
|
|
|
delete c;
|
2011-11-29 23:15:35 +00:00
|
|
|
AI::BroadcastNewEvent(new ScriptEventCompanyBankrupt(c_index));
|
2011-12-19 20:59:36 +00:00
|
|
|
Game::NewEvent(new ScriptEventCompanyBankrupt(c_index));
|
2011-10-15 20:42:32 +00:00
|
|
|
CompanyAdminRemove(c_index, (CompanyRemoveReason)reason);
|
2013-09-13 12:45:25 +00:00
|
|
|
|
|
|
|
if (StoryPage::GetNumItems() == 0 || Goal::GetNumItems() == 0) InvalidateWindowData(WC_MAIN_TOOLBAR, 0);
|
2021-04-22 23:52:57 +00:00
|
|
|
InvalidateWindowData(WC_CLIENT_LIST, 0);
|
|
|
|
|
2010-08-01 18:53:30 +00:00
|
|
|
break;
|
|
|
|
}
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2008-09-30 20:39:50 +00:00
|
|
|
default: return CMD_ERROR;
|
2005-05-12 23:46:01 +00:00
|
|
|
}
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2011-01-02 12:41:24 +00:00
|
|
|
InvalidateWindowClassesData(WC_GAME_OPTIONS);
|
|
|
|
InvalidateWindowClassesData(WC_AI_SETTINGS);
|
|
|
|
InvalidateWindowClassesData(WC_AI_LIST);
|
|
|
|
|
2007-06-18 19:53:50 +00:00
|
|
|
return CommandCost();
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
2010-01-05 17:11:56 +00:00
|
|
|
|
2010-08-01 19:22:34 +00:00
|
|
|
/**
|
|
|
|
* Change the company manager's face.
|
2010-01-05 17:11:56 +00:00
|
|
|
* @param tile unused
|
|
|
|
* @param flags operation to perform
|
|
|
|
* @param p1 unused
|
|
|
|
* @param p2 face bitmasked
|
|
|
|
* @param text unused
|
|
|
|
* @return the cost of this operation or an error
|
|
|
|
*/
|
|
|
|
CommandCost CmdSetCompanyManagerFace(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
|
|
|
|
{
|
|
|
|
CompanyManagerFace cmf = (CompanyManagerFace)p2;
|
|
|
|
|
|
|
|
if (!IsValidCompanyManagerFace(cmf)) return CMD_ERROR;
|
|
|
|
|
|
|
|
if (flags & DC_EXEC) {
|
|
|
|
Company::Get(_current_company)->face = cmf;
|
|
|
|
MarkWholeScreenDirty();
|
|
|
|
}
|
|
|
|
return CommandCost();
|
|
|
|
}
|
|
|
|
|
2010-08-01 19:22:34 +00:00
|
|
|
/**
|
|
|
|
* Change the company's company-colour
|
2010-01-05 17:11:56 +00:00
|
|
|
* @param tile unused
|
|
|
|
* @param flags operation to perform
|
|
|
|
* @param p1 bitstuffed:
|
|
|
|
* p1 bits 0-7 scheme to set
|
2019-01-31 13:57:44 +00:00
|
|
|
* p1 bit 8 set first/second colour
|
2010-01-05 17:11:56 +00:00
|
|
|
* @param p2 new colour for vehicles, property, etc.
|
|
|
|
* @param text unused
|
|
|
|
* @return the cost of this operation or an error
|
|
|
|
*/
|
|
|
|
CommandCost CmdSetCompanyColour(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
|
|
|
|
{
|
2019-01-31 13:57:44 +00:00
|
|
|
Colours colour = Extract<Colours, 0, 8>(p2);
|
2010-04-17 13:31:41 +00:00
|
|
|
LiveryScheme scheme = Extract<LiveryScheme, 0, 8>(p1);
|
2019-01-31 13:57:44 +00:00
|
|
|
bool second = HasBit(p1, 8);
|
2010-01-05 17:11:56 +00:00
|
|
|
|
2019-01-31 13:57:44 +00:00
|
|
|
if (scheme >= LS_END || (colour >= COLOUR_END && colour != INVALID_COLOUR)) return CMD_ERROR;
|
|
|
|
|
|
|
|
/* Default scheme can't be reset to invalid. */
|
|
|
|
if (scheme == LS_DEFAULT && colour == INVALID_COLOUR) return CMD_ERROR;
|
2010-01-05 17:11:56 +00:00
|
|
|
|
|
|
|
Company *c = Company::Get(_current_company);
|
|
|
|
|
|
|
|
/* Ensure no two companies have the same primary colour */
|
2019-01-31 13:57:44 +00:00
|
|
|
if (scheme == LS_DEFAULT && !second) {
|
2019-12-14 16:22:38 +00:00
|
|
|
for (const Company *cc : Company::Iterate()) {
|
2010-01-05 17:11:56 +00:00
|
|
|
if (cc != c && cc->colour == colour) return CMD_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & DC_EXEC) {
|
2019-01-31 13:57:44 +00:00
|
|
|
if (!second) {
|
|
|
|
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;
|
|
|
|
|
|
|
|
/* If setting the first colour of the default scheme, adjust the
|
|
|
|
* original and cached company colours too. */
|
|
|
|
if (scheme == LS_DEFAULT) {
|
|
|
|
for (int i = 1; i < LS_END; i++) {
|
|
|
|
if (!HasBit(c->livery[i].in_use, 0)) c->livery[i].colour1 = colour;
|
2010-01-05 17:11:56 +00:00
|
|
|
}
|
2019-01-31 13:57:44 +00:00
|
|
|
_company_colours[_current_company] = colour;
|
|
|
|
c->colour = colour;
|
|
|
|
CompanyAdminUpdate(c);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (scheme != LS_DEFAULT) SB(c->livery[scheme].in_use, 1, 1, colour != INVALID_COLOUR);
|
|
|
|
if (colour == INVALID_COLOUR) colour = (Colours)c->livery[LS_DEFAULT].colour2;
|
|
|
|
c->livery[scheme].colour2 = colour;
|
2010-01-05 17:11:56 +00:00
|
|
|
|
2019-01-31 13:57:44 +00:00
|
|
|
if (scheme == LS_DEFAULT) {
|
|
|
|
for (int i = 1; i < LS_END; i++) {
|
|
|
|
if (!HasBit(c->livery[i].in_use, 1)) c->livery[i].colour2 = colour;
|
2010-01-05 17:11:56 +00:00
|
|
|
}
|
2019-01-31 13:57:44 +00:00
|
|
|
}
|
|
|
|
}
|
2010-01-05 17:11:56 +00:00
|
|
|
|
2019-01-31 13:57:44 +00:00
|
|
|
if (c->livery[scheme].in_use != 0) {
|
|
|
|
/* If enabling a scheme, set the default scheme to be in use too */
|
|
|
|
c->livery[LS_DEFAULT].in_use = 1;
|
|
|
|
} else {
|
|
|
|
/* Else loop through all schemes to see if any are left enabled.
|
|
|
|
* If not, disable the default scheme too. */
|
|
|
|
c->livery[LS_DEFAULT].in_use = 0;
|
|
|
|
for (scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
|
|
|
|
if (c->livery[scheme].in_use != 0) {
|
|
|
|
c->livery[LS_DEFAULT].in_use = 1;
|
|
|
|
break;
|
2010-01-05 17:11:56 +00:00
|
|
|
}
|
2019-01-31 13:57:44 +00:00
|
|
|
}
|
2010-01-05 17:11:56 +00:00
|
|
|
}
|
2019-01-31 13:57:44 +00:00
|
|
|
|
2010-01-05 17:11:56 +00:00
|
|
|
ResetVehicleColourMap();
|
|
|
|
MarkWholeScreenDirty();
|
|
|
|
|
2010-04-12 17:58:09 +00:00
|
|
|
/* All graph related to companies use the company colour. */
|
|
|
|
InvalidateWindowData(WC_INCOME_GRAPH, 0);
|
|
|
|
InvalidateWindowData(WC_OPERATING_PROFIT, 0);
|
|
|
|
InvalidateWindowData(WC_DELIVERED_CARGO, 0);
|
|
|
|
InvalidateWindowData(WC_PERFORMANCE_HISTORY, 0);
|
|
|
|
InvalidateWindowData(WC_COMPANY_VALUE, 0);
|
2013-05-19 14:43:23 +00:00
|
|
|
InvalidateWindowData(WC_LINKGRAPH_LEGEND, 0);
|
2011-02-14 19:39:01 +00:00
|
|
|
/* The smallmap owner view also stores the company colours. */
|
|
|
|
BuildOwnerLegend();
|
|
|
|
InvalidateWindowData(WC_SMALLMAP, 0, 1);
|
2010-04-12 17:58:09 +00:00
|
|
|
|
2010-01-05 17:11:56 +00:00
|
|
|
/* Company colour data is indirectly cached. */
|
2019-12-17 02:37:43 +00:00
|
|
|
for (Vehicle *v : Vehicle::Iterate()) {
|
2010-01-05 17:11:56 +00:00
|
|
|
if (v->owner == _current_company) v->InvalidateNewGRFCache();
|
|
|
|
}
|
2010-10-12 19:48:42 +00:00
|
|
|
|
|
|
|
extern void UpdateObjectColours(const Company *c);
|
|
|
|
UpdateObjectColours(c);
|
2010-01-05 17:11:56 +00:00
|
|
|
}
|
|
|
|
return CommandCost();
|
|
|
|
}
|
|
|
|
|
2010-08-01 17:45:53 +00:00
|
|
|
/**
|
|
|
|
* Is the given name in use as name of a company?
|
|
|
|
* @param name Name to search.
|
|
|
|
* @return \c true if the name us unique (that is, not in use), else \c false.
|
|
|
|
*/
|
2010-01-05 17:11:56 +00:00
|
|
|
static bool IsUniqueCompanyName(const char *name)
|
|
|
|
{
|
2019-12-14 16:22:38 +00:00
|
|
|
for (const Company *c : Company::Iterate()) {
|
2020-05-17 21:31:59 +00:00
|
|
|
if (!c->name.empty() && c->name == name) return false;
|
2010-01-05 17:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-08-01 19:22:34 +00:00
|
|
|
/**
|
|
|
|
* Change the name of the company.
|
2010-01-05 17:11:56 +00:00
|
|
|
* @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 char *text)
|
|
|
|
{
|
|
|
|
bool reset = StrEmpty(text);
|
|
|
|
|
|
|
|
if (!reset) {
|
2010-12-05 22:24:50 +00:00
|
|
|
if (Utf8StringLength(text) >= MAX_LENGTH_COMPANY_NAME_CHARS) return CMD_ERROR;
|
2010-01-05 17:11:56 +00:00
|
|
|
if (!IsUniqueCompanyName(text)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & DC_EXEC) {
|
|
|
|
Company *c = Company::Get(_current_company);
|
2020-05-17 21:31:59 +00:00
|
|
|
if (reset) {
|
|
|
|
c->name.clear();
|
|
|
|
} else {
|
|
|
|
c->name = text;
|
|
|
|
}
|
2010-01-05 17:11:56 +00:00
|
|
|
MarkWholeScreenDirty();
|
2010-10-17 17:37:45 +00:00
|
|
|
CompanyAdminUpdate(c);
|
2010-01-05 17:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return CommandCost();
|
|
|
|
}
|
|
|
|
|
2010-08-01 17:45:53 +00:00
|
|
|
/**
|
|
|
|
* Is the given name in use as president name of a company?
|
|
|
|
* @param name Name to search.
|
|
|
|
* @return \c true if the name us unique (that is, not in use), else \c false.
|
|
|
|
*/
|
2010-01-05 17:11:56 +00:00
|
|
|
static bool IsUniquePresidentName(const char *name)
|
|
|
|
{
|
2019-12-14 16:22:38 +00:00
|
|
|
for (const Company *c : Company::Iterate()) {
|
2020-05-17 21:31:59 +00:00
|
|
|
if (!c->president_name.empty() && c->president_name == name) return false;
|
2010-01-05 17:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-08-01 19:22:34 +00:00
|
|
|
/**
|
|
|
|
* Change the name of the president.
|
2010-01-05 17:11:56 +00:00
|
|
|
* @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 char *text)
|
|
|
|
{
|
|
|
|
bool reset = StrEmpty(text);
|
|
|
|
|
|
|
|
if (!reset) {
|
2010-12-05 22:23:50 +00:00
|
|
|
if (Utf8StringLength(text) >= MAX_LENGTH_PRESIDENT_NAME_CHARS) return CMD_ERROR;
|
2010-01-05 17:11:56 +00:00
|
|
|
if (!IsUniquePresidentName(text)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & DC_EXEC) {
|
|
|
|
Company *c = Company::Get(_current_company);
|
|
|
|
|
|
|
|
if (reset) {
|
2020-05-17 21:31:59 +00:00
|
|
|
c->president_name.clear();
|
2010-01-05 17:11:56 +00:00
|
|
|
} else {
|
2020-05-17 21:31:59 +00:00
|
|
|
c->president_name = text;
|
2010-01-05 17:11:56 +00:00
|
|
|
|
2020-05-17 21:31:59 +00:00
|
|
|
if (c->name_1 == STR_SV_UNNAMED && c->name.empty()) {
|
2010-01-05 17:11:56 +00:00
|
|
|
char buf[80];
|
|
|
|
|
2014-04-23 21:12:09 +00:00
|
|
|
seprintf(buf, lastof(buf), "%s Transport", text);
|
2010-01-05 17:11:56 +00:00
|
|
|
DoCommand(0, 0, 0, DC_EXEC, CMD_RENAME_COMPANY, buf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MarkWholeScreenDirty();
|
2010-10-17 17:37:45 +00:00
|
|
|
CompanyAdminUpdate(c);
|
2010-01-05 17:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return CommandCost();
|
|
|
|
}
|
2013-02-14 17:06:49 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the service interval for the given company and vehicle type.
|
2019-04-10 21:07:06 +00:00
|
|
|
* @param c The company, or nullptr for client-default settings.
|
2013-02-14 17:06:49 +00:00
|
|
|
* @param type The vehicle type to get the interval for.
|
|
|
|
* @return The service interval.
|
|
|
|
*/
|
|
|
|
int CompanyServiceInterval(const Company *c, VehicleType type)
|
|
|
|
{
|
2019-04-10 21:07:06 +00:00
|
|
|
const VehicleDefaultSettings *vds = (c == nullptr) ? &_settings_client.company.vehicle : &c->settings.vehicle;
|
2013-02-14 17:06:49 +00:00
|
|
|
switch (type) {
|
|
|
|
default: NOT_REACHED();
|
|
|
|
case VEH_TRAIN: return vds->servint_trains;
|
|
|
|
case VEH_ROAD: return vds->servint_roadveh;
|
|
|
|
case VEH_AIRCRAFT: return vds->servint_aircraft;
|
|
|
|
case VEH_SHIP: return vds->servint_ships;
|
|
|
|
}
|
|
|
|
}
|
2019-04-06 06:46:15 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get total sum of all owned road bits.
|
|
|
|
* @return Combined total road road bits.
|
|
|
|
*/
|
|
|
|
uint32 CompanyInfrastructure::GetRoadTotal() const
|
|
|
|
{
|
|
|
|
uint32 total = 0;
|
|
|
|
for (RoadType rt = ROADTYPE_BEGIN; rt != ROADTYPE_END; rt++) {
|
|
|
|
if (RoadTypeIsRoad(rt)) total += this->road[rt];
|
|
|
|
}
|
|
|
|
return total;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get total sum of all owned tram bits.
|
|
|
|
* @return Combined total of tram road bits.
|
|
|
|
*/
|
|
|
|
uint32 CompanyInfrastructure::GetTramTotal() const
|
|
|
|
{
|
|
|
|
uint32 total = 0;
|
|
|
|
for (RoadType rt = ROADTYPE_BEGIN; rt != ROADTYPE_END; rt++) {
|
|
|
|
if (RoadTypeIsTram(rt)) total += this->road[rt];
|
|
|
|
}
|
|
|
|
return total;
|
|
|
|
}
|
2021-01-05 17:06:48 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Transfer funds (money) from one company to another.
|
|
|
|
* 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
|
|
|
|
* @return the cost of this operation or an error
|
|
|
|
*/
|
|
|
|
CommandCost CmdGiveMoney(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
|
|
|
|
{
|
|
|
|
if (!_settings_game.economy.give_money) return CMD_ERROR;
|
|
|
|
|
|
|
|
const Company *c = Company::Get(_current_company);
|
2021-01-08 10:16:18 +00:00
|
|
|
CommandCost amount(EXPENSES_OTHER, std::min<Money>(p1, 20000000LL));
|
2021-01-05 17:06:48 +00:00
|
|
|
CompanyID dest_company = (CompanyID)p2;
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
if (!Company::IsValidID(dest_company)) return CMD_ERROR;
|
|
|
|
|
|
|
|
if (flags & DC_EXEC) {
|
|
|
|
/* Add money to company */
|
|
|
|
Backup<CompanyID> cur_company(_current_company, dest_company, FILE_LINE);
|
|
|
|
SubtractMoneyFromCompany(CommandCost(EXPENSES_OTHER, -amount.GetCost()));
|
|
|
|
cur_company.Restore();
|
|
|
|
|
|
|
|
if (_networking) {
|
|
|
|
char dest_company_name[MAX_LENGTH_COMPANY_NAME_CHARS * MAX_CHAR_LENGTH];
|
|
|
|
SetDParam(0, dest_company);
|
|
|
|
GetString(dest_company_name, STR_COMPANY_NAME, lastof(dest_company_name));
|
|
|
|
|
|
|
|
char from_company_name[MAX_LENGTH_COMPANY_NAME_CHARS * MAX_CHAR_LENGTH];
|
|
|
|
SetDParam(0, _current_company);
|
|
|
|
GetString(from_company_name, STR_COMPANY_NAME, lastof(from_company_name));
|
|
|
|
|
|
|
|
NetworkTextMessage(NETWORK_ACTION_GIVE_MONEY, GetDrawStringCompanyColour(_current_company), false, from_company_name, dest_company_name, amount.GetCost());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Subtract money from local-company */
|
|
|
|
return amount;
|
|
|
|
}
|