Files @ r27487:4d1c2a7bde00
Branch filter:

Location: cpp/openttd-patchpack/source/src/ai/ai_gui.cpp - annotation

Patric Stout
Codechange: remove queue_wrap / last_position from mouse movement

No backend uses it anymore, so also no longer any need to support
it.
r12768:980ae0491352
r12768:980ae0491352
r12768:980ae0491352
r12768:980ae0491352
r12768:980ae0491352
r12768:980ae0491352
r12768:980ae0491352
r18845:66bf168f1100
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r18617:524f2e0f54dc
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r11185:ac324a2379e8
r10840:7a608f4ad153
r22386:2ec8551a1144
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r20388:7a2f2cbf65ab
r10840:7a608f4ad153
r18510:9d33e9643f80
r26856:c988753485d9
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r21383:942c32fb8b0e
r21383:942c32fb8b0e
r19068:3e8bf48b7b8a
r15620:0378519ad922
r11486:edda18b2134e
r11486:edda18b2134e
r13742:180ad925befc
r26532:48cddf601bc5
r11486:edda18b2134e
r18673:e5a4490b411b
r13968:ef1d3e81523a
r18749:61ed9890edec
r27104:635f8101e375
r27104:635f8101e375
r13659:b0b84c1c2151
r26498:675708fb9285
r13659:b0b84c1c2151
r27104:635f8101e375
r27104:635f8101e375
r27104:635f8101e375
r27104:635f8101e375
r27104:635f8101e375
r27104:635f8101e375
r18749:61ed9890edec
r18673:e5a4490b411b
r18673:e5a4490b411b
r13968:ef1d3e81523a
r13659:b0b84c1c2151
r18749:61ed9890edec
r18749:61ed9890edec
r20507:d54715c529f7
r18749:61ed9890edec
r18749:61ed9890edec
r11486:edda18b2134e
r11486:edda18b2134e
r26532:48cddf601bc5
r26532:48cddf601bc5
r26532:48cddf601bc5
r26532:48cddf601bc5
r18749:61ed9890edec
r18749:61ed9890edec
r25190:c33b3edbcf73
r19068:3e8bf48b7b8a
r19068:3e8bf48b7b8a
r11486:edda18b2134e
r25190:c33b3edbcf73
r11486:edda18b2134e
r11486:edda18b2134e
r11486:edda18b2134e
r15620:0378519ad922
r20280:ca1fc41725ff
r20283:2a199c78224c
r10840:7a608f4ad153
r19745:d8f95208ad9e
r13554:d1964ead02ee
r11368:058349c3a02c
r10840:7a608f4ad153
r10840:7a608f4ad153
r10840:7a608f4ad153
r10840:7a608f4ad153
r10840:7a608f4ad153
r15620:0378519ad922
r15620:0378519ad922
r17616:3ed8a6b01283
r10840:7a608f4ad153
r20280:ca1fc41725ff
r10840:7a608f4ad153
r20280:ca1fc41725ff
r18673:e5a4490b411b
r12591:0f17c8004d0f
r18673:e5a4490b411b
r15769:4a935f419828
r15769:4a935f419828
r12591:0f17c8004d0f
r10840:7a608f4ad153
r10840:7a608f4ad153
r25564:c875d92c537a
r10840:7a608f4ad153
r26856:c988753485d9
r26856:c988753485d9
r25564:c875d92c537a
r10840:7a608f4ad153
r10840:7a608f4ad153
r23499:f9bf6ad58697
r12591:0f17c8004d0f
r13567:9f40d27b2fd6
r18673:e5a4490b411b
r16950:9855f8364bec
r13567:9f40d27b2fd6
r27104:635f8101e375
r27104:635f8101e375
r27104:635f8101e375
r27104:635f8101e375
r13659:b0b84c1c2151
r13659:b0b84c1c2151
r13567:9f40d27b2fd6
r23499:f9bf6ad58697
r13659:b0b84c1c2151
r13659:b0b84c1c2151
r27104:635f8101e375
r27104:635f8101e375
r27104:635f8101e375
r27104:635f8101e375
r26423:b2ef3bb21347
r26423:b2ef3bb21347
r26423:b2ef3bb21347
r18673:e5a4490b411b
r26563:75f924e74612
r25213:cae9268da683
r20508:eda733209ea3
r13567:9f40d27b2fd6
r12591:0f17c8004d0f
r12591:0f17c8004d0f
r12591:0f17c8004d0f
r16950:9855f8364bec
r16950:9855f8364bec
r16950:9855f8364bec
r16950:9855f8364bec
r16950:9855f8364bec
r16950:9855f8364bec
r16950:9855f8364bec
r16950:9855f8364bec
r16950:9855f8364bec
r16950:9855f8364bec
r23674:a5bafa1a02c5
r16950:9855f8364bec
r16950:9855f8364bec
r16950:9855f8364bec
r16950:9855f8364bec
r16950:9855f8364bec
r16950:9855f8364bec
r16950:9855f8364bec
r16950:9855f8364bec
r23499:f9bf6ad58697
r12591:0f17c8004d0f
r12591:0f17c8004d0f
r18673:e5a4490b411b
r26575:d5725bf82346
r15769:4a935f419828
r12591:0f17c8004d0f
r12591:0f17c8004d0f
r16950:9855f8364bec
r16950:9855f8364bec
r23607:36c15679007d
r12591:0f17c8004d0f
r12591:0f17c8004d0f
r12591:0f17c8004d0f
r12622:202e83a6cee7
r12591:0f17c8004d0f
r26549:82dacf005b0a
r16950:9855f8364bec
r26549:82dacf005b0a
r12591:0f17c8004d0f
r12591:0f17c8004d0f
r12591:0f17c8004d0f
r10840:7a608f4ad153
r10840:7a608f4ad153
r10840:7a608f4ad153
r23499:f9bf6ad58697
r10840:7a608f4ad153
r27371:b9ad4c1bff08
r26856:c988753485d9
r19068:3e8bf48b7b8a
r19068:3e8bf48b7b8a
r19068:3e8bf48b7b8a
r19068:3e8bf48b7b8a
r19068:3e8bf48b7b8a
r10840:7a608f4ad153
r27104:635f8101e375
r27104:635f8101e375
r13659:b0b84c1c2151
r27104:635f8101e375
r24597:afde5721a3b6
r13659:b0b84c1c2151
r24597:afde5721a3b6
r10853:44b4b13121cb
r13659:b0b84c1c2151
r10853:44b4b13121cb
r10853:44b4b13121cb
r10853:44b4b13121cb
r27104:635f8101e375
r27104:635f8101e375
r27104:635f8101e375
r27104:635f8101e375
r27104:635f8101e375
r27104:635f8101e375
r27104:635f8101e375
r27104:635f8101e375
r27104:635f8101e375
r27104:635f8101e375
r27104:635f8101e375
r27104:635f8101e375
r18673:e5a4490b411b
r25213:cae9268da683
r13159:03d1e6e6c70a
r27038:297671ffbe62
r10840:7a608f4ad153
r10840:7a608f4ad153
r10840:7a608f4ad153
r18673:e5a4490b411b
r16950:9855f8364bec
r16950:9855f8364bec
r13968:ef1d3e81523a
r15769:4a935f419828
r13968:ef1d3e81523a
r13968:ef1d3e81523a
r13968:ef1d3e81523a
r13968:ef1d3e81523a
r18673:e5a4490b411b
r16950:9855f8364bec
r16950:9855f8364bec
r13968:ef1d3e81523a
r15769:4a935f419828
r13968:ef1d3e81523a
r13968:ef1d3e81523a
r13968:ef1d3e81523a
r13968:ef1d3e81523a
r18673:e5a4490b411b
r27038:297671ffbe62
r10840:7a608f4ad153
r10840:7a608f4ad153
r18673:e5a4490b411b
r26856:c988753485d9
r10840:7a608f4ad153
r10840:7a608f4ad153
r18673:e5a4490b411b
r25564:c875d92c537a
r10840:7a608f4ad153
r13959:44bb928ae22d
r18673:e5a4490b411b
r13959:44bb928ae22d
r14635:a75264d517b7
r13959:44bb928ae22d
r26532:48cddf601bc5
r13959:44bb928ae22d
r13959:44bb928ae22d
r10840:7a608f4ad153
r10840:7a608f4ad153
r10840:7a608f4ad153
r17476:d3b7a183536d
r17476:d3b7a183536d
r17476:d3b7a183536d
r17476:d3b7a183536d
r17476:d3b7a183536d
r23499:f9bf6ad58697
r10840:7a608f4ad153
r16950:9855f8364bec
r13895:009db002ff3f
r13895:009db002ff3f
r13895:009db002ff3f
r17484:696d6356f836
r17484:696d6356f836
r27104:635f8101e375
r27104:635f8101e375
r27104:635f8101e375
r27104:635f8101e375
r26532:48cddf601bc5
r26856:c988753485d9
r26532:48cddf601bc5
r26532:48cddf601bc5
r19068:3e8bf48b7b8a
r27371:b9ad4c1bff08
r27259:59b91be38623
r19068:3e8bf48b7b8a
r10840:7a608f4ad153
r10840:7a608f4ad153
r10840:7a608f4ad153
r15620:0378519ad922
r10840:7a608f4ad153
r10840:7a608f4ad153
r25565:6a5de7df7ea1
r10840:7a608f4ad153
r10840:7a608f4ad153
r10840:7a608f4ad153
/*
 * 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/>.
 */

/** @file ai_gui.cpp %Window for configuring the AIs */

#include "../stdafx.h"
#include "../error.h"
#include "../company_base.h"
#include "../window_func.h"
#include "../network/network.h"
#include "../settings_func.h"
#include "../network/network_content.h"
#include "../core/geometry_func.hpp"

#include "ai.hpp"
#include "ai_gui.hpp"
#include "ai_config.hpp"
#include "ai_info.hpp"
#include "../script/script_gui.h"
#include "table/strings.h"

#include "../safeguards.h"


/** Widgets for the configure AI window. */
static const NWidgetPart _nested_ai_config_widgets[] = {
	NWidget(NWID_HORIZONTAL),
		NWidget(WWT_CLOSEBOX, COLOUR_MAUVE),
		NWidget(WWT_CAPTION, COLOUR_MAUVE), SetDataTip(STR_AI_CONFIG_CAPTION_AI, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
	EndContainer(),
	NWidget(WWT_PANEL, COLOUR_MAUVE, WID_AIC_BACKGROUND),
		NWidget(NWID_VERTICAL), SetPIP(4, 4, 4),
			NWidget(NWID_HORIZONTAL), SetPIP(7, 0, 7),
				NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_AIC_DECREASE_NUMBER), SetDataTip(AWV_DECREASE, STR_NULL),
				NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_AIC_INCREASE_NUMBER), SetDataTip(AWV_INCREASE, STR_NULL),
				NWidget(NWID_SPACER), SetMinimalSize(6, 0),
				NWidget(WWT_TEXT, COLOUR_MAUVE, WID_AIC_NUMBER), SetDataTip(STR_AI_CONFIG_MAX_COMPETITORS, STR_NULL), SetFill(1, 0),
			EndContainer(),
			NWidget(NWID_HORIZONTAL), SetPIP(7, 0, 7),
				NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_AIC_DECREASE_INTERVAL), SetDataTip(AWV_DECREASE, STR_NULL),
				NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_AIC_INCREASE_INTERVAL), SetDataTip(AWV_INCREASE, STR_NULL),
				NWidget(NWID_SPACER), SetMinimalSize(6, 0),
				NWidget(WWT_TEXT, COLOUR_MAUVE, WID_AIC_INTERVAL), SetDataTip(STR_AI_CONFIG_COMPETITORS_INTERVAL, STR_NULL), SetFill(1, 0),
			EndContainer(),
			NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7),
				NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_MOVE_UP), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_AI_CONFIG_MOVE_UP, STR_AI_CONFIG_MOVE_UP_TOOLTIP),
				NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_MOVE_DOWN), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_AI_CONFIG_MOVE_DOWN, STR_AI_CONFIG_MOVE_DOWN_TOOLTIP),
			EndContainer(),
		EndContainer(),
		NWidget(WWT_FRAME, COLOUR_MAUVE), SetDataTip(STR_AI_CONFIG_AI, STR_NULL), SetPadding(0, 5, 0, 5),
			NWidget(NWID_HORIZONTAL),
				NWidget(WWT_MATRIX, COLOUR_MAUVE, WID_AIC_LIST), SetMinimalSize(288, 112), SetFill(1, 0), SetMatrixDataTip(1, 8, STR_AI_CONFIG_AILIST_TOOLTIP), SetScrollbar(WID_AIC_SCROLLBAR),
				NWidget(NWID_VSCROLLBAR, COLOUR_MAUVE, WID_AIC_SCROLLBAR),
			EndContainer(),
		EndContainer(),
		NWidget(NWID_SPACER), SetMinimalSize(0, 9),
		NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7),
			NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_CHANGE), SetFill(1, 0), SetMinimalSize(93, 0), SetDataTip(STR_AI_CONFIG_CHANGE_AI, STR_AI_CONFIG_CHANGE_TOOLTIP),
			NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_CONFIGURE), SetFill(1, 0), SetMinimalSize(93, 0), SetDataTip(STR_AI_CONFIG_CONFIGURE, STR_AI_CONFIG_CONFIGURE_TOOLTIP),
			NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_NULL),
		EndContainer(),
		NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7),
			NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_CLOSE), SetFill(1, 0), SetMinimalSize(93, 0), SetDataTip(STR_AI_SETTINGS_CLOSE, STR_NULL),
			NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_NULL),
			NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_NULL),
		EndContainer(),
		NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_CONTENT_DOWNLOAD), SetFill(1, 0), SetMinimalSize(279, 0), SetPadding(0, 7, 9, 7), SetDataTip(STR_INTRO_ONLINE_CONTENT, STR_INTRO_TOOLTIP_ONLINE_CONTENT),
	EndContainer(),
};

/** Window definition for the configure AI window. */
static WindowDesc _ai_config_desc(
	WDP_CENTER, "settings_script_config", 0, 0,
	WC_GAME_OPTIONS, WC_NONE,
	0,
	_nested_ai_config_widgets, lengthof(_nested_ai_config_widgets)
);

/**
 * Window to configure which AIs will start.
 */
struct AIConfigWindow : public Window {
	CompanyID selected_slot; ///< The currently selected AI slot or \c INVALID_COMPANY.
	int line_height;         ///< Height of a single AI-name line.
	Scrollbar *vscroll;      ///< Cache of the vertical scrollbar.

	AIConfigWindow() : Window(&_ai_config_desc)
	{
		this->InitNested(WN_GAME_OPTIONS_AI); // Initializes 'this->line_height' as a side effect.
		this->vscroll = this->GetScrollbar(WID_AIC_SCROLLBAR);
		this->selected_slot = INVALID_COMPANY;
		NWidgetCore *nwi = this->GetWidget<NWidgetCore>(WID_AIC_LIST);
		this->vscroll->SetCapacity(nwi->current_y / this->line_height);
		this->vscroll->SetCount(MAX_COMPANIES);
		this->OnInvalidateData(0);
	}

	void Close() override
	{
		CloseWindowByClass(WC_SCRIPT_LIST);
		CloseWindowByClass(WC_SCRIPT_SETTINGS);
		this->Window::Close();
	}

	void SetStringParameters(int widget) const override
	{
		switch (widget) {
			case WID_AIC_NUMBER:
				SetDParam(0, GetGameSettings().difficulty.max_no_competitors);
				break;

			case WID_AIC_INTERVAL:
				SetDParam(0, GetGameSettings().difficulty.competitors_interval);
				break;
		}
	}

	void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
	{
		switch (widget) {
			case WID_AIC_DECREASE_NUMBER:
			case WID_AIC_INCREASE_NUMBER:
			case WID_AIC_DECREASE_INTERVAL:
			case WID_AIC_INCREASE_INTERVAL:
				*size = maxdim(*size, NWidgetScrollbar::GetHorizontalDimension());
				break;

			case WID_AIC_LIST:
				this->line_height = FONT_HEIGHT_NORMAL + padding.height;
				resize->height = this->line_height;
				size->height = 8 * this->line_height;
				break;
		}
	}

	/**
	 * Can the AI config in the given company slot be edited?
	 * @param slot The slot to query.
	 * @return True if and only if the given AI Config slot can e edited.
	 */
	static bool IsEditable(CompanyID slot)
	{
		if (_game_mode != GM_NORMAL) {
			return slot > 0 && slot <= GetGameSettings().difficulty.max_no_competitors;
		}
		if (Company::IsValidID(slot)) return false;

		int max_slot = GetGameSettings().difficulty.max_no_competitors;
		for (CompanyID cid = COMPANY_FIRST; cid < (CompanyID)max_slot && cid < MAX_COMPANIES; cid++) {
			if (Company::IsValidHumanID(cid)) max_slot++;
		}
		return slot < max_slot;
	}

	void DrawWidget(const Rect &r, int widget) const override
	{
		switch (widget) {
			case WID_AIC_LIST: {
				Rect tr = r.Shrink(WidgetDimensions::scaled.matrix);
				for (int i = this->vscroll->GetPosition(); this->vscroll->IsVisible(i) && i < MAX_COMPANIES; i++) {
					StringID text;

					if ((_game_mode != GM_NORMAL && i == 0) || (_game_mode == GM_NORMAL && Company::IsValidHumanID(i))) {
						text = STR_AI_CONFIG_HUMAN_PLAYER;
					} else if (AIConfig::GetConfig((CompanyID)i)->GetInfo() != nullptr) {
						SetDParamStr(0, AIConfig::GetConfig((CompanyID)i)->GetInfo()->GetName());
						text = STR_JUST_RAW_STRING;
					} else {
						text = STR_AI_CONFIG_RANDOM_AI;
					}
					DrawString(tr, text,
							(this->selected_slot == i) ? TC_WHITE : (IsEditable((CompanyID)i) ? TC_ORANGE : TC_SILVER));
					tr.top += this->line_height;
				}
				break;
			}
		}
	}

	void OnClick(Point pt, int widget, int click_count) override
	{
		if (widget >= WID_AIC_TEXTFILE && widget < WID_AIC_TEXTFILE + TFT_CONTENT_END) {
			if (this->selected_slot == INVALID_COMPANY || AIConfig::GetConfig(this->selected_slot) == nullptr) return;

			ShowScriptTextfileWindow((TextfileType)(widget - WID_AIC_TEXTFILE), this->selected_slot);
			return;
		}

		switch (widget) {
			case WID_AIC_DECREASE_NUMBER:
			case WID_AIC_INCREASE_NUMBER: {
				int new_value;
				if (widget == WID_AIC_DECREASE_NUMBER) {
					new_value = std::max(0, GetGameSettings().difficulty.max_no_competitors - 1);
				} else {
					new_value = std::min(MAX_COMPANIES - 1, GetGameSettings().difficulty.max_no_competitors + 1);
				}
				IConsoleSetSetting("difficulty.max_no_competitors", new_value);
				break;
			}

			case WID_AIC_DECREASE_INTERVAL:
			case WID_AIC_INCREASE_INTERVAL: {
				int new_value;
				if (widget == WID_AIC_DECREASE_INTERVAL) {
					new_value = std::max(static_cast<int>(MIN_COMPETITORS_INTERVAL), GetGameSettings().difficulty.competitors_interval - 1);
				} else {
					new_value = std::min(static_cast<int>(MAX_COMPETITORS_INTERVAL), GetGameSettings().difficulty.competitors_interval + 1);
				}
				IConsoleSetSetting("difficulty.competitors_interval", new_value);
				break;
			}

			case WID_AIC_LIST: { // Select a slot
				this->selected_slot = (CompanyID)this->vscroll->GetScrolledRowFromWidget(pt.y, this, widget);
				this->InvalidateData();
				if (click_count > 1 && this->selected_slot != INVALID_COMPANY) ShowScriptListWindow((CompanyID)this->selected_slot, _ctrl_pressed);
				break;
			}

			case WID_AIC_MOVE_UP:
				if (IsEditable(this->selected_slot) && IsEditable((CompanyID)(this->selected_slot - 1))) {
					Swap(GetGameSettings().ai_config[this->selected_slot], GetGameSettings().ai_config[this->selected_slot - 1]);
					this->selected_slot--;
					this->vscroll->ScrollTowards(this->selected_slot);
					this->InvalidateData();
				}
				break;

			case WID_AIC_MOVE_DOWN:
				if (IsEditable(this->selected_slot) && IsEditable((CompanyID)(this->selected_slot + 1))) {
					Swap(GetGameSettings().ai_config[this->selected_slot], GetGameSettings().ai_config[this->selected_slot + 1]);
					this->selected_slot++;
					this->vscroll->ScrollTowards(this->selected_slot);
					this->InvalidateData();
				}
				break;

			case WID_AIC_CHANGE:  // choose other AI
				ShowScriptListWindow((CompanyID)this->selected_slot, _ctrl_pressed);
				break;

			case WID_AIC_CONFIGURE: // change the settings for an AI
				ShowScriptSettingsWindow((CompanyID)this->selected_slot);
				break;

			case WID_AIC_CLOSE:
				this->Close();
				break;

			case WID_AIC_CONTENT_DOWNLOAD:
				if (!_network_available) {
					ShowErrorMessage(STR_NETWORK_ERROR_NOTAVAILABLE, INVALID_STRING_ID, WL_ERROR);
				} else {
					ShowNetworkContentListWindow(nullptr, CONTENT_TYPE_AI);
				}
				break;
		}
	}

	/**
	 * Some data on this window has become invalid.
	 * @param data Information about the changed data.
	 * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details.
	 */
	void OnInvalidateData(int data = 0, bool gui_scope = true) override
	{
		if (!IsEditable(this->selected_slot)) {
			this->selected_slot = INVALID_COMPANY;
		}

		if (!gui_scope) return;

		this->SetWidgetDisabledState(WID_AIC_DECREASE_NUMBER, GetGameSettings().difficulty.max_no_competitors == 0);
		this->SetWidgetDisabledState(WID_AIC_INCREASE_NUMBER, GetGameSettings().difficulty.max_no_competitors == MAX_COMPANIES - 1);
		this->SetWidgetDisabledState(WID_AIC_DECREASE_INTERVAL, GetGameSettings().difficulty.competitors_interval == MIN_COMPETITORS_INTERVAL);
		this->SetWidgetDisabledState(WID_AIC_INCREASE_INTERVAL, GetGameSettings().difficulty.competitors_interval == MAX_COMPETITORS_INTERVAL);
		this->SetWidgetDisabledState(WID_AIC_CHANGE, this->selected_slot == INVALID_COMPANY);
		this->SetWidgetDisabledState(WID_AIC_CONFIGURE, this->selected_slot == INVALID_COMPANY || AIConfig::GetConfig(this->selected_slot)->GetConfigList()->size() == 0);
		this->SetWidgetDisabledState(WID_AIC_MOVE_UP, this->selected_slot == INVALID_COMPANY || !IsEditable((CompanyID)(this->selected_slot - 1)));
		this->SetWidgetDisabledState(WID_AIC_MOVE_DOWN, this->selected_slot == INVALID_COMPANY || !IsEditable((CompanyID)(this->selected_slot + 1)));

		for (TextfileType tft = TFT_CONTENT_BEGIN; tft < TFT_CONTENT_END; tft++) {
			this->SetWidgetDisabledState(WID_AIC_TEXTFILE + tft, this->selected_slot == INVALID_COMPANY || !AIConfig::GetConfig(this->selected_slot)->GetTextfile(tft, this->selected_slot).has_value());
		}
	}
};

/** Open the AI config window. */
void ShowAIConfigWindow()
{
	CloseWindowByClass(WC_GAME_OPTIONS);
	new AIConfigWindow();
}