1
0
Fork 0

Add: Client setting gui.start_spectator

Activates a spectator slot in single player and initiate games as a spectator
pull/13673/head
Samu 2019-02-01 14:34:01 +00:00 committed by SamuXarick
parent e70f20a781
commit 402660e447
12 changed files with 86 additions and 50 deletions

View File

@ -72,8 +72,8 @@ static int32_t ClickMoneyCheat(int32_t, int32_t change_direction)
*/
static int32_t ClickChangeCompanyCheat(int32_t new_value, int32_t change_direction)
{
while ((uint)new_value < Company::GetPoolSize()) {
if (Company::IsValidID((CompanyID)new_value)) {
while ((uint)new_value <= COMPANY_SPECTATOR) {
if (Company::IsValidID((CompanyID)new_value) || (new_value == COMPANY_SPECTATOR && _settings_client.gui.start_spectator)) {
SetLocalCompany((CompanyID)new_value);
return _local_company.base();
}
@ -303,7 +303,7 @@ struct CheatWindow : Window {
case STR_CHEAT_CHANGE_COMPANY: {
SetDParam(0, val + 1);
uint offset = WidgetDimensions::scaled.hsep_indent + GetStringBoundingBox(ce->str).width;
DrawCompanyIcon(_local_company, rtl ? text_right - offset - WidgetDimensions::scaled.hsep_indent : text_left + offset, y + icon_y_offset);
if (_local_company != COMPANY_SPECTATOR) DrawCompanyIcon(_local_company, rtl ? text_right - offset - WidgetDimensions::scaled.hsep_indent : text_left + offset, y + icon_y_offset);
break;
}

View File

@ -925,9 +925,6 @@ CommandCost CmdCompanyCtrl(DoCommandFlags flags, CompanyCtrlAction cca, CompanyI
case CCA_DELETE: { // Delete a company
if (reason >= CRR_END) return CMD_ERROR;
/* We can't delete the last existing company in singleplayer mode. */
if (!_networking && Company::GetNumItems() == 1) return CMD_ERROR;
Company *c = Company::GetIfValid(company_id);
if (c == nullptr) return CMD_ERROR;

View File

@ -2246,7 +2246,7 @@ struct CompanyWindow : Window
reinit |= this->GetWidget<NWidgetStacked>(WID_C_SELECT_HOSTILE_TAKEOVER)->SetDisplayedPlane((local || _local_company == COMPANY_SPECTATOR || !c->is_ai || _networking) ? SZSP_NONE : 0);
/* Multiplayer buttons. */
reinit |= this->GetWidget<NWidgetStacked>(WID_C_SELECT_MULTIPLAYER)->SetDisplayedPlane((!_networking || !NetworkCanJoinCompany(c->index) || _local_company == c->index) ? (int)SZSP_NONE : 0);
reinit |= this->GetWidget<NWidgetStacked>(WID_C_SELECT_MULTIPLAYER)->SetDisplayedPlane(((!_networking && (c->is_ai || local || _local_company != COMPANY_SPECTATOR)) || (_networking && (!NetworkCanJoinCompany(c->index) || _local_company == c->index))) ? (int)SZSP_NONE : 0);
this->SetWidgetDisabledState(WID_C_COMPANY_JOIN, c->is_ai);
@ -2512,6 +2512,11 @@ struct CompanyWindow : Window
break;
case WID_C_COMPANY_JOIN: {
if (!_networking) {
if (_local_company == COMPANY_SPECTATOR) SetLocalCompany((CompanyID)this->window_number);
break;
}
this->query_widget = WID_C_COMPANY_JOIN;
CompanyID company = this->window_number;
if (_network_server) {

View File

@ -1480,8 +1480,7 @@ DEF_CONSOLE_CMD(ConReloadAI)
return true;
}
/* In singleplayer mode the player can be in an AI company, after cheating or loading network save with an AI in first slot. */
if (Company::IsHumanID(company_id) || company_id == _local_company) {
if (Company::IsHumanID(company_id)) {
IConsolePrint(CC_ERROR, "Company is not controlled by an AI.");
return true;
}
@ -1518,8 +1517,7 @@ DEF_CONSOLE_CMD(ConStopAI)
return true;
}
/* In singleplayer mode the player can be in an AI company, after cheating or loading network save with an AI in first slot. */
if (Company::IsHumanID(company_id) || company_id == _local_company) {
if (Company::IsHumanID(company_id)) {
IConsolePrint(CC_ERROR, "Company is not controlled by an AI.");
return true;
}

View File

@ -328,16 +328,10 @@ void ChangeOwnershipOfCompanyItems(Owner old_owner, Owner new_owner)
/* In all cases, make spectators of clients connected to that company */
if (_networking) NetworkClientsToSpectators(old_owner);
if (old_owner == _local_company) {
/* Single player cheated to AI company.
* There are no spectators in singleplayer mode, so we must pick some other company. */
/* Single player company bankrupts. Move player to Spectator. */
assert(!_networking);
Backup<CompanyID> cur_company2(_current_company);
for (const Company *c : Company::Iterate()) {
if (c->index != old_owner) {
SetLocalCompany(c->index);
break;
}
}
SetLocalCompany(COMPANY_SPECTATOR);
cur_company2.Restore();
assert(old_owner != _local_company);
}
@ -609,10 +603,11 @@ static void CompanyCheckBankrupt(Company *c)
default:
case 10: {
if (!_networking && _local_company == c->index) {
/* If we are in singleplayer mode, leave the company playing. Eg. there
* is no THE-END, otherwise mark the client as spectator to make sure
* they are no longer in control of this company. However... when you
* join another company (cheat) the "unowned" company can bankrupt. */
/* If we are in singleplayer mode and if spectator mode isn't active,
* leave the company playing. Eg. there is no THE-END, otherwise mark
* the client as spectator to make sure they are no longer in control
* of this company. However... when you join another company (cheat)
* the "unowned" company can bankrupt. */
c->bankrupt_asked.Set();
break;
}
@ -624,8 +619,8 @@ static void CompanyCheckBankrupt(Company *c)
* updating the local company triggers an assert later on. In the
* case of a network game the command will be processed at a time
* that changing the current company is okay. In case of single
* player we are sure (the above check) that we are not the local
* company and thus we won't be moved. */
* player we ensure that the local company remains the same until
* the end of StateGameLoop, where it could be changed. */
if (!_networking || _network_server) {
Command<CMD_COMPANY_CTRL>::Post(CCA_DELETE, c->index, CRR_BANKRUPT, INVALID_CLIENT_ID);
return;
@ -645,7 +640,11 @@ static void CompaniesGenStatistics()
{
/* Check for bankruptcy each month */
for (Company *c : Company::Iterate()) {
Backup<CompanyID> cur_company(_current_company);
Backup<CompanyID> loc_company(_local_company);
CompanyCheckBankrupt(c);
loc_company.Restore();
cur_company.Restore();
}
Backup<CompanyID> cur_company(_current_company);

View File

@ -644,6 +644,9 @@ STR_GRAPH_PERFORMANCE_DETAIL_TOOLTIP :{BLACK}Show det
STR_GRAPH_KEY_CAPTION :{WHITE}Key to company graphs
STR_GRAPH_KEY_COMPANY_SELECTION_TOOLTIP :{BLACK}Toggle graph of this company
# Company list toolbar dropdown
STR_COMPANY_LIST_NEW_COMPANY :New company
# Company league window
STR_COMPANY_LEAGUE_TABLE_CAPTION :{WHITE}Company League Table
STR_COMPANY_LEAGUE_COMPANY_NAME :{ORANGE}{COMPANY} {BLACK}{COMPANY_NUM} '{STRING}'

View File

@ -842,8 +842,8 @@ static void OnStartScenario()
static void OnStartGame(bool dedicated_server)
{
/* Update the local company for a loaded game. It is either the first available company
* or in the case of a dedicated server, a spectator */
SetLocalCompany(dedicated_server ? COMPANY_SPECTATOR : GetFirstPlayableCompanyID());
* or, in the case of starting as spectator or a dedicated server, a spectator. */
SetLocalCompany((dedicated_server || _settings_client.gui.start_spectator) ? COMPANY_SPECTATOR : GetFirstPlayableCompanyID());
NetworkOnGameStart();
@ -862,23 +862,25 @@ static void MakeNewGameDone()
return;
}
/* Create a single company */
DoStartupNewCompany(false);
if (!_settings_client.gui.start_spectator) {
/* Create a single company */
DoStartupNewCompany(false);
Company *c = Company::Get(CompanyID::Begin());
c->settings = _settings_client.company;
Company *c = Company::Get(CompanyID::Begin());
c->settings = _settings_client.company;
/* Overwrite color from settings if needed
* COLOUR_END corresponds to Random colour */
/* Overwrite color from settings if needed
* COLOUR_END corresponds to Random colour */
if (_settings_client.gui.starting_colour != COLOUR_END) {
c->colour = _settings_client.gui.starting_colour;
ResetCompanyLivery(c);
_company_colours[c->index] = c->colour;
}
if (_settings_client.gui.starting_colour != COLOUR_END) {
c->colour = _settings_client.gui.starting_colour;
ResetCompanyLivery(c);
_company_colours[c->index] = c->colour;
}
if (_settings_client.gui.starting_colour_secondary != COLOUR_END && HasBit(_loaded_newgrf_features.used_liveries, LS_DEFAULT)) {
Command<CMD_SET_COMPANY_COLOUR>::Post(LS_DEFAULT, false, _settings_client.gui.starting_colour_secondary);
if (_settings_client.gui.starting_colour_secondary != COLOUR_END && HasBit(_loaded_newgrf_features.used_liveries, LS_DEFAULT)) {
Command<CMD_SET_COMPANY_COLOUR>::Post(LS_DEFAULT, false, _settings_client.gui.starting_colour_secondary);
}
}
OnStartGame(false);
@ -1231,6 +1233,7 @@ void StateGameLoop()
Layouter::ReduceLineCache();
bool valid_local_company = _game_mode != GM_EDITOR && !_networking && _settings_client.gui.start_spectator && Company::IsValidID(_local_company);
if (_game_mode == GM_EDITOR) {
BasePersistentStorageArray::SwitchMode(PSM_ENTER_GAMELOOP);
RunTileLoop();
@ -1281,6 +1284,10 @@ void StateGameLoop()
}
assert(IsLocalCompany());
if (valid_local_company && !Company::IsValidID(_local_company)) {
/* _local_company no longer exists due to bankruptcy. */
SetLocalCompany(COMPANY_SPECTATOR);
}
}
/** Interval for regular autosaves. Initialized at zero to disable till settings are loaded. */

View File

@ -3377,11 +3377,10 @@ bool AfterLoadGame()
* starting a new company. */
StartScripts();
/* If Load Scenario / New (Scenario) Game is used,
* a company does not exist yet. So create one here.
* 1 exception: network-games. Those can have 0 companies
* But this exception is not true for non-dedicated network servers! */
if (!_networking || (_networking && _network_server && !_network_dedicated)) {
/* If Load Scenario / New (Scenario) Game is used, a company does not exist yet.
* Create one here whenever start_spectator is disabled.
* 1 exception: dedicated network servers. Those can have 0 companies. */
if (!_settings_client.gui.start_spectator && !_networking || (_networking && _network_server && !_network_dedicated)) {
CompanyID first_human_company = GetFirstPlayableCompanyID();
if (!Company::IsValidID(first_human_company)) {
Company *c = DoStartupNewCompany(false, first_human_company);

View File

@ -1139,11 +1139,9 @@ struct ScriptDebugWindow : public Window {
this->SetWidgetDisabledState(WID_SCRD_SETTINGS, this->filter.script_debug_company == CompanyID::Invalid() ||
GetConfig(this->filter.script_debug_company)->GetConfigList()->empty());
extern CompanyID _local_company;
this->SetWidgetDisabledState(WID_SCRD_RELOAD_TOGGLE,
this->filter.script_debug_company == CompanyID::Invalid() ||
this->filter.script_debug_company == OWNER_DEITY ||
this->filter.script_debug_company == _local_company);
this->filter.script_debug_company == OWNER_DEITY);
this->SetWidgetDisabledState(WID_SCRD_CONTINUE_BTN, this->filter.script_debug_company == CompanyID::Invalid() ||
(this->filter.script_debug_company == OWNER_DEITY ? !Game::IsPaused() : !AI::IsPaused(this->filter.script_debug_company)));
}

View File

@ -230,6 +230,7 @@ struct GUISettings {
bool show_date_in_logs; ///< whether to show dates in console logs
bool newgrf_developer_tools; ///< activate NewGRF developer tools and allow modifying NewGRFs in an existing game
bool ai_developer_tools; ///< activate AI/GS developer tools
bool start_spectator; ///< activate a spectator slot in single player and initiate games as a spectator
bool scenario_developer; ///< activate scenario developer: allow modifying NewGRFs in an existing game
uint8_t settings_restriction_mode; ///< selected restriction mode in adv. settings GUI. @see RestrictionMode
bool newgrf_show_old_versions; ///< whether to show old versions in the NewGRF list

View File

@ -816,6 +816,12 @@ def = false
post_cb = [](auto) { InvalidateWindowClassesData(WC_GAME_OPTIONS); InvalidateWindowClassesData(WC_SCRIPT_DEBUG); InvalidateWindowClassesData(WC_SCRIPT_SETTINGS); }
cat = SC_EXPERT
[SDTC_BOOL]
var = gui.start_spectator
flags = SettingFlag::NotInSave, SettingFlag::NoNetworkSync
def = false
post_cb = [](auto) { InvalidateWindowClassesData(WC_COMPANY); }
[SDTC_BOOL]
var = gui.scenario_developer
flags = SettingFlag::NotInSave, SettingFlag::NoNetworkSync

View File

@ -141,6 +141,7 @@ static void PopupMainToolbarMenu(Window *w, WidgetID widget, const std::initiali
static const int CTMN_CLIENT_LIST = -1; ///< Show the client list
static const int CTMN_SPECTATE = -2; ///< Become spectator
static const int CTMN_SPECTATOR = -3; ///< Show a company window as spectator
static const int CTMN_NEW_COMPANY = -4; ///< Create a new company
/**
* Pop up a generic company list menu.
@ -154,8 +155,19 @@ static void PopupMainCompanyToolbMenu(Window *w, WidgetID widget, CompanyMask gr
switch (widget) {
case WID_TN_COMPANIES:
if (!_networking) break;
if (!_networking) {
if (_local_company == COMPANY_SPECTATOR) {
bool human = false;
for (CompanyID c = CompanyID::Begin(); c < MAX_COMPANIES; ++c) {
if (Company::IsValidHumanID(c)) {
human = true;
break;
}
}
if (!human) list.push_back(MakeDropDownListStringItem(STR_COMPANY_LIST_NEW_COMPANY, CTMN_NEW_COMPANY, Company::GetNumItems() >= MAX_COMPANIES));
}
break;
}
/* Add the client list button for the companies menu */
list.push_back(MakeDropDownListStringItem(STR_NETWORK_COMPANY_LIST_CLIENT_LIST, CTMN_CLIENT_LIST));
@ -594,6 +606,17 @@ static CallBackFunction MenuClickCompany(int index)
return CBF_NONE;
}
}
if (!_networking && _local_company == COMPANY_SPECTATOR) {
if (index == CTMN_NEW_COMPANY) {
extern Company *DoStartupNewCompany(bool is_ai, CompanyID company = CompanyID::Invalid());
Company *c = DoStartupNewCompany(false);
c->settings = _settings_client.company;
SetLocalCompany(c->index);
return CBF_NONE;
}
}
ShowCompany((CompanyID)index);
return CBF_NONE;
}