src/network/network_gui.cpp
branchnoai
changeset 10829 8a0ec0f0f928
parent 10776 07203fc29812
child 10920 e33442a2b239
equal deleted inserted replaced
10804:a02ab0ca5ae9 10829:8a0ec0f0f928
     7 #include "../openttd.h"
     7 #include "../openttd.h"
     8 #include "../strings_func.h"
     8 #include "../strings_func.h"
     9 #include "network.h"
     9 #include "network.h"
    10 #include "../date_func.h"
    10 #include "../date_func.h"
    11 #include "../fios.h"
    11 #include "../fios.h"
    12 #include "network_data.h"
    12 #include "network_internal.h"
    13 #include "network_client.h"
    13 #include "network_client.h"
    14 #include "network_gui.h"
    14 #include "network_gui.h"
    15 #include "network_gamelist.h"
    15 #include "network_gamelist.h"
    16 #include "../gui.h"
    16 #include "../gui.h"
    17 #include "../window_gui.h"
    17 #include "../window_gui.h"
    36 #include "../table/sprites.h"
    36 #include "../table/sprites.h"
    37 
    37 
    38 #define BGC 5
    38 #define BGC 5
    39 #define BTC 15
    39 #define BTC 15
    40 
    40 
    41 /* Global to remember sorting after window has been closed */
       
    42 static Listing _ng_sorting;
       
    43 
       
    44 static bool _chat_tab_completion_active;
    41 static bool _chat_tab_completion_active;
    45 
    42 
    46 static void ShowNetworkStartServerWindow();
    43 static void ShowNetworkStartServerWindow();
    47 static void ShowNetworkLobbyWindow(NetworkGameList *ngl);
    44 static void ShowNetworkLobbyWindow(NetworkGameList *ngl);
    48 extern void SwitchMode(int new_mode);
    45 extern void SwitchMode(int new_mode);
    83  * found on the network.
    80  * found on the network.
    84  * @param unselect unselect the currently selected item */
    81  * @param unselect unselect the currently selected item */
    85 void UpdateNetworkGameWindow(bool unselect)
    82 void UpdateNetworkGameWindow(bool unselect)
    86 {
    83 {
    87 	InvalidateWindowData(WC_NETWORK_WINDOW, 0, unselect);
    84 	InvalidateWindowData(WC_NETWORK_WINDOW, 0, unselect);
    88 }
       
    89 
       
    90 static bool _internal_sort_order; // Used for Qsort order-flipping
       
    91 typedef int CDECL NGameNameSortFunction(const void*, const void*);
       
    92 
       
    93 /** Qsort function to sort by name. */
       
    94 static int CDECL NGameNameSorter(const void *a, const void *b)
       
    95 {
       
    96 	const NetworkGameList *cmp1 = *(const NetworkGameList**)a;
       
    97 	const NetworkGameList *cmp2 = *(const NetworkGameList**)b;
       
    98 	int r = strcasecmp(cmp1->info.server_name, cmp2->info.server_name);
       
    99 
       
   100 	return _internal_sort_order ? -r : r;
       
   101 }
       
   102 
       
   103 /** Qsort function to sort by the amount of clients online on a
       
   104  * server. If the two servers have the same amount, the one with the
       
   105  * higher maximum is preferred. */
       
   106 static int CDECL NGameClientSorter(const void *a, const void *b)
       
   107 {
       
   108 	const NetworkGameList *cmp1 = *(const NetworkGameList**)a;
       
   109 	const NetworkGameList *cmp2 = *(const NetworkGameList**)b;
       
   110 	/* Reverse as per default we are interested in most-clients first */
       
   111 	int r = cmp1->info.clients_on - cmp2->info.clients_on;
       
   112 
       
   113 	if (r == 0) r = cmp1->info.clients_max - cmp2->info.clients_max;
       
   114 	if (r == 0) r = strcasecmp(cmp1->info.server_name, cmp2->info.server_name);
       
   115 
       
   116 	return _internal_sort_order ? -r : r;
       
   117 }
       
   118 
       
   119 /** Qsort function to sort by joinability. If both servers are the
       
   120  * same, prefer the non-passworded server first. */
       
   121 static int CDECL NGameAllowedSorter(const void *a, const void *b)
       
   122 {
       
   123 	const NetworkGameList *cmp1 = *(const NetworkGameList**)a;
       
   124 	const NetworkGameList *cmp2 = *(const NetworkGameList**)b;
       
   125 
       
   126 	/* The servers we do not know anything about (the ones that did not reply) should be at the bottom) */
       
   127 	int r = StrEmpty(cmp1->info.server_revision) - StrEmpty(cmp2->info.server_revision);
       
   128 
       
   129 	/* Reverse default as we are interested in version-compatible clients first */
       
   130 	if (r == 0) r = cmp2->info.version_compatible - cmp1->info.version_compatible;
       
   131 	/* The version-compatible ones are then sorted with NewGRF compatible first, incompatible last */
       
   132 	if (r == 0) r = cmp2->info.compatible - cmp1->info.compatible;
       
   133 	/* Passworded servers should be below unpassworded servers */
       
   134 	if (r == 0) r = cmp1->info.use_password - cmp2->info.use_password;
       
   135 	/* Finally sort on the name of the server */
       
   136 	if (r == 0) r = strcasecmp(cmp1->info.server_name, cmp2->info.server_name);
       
   137 
       
   138 	return _internal_sort_order ? -r : r;
       
   139 }
    85 }
   140 
    86 
   141 /** Enum for NetworkGameWindow, referring to _network_game_window_widgets */
    87 /** Enum for NetworkGameWindow, referring to _network_game_window_widgets */
   142 enum NetworkGameWindowWidgets {
    88 enum NetworkGameWindowWidgets {
   143 	NGWW_CLOSE,         ///< Close 'X' button
    89 	NGWW_CLOSE,         ///< Close 'X' button
   169 	NGWW_CANCEL,        ///< 'Cancel' button
   115 	NGWW_CANCEL,        ///< 'Cancel' button
   170 };
   116 };
   171 
   117 
   172 typedef GUIList<NetworkGameList*> GUIGameServerList;
   118 typedef GUIList<NetworkGameList*> GUIGameServerList;
   173 
   119 
   174 struct NetworkGameWindow : public QueryStringBaseWindow {
   120 class NetworkGameWindow : public QueryStringBaseWindow {
       
   121 protected:
       
   122 	/* Runtime saved values */
       
   123 	static Listing last_sorting;
       
   124 
       
   125 	/* Constants for sorting servers */
       
   126 	static GUIGameServerList::SortFunction *const sorter_funcs[];
       
   127 
   175 	byte field;                  ///< selected text-field
   128 	byte field;                  ///< selected text-field
   176 	NetworkGameList *server;     ///< selected server
   129 	NetworkGameList *server;     ///< selected server
   177 	GUIGameServerList servers;   ///< list with game servers.
   130 	GUIGameServerList servers;   ///< list with game servers.
   178 
       
   179 	NetworkGameWindow(const WindowDesc *desc) : QueryStringBaseWindow(desc)
       
   180 	{
       
   181 		ttd_strlcpy(this->edit_str_buf, _network_player_name, lengthof(this->edit_str_buf));
       
   182 		this->afilter = CS_ALPHANUMERAL;
       
   183 		InitializeTextBuffer(&this->text, this->edit_str_buf, lengthof(this->edit_str_buf), 120);
       
   184 
       
   185 		UpdateNetworkGameWindow(true);
       
   186 
       
   187 		this->vscroll.cap = 11;
       
   188 		this->resize.step_height = NET_PRC__SIZE_OF_ROW;
       
   189 
       
   190 		this->field = NGWW_PLAYER;
       
   191 		this->server = NULL;
       
   192 
       
   193 		this->servers.flags = VL_REBUILD | (_ng_sorting.order ? VL_DESC : VL_NONE);
       
   194 		this->servers.sort_type = _ng_sorting.criteria;
       
   195 
       
   196 		this->FindWindowPlacementAndResize(desc);
       
   197 	}
       
   198 
       
   199 	~NetworkGameWindow()
       
   200 	{
       
   201 	}
       
   202 
   131 
   203 	/**
   132 	/**
   204 	 * (Re)build the network game list as its amount has changed because
   133 	 * (Re)build the network game list as its amount has changed because
   205 	 * an item has been added or deleted for example
   134 	 * an item has been added or deleted for example
   206 	 */
   135 	 */
   207 	void BuildNetworkGameList()
   136 	void BuildNetworkGameList()
   208 	{
   137 	{
   209 		if (!(this->servers.flags & VL_REBUILD)) return;
   138 		if (!this->servers.NeedRebuild()) return;
   210 
   139 
   211 		/* Create temporary array of games to use for listing */
   140 		/* Create temporary array of games to use for listing */
   212 		this->servers.Clear();
   141 		this->servers.Clear();
   213 
   142 
   214 		for (NetworkGameList *ngl = _network_game_list; ngl != NULL; ngl = ngl->next) {
   143 		for (NetworkGameList *ngl = _network_game_list; ngl != NULL; ngl = ngl->next) {
   215 			*this->servers.Append() = ngl;
   144 			*this->servers.Append() = ngl;
   216 		}
   145 		}
   217 
   146 
   218 		this->servers.Compact();
   147 		this->servers.Compact();
   219 
   148 		this->servers.RebuildDone();
   220 		/* Force resort */
   149 	}
   221 		this->servers.flags &= ~VL_REBUILD;
   150 
   222 		this->servers.flags |= VL_RESORT;
   151 	/** Sort servers by name. */
   223 	}
   152 	static int CDECL NGameNameSorter(NetworkGameList* const *a, NetworkGameList* const *b)
   224 
   153 	{
       
   154 		return strcasecmp((*a)->info.server_name, (*b)->info.server_name);
       
   155 	}
       
   156 
       
   157 	/** Sort servers by the amount of clients online on a
       
   158 	 * server. If the two servers have the same amount, the one with the
       
   159 	 * higher maximum is preferred. */
       
   160 	static int CDECL NGameClientSorter(NetworkGameList* const *a, NetworkGameList* const *b)
       
   161 	{
       
   162 		/* Reverse as per default we are interested in most-clients first */
       
   163 		int r = (*a)->info.clients_on - (*b)->info.clients_on;
       
   164 
       
   165 		if (r == 0) r = (*a)->info.clients_max - (*b)->info.clients_max;
       
   166 		if (r == 0) r = NGameNameSorter(a, b);
       
   167 
       
   168 		return r;
       
   169 	}
       
   170 
       
   171 	/** Sort servers by joinability. If both servers are the
       
   172 	 * same, prefer the non-passworded server first. */
       
   173 	static int CDECL NGameAllowedSorter(NetworkGameList* const *a, NetworkGameList* const *b)
       
   174 	{
       
   175 		/* The servers we do not know anything about (the ones that did not reply) should be at the bottom) */
       
   176 		int r = StrEmpty((*a)->info.server_revision) - StrEmpty((*b)->info.server_revision);
       
   177 
       
   178 		/* Reverse default as we are interested in version-compatible clients first */
       
   179 		if (r == 0) r = (*b)->info.version_compatible - (*a)->info.version_compatible;
       
   180 		/* The version-compatible ones are then sorted with NewGRF compatible first, incompatible last */
       
   181 		if (r == 0) r = (*b)->info.compatible - (*a)->info.compatible;
       
   182 		/* Passworded servers should be below unpassworded servers */
       
   183 		if (r == 0) r = (*a)->info.use_password - (*b)->info.use_password;
       
   184 		/* Finally sort on the name of the server */
       
   185 		if (r == 0) r = NGameNameSorter(a, b);
       
   186 
       
   187 		return r;
       
   188 	}
       
   189 
       
   190 	/** Sort the server list */
   225 	void SortNetworkGameList()
   191 	void SortNetworkGameList()
   226 	{
   192 	{
   227 		static NGameNameSortFunction * const ngame_sorter[] = {
   193 		if (!this->servers.Sort()) return;
   228 			&NGameNameSorter,
       
   229 			&NGameClientSorter,
       
   230 			&NGameAllowedSorter
       
   231 		};
       
   232 
       
   233 		NetworkGameList *item;
       
   234 		uint i;
       
   235 
       
   236 		if (!(this->servers.flags & VL_RESORT)) return;
       
   237 		if (this->servers.Length() == 0) return;
       
   238 
       
   239 		_internal_sort_order = !!(this->servers.flags & VL_DESC);
       
   240 		qsort(this->servers.Begin(), this->servers.Length(), sizeof(*this->servers.Begin()), ngame_sorter[this->servers.sort_type]);
       
   241 
   194 
   242 		/* After sorting ngl->sort_list contains the sorted items. Put these back
   195 		/* After sorting ngl->sort_list contains the sorted items. Put these back
   243 		 * into the original list. Basically nothing has changed, we are only
   196 		 * into the original list. Basically nothing has changed, we are only
   244 		 * shuffling the ->next pointers */
   197 		 * shuffling the ->next pointers */
   245 		_network_game_list = this->servers[0];
   198 		_network_game_list = this->servers[0];
   246 		for (item = _network_game_list, i = 1; i != this->servers.Length(); i++) {
   199 		NetworkGameList *item = _network_game_list;
       
   200 		for (uint i = 1; i != this->servers.Length(); i++) {
   247 			item->next = this->servers[i];
   201 			item->next = this->servers[i];
   248 			item = item->next;
   202 			item = item->next;
   249 		}
   203 		}
   250 		item->next = NULL;
   204 		item->next = NULL;
   251 
       
   252 		this->servers.flags &= ~VL_RESORT;
       
   253 	}
   205 	}
   254 
   206 
   255 	/**
   207 	/**
   256 	 * Draw a single server line.
   208 	 * Draw a single server line.
   257 	 * @param cur_item  the server to draw.
   209 	 * @param cur_item  the server to draw.
   283 			/* draw flag according to server language */
   235 			/* draw flag according to server language */
   284 			DrawSprite(SPR_FLAGS_BASE + cur_item->info.server_lang, PAL_NONE, this->widget[NGWW_INFO].left + 25, y);
   236 			DrawSprite(SPR_FLAGS_BASE + cur_item->info.server_lang, PAL_NONE, this->widget[NGWW_INFO].left + 25, y);
   285 		}
   237 		}
   286 	}
   238 	}
   287 
   239 
       
   240 public:
       
   241 	NetworkGameWindow(const WindowDesc *desc) : QueryStringBaseWindow(desc)
       
   242 	{
       
   243 		ttd_strlcpy(this->edit_str_buf, _settings_client.network.player_name, lengthof(this->edit_str_buf));
       
   244 		this->afilter = CS_ALPHANUMERAL;
       
   245 		InitializeTextBuffer(&this->text, this->edit_str_buf, lengthof(this->edit_str_buf), 120);
       
   246 
       
   247 		UpdateNetworkGameWindow(true);
       
   248 
       
   249 		this->vscroll.cap = 11;
       
   250 		this->resize.step_height = NET_PRC__SIZE_OF_ROW;
       
   251 
       
   252 		this->field = NGWW_PLAYER;
       
   253 		this->server = NULL;
       
   254 
       
   255 		this->servers.SetListing(this->last_sorting);
       
   256 		this->servers.SetSortFuncs(this->sorter_funcs);
       
   257 		this->servers.ForceRebuild();
       
   258 		this->SortNetworkGameList();
       
   259 
       
   260 		this->FindWindowPlacementAndResize(desc);
       
   261 	}
       
   262 
       
   263 	~NetworkGameWindow()
       
   264 	{
       
   265 		this->last_sorting = this->servers.GetListing();
       
   266 	}
       
   267 
   288 	virtual void OnPaint()
   268 	virtual void OnPaint()
   289 	{
   269 	{
   290 		const NetworkGameList *sel = this->server;
   270 		const NetworkGameList *sel = this->server;
   291 		const SortButtonState arrow = (this->servers.flags & VL_DESC) ? SBS_DOWN : SBS_UP;
   271 		const SortButtonState arrow = this->servers.IsDescSortOrder() ? SBS_DOWN : SBS_UP;
   292 
   272 
   293 		if (this->servers.flags & VL_REBUILD) {
   273 		if (this->servers.NeedRebuild()) {
   294 			this->BuildNetworkGameList();
   274 			this->BuildNetworkGameList();
   295 			SetVScrollCount(this, this->servers.Length());
   275 			SetVScrollCount(this, this->servers.Length());
   296 		}
   276 		}
   297 		if (this->servers.flags & VL_RESORT) this->SortNetworkGameList();
   277 		this->SortNetworkGameList();
   298 
   278 
   299 		/* 'Refresh' button invisible if no server selected */
   279 		/* 'Refresh' button invisible if no server selected */
   300 		this->SetWidgetDisabledState(NGWW_REFRESH, sel == NULL);
   280 		this->SetWidgetDisabledState(NGWW_REFRESH, sel == NULL);
   301 		/* 'Join' button disabling conditions */
   281 		/* 'Join' button disabling conditions */
   302 		this->SetWidgetDisabledState(NGWW_JOIN, sel == NULL || // no Selected Server
   282 		this->SetWidgetDisabledState(NGWW_JOIN, sel == NULL || // no Selected Server
   308 		this->SetWidgetHiddenState(NGWW_NEWGRF, sel == NULL ||
   288 		this->SetWidgetHiddenState(NGWW_NEWGRF, sel == NULL ||
   309 				!sel->online ||
   289 				!sel->online ||
   310 				sel->info.grfconfig == NULL);
   290 				sel->info.grfconfig == NULL);
   311 
   291 
   312 		SetDParam(0, 0x00);
   292 		SetDParam(0, 0x00);
   313 		SetDParam(1, _lan_internet_types_dropdown[_network_lan_internet]);
   293 		SetDParam(1, _lan_internet_types_dropdown[_settings_client.network.lan_internet]);
   314 		this->DrawWidgets();
   294 		this->DrawWidgets();
   315 
   295 
   316 		/* Edit box to set player name */
   296 		/* Edit box to set player name */
   317 		this->DrawEditBox(NGWW_PLAYER);
   297 		this->DrawEditBox(NGWW_PLAYER);
   318 
   298 
   319 		DrawString(this->widget[NGWW_PLAYER].left - 100, 23, STR_NETWORK_PLAYER_NAME, TC_GOLD);
   299 		DrawString(this->widget[NGWW_PLAYER].left - 100, 23, STR_NETWORK_PLAYER_NAME, TC_GOLD);
   320 
   300 
   321 		/* Sort based on widgets: name, clients, compatibility */
   301 		/* Sort based on widgets: name, clients, compatibility */
   322 		switch (this->servers.sort_type) {
   302 		switch (this->servers.SortType()) {
   323 			case NGWW_NAME    - NGWW_NAME: this->DrawSortButtonState(NGWW_NAME,    arrow); break;
   303 			case NGWW_NAME    - NGWW_NAME: this->DrawSortButtonState(NGWW_NAME,    arrow); break;
   324 			case NGWW_CLIENTS - NGWW_NAME: this->DrawSortButtonState(NGWW_CLIENTS, arrow); break;
   304 			case NGWW_CLIENTS - NGWW_NAME: this->DrawSortButtonState(NGWW_CLIENTS, arrow); break;
   325 			case NGWW_INFO    - NGWW_NAME: this->DrawSortButtonState(NGWW_INFO,    arrow); break;
   305 			case NGWW_INFO    - NGWW_NAME: this->DrawSortButtonState(NGWW_INFO,    arrow); break;
   326 		}
   306 		}
   327 
   307 
   328 		uint16 y = NET_PRC__OFFSET_TOP_WIDGET + 3;
   308 		uint16 y = NET_PRC__OFFSET_TOP_WIDGET + 3;
   329 		int32 n = 0;
   309 
   330 		int32 pos = this->vscroll.pos;
   310 		const int max = min(this->vscroll.pos + this->vscroll.cap, (int)this->servers.Length());
   331 		const NetworkGameList *cur_item = _network_game_list;
   311 
   332 
   312 		for (int i = this->vscroll.pos; i < max; ++i) {
   333 		while (pos > 0 && cur_item != NULL) {
   313 			const NetworkGameList *ngl = this->servers[i];
   334 			pos--;
   314 			this->DrawServerLine(ngl, y, ngl == sel);
   335 			cur_item = cur_item->next;
       
   336 		}
       
   337 
       
   338 		while (cur_item != NULL) {
       
   339 			this->DrawServerLine(cur_item, y, cur_item == sel);
       
   340 
       
   341 			cur_item = cur_item->next;
       
   342 			y += NET_PRC__SIZE_OF_ROW;
   315 			y += NET_PRC__SIZE_OF_ROW;
   343 			if (++n == this->vscroll.cap) break; // max number of games in the window
   316 		}
   344 		}
   317 
   345 
   318 		const NetworkGameList *last_joined = NetworkGameListAddItem(inet_addr(_settings_client.network.last_host), _settings_client.network.last_port);
   346 		const NetworkGameList *last_joined = NetworkGameListAddItem(inet_addr(_network_last_host), _network_last_port);
       
   347 		/* Draw the last joined server, if any */
   319 		/* Draw the last joined server, if any */
   348 		if (last_joined != NULL) this->DrawServerLine(last_joined, y = this->widget[NGWW_LASTJOINED].top + 3, last_joined == sel);
   320 		if (last_joined != NULL) this->DrawServerLine(last_joined, y = this->widget[NGWW_LASTJOINED].top + 3, last_joined == sel);
   349 
   321 
   350 		/* Draw the right menu */
   322 		/* Draw the right menu */
   351 		GfxFillRect(this->widget[NGWW_DETAILS].left + 1, 43, this->widget[NGWW_DETAILS].right - 1, 92, 157);
   323 		GfxFillRect(this->widget[NGWW_DETAILS].left + 1, 43, this->widget[NGWW_DETAILS].right - 1, 92, 157);
   409 			y += 2;
   381 			y += 2;
   410 
   382 
   411 			if (!sel->info.compatible) {
   383 			if (!sel->info.compatible) {
   412 				DrawStringCentered(this->widget[NGWW_DETAILS].left + 115, y, sel->info.version_compatible ? STR_NETWORK_GRF_MISMATCH : STR_NETWORK_VERSION_MISMATCH, TC_FROMSTRING); // server mismatch
   384 				DrawStringCentered(this->widget[NGWW_DETAILS].left + 115, y, sel->info.version_compatible ? STR_NETWORK_GRF_MISMATCH : STR_NETWORK_VERSION_MISMATCH, TC_FROMSTRING); // server mismatch
   413 			} else if (sel->info.clients_on == sel->info.clients_max) {
   385 			} else if (sel->info.clients_on == sel->info.clients_max) {
   414 				/* Show: server full, when clients_on == clients_max */
   386 				/* Show: server full, when clients_on == max_clients */
   415 				DrawStringCentered(this->widget[NGWW_DETAILS].left + 115, y, STR_NETWORK_SERVER_FULL, TC_FROMSTRING); // server full
   387 				DrawStringCentered(this->widget[NGWW_DETAILS].left + 115, y, STR_NETWORK_SERVER_FULL, TC_FROMSTRING); // server full
   416 			} else if (sel->info.use_password) {
   388 			} else if (sel->info.use_password) {
   417 				DrawStringCentered(this->widget[NGWW_DETAILS].left + 115, y, STR_NETWORK_PASSWORD, TC_FROMSTRING); // password warning
   389 				DrawStringCentered(this->widget[NGWW_DETAILS].left + 115, y, STR_NETWORK_PASSWORD, TC_FROMSTRING); // password warning
   418 			}
   390 			}
   419 
   391 
   432 			case NGWW_CANCEL: // Cancel button
   404 			case NGWW_CANCEL: // Cancel button
   433 				DeleteWindowById(WC_NETWORK_WINDOW, 0);
   405 				DeleteWindowById(WC_NETWORK_WINDOW, 0);
   434 				break;
   406 				break;
   435 
   407 
   436 			case NGWW_CONN_BTN: // 'Connection' droplist
   408 			case NGWW_CONN_BTN: // 'Connection' droplist
   437 				ShowDropDownMenu(this, _lan_internet_types_dropdown, _network_lan_internet, NGWW_CONN_BTN, 0, 0); // do it for widget NSSW_CONN_BTN
   409 				ShowDropDownMenu(this, _lan_internet_types_dropdown, _settings_client.network.lan_internet, NGWW_CONN_BTN, 0, 0); // do it for widget NSSW_CONN_BTN
   438 				break;
   410 				break;
   439 
   411 
   440 			case NGWW_NAME: // Sort by name
   412 			case NGWW_NAME: // Sort by name
   441 			case NGWW_CLIENTS: // Sort by connected clients
   413 			case NGWW_CLIENTS: // Sort by connected clients
   442 			case NGWW_INFO: // Connectivity (green dot)
   414 			case NGWW_INFO: // Connectivity (green dot)
   443 				if (this->servers.sort_type == widget - NGWW_NAME) this->servers.flags ^= VL_DESC;
   415 				if (this->servers.SortType() == widget - NGWW_NAME) {
   444 				this->servers.flags |= VL_RESORT;
   416 					this->servers.ToggleSortOrder();
   445 				this->servers.sort_type = widget - NGWW_NAME;
   417 				} else {
   446 
   418 					this->servers.SetSortType(widget - NGWW_NAME);
   447 				_ng_sorting.order = !!(this->servers.flags & VL_DESC);
   419 					this->servers.ForceResort();
   448 				_ng_sorting.criteria = this->servers.sort_type;
   420 				}
   449 				this->SetDirty();
   421 				this->SetDirty();
   450 				break;
   422 				break;
   451 
   423 
   452 			case NGWW_MATRIX: { // Matrix to show networkgames
   424 			case NGWW_MATRIX: { // Matrix to show networkgames
   453 				NetworkGameList *cur_item;
       
   454 				uint32 id_v = (pt.y - NET_PRC__OFFSET_TOP_WIDGET) / NET_PRC__SIZE_OF_ROW;
   425 				uint32 id_v = (pt.y - NET_PRC__OFFSET_TOP_WIDGET) / NET_PRC__SIZE_OF_ROW;
   455 
   426 
   456 				if (id_v >= this->vscroll.cap) return; // click out of bounds
   427 				if (id_v >= this->vscroll.cap) return; // click out of bounds
   457 				id_v += this->vscroll.pos;
   428 				id_v += this->vscroll.pos;
   458 
   429 
   459 				cur_item = _network_game_list;
   430 				this->server = (id_v < this->servers.Length()) ? this->servers[id_v] : NULL;
   460 				for (; id_v > 0 && cur_item != NULL; id_v--) cur_item = cur_item->next;
       
   461 
       
   462 				this->server = cur_item;
       
   463 				this->SetDirty();
   431 				this->SetDirty();
   464 			} break;
   432 			} break;
   465 
   433 
   466 			case NGWW_LASTJOINED: {
   434 			case NGWW_LASTJOINED: {
   467 				NetworkGameList *last_joined = NetworkGameListAddItem(inet_addr(_network_last_host), _network_last_port);
   435 				NetworkGameList *last_joined = NetworkGameListAddItem(inet_addr(_settings_client.network.last_host), _settings_client.network.last_port);
   468 				if (last_joined != NULL) {
   436 				if (last_joined != NULL) {
   469 					this->server = last_joined;
   437 					this->server = last_joined;
   470 					this->SetDirty();
   438 					this->SetDirty();
   471 				}
   439 				}
   472 			} break;
   440 			} break;
   473 
   441 
   474 			case NGWW_FIND: // Find server automatically
   442 			case NGWW_FIND: // Find server automatically
   475 				switch (_network_lan_internet) {
   443 				switch (_settings_client.network.lan_internet) {
   476 					case 0: NetworkUDPSearchGame(); break;
   444 					case 0: NetworkUDPSearchGame(); break;
   477 					case 1: NetworkUDPQueryMasterServer(); break;
   445 					case 1: NetworkUDPQueryMasterServer(); break;
   478 				}
   446 				}
   479 				break;
   447 				break;
   480 
   448 
   481 			case NGWW_ADD: // Add a server
   449 			case NGWW_ADD: // Add a server
   482 				ShowQueryString(
   450 				ShowQueryString(
   483 					BindCString(_network_default_ip),
   451 					BindCString(_settings_client.network.connect_to_ip),
   484 					STR_NETWORK_ENTER_IP,
   452 					STR_NETWORK_ENTER_IP,
   485 					31 | 0x1000,  // maximum number of characters OR
   453 					31 | 0x1000,  // maximum number of characters OR
   486 					250, // characters up to this width pixels, whichever is satisfied first
   454 					250, // characters up to this width pixels, whichever is satisfied first
   487 					this, CS_ALPHANUMERAL);
   455 					this, CS_ALPHANUMERAL);
   488 				break;
   456 				break;
   491 				ShowNetworkStartServerWindow();
   459 				ShowNetworkStartServerWindow();
   492 				break;
   460 				break;
   493 
   461 
   494 			case NGWW_JOIN: // Join Game
   462 			case NGWW_JOIN: // Join Game
   495 				if (this->server != NULL) {
   463 				if (this->server != NULL) {
   496 					snprintf(_network_last_host, sizeof(_network_last_host), "%s", inet_ntoa(*(struct in_addr *)&this->server->ip));
   464 					snprintf(_settings_client.network.last_host, sizeof(_settings_client.network.last_host), "%s", inet_ntoa(*(struct in_addr *)&this->server->ip));
   497 					_network_last_port = this->server->port;
   465 					_settings_client.network.last_port = this->server->port;
   498 					ShowNetworkLobbyWindow(this->server);
   466 					ShowNetworkLobbyWindow(this->server);
   499 				}
   467 				}
   500 				break;
   468 				break;
   501 
   469 
   502 			case NGWW_REFRESH: // Refresh
   470 			case NGWW_REFRESH: // Refresh
   511 
   479 
   512 	virtual void OnDropdownSelect(int widget, int index)
   480 	virtual void OnDropdownSelect(int widget, int index)
   513 	{
   481 	{
   514 		switch (widget) {
   482 		switch (widget) {
   515 			case NGWW_CONN_BTN:
   483 			case NGWW_CONN_BTN:
   516 				_network_lan_internet = index;
   484 				_settings_client.network.lan_internet = index;
   517 				break;
   485 				break;
   518 
   486 
   519 			default:
   487 			default:
   520 				NOT_REACHED();
   488 				NOT_REACHED();
   521 		}
   489 		}
   529 	}
   497 	}
   530 
   498 
   531 	virtual void OnInvalidateData(int data)
   499 	virtual void OnInvalidateData(int data)
   532 	{
   500 	{
   533 		if (data != 0) this->server = NULL;
   501 		if (data != 0) this->server = NULL;
   534 		this->servers.flags |= VL_REBUILD;
   502 		this->servers.ForceRebuild();
   535 		this->SetDirty();
   503 		this->SetDirty();
   536 	}
   504 	}
   537 
   505 
   538 	virtual EventState OnKeyPress(uint16 key, uint16 keycode)
   506 	virtual EventState OnKeyPress(uint16 key, uint16 keycode)
   539 	{
   507 	{
   547 				}
   515 				}
   548 			}
   516 			}
   549 			return state;
   517 			return state;
   550 		}
   518 		}
   551 
   519 
   552 		if (this->HandleEditBoxKey(NGWW_PLAYER, keycode, key, state) == 1) return state; // enter pressed
   520 		if (this->HandleEditBoxKey(NGWW_PLAYER, key, keycode, state) == 1) return state; // enter pressed
   553 
   521 
   554 		/* The name is only allowed when it starts with a letter! */
   522 		/* The name is only allowed when it starts with a letter! */
   555 		if (StrEmpty(this->edit_str_buf) && this->edit_str_buf[0] != ' ') {
   523 		if (!StrEmpty(this->edit_str_buf) && this->edit_str_buf[0] != ' ') {
   556 			ttd_strlcpy(_network_player_name, this->edit_str_buf, lengthof(_network_player_name));
   524 			ttd_strlcpy(_settings_client.network.player_name, this->edit_str_buf, lengthof(_settings_client.network.player_name));
   557 		} else {
   525 		} else {
   558 			ttd_strlcpy(_network_player_name, "Player", lengthof(_network_player_name));
   526 			ttd_strlcpy(_settings_client.network.player_name, "Player", lengthof(_settings_client.network.player_name));
   559 		}
   527 		}
   560 		return state;
   528 		return state;
   561 	}
   529 	}
   562 
   530 
   563 	virtual void OnQueryTextFinished(char *str)
   531 	virtual void OnQueryTextFinished(char *str)
   587 			offset += space;
   555 			offset += space;
   588 		}
   556 		}
   589 	}
   557 	}
   590 };
   558 };
   591 
   559 
       
   560 Listing NetworkGameWindow::last_sorting = {false, 2};
       
   561 GUIGameServerList::SortFunction *const NetworkGameWindow::sorter_funcs[] = {
       
   562 	&NGameNameSorter,
       
   563 	&NGameClientSorter,
       
   564 	&NGameAllowedSorter
       
   565 };
       
   566 
       
   567 
   592 static const Widget _network_game_window_widgets[] = {
   568 static const Widget _network_game_window_widgets[] = {
   593 /* TOP */
   569 /* TOP */
   594 {   WWT_CLOSEBOX,   RESIZE_NONE,   BGC,     0,    10,     0,    13, STR_00C5,                         STR_018B_CLOSE_WINDOW},            // NGWW_CLOSE
   570 {   WWT_CLOSEBOX,   RESIZE_NONE,   BGC,     0,    10,     0,    13, STR_00C5,                         STR_018B_CLOSE_WINDOW},            // NGWW_CLOSE
   595 {    WWT_CAPTION,   RESIZE_RIGHT,  BGC,    11,   449,     0,    13, STR_NETWORK_MULTIPLAYER,          STR_NULL},                         // NGWW_CAPTION
   571 {    WWT_CAPTION,   RESIZE_RIGHT,  BGC,    11,   449,     0,    13, STR_NETWORK_MULTIPLAYER,          STR_NULL},                         // NGWW_CAPTION
   596 {      WWT_PANEL,   RESIZE_RB,     BGC,     0,   449,    14,   263, 0x0,                              STR_NULL},                         // NGWW_RESIZE
   572 {      WWT_PANEL,   RESIZE_RB,     BGC,     0,   449,    14,   263, 0x0,                              STR_NULL},                         // NGWW_RESIZE
   648 		first = false;
   624 		first = false;
   649 		// add all servers from the config file to our list
   625 		// add all servers from the config file to our list
   650 		for (srv = &_network_host_list[0]; srv != endof(_network_host_list) && *srv != NULL; srv++) {
   626 		for (srv = &_network_host_list[0]; srv != endof(_network_host_list) && *srv != NULL; srv++) {
   651 			NetworkAddServer(*srv);
   627 			NetworkAddServer(*srv);
   652 		}
   628 		}
   653 
       
   654 		_ng_sorting.criteria = 2; // sort default by collectivity (green-dots on top)
       
   655 		_ng_sorting.order = 0;    // sort ascending by default
       
   656 	}
   629 	}
   657 
   630 
   658 	new NetworkGameWindow(&_network_game_window_desc);
   631 	new NetworkGameWindow(&_network_game_window_desc);
   659 }
   632 }
   660 
   633 
   690 	FiosItem *map;               ///< Selected map
   663 	FiosItem *map;               ///< Selected map
   691 	byte widget_id;              ///< The widget that has the pop-up input menu
   664 	byte widget_id;              ///< The widget that has the pop-up input menu
   692 
   665 
   693 	NetworkStartServerWindow(const WindowDesc *desc) : QueryStringBaseWindow(desc)
   666 	NetworkStartServerWindow(const WindowDesc *desc) : QueryStringBaseWindow(desc)
   694 	{
   667 	{
   695 		ttd_strlcpy(this->edit_str_buf, _network_server_name, lengthof(this->edit_str_buf));
   668 		ttd_strlcpy(this->edit_str_buf, _settings_client.network.server_name, lengthof(this->edit_str_buf));
   696 
   669 
   697 		_saveload_mode = SLD_NEW_GAME;
   670 		_saveload_mode = SLD_NEW_GAME;
   698 		BuildFileList();
   671 		BuildFileList();
   699 		this->vscroll.cap = 12;
   672 		this->vscroll.cap = 12;
   700 		this->vscroll.count = _fios_num + 1;
   673 		this->vscroll.count = _fios_items.Length();
   701 
   674 
   702 		this->afilter = CS_ALPHANUMERAL;
   675 		this->afilter = CS_ALPHANUMERAL;
   703 		InitializeTextBuffer(&this->text, this->edit_str_buf, lengthof(this->edit_str_buf), 160);
   676 		InitializeTextBuffer(&this->text, this->edit_str_buf, lengthof(this->edit_str_buf), 160);
   704 
   677 
   705 		this->field = NSSW_GAMENAME;
   678 		this->field = NSSW_GAMENAME;
   706 		_network_game_info.use_password = !StrEmpty(_network_server_password);
       
   707 
   679 
   708 		this->FindWindowPlacementAndResize(desc);
   680 		this->FindWindowPlacementAndResize(desc);
   709 	}
   681 	}
   710 
   682 
   711 	virtual void OnPaint()
   683 	virtual void OnPaint()
   712 	{
   684 	{
   713 		int y = NSSWND_START, pos;
   685 		int y = NSSWND_START;
   714 		const FiosItem *item;
   686 		const FiosItem *item;
   715 
   687 
   716 		/* draw basic widgets */
   688 		/* draw basic widgets */
   717 		SetDParam(1, _connection_types_dropdown[_network_advertise]);
   689 		SetDParam(1, _connection_types_dropdown[_network_advertise]);
   718 		SetDParam(2, _network_game_info.clients_max);
   690 		SetDParam(2, _settings_client.network.max_clients);
   719 		SetDParam(3, _network_game_info.companies_max);
   691 		SetDParam(3, _settings_client.network.max_companies);
   720 		SetDParam(4, _network_game_info.spectators_max);
   692 		SetDParam(4, _settings_client.network.max_spectators);
   721 		SetDParam(5, STR_NETWORK_LANG_ANY + _network_game_info.server_lang);
   693 		SetDParam(5, STR_NETWORK_LANG_ANY + _settings_client.network.server_lang);
   722 		this->DrawWidgets();
   694 		this->DrawWidgets();
   723 
   695 
   724 		/* editbox to set game name */
   696 		/* editbox to set game name */
   725 		this->DrawEditBox(NSSW_GAMENAME);
   697 		this->DrawEditBox(NSSW_GAMENAME);
   726 
   698 
   727 		/* if password is set, draw red '*' next to 'Set password' button */
   699 		/* if password is set, draw red '*' next to 'Set password' button */
   728 		if (_network_game_info.use_password) DoDrawString("*", 408, 23, TC_RED);
   700 		if (!StrEmpty(_settings_client.network.server_password)) DoDrawString("*", 408, 23, TC_RED);
   729 
   701 
   730 		/* draw list of maps */
   702 		/* draw list of maps */
   731 		GfxFillRect(11, 63, 258, 215, 0xD7);  // black background of maps list
   703 		GfxFillRect(11, 63, 258, 215, 0xD7);  // black background of maps list
   732 
   704 
   733 		pos = this->vscroll.pos;
   705 		for (uint pos = this->vscroll.pos; pos < _fios_items.Length() + 1; pos++) {
   734 		while (pos < _fios_num + 1) {
   706 			item = _fios_items.Get(pos - 1);
   735 			item = _fios_list + pos - 1;
       
   736 			if (item == this->map || (pos == 0 && this->map == NULL))
   707 			if (item == this->map || (pos == 0 && this->map == NULL))
   737 				GfxFillRect(11, y - 1, 258, y + 10, 155); // show highlighted item with a different colour
   708 				GfxFillRect(11, y - 1, 258, y + 10, 155); // show highlighted item with a different colour
   738 
   709 
   739 			if (pos == 0) {
   710 			if (pos == 0) {
   740 				DrawString(14, y, STR_4010_GENERATE_RANDOM_NEW_GAME, TC_DARK_GREEN);
   711 				DrawString(14, y, STR_4010_GENERATE_RANDOM_NEW_GAME, TC_DARK_GREEN);
   741 			} else {
   712 			} else {
   742 				DoDrawString(item->title, 14, y, _fios_colors[item->type] );
   713 				DoDrawString(item->title, 14, y, _fios_colors[item->type] );
   743 			}
   714 			}
   744 			pos++;
       
   745 			y += NSSWND_ROWSIZE;
   715 			y += NSSWND_ROWSIZE;
   746 
   716 
   747 			if (y >= this->vscroll.cap * NSSWND_ROWSIZE + NSSWND_START) break;
   717 			if (y >= this->vscroll.cap * NSSWND_ROWSIZE + NSSWND_START) break;
   748 		}
   718 		}
   749 	}
   719 	}
   762 				ShowOnScreenKeyboard(this, NSSW_GAMENAME, 0, 0);
   732 				ShowOnScreenKeyboard(this, NSSW_GAMENAME, 0, 0);
   763 				break;
   733 				break;
   764 
   734 
   765 			case NSSW_SETPWD: // Set password button
   735 			case NSSW_SETPWD: // Set password button
   766 				this->widget_id = NSSW_SETPWD;
   736 				this->widget_id = NSSW_SETPWD;
   767 				ShowQueryString(BindCString(_network_server_password), STR_NETWORK_SET_PASSWORD, 20, 250, this, CS_ALPHANUMERAL);
   737 				ShowQueryString(BindCString(_settings_client.network.server_password), STR_NETWORK_SET_PASSWORD, 20, 250, this, CS_ALPHANUMERAL);
   768 				break;
   738 				break;
   769 
   739 
   770 			case NSSW_SELMAP: { // Select map
   740 			case NSSW_SELMAP: { // Select map
   771 				int y = (pt.y - NSSWND_START) / NSSWND_ROWSIZE;
   741 				int y = (pt.y - NSSWND_START) / NSSWND_ROWSIZE;
   772 
   742 
   773 				y += this->vscroll.pos;
   743 				y += this->vscroll.pos;
   774 				if (y >= this->vscroll.count) return;
   744 				if (y >= this->vscroll.count) return;
   775 
   745 
   776 				this->map = (y == 0) ? NULL : _fios_list + y - 1;
   746 				this->map = (y == 0) ? NULL : _fios_items.Get(y - 1);
   777 				this->SetDirty();
   747 				this->SetDirty();
   778 			} break;
   748 			} break;
   779 
   749 
   780 			case NSSW_CONNTYPE_BTN: // Connection type
   750 			case NSSW_CONNTYPE_BTN: // Connection type
   781 				ShowDropDownMenu(this, _connection_types_dropdown, _network_advertise, NSSW_CONNTYPE_BTN, 0, 0); // do it for widget NSSW_CONNTYPE_BTN
   751 				ShowDropDownMenu(this, _connection_types_dropdown, _network_advertise, NSSW_CONNTYPE_BTN, 0, 0); // do it for widget NSSW_CONNTYPE_BTN
   789 					this->HandleButtonClick(widget);
   759 					this->HandleButtonClick(widget);
   790 					this->SetDirty();
   760 					this->SetDirty();
   791 					switch (widget) {
   761 					switch (widget) {
   792 						default: NOT_REACHED();
   762 						default: NOT_REACHED();
   793 						case NSSW_CLIENTS_BTND: case NSSW_CLIENTS_BTNU:
   763 						case NSSW_CLIENTS_BTND: case NSSW_CLIENTS_BTNU:
   794 							_network_game_info.clients_max    = Clamp(_network_game_info.clients_max    + widget - NSSW_CLIENTS_TXT,    2, MAX_CLIENTS);
   764 							_settings_client.network.max_clients    = Clamp(_settings_client.network.max_clients    + widget - NSSW_CLIENTS_TXT,    2, MAX_CLIENTS);
   795 							break;
   765 							break;
   796 						case NSSW_COMPANIES_BTND: case NSSW_COMPANIES_BTNU:
   766 						case NSSW_COMPANIES_BTND: case NSSW_COMPANIES_BTNU:
   797 							_network_game_info.companies_max  = Clamp(_network_game_info.companies_max  + widget - NSSW_COMPANIES_TXT,  1, MAX_PLAYERS);
   767 							_settings_client.network.max_companies  = Clamp(_settings_client.network.max_companies  + widget - NSSW_COMPANIES_TXT,  1, MAX_PLAYERS);
   798 							break;
   768 							break;
   799 						case NSSW_SPECTATORS_BTND: case NSSW_SPECTATORS_BTNU:
   769 						case NSSW_SPECTATORS_BTND: case NSSW_SPECTATORS_BTNU:
   800 							_network_game_info.spectators_max = Clamp(_network_game_info.spectators_max + widget - NSSW_SPECTATORS_TXT, 0, MAX_CLIENTS);
   770 							_settings_client.network.max_spectators = Clamp(_settings_client.network.max_spectators + widget - NSSW_SPECTATORS_TXT, 0, MAX_CLIENTS);
   801 							break;
   771 							break;
   802 					}
   772 					}
   803 				}
   773 				}
   804 				_left_button_clicked = false;
   774 				_left_button_clicked = false;
   805 				break;
   775 				break;
   806 
   776 
   807 			case NSSW_CLIENTS_TXT:    // Click on number of players
   777 			case NSSW_CLIENTS_TXT:    // Click on number of players
   808 				this->widget_id = NSSW_CLIENTS_TXT;
   778 				this->widget_id = NSSW_CLIENTS_TXT;
   809 				SetDParam(0, _network_game_info.clients_max);
   779 				SetDParam(0, _settings_client.network.max_clients);
   810 				ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_NETWORK_NUMBER_OF_CLIENTS,    3, 50, this, CS_NUMERAL);
   780 				ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_NETWORK_NUMBER_OF_CLIENTS,    3, 50, this, CS_NUMERAL);
   811 				break;
   781 				break;
   812 
   782 
   813 			case NSSW_COMPANIES_TXT:  // Click on number of companies
   783 			case NSSW_COMPANIES_TXT:  // Click on number of companies
   814 				this->widget_id = NSSW_COMPANIES_TXT;
   784 				this->widget_id = NSSW_COMPANIES_TXT;
   815 				SetDParam(0, _network_game_info.companies_max);
   785 				SetDParam(0, _settings_client.network.max_companies);
   816 				ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_NETWORK_NUMBER_OF_COMPANIES,  3, 50, this, CS_NUMERAL);
   786 				ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_NETWORK_NUMBER_OF_COMPANIES,  3, 50, this, CS_NUMERAL);
   817 				break;
   787 				break;
   818 
   788 
   819 			case NSSW_SPECTATORS_TXT: // Click on number of spectators
   789 			case NSSW_SPECTATORS_TXT: // Click on number of spectators
   820 				this->widget_id = NSSW_SPECTATORS_TXT;
   790 				this->widget_id = NSSW_SPECTATORS_TXT;
   821 				SetDParam(0, _network_game_info.spectators_max);
   791 				SetDParam(0, _settings_client.network.max_spectators);
   822 				ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_NETWORK_NUMBER_OF_SPECTATORS, 3, 50, this, CS_NUMERAL);
   792 				ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_NETWORK_NUMBER_OF_SPECTATORS, 3, 50, this, CS_NUMERAL);
   823 				break;
   793 				break;
   824 
   794 
   825 			case NSSW_LANGUAGE_BTN: { // Language
   795 			case NSSW_LANGUAGE_BTN: { // Language
   826 				uint sel = 0;
   796 				uint sel = 0;
   827 				for (uint i = 0; i < lengthof(_language_dropdown) - 1; i++) {
   797 				for (uint i = 0; i < lengthof(_language_dropdown) - 1; i++) {
   828 					if (_language_dropdown[i] == STR_NETWORK_LANG_ANY + _network_game_info.server_lang) {
   798 					if (_language_dropdown[i] == STR_NETWORK_LANG_ANY + _settings_client.network.server_lang) {
   829 						sel = i;
   799 						sel = i;
   830 						break;
   800 						break;
   831 					}
   801 					}
   832 				}
   802 				}
   833 				ShowDropDownMenu(this, _language_dropdown, sel, NSSW_LANGUAGE_BTN, 0, 0);
   803 				ShowDropDownMenu(this, _language_dropdown, sel, NSSW_LANGUAGE_BTN, 0, 0);
   867 		switch (widget) {
   837 		switch (widget) {
   868 			case NSSW_CONNTYPE_BTN:
   838 			case NSSW_CONNTYPE_BTN:
   869 				_network_advertise = (index != 0);
   839 				_network_advertise = (index != 0);
   870 				break;
   840 				break;
   871 			case NSSW_LANGUAGE_BTN:
   841 			case NSSW_LANGUAGE_BTN:
   872 				_network_game_info.server_lang = _language_dropdown[index] - STR_NETWORK_LANG_ANY;
   842 				_settings_client.network.server_lang = _language_dropdown[index] - STR_NETWORK_LANG_ANY;
   873 				break;
   843 				break;
   874 			default:
   844 			default:
   875 				NOT_REACHED();
   845 				NOT_REACHED();
   876 		}
   846 		}
   877 
   847 
   887 	{
   857 	{
   888 		EventState state = ES_NOT_HANDLED;
   858 		EventState state = ES_NOT_HANDLED;
   889 		if (this->field == NSSW_GAMENAME) {
   859 		if (this->field == NSSW_GAMENAME) {
   890 			if (this->HandleEditBoxKey(NSSW_GAMENAME, key, keycode, state) == 1) return state; // enter pressed
   860 			if (this->HandleEditBoxKey(NSSW_GAMENAME, key, keycode, state) == 1) return state; // enter pressed
   891 
   861 
   892 			ttd_strlcpy(_network_server_name, this->text.buf, sizeof(_network_server_name));
   862 			ttd_strlcpy(_settings_client.network.server_name, this->text.buf, sizeof(_settings_client.network.server_name));
   893 		}
   863 		}
   894 
   864 
   895 		return state;
   865 		return state;
   896 	}
   866 	}
   897 
   867 
   898 	virtual void OnQueryTextFinished(char *str)
   868 	virtual void OnQueryTextFinished(char *str)
   899 	{
   869 	{
   900 		if (str == NULL) return;
   870 		if (str == NULL) return;
   901 
   871 
   902 		if (this->widget_id == NSSW_SETPWD) {
   872 		if (this->widget_id == NSSW_SETPWD) {
   903 			ttd_strlcpy(_network_server_password, str, lengthof(_network_server_password));
   873 			ttd_strlcpy(_settings_client.network.server_password, str, lengthof(_settings_client.network.server_password));
   904 			_network_game_info.use_password = !StrEmpty(_network_server_password);
       
   905 		} else {
   874 		} else {
   906 			int32 value = atoi(str);
   875 			int32 value = atoi(str);
   907 			this->InvalidateWidget(this->widget_id);
   876 			this->InvalidateWidget(this->widget_id);
   908 			switch (this->widget_id) {
   877 			switch (this->widget_id) {
   909 				default: NOT_REACHED();
   878 				default: NOT_REACHED();
   910 				case NSSW_CLIENTS_TXT:    _network_game_info.clients_max    = Clamp(value, 2, MAX_CLIENTS); break;
   879 				case NSSW_CLIENTS_TXT:    _settings_client.network.max_clients    = Clamp(value, 2, MAX_CLIENTS); break;
   911 				case NSSW_COMPANIES_TXT:  _network_game_info.companies_max  = Clamp(value, 1, MAX_PLAYERS); break;
   880 				case NSSW_COMPANIES_TXT:  _settings_client.network.max_companies  = Clamp(value, 1, MAX_PLAYERS); break;
   912 				case NSSW_SPECTATORS_TXT: _network_game_info.spectators_max = Clamp(value, 0, MAX_CLIENTS); break;
   881 				case NSSW_SPECTATORS_TXT: _settings_client.network.max_spectators = Clamp(value, 0, MAX_CLIENTS); break;
   913 			}
   882 			}
   914 		}
   883 		}
   915 
   884 
   916 		this->SetDirty();
   885 		this->SetDirty();
   917 	}
   886 	}
  1129 			} break;
  1098 			} break;
  1130 
  1099 
  1131 			case NLWW_JOIN:     // Join company
  1100 			case NLWW_JOIN:     // Join company
  1132 				/* Button can be clicked only when it is enabled */
  1101 				/* Button can be clicked only when it is enabled */
  1133 				_network_playas = this->company;
  1102 				_network_playas = this->company;
  1134 				NetworkClientConnectGame(_network_last_host, _network_last_port);
  1103 				NetworkClientConnectGame(_settings_client.network.last_host, _settings_client.network.last_port);
  1135 				break;
  1104 				break;
  1136 
  1105 
  1137 			case NLWW_NEW:      // New company
  1106 			case NLWW_NEW:      // New company
  1138 				_network_playas = PLAYER_NEW_COMPANY;
  1107 				_network_playas = PLAYER_NEW_COMPANY;
  1139 				NetworkClientConnectGame(_network_last_host, _network_last_port);
  1108 				NetworkClientConnectGame(_settings_client.network.last_host, _settings_client.network.last_port);
  1140 				break;
  1109 				break;
  1141 
  1110 
  1142 			case NLWW_SPECTATE: // Spectate game
  1111 			case NLWW_SPECTATE: // Spectate game
  1143 				_network_playas = PLAYER_SPECTATOR;
  1112 				_network_playas = PLAYER_SPECTATOR;
  1144 				NetworkClientConnectGame(_network_last_host, _network_last_port);
  1113 				NetworkClientConnectGame(_settings_client.network.last_host, _settings_client.network.last_port);
  1145 				break;
  1114 				break;
  1146 
  1115 
  1147 			case NLWW_REFRESH:  // Refresh
  1116 			case NLWW_REFRESH:  // Refresh
  1148 				NetworkTCPQueryServer(_network_last_host, _network_last_port); // company info
  1117 				NetworkTCPQueryServer(_settings_client.network.last_host, _settings_client.network.last_port); // company info
  1149 				NetworkUDPQueryServer(_network_last_host, _network_last_port); // general data
  1118 				NetworkUDPQueryServer(_settings_client.network.last_host, _settings_client.network.last_port); // general data
  1150 				break;
  1119 				break;
  1151 		}
  1120 		}
  1152 	}
  1121 	}
  1153 };
  1122 };
  1154 
  1123 
  1187  * @param ngl Selected game pointer which is passed to the new window */
  1156  * @param ngl Selected game pointer which is passed to the new window */
  1188 static void ShowNetworkLobbyWindow(NetworkGameList *ngl)
  1157 static void ShowNetworkLobbyWindow(NetworkGameList *ngl)
  1189 {
  1158 {
  1190 	DeleteWindowById(WC_NETWORK_WINDOW, 0);
  1159 	DeleteWindowById(WC_NETWORK_WINDOW, 0);
  1191 
  1160 
  1192 	NetworkTCPQueryServer(_network_last_host, _network_last_port); // company info
  1161 	NetworkTCPQueryServer(_settings_client.network.last_host, _settings_client.network.last_port); // company info
  1193 	NetworkUDPQueryServer(_network_last_host, _network_last_port); // general data
  1162 	NetworkUDPQueryServer(_settings_client.network.last_host, _settings_client.network.last_port); // general data
  1194 
  1163 
  1195 	new NetworkLobbyWindow(&_network_lobby_window_desc, ngl);
  1164 	new NetworkLobbyWindow(&_network_lobby_window_desc, ngl);
  1196 }
  1165 }
  1197 
  1166 
  1198 // The window below gives information about the connected clients
  1167 // The window below gives information about the connected clients
  1584 		case NETWORK_COMPANY_PASSWORD: caption = STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION; break;
  1553 		case NETWORK_COMPANY_PASSWORD: caption = STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION; break;
  1585 	}
  1554 	}
  1586 	ShowQueryString(STR_EMPTY, caption, 20, 180, FindWindowById(WC_NETWORK_STATUS_WINDOW, 0), CS_ALPHANUMERAL);
  1555 	ShowQueryString(STR_EMPTY, caption, 20, 180, FindWindowById(WC_NETWORK_STATUS_WINDOW, 0), CS_ALPHANUMERAL);
  1587 }
  1556 }
  1588 
  1557 
       
  1558 // Vars needed for the join-GUI
       
  1559 NetworkJoinStatus _network_join_status;
       
  1560 uint8 _network_join_waiting;
       
  1561 uint16 _network_join_kbytes;
       
  1562 uint16 _network_join_kbytes_total;
       
  1563 
  1589 struct NetworkJoinStatusWindow : Window {
  1564 struct NetworkJoinStatusWindow : Window {
  1590 	NetworkJoinStatusWindow(const WindowDesc *desc) : Window(desc)
  1565 	NetworkJoinStatusWindow(const WindowDesc *desc) : Window(desc)
  1591 	{
  1566 	{
  1592 		this->parent = FindWindowById(WC_NETWORK_WINDOW, 0);
  1567 		this->parent = FindWindowById(WC_NETWORK_WINDOW, 0);
  1593 	}
  1568 	}
  1665 {
  1640 {
  1666 	if (StrEmpty(buf)) return;
  1641 	if (StrEmpty(buf)) return;
  1667 	if (!_network_server) {
  1642 	if (!_network_server) {
  1668 		SEND_COMMAND(PACKET_CLIENT_CHAT)((NetworkAction)(NETWORK_ACTION_CHAT + type), type, dest, buf);
  1643 		SEND_COMMAND(PACKET_CLIENT_CHAT)((NetworkAction)(NETWORK_ACTION_CHAT + type), type, dest, buf);
  1669 	} else {
  1644 	} else {
  1670 		NetworkServer_HandleChat((NetworkAction)(NETWORK_ACTION_CHAT + type), type, dest, buf, NETWORK_SERVER_INDEX);
  1645 		NetworkServerSendChat((NetworkAction)(NETWORK_ACTION_CHAT + type), type, dest, buf, NETWORK_SERVER_INDEX);
  1671 	}
  1646 	}
  1672 }
  1647 }
  1673 
  1648 
  1674 
  1649 
  1675 struct NetworkChatWindow : public QueryStringBaseWindow {
  1650 struct NetworkChatWindow : public QueryStringBaseWindow {
  1919 struct NetworkCompanyPasswordWindow : public QueryStringBaseWindow {
  1894 struct NetworkCompanyPasswordWindow : public QueryStringBaseWindow {
  1920 	NetworkCompanyPasswordWindow(const WindowDesc *desc, Window *parent) : QueryStringBaseWindow(desc)
  1895 	NetworkCompanyPasswordWindow(const WindowDesc *desc, Window *parent) : QueryStringBaseWindow(desc)
  1921 	{
  1896 	{
  1922 		this->parent = parent;
  1897 		this->parent = parent;
  1923 		this->afilter = CS_ALPHANUMERAL;
  1898 		this->afilter = CS_ALPHANUMERAL;
  1924 		InitializeTextBuffer(&this->text, this->edit_str_buf, min(lengthof(_network_default_company_pass), lengthof(this->edit_str_buf)), 0);
  1899 		InitializeTextBuffer(&this->text, this->edit_str_buf, min(lengthof(_settings_client.network.default_company_pass), lengthof(this->edit_str_buf)), 0);
  1925 
  1900 
  1926 		this->FindWindowPlacementAndResize(desc);
  1901 		this->FindWindowPlacementAndResize(desc);
  1927 	}
  1902 	}
  1928 
  1903 
  1929 	void OnOk()
  1904 	void OnOk()
  1930 	{
  1905 	{
  1931 		if (this->IsWidgetLowered(NCPWW_SAVE_AS_DEFAULT_PASSWORD)) {
  1906 		if (this->IsWidgetLowered(NCPWW_SAVE_AS_DEFAULT_PASSWORD)) {
  1932 			snprintf(_network_default_company_pass, lengthof(_network_default_company_pass), "%s", this->edit_str_buf);
  1907 			snprintf(_settings_client.network.default_company_pass, lengthof(_settings_client.network.default_company_pass), "%s", this->edit_str_buf);
  1933 		}
  1908 		}
  1934 
  1909 
  1935 		/* empty password is a '*' because of console argument */
  1910 		/* empty password is a '*' because of console argument */
  1936 		if (StrEmpty(this->edit_str_buf)) snprintf(this->edit_str_buf, lengthof(this->edit_str_buf), "*");
  1911 		if (StrEmpty(this->edit_str_buf)) snprintf(this->edit_str_buf, lengthof(this->edit_str_buf), "*");
  1937 		char *password = this->edit_str_buf;
  1912 		char *password = this->edit_str_buf;