src/network/network_gui.cpp
changeset 9414 d2374f994ac9
parent 9413 7042a8ec3fa8
child 9415 565481e82c56
equal deleted inserted replaced
9413:7042a8ec3fa8 9414:d2374f994ac9
    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, _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
   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, 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
       
   344 		}
   316 		}
   345 
   317 
   346 		const NetworkGameList *last_joined = NetworkGameListAddItem(inet_addr(_network_last_host), _network_last_port);
   318 		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);
   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 = this->servers[id_v];
   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(_network_last_host), _network_last_port);
   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 	{
   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