File diff r25885:43fa080bc3b4 → r25886:4a328504ff89
src/network/network_gui.cpp
Show inline comments
 
@@ -53,7 +53,6 @@
 
#include "../safeguards.h"
 

	
 
static void ShowNetworkStartServerWindow();
 
static void ShowNetworkLobbyWindow(NetworkGameList *ngl);
 

	
 
static const int NETWORK_LIST_REFRESH_DELAY = 30; ///< Time, in seconds, between updates of the network list.
 

	
 
@@ -770,7 +769,7 @@ public:
 

	
 
			case WID_NG_JOIN: // Join Game
 
				if (this->server != nullptr) {
 
					ShowNetworkLobbyWindow(this->server);
 
					NetworkClientConnectGame(this->server->connection_string, COMPANY_SPECTATOR);
 
				}
 
				break;
 

	
 
@@ -990,7 +989,6 @@ static WindowDesc _network_game_window_d
 
void ShowNetworkGameWindow()
 
{
 
	static bool first = true;
 
	CloseWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_LOBBY);
 
	CloseWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_START);
 

	
 
	/* Only show once */
 
@@ -1266,328 +1264,10 @@ static void ShowNetworkStartServerWindow
 
	if (!NetworkValidateOurClientName()) return;
 

	
 
	CloseWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_GAME);
 
	CloseWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_LOBBY);
 

	
 
	new NetworkStartServerWindow(&_network_start_server_window_desc);
 
}
 

	
 
struct NetworkLobbyWindow : public Window {
 
	CompanyID company;       ///< Selected company
 
	NetworkGameList *server; ///< Selected server
 
	NetworkCompanyInfo company_info[MAX_COMPANIES];
 
	Scrollbar *vscroll;
 

	
 
	NetworkLobbyWindow(WindowDesc *desc, NetworkGameList *ngl) :
 
			Window(desc), company(INVALID_COMPANY), server(ngl)
 
	{
 
		this->CreateNestedTree();
 
		this->vscroll = this->GetScrollbar(WID_NL_SCROLLBAR);
 
		this->FinishInitNested(WN_NETWORK_WINDOW_LOBBY);
 
	}
 

	
 
	CompanyID NetworkLobbyFindCompanyIndex(byte pos) const
 
	{
 
		/* Scroll through all this->company_info and get the 'pos' item that is not empty. */
 
		for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) {
 
			if (!this->company_info[i].company_name.empty()) {
 
				if (pos-- == 0) return i;
 
			}
 
		}
 

	
 
		return COMPANY_FIRST;
 
	}
 

	
 
	void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
 
	{
 
		switch (widget) {
 
			case WID_NL_HEADER:
 
				size->height = WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM;
 
				break;
 

	
 
			case WID_NL_MATRIX:
 
				resize->height = WD_MATRIX_TOP + std::max<uint>(std::max(GetSpriteSize(SPR_LOCK).height, GetSpriteSize(SPR_PROFIT_LOT).height), FONT_HEIGHT_NORMAL) + WD_MATRIX_BOTTOM;
 
				size->height = 10 * resize->height;
 
				break;
 

	
 
			case WID_NL_DETAILS:
 
				size->height = 30 + 11 * FONT_HEIGHT_NORMAL;
 
				break;
 
		}
 
	}
 

	
 
	void SetStringParameters(int widget) const override
 
	{
 
		switch (widget) {
 
			case WID_NL_TEXT:
 
				SetDParamStr(0, this->server->info.server_name);
 
				break;
 
		}
 
	}
 

	
 
	void DrawWidget(const Rect &r, int widget) const override
 
	{
 
		switch (widget) {
 
			case WID_NL_DETAILS:
 
				this->DrawDetails(r);
 
				break;
 

	
 
			case WID_NL_MATRIX:
 
				this->DrawMatrix(r);
 
				break;
 
		}
 
	}
 

	
 
	void OnPaint() override
 
	{
 
		const NetworkGameInfo *gi = &this->server->info;
 

	
 
		/* Join button is disabled when no company is selected and for AI companies. */
 
		this->SetWidgetDisabledState(WID_NL_JOIN, this->company == INVALID_COMPANY || GetLobbyCompanyInfo(this->company)->ai);
 
		/* Cannot start new company if there are too many. */
 
		this->SetWidgetDisabledState(WID_NL_NEW, gi->companies_on >= gi->companies_max);
 

	
 
		this->vscroll->SetCount(gi->companies_on);
 

	
 
		/* Draw window widgets */
 
		this->DrawWidgets();
 
	}
 

	
 
	void DrawMatrix(const Rect &r) const
 
	{
 
		bool rtl = _current_text_dir == TD_RTL;
 
		uint left = r.left + WD_FRAMERECT_LEFT;
 
		uint right = r.right - WD_FRAMERECT_RIGHT;
 
		uint text_offset = (this->resize.step_height - WD_MATRIX_TOP - WD_MATRIX_BOTTOM - FONT_HEIGHT_NORMAL) / 2 + WD_MATRIX_TOP;
 

	
 
		Dimension lock_size = GetSpriteSize(SPR_LOCK);
 
		int lock_width      = lock_size.width;
 
		int lock_y_offset   = (this->resize.step_height - WD_MATRIX_TOP - WD_MATRIX_BOTTOM - lock_size.height) / 2 + WD_MATRIX_TOP;
 

	
 
		Dimension profit_size = GetSpriteSize(SPR_PROFIT_LOT);
 
		int profit_width      = lock_size.width;
 
		int profit_y_offset   = (this->resize.step_height - WD_MATRIX_TOP - WD_MATRIX_BOTTOM - profit_size.height) / 2 + WD_MATRIX_TOP;
 

	
 
		uint text_left   = left  + (rtl ? lock_width + profit_width + 4 : 0);
 
		uint text_right  = right - (rtl ? 0 : lock_width + profit_width + 4);
 
		uint profit_left = rtl ? left : right - profit_width;
 
		uint lock_left   = rtl ? left + profit_width + 2 : right - profit_width - lock_width - 2;
 

	
 
		int y = r.top;
 
		/* Draw company list */
 
		int pos = this->vscroll->GetPosition();
 
		while (pos < this->server->info.companies_on) {
 
			byte company = NetworkLobbyFindCompanyIndex(pos);
 
			bool income = false;
 
			if (this->company == company) {
 
				GfxFillRect(r.left + WD_BEVEL_LEFT, y + 1, r.right - WD_BEVEL_RIGHT, y + this->resize.step_height - 2, PC_GREY);  // show highlighted item with a different colour
 
			}
 

	
 
			DrawString(text_left, text_right, y + text_offset, this->company_info[company].company_name, TC_BLACK);
 
			if (this->company_info[company].use_password != 0) DrawSprite(SPR_LOCK, PAL_NONE, lock_left, y + lock_y_offset);
 

	
 
			/* If the company's income was positive puts a green dot else a red dot */
 
			if (this->company_info[company].income >= 0) income = true;
 
			DrawSprite(income ? SPR_PROFIT_LOT : SPR_PROFIT_NEGATIVE, PAL_NONE, profit_left, y + profit_y_offset);
 

	
 
			pos++;
 
			y += this->resize.step_height;
 
			if (pos >= this->vscroll->GetPosition() + this->vscroll->GetCapacity()) break;
 
		}
 
	}
 

	
 
	void DrawDetails(const Rect &r) const
 
	{
 
		const int detail_height = 12 + FONT_HEIGHT_NORMAL + 12;
 
		/* Draw info about selected company when it is selected in the left window. */
 
		GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.top + detail_height - 1, PC_DARK_BLUE);
 
		DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + 12, STR_NETWORK_GAME_LOBBY_COMPANY_INFO, TC_FROMSTRING, SA_HOR_CENTER);
 

	
 
		if (this->company == INVALID_COMPANY || this->company_info[this->company].company_name.empty()) return;
 

	
 
		int y = r.top + detail_height + 4;
 
		const NetworkGameInfo *gi = &this->server->info;
 

	
 
		SetDParam(0, gi->clients_on);
 
		SetDParam(1, gi->clients_max);
 
		SetDParam(2, gi->companies_on);
 
		SetDParam(3, gi->companies_max);
 
		DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_CLIENTS);
 
		y += FONT_HEIGHT_NORMAL;
 

	
 
		SetDParamStr(0, this->company_info[this->company].company_name);
 
		DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_COMPANY_NAME);
 
		y += FONT_HEIGHT_NORMAL;
 

	
 
		SetDParam(0, this->company_info[this->company].inaugurated_year);
 
		DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_INAUGURATION_YEAR); // inauguration year
 
		y += FONT_HEIGHT_NORMAL;
 

	
 
		SetDParam(0, this->company_info[this->company].company_value);
 
		DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_VALUE); // company value
 
		y += FONT_HEIGHT_NORMAL;
 

	
 
		SetDParam(0, this->company_info[this->company].money);
 
		DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_CURRENT_BALANCE); // current balance
 
		y += FONT_HEIGHT_NORMAL;
 

	
 
		SetDParam(0, this->company_info[this->company].income);
 
		DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_LAST_YEARS_INCOME); // last year's income
 
		y += FONT_HEIGHT_NORMAL;
 

	
 
		SetDParam(0, this->company_info[this->company].performance);
 
		DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_PERFORMANCE); // performance
 
		y += FONT_HEIGHT_NORMAL;
 

	
 
		SetDParam(0, this->company_info[this->company].num_vehicle[NETWORK_VEH_TRAIN]);
 
		SetDParam(1, this->company_info[this->company].num_vehicle[NETWORK_VEH_LORRY]);
 
		SetDParam(2, this->company_info[this->company].num_vehicle[NETWORK_VEH_BUS]);
 
		SetDParam(3, this->company_info[this->company].num_vehicle[NETWORK_VEH_SHIP]);
 
		SetDParam(4, this->company_info[this->company].num_vehicle[NETWORK_VEH_PLANE]);
 
		DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_VEHICLES); // vehicles
 
		y += FONT_HEIGHT_NORMAL;
 

	
 
		SetDParam(0, this->company_info[this->company].num_station[NETWORK_VEH_TRAIN]);
 
		SetDParam(1, this->company_info[this->company].num_station[NETWORK_VEH_LORRY]);
 
		SetDParam(2, this->company_info[this->company].num_station[NETWORK_VEH_BUS]);
 
		SetDParam(3, this->company_info[this->company].num_station[NETWORK_VEH_SHIP]);
 
		SetDParam(4, this->company_info[this->company].num_station[NETWORK_VEH_PLANE]);
 
		DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_STATIONS); // stations
 
		y += FONT_HEIGHT_NORMAL;
 

	
 
		SetDParamStr(0, this->company_info[this->company].clients);
 
		DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_PLAYERS); // players
 
	}
 

	
 
	void OnClick(Point pt, int widget, int click_count) override
 
	{
 
		switch (widget) {
 
			case WID_NL_CANCEL:   // Cancel button
 
				ShowNetworkGameWindow();
 
				break;
 

	
 
			case WID_NL_MATRIX: { // Company list
 
				uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NL_MATRIX);
 
				this->company = (id_v >= this->server->info.companies_on) ? INVALID_COMPANY : NetworkLobbyFindCompanyIndex(id_v);
 
				this->SetDirty();
 

	
 
				/* FIXME the disabling should go into some InvalidateData, which is called instead of the SetDirty */
 
				if (click_count > 1 && !this->IsWidgetDisabled(WID_NL_JOIN)) this->OnClick(pt, WID_NL_JOIN, 1);
 
				break;
 
			}
 

	
 
			case WID_NL_JOIN:     // Join company
 
				/* Button can be clicked only when it is enabled. */
 
				NetworkClientConnectGame(this->server->connection_string, this->company);
 
				break;
 

	
 
			case WID_NL_NEW:      // New company
 
				NetworkClientConnectGame(this->server->connection_string, COMPANY_NEW_COMPANY);
 
				break;
 

	
 
			case WID_NL_SPECTATE: // Spectate game
 
				NetworkClientConnectGame(this->server->connection_string, COMPANY_SPECTATOR);
 
				break;
 

	
 
			case WID_NL_REFRESH:  // Refresh
 
				/* Clear the information so removed companies don't remain */
 
				for (auto &company : this->company_info) company = {};
 

	
 
				NetworkQueryLobbyServer(this->server->connection_string);
 
				break;
 
		}
 
	}
 

	
 
	void OnResize() override
 
	{
 
		this->vscroll->SetCapacityFromWidget(this, WID_NL_MATRIX);
 
	}
 
};
 

	
 
static const NWidgetPart _nested_network_lobby_window_widgets[] = {
 
	NWidget(NWID_HORIZONTAL),
 
		NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
 
		NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE), SetDataTip(STR_NETWORK_GAME_LOBBY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
 
	EndContainer(),
 
	NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NL_BACKGROUND),
 
		NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NL_TEXT), SetDataTip(STR_NETWORK_GAME_LOBBY_PREPARE_TO_JOIN, STR_NULL), SetResize(1, 0), SetPadding(10, 10, 0, 10),
 
		NWidget(NWID_SPACER), SetMinimalSize(0, 3),
 
		NWidget(NWID_HORIZONTAL), SetPIP(10, 0, 10),
 
			/* Company list. */
 
			NWidget(NWID_VERTICAL),
 
				NWidget(WWT_PANEL, COLOUR_WHITE, WID_NL_HEADER), SetMinimalSize(146, 0), SetResize(1, 0), SetFill(1, 0), EndContainer(),
 
				NWidget(WWT_MATRIX, COLOUR_LIGHT_BLUE, WID_NL_MATRIX), SetMinimalSize(146, 0), SetResize(1, 1), SetFill(1, 1), SetMatrixDataTip(1, 0, STR_NETWORK_GAME_LOBBY_COMPANY_LIST_TOOLTIP), SetScrollbar(WID_NL_SCROLLBAR),
 
			EndContainer(),
 
			NWidget(NWID_VSCROLLBAR, COLOUR_LIGHT_BLUE, WID_NL_SCROLLBAR),
 
			NWidget(NWID_SPACER), SetMinimalSize(5, 0), SetResize(0, 1),
 
			/* Company info. */
 
			NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NL_DETAILS), SetMinimalSize(232, 0), SetResize(1, 1), SetFill(1, 1), EndContainer(),
 
		EndContainer(),
 
		NWidget(NWID_SPACER), SetMinimalSize(0, 9),
 
		/* Buttons. */
 
		NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(10, 3, 10),
 
			NWidget(NWID_VERTICAL, NC_EQUALSIZE), SetPIP(0, 3, 0),
 
				NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NL_JOIN), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_GAME_LOBBY_JOIN_COMPANY, STR_NETWORK_GAME_LOBBY_JOIN_COMPANY_TOOLTIP),
 
				NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NL_NEW), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_GAME_LOBBY_NEW_COMPANY, STR_NETWORK_GAME_LOBBY_NEW_COMPANY_TOOLTIP),
 
			EndContainer(),
 
			NWidget(NWID_VERTICAL, NC_EQUALSIZE), SetPIP(0, 3, 0),
 
				NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NL_SPECTATE), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_GAME_LOBBY_SPECTATE_GAME, STR_NETWORK_GAME_LOBBY_SPECTATE_GAME_TOOLTIP),
 
				NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NL_REFRESH), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_REFRESH, STR_NETWORK_SERVER_LIST_REFRESH_TOOLTIP),
 
			EndContainer(),
 
			NWidget(NWID_VERTICAL, NC_EQUALSIZE), SetPIP(0, 3, 0),
 
				NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NL_CANCEL), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_BUTTON_CANCEL, STR_NULL),
 
				NWidget(NWID_SPACER), SetFill(1, 1),
 
			EndContainer(),
 
		EndContainer(),
 
		NWidget(NWID_SPACER), SetMinimalSize(0, 8),
 
	EndContainer(),
 
};
 

	
 
static WindowDesc _network_lobby_window_desc(
 
	WDP_CENTER, nullptr, 0, 0,
 
	WC_NETWORK_WINDOW, WC_NONE,
 
	0,
 
	_nested_network_lobby_window_widgets, lengthof(_nested_network_lobby_window_widgets)
 
);
 

	
 
/**
 
 * Show the networklobbywindow with the selected server.
 
 * @param ngl Selected game pointer which is passed to the new window.
 
 */
 
static void ShowNetworkLobbyWindow(NetworkGameList *ngl)
 
{
 
	if (!NetworkValidateOurClientName()) return;
 

	
 
	CloseWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_START);
 
	CloseWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_GAME);
 

	
 
	_settings_client.network.last_joined = ngl->connection_string;
 

	
 
	NetworkQueryLobbyServer(ngl->connection_string);
 

	
 
	new NetworkLobbyWindow(&_network_lobby_window_desc, ngl);
 
}
 

	
 
/**
 
 * Get the company information of a given company to fill for the lobby.
 
 * @param company the company to get the company info struct from.
 
 * @return the company info struct to write the (downloaded) data to.
 
 */
 
NetworkCompanyInfo *GetLobbyCompanyInfo(CompanyID company)
 
{
 
	NetworkLobbyWindow *lobby = dynamic_cast<NetworkLobbyWindow*>(FindWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_LOBBY));
 
	return (lobby != nullptr && company < MAX_COMPANIES) ? &lobby->company_info[company] : nullptr;
 
}
 

	
 
/**
 
 * Get the game information for the lobby.
 
 * @return the game info struct to write the (downloaded) data to.
 
 */
 
NetworkGameList *GetLobbyGameInfo()
 
{
 
	NetworkLobbyWindow *lobby = dynamic_cast<NetworkLobbyWindow *>(FindWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_LOBBY));
 
	return lobby != nullptr ? lobby->server : nullptr;
 
}
 

	
 
/* The window below gives information about the connected clients
 
 * and also makes able to kick them (if server) and stuff like that. */