src/network/network_gui.cpp
changeset 9234 8123d1c8e796
parent 9233 4daa9bb8dbf7
child 10170 39c950e2ab9d
equal deleted inserted replaced
9233:4daa9bb8dbf7 9234:8123d1c8e796
   253 {
   253 {
   254 	network_d *nd = &WP(w, network_ql_d).n;
   254 	network_d *nd = &WP(w, network_ql_d).n;
   255 	list_d *ld = &WP(w, network_ql_d).l;
   255 	list_d *ld = &WP(w, network_ql_d).l;
   256 
   256 
   257 	switch (e->event) {
   257 	switch (e->event) {
   258 	case WE_CREATE: // Focus input box
   258 		case WE_CREATE: // Focus input box
   259 		w->vscroll.cap = 13;
   259 			w->vscroll.cap = 13;
   260 		w->resize.step_height = NET_PRC__SIZE_OF_ROW;
   260 			w->resize.step_height = NET_PRC__SIZE_OF_ROW;
   261 
   261 
   262 		nd->field = NGWW_PLAYER;
   262 			nd->field = NGWW_PLAYER;
   263 		nd->server = NULL;
   263 			nd->server = NULL;
   264 
   264 
   265 		WP(w, network_ql_d).sort_list = NULL;
   265 			WP(w, network_ql_d).sort_list = NULL;
   266 		ld->flags = VL_REBUILD | (_ng_sorting.order ? VL_DESC : VL_NONE);
   266 			ld->flags = VL_REBUILD | (_ng_sorting.order ? VL_DESC : VL_NONE);
   267 		ld->sort_type = _ng_sorting.criteria;
   267 			ld->sort_type = _ng_sorting.criteria;
   268 		break;
   268 			break;
   269 
   269 
   270 	case WE_PAINT: {
   270 		case WE_PAINT: {
   271 		const NetworkGameList *sel = nd->server;
   271 			const NetworkGameList *sel = nd->server;
   272 		const SortButtonState arrow = (ld->flags & VL_DESC) ? SBS_DOWN : SBS_UP;
   272 			const SortButtonState arrow = (ld->flags & VL_DESC) ? SBS_DOWN : SBS_UP;
   273 
   273 
   274 		if (ld->flags & VL_REBUILD) {
   274 			if (ld->flags & VL_REBUILD) {
   275 			BuildNetworkGameList(&WP(w, network_ql_d));
   275 				BuildNetworkGameList(&WP(w, network_ql_d));
   276 			SetVScrollCount(w, ld->list_length);
   276 				SetVScrollCount(w, ld->list_length);
   277 		}
   277 			}
   278 		if (ld->flags & VL_RESORT) SortNetworkGameList(&WP(w, network_ql_d));
   278 			if (ld->flags & VL_RESORT) SortNetworkGameList(&WP(w, network_ql_d));
   279 
   279 
   280 		/* 'Refresh' button invisible if no server selected */
   280 			/* 'Refresh' button invisible if no server selected */
   281 		w->SetWidgetDisabledState(NGWW_REFRESH, sel == NULL);
   281 			w->SetWidgetDisabledState(NGWW_REFRESH, sel == NULL);
   282 		/* 'Join' button disabling conditions */
   282 			/* 'Join' button disabling conditions */
   283 		w->SetWidgetDisabledState(NGWW_JOIN, sel == NULL || // no Selected Server
   283 			w->SetWidgetDisabledState(NGWW_JOIN, sel == NULL || // no Selected Server
   284 				!sel->online || // Server offline
   284 					!sel->online || // Server offline
   285 				sel->info.clients_on >= sel->info.clients_max || // Server full
   285 					sel->info.clients_on >= sel->info.clients_max || // Server full
   286 				!sel->info.compatible); // Revision mismatch
   286 					!sel->info.compatible); // Revision mismatch
   287 
   287 
   288 		/* 'NewGRF Settings' button invisible if no NewGRF is used */
   288 			/* 'NewGRF Settings' button invisible if no NewGRF is used */
   289 		w->SetWidgetHiddenState(NGWW_NEWGRF, sel == NULL ||
   289 			w->SetWidgetHiddenState(NGWW_NEWGRF, sel == NULL ||
   290 				!sel->online ||
   290 					!sel->online ||
   291 				sel->info.grfconfig == NULL);
   291 					sel->info.grfconfig == NULL);
   292 
   292 
   293 		SetDParam(0, 0x00);
   293 			SetDParam(0, 0x00);
   294 		SetDParam(1, _lan_internet_types_dropdown[_network_lan_internet]);
   294 			SetDParam(1, _lan_internet_types_dropdown[_network_lan_internet]);
   295 		DrawWindowWidgets(w);
   295 			DrawWindowWidgets(w);
   296 
   296 
   297 		/* Edit box to set player name */
   297 			/* Edit box to set player name */
   298 		DrawEditBox(w, &WP(w, network_ql_d).q, NGWW_PLAYER);
   298 			DrawEditBox(w, &WP(w, network_ql_d).q, NGWW_PLAYER);
   299 
   299 
   300 		DrawString(w->widget[NGWW_PLAYER].left - 100, 23, STR_NETWORK_PLAYER_NAME, TC_GOLD);
   300 			DrawString(w->widget[NGWW_PLAYER].left - 100, 23, STR_NETWORK_PLAYER_NAME, TC_GOLD);
   301 
   301 
   302 		/* Sort based on widgets: name, clients, compatibility */
   302 			/* Sort based on widgets: name, clients, compatibility */
   303 		switch (ld->sort_type) {
   303 			switch (ld->sort_type) {
   304 			case NGWW_NAME    - NGWW_NAME: DrawSortButtonState(w, NGWW_NAME,    arrow); break;
   304 				case NGWW_NAME    - NGWW_NAME: DrawSortButtonState(w, NGWW_NAME,    arrow); break;
   305 			case NGWW_CLIENTS - NGWW_NAME: DrawSortButtonState(w, NGWW_CLIENTS, arrow); break;
   305 				case NGWW_CLIENTS - NGWW_NAME: DrawSortButtonState(w, NGWW_CLIENTS, arrow); break;
   306 			case NGWW_INFO    - NGWW_NAME: DrawSortButtonState(w, NGWW_INFO,    arrow); break;
   306 				case NGWW_INFO    - NGWW_NAME: DrawSortButtonState(w, NGWW_INFO,    arrow); break;
   307 		}
   307 			}
   308 
   308 
   309 		{ // draw list of games
       
   310 			uint16 y = NET_PRC__OFFSET_TOP_WIDGET + 3;
   309 			uint16 y = NET_PRC__OFFSET_TOP_WIDGET + 3;
   311 			int32 n = 0;
   310 			int32 n = 0;
   312 			int32 pos = w->vscroll.pos;
   311 			int32 pos = w->vscroll.pos;
   313 			uint max_name_width = w->widget[NGWW_NAME].right - w->widget[NGWW_NAME].left - 5;
   312 			uint max_name_width = w->widget[NGWW_NAME].right - w->widget[NGWW_NAME].left - 5;
   314 			const NetworkGameList *cur_item = _network_game_list;
   313 			const NetworkGameList *cur_item = _network_game_list;
   345 
   344 
   346 				cur_item = cur_item->next;
   345 				cur_item = cur_item->next;
   347 				y += NET_PRC__SIZE_OF_ROW;
   346 				y += NET_PRC__SIZE_OF_ROW;
   348 				if (++n == w->vscroll.cap) break; // max number of games in the window
   347 				if (++n == w->vscroll.cap) break; // max number of games in the window
   349 			}
   348 			}
   350 		}
   349 
   351 
   350 			/* Draw the right menu */
   352 		/* Draw the right menu */
   351 			GfxFillRect(w->widget[NGWW_DETAILS].left + 1, 43, w->widget[NGWW_DETAILS].right - 1, 92, 157);
   353 		GfxFillRect(w->widget[NGWW_DETAILS].left + 1, 43, w->widget[NGWW_DETAILS].right - 1, 92, 157);
   352 			if (sel == NULL) {
   354 		if (sel == NULL) {
   353 				DrawStringCentered(w->widget[NGWW_DETAILS].left + 115, 58, STR_NETWORK_GAME_INFO, TC_FROMSTRING);
   355 			DrawStringCentered(w->widget[NGWW_DETAILS].left + 115, 58, STR_NETWORK_GAME_INFO, TC_FROMSTRING);
   354 			} else if (!sel->online) {
   356 		} else if (!sel->online) {
   355 				SetDParamStr(0, sel->info.server_name);
   357 			SetDParamStr(0, sel->info.server_name);
   356 				DrawStringCentered(w->widget[NGWW_DETAILS].left + 115, 68, STR_ORANGE, TC_FROMSTRING); // game name
   358 			DrawStringCentered(w->widget[NGWW_DETAILS].left + 115, 68, STR_ORANGE, TC_FROMSTRING); // game name
   357 
   359 
   358 				DrawStringCentered(w->widget[NGWW_DETAILS].left + 115, 132, STR_NETWORK_SERVER_OFFLINE, TC_FROMSTRING); // server offline
   360 			DrawStringCentered(w->widget[NGWW_DETAILS].left + 115, 132, STR_NETWORK_SERVER_OFFLINE, TC_FROMSTRING); // server offline
   359 			} else { // show game info
   361 		} else { // show game info
   360 				uint16 y = 100;
   362 			uint16 y = 100;
   361 				const uint16 x = w->widget[NGWW_DETAILS].left + 5;
   363 			const uint16 x = w->widget[NGWW_DETAILS].left + 5;
   362 
   364 
   363 				DrawStringCentered(w->widget[NGWW_DETAILS].left + 115, 48, STR_NETWORK_GAME_INFO, TC_FROMSTRING);
   365 			DrawStringCentered(w->widget[NGWW_DETAILS].left + 115, 48, STR_NETWORK_GAME_INFO, TC_FROMSTRING);
   364 
   366 
   365 
   367 
   366 				SetDParamStr(0, sel->info.server_name);
   368 			SetDParamStr(0, sel->info.server_name);
   367 				DrawStringCenteredTruncated(w->widget[NGWW_DETAILS].left, w->widget[NGWW_DETAILS].right, 62, STR_ORANGE, TC_BLACK); // game name
   369 			DrawStringCenteredTruncated(w->widget[NGWW_DETAILS].left, w->widget[NGWW_DETAILS].right, 62, STR_ORANGE, TC_BLACK); // game name
   368 
   370 
   369 				SetDParamStr(0, sel->info.map_name);
   371 			SetDParamStr(0, sel->info.map_name);
   370 				DrawStringCenteredTruncated(w->widget[NGWW_DETAILS].left, w->widget[NGWW_DETAILS].right, 74, STR_02BD, TC_BLACK); // map name
   372 			DrawStringCenteredTruncated(w->widget[NGWW_DETAILS].left, w->widget[NGWW_DETAILS].right, 74, STR_02BD, TC_BLACK); // map name
   371 
   373 
   372 				SetDParam(0, sel->info.clients_on);
   374 			SetDParam(0, sel->info.clients_on);
   373 				SetDParam(1, sel->info.clients_max);
   375 			SetDParam(1, sel->info.clients_max);
   374 				SetDParam(2, sel->info.companies_on);
   376 			SetDParam(2, sel->info.companies_on);
   375 				SetDParam(3, sel->info.companies_max);
   377 			SetDParam(3, sel->info.companies_max);
   376 				DrawString(x, y, STR_NETWORK_CLIENTS, TC_GOLD);
   378 			DrawString(x, y, STR_NETWORK_CLIENTS, TC_GOLD);
   377 				y += 10;
   379 			y += 10;
   378 
   380 
   379 				SetDParam(0, STR_NETWORK_LANG_ANY + sel->info.server_lang);
   381 			SetDParam(0, STR_NETWORK_LANG_ANY + sel->info.server_lang);
   380 				DrawString(x, y, STR_NETWORK_LANGUAGE, TC_GOLD); // server language
   382 			DrawString(x, y, STR_NETWORK_LANGUAGE, TC_GOLD); // server language
   381 				y += 10;
   383 			y += 10;
   382 
   384 
   383 				SetDParam(0, STR_TEMPERATE_LANDSCAPE + sel->info.map_set);
   385 			SetDParam(0, STR_TEMPERATE_LANDSCAPE + sel->info.map_set);
   384 				DrawString(x, y, STR_NETWORK_TILESET, TC_GOLD); // tileset
   386 			DrawString(x, y, STR_NETWORK_TILESET, TC_GOLD); // tileset
   385 				y += 10;
   387 			y += 10;
   386 
   388 
   387 				SetDParam(0, sel->info.map_width);
   389 			SetDParam(0, sel->info.map_width);
   388 				SetDParam(1, sel->info.map_height);
   390 			SetDParam(1, sel->info.map_height);
   389 				DrawString(x, y, STR_NETWORK_MAP_SIZE, TC_GOLD); // map size
   391 			DrawString(x, y, STR_NETWORK_MAP_SIZE, TC_GOLD); // map size
   390 				y += 10;
   392 			y += 10;
   391 
   393 
   392 				SetDParamStr(0, sel->info.server_revision);
   394 			SetDParamStr(0, sel->info.server_revision);
   393 				DrawString(x, y, STR_NETWORK_SERVER_VERSION, TC_GOLD); // server version
   395 			DrawString(x, y, STR_NETWORK_SERVER_VERSION, TC_GOLD); // server version
   394 				y += 10;
   396 			y += 10;
   395 
   397 
   396 				SetDParamStr(0, sel->info.hostname);
   398 			SetDParamStr(0, sel->info.hostname);
   397 				SetDParam(1, sel->port);
   399 			SetDParam(1, sel->port);
   398 				DrawString(x, y, STR_NETWORK_SERVER_ADDRESS, TC_GOLD); // server address
   400 			DrawString(x, y, STR_NETWORK_SERVER_ADDRESS, TC_GOLD); // server address
   399 				y += 10;
   401 			y += 10;
   400 
   402 
   401 				SetDParam(0, sel->info.start_date);
   403 			SetDParam(0, sel->info.start_date);
   402 				DrawString(x, y, STR_NETWORK_START_DATE, TC_GOLD); // start date
   404 			DrawString(x, y, STR_NETWORK_START_DATE, TC_GOLD); // start date
   403 				y += 10;
   405 			y += 10;
   404 
   406 
   405 				SetDParam(0, sel->info.game_date);
   407 			SetDParam(0, sel->info.game_date);
   406 				DrawString(x, y, STR_NETWORK_CURRENT_DATE, TC_GOLD); // current date
   408 			DrawString(x, y, STR_NETWORK_CURRENT_DATE, TC_GOLD); // current date
   407 				y += 10;
   409 			y += 10;
   408 
   410 
   409 				y += 2;
   411 			y += 2;
   410 
   412 
   411 				if (!sel->info.compatible) {
   413 			if (!sel->info.compatible) {
   412 					DrawStringCentered(w->widget[NGWW_DETAILS].left + 115, y, sel->info.version_compatible ? STR_NETWORK_GRF_MISMATCH : STR_NETWORK_VERSION_MISMATCH, TC_FROMSTRING); // server mismatch
   414 				DrawStringCentered(w->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) {
   415 			} else if (sel->info.clients_on == sel->info.clients_max) {
   414 					/* Show: server full, when clients_on == clients_max */
   416 				/* Show: server full, when clients_on == clients_max */
   415 					DrawStringCentered(w->widget[NGWW_DETAILS].left + 115, y, STR_NETWORK_SERVER_FULL, TC_FROMSTRING); // server full
   417 				DrawStringCentered(w->widget[NGWW_DETAILS].left + 115, y, STR_NETWORK_SERVER_FULL, TC_FROMSTRING); // server full
   416 				} else if (sel->info.use_password) {
   418 			} else if (sel->info.use_password) {
   417 					DrawStringCentered(w->widget[NGWW_DETAILS].left + 115, y, STR_NETWORK_PASSWORD, TC_FROMSTRING); // password warning
   419 				DrawStringCentered(w->widget[NGWW_DETAILS].left + 115, y, STR_NETWORK_PASSWORD, TC_FROMSTRING); // password warning
   418 				}
   420 			}
   419 
   421 
   420 				y += 10;
   422 			y += 10;
   421 			}
   423 		}
   422 		} break;
   424 	} break;
   423 
   425 
   424 		case WE_CLICK:
   426 	case WE_CLICK:
   425 			nd->field = e->we.click.widget;
   427 		nd->field = e->we.click.widget;
   426 			switch (e->we.click.widget) {
   428 		switch (e->we.click.widget) {
   427 				case NGWW_PLAYER:
   429 		case NGWW_PLAYER:
   428 					ShowOnScreenKeyboard(w, &WP(w, network_ql_d).q,  NGWW_PLAYER, 0, 0);
   430 			ShowOnScreenKeyboard(w, &WP(w, network_ql_d).q,  NGWW_PLAYER, 0, 0);
   429 					break;
   431 			break;
   430 
   432 		case NGWW_CANCEL: // Cancel button
   431 				case NGWW_CANCEL: // Cancel button
   433 			DeleteWindowById(WC_NETWORK_WINDOW, 0);
   432 					DeleteWindowById(WC_NETWORK_WINDOW, 0);
   434 			break;
   433 					break;
   435 		case NGWW_CONN_BTN: // 'Connection' droplist
   434 
   436 			ShowDropDownMenu(w, _lan_internet_types_dropdown, _network_lan_internet, NGWW_CONN_BTN, 0, 0); // do it for widget NSSW_CONN_BTN
   435 				case NGWW_CONN_BTN: // 'Connection' droplist
   437 			break;
   436 					ShowDropDownMenu(w, _lan_internet_types_dropdown, _network_lan_internet, NGWW_CONN_BTN, 0, 0); // do it for widget NSSW_CONN_BTN
   438 		case NGWW_NAME: // Sort by name
   437 					break;
   439 		case NGWW_CLIENTS: // Sort by connected clients
   438 
   440 		case NGWW_INFO: // Connectivity (green dot)
   439 				case NGWW_NAME: // Sort by name
   441 			if (ld->sort_type == e->we.click.widget - NGWW_NAME) ld->flags ^= VL_DESC;
   440 				case NGWW_CLIENTS: // Sort by connected clients
   442 			ld->flags |= VL_RESORT;
   441 				case NGWW_INFO: // Connectivity (green dot)
   443 			ld->sort_type = e->we.click.widget - NGWW_NAME;
   442 					if (ld->sort_type == e->we.click.widget - NGWW_NAME) ld->flags ^= VL_DESC;
   444 
   443 					ld->flags |= VL_RESORT;
   445 			_ng_sorting.order = !!(ld->flags & VL_DESC);
   444 					ld->sort_type = e->we.click.widget - NGWW_NAME;
   446 			_ng_sorting.criteria = ld->sort_type;
   445 
       
   446 					_ng_sorting.order = !!(ld->flags & VL_DESC);
       
   447 					_ng_sorting.criteria = ld->sort_type;
       
   448 					SetWindowDirty(w);
       
   449 					break;
       
   450 
       
   451 				case NGWW_MATRIX: { // Matrix to show networkgames
       
   452 					NetworkGameList *cur_item;
       
   453 					uint32 id_v = (e->we.click.pt.y - NET_PRC__OFFSET_TOP_WIDGET) / NET_PRC__SIZE_OF_ROW;
       
   454 
       
   455 					if (id_v >= w->vscroll.cap) return; // click out of bounds
       
   456 					id_v += w->vscroll.pos;
       
   457 
       
   458 					cur_item = _network_game_list;
       
   459 					for (; id_v > 0 && cur_item != NULL; id_v--) cur_item = cur_item->next;
       
   460 
       
   461 					nd->server = cur_item;
       
   462 					SetWindowDirty(w);
       
   463 				} break;
       
   464 
       
   465 				case NGWW_FIND: // Find server automatically
       
   466 					switch (_network_lan_internet) {
       
   467 						case 0: NetworkUDPSearchGame(); break;
       
   468 						case 1: NetworkUDPQueryMasterServer(); break;
       
   469 					}
       
   470 					break;
       
   471 
       
   472 				case NGWW_ADD: // Add a server
       
   473 					ShowQueryString(
       
   474 						BindCString(_network_default_ip),
       
   475 						STR_NETWORK_ENTER_IP,
       
   476 						31 | 0x1000,  // maximum number of characters OR
       
   477 						250, // characters up to this width pixels, whichever is satisfied first
       
   478 						w, CS_ALPHANUMERAL);
       
   479 					break;
       
   480 
       
   481 				case NGWW_START: // Start server
       
   482 					ShowNetworkStartServerWindow();
       
   483 					break;
       
   484 
       
   485 				case NGWW_JOIN: // Join Game
       
   486 					if (nd->server != NULL) {
       
   487 						snprintf(_network_last_host, sizeof(_network_last_host), "%s", inet_ntoa(*(struct in_addr *)&nd->server->ip));
       
   488 						_network_last_port = nd->server->port;
       
   489 						ShowNetworkLobbyWindow(nd->server);
       
   490 					}
       
   491 					break;
       
   492 
       
   493 				case NGWW_REFRESH: // Refresh
       
   494 					if (nd->server != NULL) NetworkUDPQueryServer(nd->server->info.hostname, nd->server->port);
       
   495 					break;
       
   496 
       
   497 				case NGWW_NEWGRF: // NewGRF Settings
       
   498 					if (nd->server != NULL) ShowNewGRFSettings(false, false, false, &nd->server->info.grfconfig);
       
   499 					break;
       
   500 			}
       
   501 			break;
       
   502 
       
   503 		case WE_DROPDOWN_SELECT: // we have selected a dropdown item in the list
       
   504 			switch (e->we.dropdown.button) {
       
   505 				case NGWW_CONN_BTN:
       
   506 					_network_lan_internet = e->we.dropdown.index;
       
   507 					break;
       
   508 
       
   509 				default:
       
   510 					NOT_REACHED();
       
   511 			}
       
   512 
   447 			SetWindowDirty(w);
   513 			SetWindowDirty(w);
   448 			break;
   514 			break;
   449 		case NGWW_MATRIX: { // Matrix to show networkgames
   515 
   450 			NetworkGameList *cur_item;
   516 		case WE_MOUSELOOP:
   451 			uint32 id_v = (e->we.click.pt.y - NET_PRC__OFFSET_TOP_WIDGET) / NET_PRC__SIZE_OF_ROW;
   517 			if (nd->field == NGWW_PLAYER) HandleEditBox(w, &WP(w, network_ql_d).q, NGWW_PLAYER);
   452 
   518 			break;
   453 			if (id_v >= w->vscroll.cap) return; // click out of bounds
   519 
   454 			id_v += w->vscroll.pos;
   520 		case WE_MESSAGE:
   455 
   521 			if (e->we.message.msg != 0) nd->server = NULL;
   456 			cur_item = _network_game_list;
   522 			ld->flags |= VL_REBUILD;
   457 			for (; id_v > 0 && cur_item != NULL; id_v--) cur_item = cur_item->next;
       
   458 
       
   459 			nd->server = cur_item;
       
   460 			SetWindowDirty(w);
   523 			SetWindowDirty(w);
       
   524 			break;
       
   525 
       
   526 		case WE_KEYPRESS:
       
   527 			if (nd->field != NGWW_PLAYER) {
       
   528 				if (nd->server != NULL) {
       
   529 					if (e->we.keypress.keycode == WKC_DELETE) { // Press 'delete' to remove servers
       
   530 						NetworkGameListRemoveItem(nd->server);
       
   531 						NetworkRebuildHostList();
       
   532 						nd->server = NULL;
       
   533 					}
       
   534 				}
       
   535 				break;
       
   536 			}
       
   537 
       
   538 			if (HandleEditBoxKey(w, &WP(w, network_ql_d).q, NGWW_PLAYER, e) == 1) break; // enter pressed
       
   539 
       
   540 			/* The name is only allowed when it starts with a letter! */
       
   541 			if (_edit_str_net_buf[0] != '\0' && _edit_str_net_buf[0] != ' ') {
       
   542 				ttd_strlcpy(_network_player_name, _edit_str_net_buf, lengthof(_network_player_name));
       
   543 			} else {
       
   544 				ttd_strlcpy(_network_player_name, "Player", lengthof(_network_player_name));
       
   545 			}
       
   546 
       
   547 			break;
       
   548 
       
   549 		case WE_ON_EDIT_TEXT:
       
   550 			NetworkAddServer(e->we.edittext.str);
       
   551 			NetworkRebuildHostList();
       
   552 			break;
       
   553 
       
   554 		case WE_RESIZE: {
       
   555 			w->vscroll.cap += e->we.sizing.diff.y / (int)w->resize.step_height;
       
   556 
       
   557 			w->widget[NGWW_MATRIX].data = (w->vscroll.cap << 8) + 1;
       
   558 
       
   559 			SetVScrollCount(w, ld->list_length);
       
   560 
       
   561 			int widget_width = w->widget[NGWW_FIND].right - w->widget[NGWW_FIND].left;
       
   562 			int space = (w->width - 4 * widget_width - 25) / 3;
       
   563 
       
   564 			int offset = 10;
       
   565 			for (uint i = 0; i < 4; i++) {
       
   566 				w->widget[NGWW_FIND + i].left  = offset;
       
   567 				offset += widget_width;
       
   568 				w->widget[NGWW_FIND + i].right = offset;
       
   569 				offset += space;
       
   570 			}
   461 		} break;
   571 		} break;
   462 		case NGWW_FIND: // Find server automatically
   572 
   463 			switch (_network_lan_internet) {
   573 		case WE_DESTROY: // Nicely clean up the sort-list
   464 				case 0: NetworkUDPSearchGame(); break;
   574 			free(WP(w, network_ql_d).sort_list);
   465 				case 1: NetworkUDPQueryMasterServer(); break;
   575 			break;
   466 			}
       
   467 			break;
       
   468 		case NGWW_ADD: { // Add a server
       
   469 			ShowQueryString(
       
   470 				BindCString(_network_default_ip),
       
   471 				STR_NETWORK_ENTER_IP,
       
   472 				31 | 0x1000,  // maximum number of characters OR
       
   473 				250, // characters up to this width pixels, whichever is satisfied first
       
   474 				w, CS_ALPHANUMERAL);
       
   475 		} break;
       
   476 		case NGWW_START: // Start server
       
   477 			ShowNetworkStartServerWindow();
       
   478 			break;
       
   479 		case NGWW_JOIN: // Join Game
       
   480 			if (nd->server != NULL) {
       
   481 				snprintf(_network_last_host, sizeof(_network_last_host), "%s", inet_ntoa(*(struct in_addr *)&nd->server->ip));
       
   482 				_network_last_port = nd->server->port;
       
   483 				ShowNetworkLobbyWindow(nd->server);
       
   484 			}
       
   485 			break;
       
   486 		case NGWW_REFRESH: // Refresh
       
   487 			if (nd->server != NULL)
       
   488 				NetworkUDPQueryServer(nd->server->info.hostname, nd->server->port);
       
   489 			break;
       
   490 		case NGWW_NEWGRF: // NewGRF Settings
       
   491 			if (nd->server != NULL) ShowNewGRFSettings(false, false, false, &nd->server->info.grfconfig);
       
   492 			break;
       
   493 
       
   494 	} break;
       
   495 
       
   496 	case WE_DROPDOWN_SELECT: // we have selected a dropdown item in the list
       
   497 		switch (e->we.dropdown.button) {
       
   498 			case NGWW_CONN_BTN:
       
   499 				_network_lan_internet = e->we.dropdown.index;
       
   500 				break;
       
   501 			default:
       
   502 				NOT_REACHED();
       
   503 		}
       
   504 
       
   505 		SetWindowDirty(w);
       
   506 		break;
       
   507 
       
   508 	case WE_MOUSELOOP:
       
   509 		if (nd->field == NGWW_PLAYER) HandleEditBox(w, &WP(w, network_ql_d).q, NGWW_PLAYER);
       
   510 		break;
       
   511 
       
   512 	case WE_MESSAGE:
       
   513 		if (e->we.message.msg != 0) nd->server = NULL;
       
   514 		ld->flags |= VL_REBUILD;
       
   515 		SetWindowDirty(w);
       
   516 		break;
       
   517 
       
   518 	case WE_KEYPRESS:
       
   519 		if (nd->field != NGWW_PLAYER) {
       
   520 			if (nd->server != NULL) {
       
   521 				if (e->we.keypress.keycode == WKC_DELETE) { // Press 'delete' to remove servers
       
   522 					NetworkGameListRemoveItem(nd->server);
       
   523 					NetworkRebuildHostList();
       
   524 					nd->server = NULL;
       
   525 				}
       
   526 			}
       
   527 			break;
       
   528 		}
       
   529 
       
   530 		if (HandleEditBoxKey(w, &WP(w, network_ql_d).q, NGWW_PLAYER, e) == 1) break; // enter pressed
       
   531 
       
   532 		/* The name is only allowed when it starts with a letter! */
       
   533 		if (_edit_str_net_buf[0] != '\0' && _edit_str_net_buf[0] != ' ') {
       
   534 			ttd_strlcpy(_network_player_name, _edit_str_net_buf, lengthof(_network_player_name));
       
   535 		} else {
       
   536 			ttd_strlcpy(_network_player_name, "Player", lengthof(_network_player_name));
       
   537 		}
       
   538 
       
   539 		break;
       
   540 
       
   541 	case WE_ON_EDIT_TEXT:
       
   542 		NetworkAddServer(e->we.edittext.str);
       
   543 		NetworkRebuildHostList();
       
   544 		break;
       
   545 
       
   546 	case WE_RESIZE: {
       
   547 		w->vscroll.cap += e->we.sizing.diff.y / (int)w->resize.step_height;
       
   548 
       
   549 		w->widget[NGWW_MATRIX].data = (w->vscroll.cap << 8) + 1;
       
   550 
       
   551 		SetVScrollCount(w, ld->list_length);
       
   552 
       
   553 		int widget_width = w->widget[NGWW_FIND].right - w->widget[NGWW_FIND].left;
       
   554 		int space = (w->width - 4 * widget_width - 25) / 3;
       
   555 
       
   556 		int offset = 10;
       
   557 		for (uint i = 0; i < 4; i++) {
       
   558 			w->widget[NGWW_FIND + i].left  = offset;
       
   559 			offset += widget_width;
       
   560 			w->widget[NGWW_FIND + i].right = offset;
       
   561 			offset += space;
       
   562 		}
       
   563 	} break;
       
   564 
       
   565 	case WE_DESTROY: // Nicely clean up the sort-list
       
   566 		free(WP(w, network_ql_d).sort_list);
       
   567 		break;
       
   568 	}
   576 	}
   569 }
   577 }
   570 
   578 
   571 static const Widget _network_game_window_widgets[] = {
   579 static const Widget _network_game_window_widgets[] = {
   572 /* TOP */
   580 /* TOP */
   573 {   WWT_CLOSEBOX,   RESIZE_NONE,   BGC,     0,    10,     0,    13, STR_00C5,                       STR_018B_CLOSE_WINDOW},            // NGWW_CLOSE
   581 {   WWT_CLOSEBOX,   RESIZE_NONE,   BGC,     0,    10,     0,    13, STR_00C5,                         STR_018B_CLOSE_WINDOW},            // NGWW_CLOSE
   574 {    WWT_CAPTION,   RESIZE_RIGHT,  BGC,    11,   449,     0,    13, STR_NETWORK_MULTIPLAYER,        STR_NULL},
   582 {    WWT_CAPTION,   RESIZE_RIGHT,  BGC,    11,   449,     0,    13, STR_NETWORK_MULTIPLAYER,          STR_NULL},
   575 {      WWT_PANEL,   RESIZE_RB,     BGC,     0,   449,    14,   263, 0x0,                            STR_NULL},
   583 {      WWT_PANEL,   RESIZE_RB,     BGC,     0,   449,    14,   263, 0x0,                              STR_NULL},
   576 
   584 
   577 {       WWT_TEXT,   RESIZE_NONE,   BGC,     9,    85,    23,    35, STR_NETWORK_CONNECTION,         STR_NULL},
   585 {       WWT_TEXT,   RESIZE_NONE,   BGC,     9,    85,    23,    35, STR_NETWORK_CONNECTION,           STR_NULL},
   578 { WWT_DROPDOWNIN,   RESIZE_NONE,   BGC,    90,   181,    22,    33, STR_NETWORK_LAN_INTERNET_COMBO, STR_NETWORK_CONNECTION_TIP},       // NGWW_CONN_BTN
   586 { WWT_DROPDOWNIN,   RESIZE_NONE,   BGC,    90,   181,    22,    33, STR_NETWORK_LAN_INTERNET_COMBO,   STR_NETWORK_CONNECTION_TIP},       // NGWW_CONN_BTN
   579 
   587 
   580 {    WWT_EDITBOX,   RESIZE_LR,     BGC,   290,   440,    22,    33, STR_NETWORK_PLAYER_NAME_OSKTITLE, STR_NETWORK_ENTER_NAME_TIP},       // NGWW_PLAYER
   588 {    WWT_EDITBOX,   RESIZE_LR,     BGC,   290,   440,    22,    33, STR_NETWORK_PLAYER_NAME_OSKTITLE, STR_NETWORK_ENTER_NAME_TIP},       // NGWW_PLAYER
   581 
   589 
   582 /* LEFT SIDE */
   590 /* LEFT SIDE */
   583 { WWT_PUSHTXTBTN,   RESIZE_RIGHT,  BTC,    10,    70,    42,    53, STR_NETWORK_GAME_NAME,          STR_NETWORK_GAME_NAME_TIP},        // NGWW_NAME
   591 { WWT_PUSHTXTBTN,   RESIZE_RIGHT,  BTC,    10,    70,    42,    53, STR_NETWORK_GAME_NAME,            STR_NETWORK_GAME_NAME_TIP},        // NGWW_NAME
   584 { WWT_PUSHTXTBTN,   RESIZE_LR,     BTC,    71,   150,    42,    53, STR_NETWORK_CLIENTS_CAPTION,    STR_NETWORK_CLIENTS_CAPTION_TIP},  // NGWW_CLIENTS
   592 { WWT_PUSHTXTBTN,   RESIZE_LR,     BTC,    71,   150,    42,    53, STR_NETWORK_CLIENTS_CAPTION,      STR_NETWORK_CLIENTS_CAPTION_TIP},  // NGWW_CLIENTS
   585 { WWT_PUSHTXTBTN,   RESIZE_LR,     BTC,   151,   190,    42,    53, STR_EMPTY,                      STR_NETWORK_INFO_ICONS_TIP},       // NGWW_INFO
   593 { WWT_PUSHTXTBTN,   RESIZE_LR,     BTC,   151,   190,    42,    53, STR_EMPTY,                        STR_NETWORK_INFO_ICONS_TIP},       // NGWW_INFO
   586 
   594 
   587 {     WWT_MATRIX,   RESIZE_RB,     BGC,    10,   190,    54,   236, (13 << 8) + 1,                  STR_NETWORK_CLICK_GAME_TO_SELECT}, // NGWW_MATRIX
   595 {     WWT_MATRIX,   RESIZE_RB,     BGC,    10,   190,    54,   236, (13 << 8) + 1,                    STR_NETWORK_CLICK_GAME_TO_SELECT}, // NGWW_MATRIX
   588 {  WWT_SCROLLBAR,   RESIZE_LRB,    BGC,   191,   202,    42,   236, 0x0,                            STR_0190_SCROLL_BAR_SCROLLS_LIST},
   596 {  WWT_SCROLLBAR,   RESIZE_LRB,    BGC,   191,   202,    42,   236, 0x0,                              STR_0190_SCROLL_BAR_SCROLLS_LIST},
   589 
   597 
   590 /* RIGHT SIDE */
   598 /* RIGHT SIDE */
   591 {      WWT_PANEL,   RESIZE_LRB,    BGC,   210,   440,    42,   236, 0x0,                            STR_NULL},                         // NGWW_DETAILS
   599 {      WWT_PANEL,   RESIZE_LRB,    BGC,   210,   440,    42,   236, 0x0,                              STR_NULL},                         // NGWW_DETAILS
   592 
   600 
   593 { WWT_PUSHTXTBTN,   RESIZE_LRTB,   BTC,   215,   315,   215,   226, STR_NETWORK_JOIN_GAME,          STR_NULL},                         // NGWW_JOIN
   601 { WWT_PUSHTXTBTN,   RESIZE_LRTB,   BTC,   215,   315,   215,   226, STR_NETWORK_JOIN_GAME,            STR_NULL},                         // NGWW_JOIN
   594 { WWT_PUSHTXTBTN,   RESIZE_LRTB,   BTC,   330,   435,   215,   226, STR_NETWORK_REFRESH,            STR_NETWORK_REFRESH_TIP},          // NGWW_REFRESH
   602 { WWT_PUSHTXTBTN,   RESIZE_LRTB,   BTC,   330,   435,   215,   226, STR_NETWORK_REFRESH,              STR_NETWORK_REFRESH_TIP},          // NGWW_REFRESH
   595 
   603 
   596 { WWT_PUSHTXTBTN,   RESIZE_LRTB,   BTC,   330,   435,   197,   208, STR_NEWGRF_SETTINGS_BUTTON,     STR_NULL},                         // NGWW_NEWGRF
   604 { WWT_PUSHTXTBTN,   RESIZE_LRTB,   BTC,   330,   435,   197,   208, STR_NEWGRF_SETTINGS_BUTTON,       STR_NULL},                         // NGWW_NEWGRF
   597 
   605 
   598 /* BOTTOM */
   606 /* BOTTOM */
   599 { WWT_PUSHTXTBTN,   RESIZE_TB,     BTC,    10,   110,   246,   257, STR_NETWORK_FIND_SERVER,        STR_NETWORK_FIND_SERVER_TIP},      // NGWW_FIND
   607 { WWT_PUSHTXTBTN,   RESIZE_TB,     BTC,    10,   110,   246,   257, STR_NETWORK_FIND_SERVER,          STR_NETWORK_FIND_SERVER_TIP},      // NGWW_FIND
   600 { WWT_PUSHTXTBTN,   RESIZE_TB,     BTC,   118,   218,   246,   257, STR_NETWORK_ADD_SERVER,         STR_NETWORK_ADD_SERVER_TIP},       // NGWW_ADD
   608 { WWT_PUSHTXTBTN,   RESIZE_TB,     BTC,   118,   218,   246,   257, STR_NETWORK_ADD_SERVER,           STR_NETWORK_ADD_SERVER_TIP},       // NGWW_ADD
   601 { WWT_PUSHTXTBTN,   RESIZE_TB,     BTC,   226,   326,   246,   257, STR_NETWORK_START_SERVER,       STR_NETWORK_START_SERVER_TIP},     // NGWW_START
   609 { WWT_PUSHTXTBTN,   RESIZE_TB,     BTC,   226,   326,   246,   257, STR_NETWORK_START_SERVER,         STR_NETWORK_START_SERVER_TIP},     // NGWW_START
   602 { WWT_PUSHTXTBTN,   RESIZE_TB,     BTC,   334,   434,   246,   257, STR_012E_CANCEL,                STR_NULL},                         // NGWW_CANCEL
   610 { WWT_PUSHTXTBTN,   RESIZE_TB,     BTC,   334,   434,   246,   257, STR_012E_CANCEL,                  STR_NULL},                         // NGWW_CANCEL
   603 
   611 
   604 {  WWT_RESIZEBOX,   RESIZE_LRTB,   BGC,   438,   449,   252,   263, 0x0,                            STR_RESIZE_BUTTON },
   612 {  WWT_RESIZEBOX,   RESIZE_LRTB,   BGC,   438,   449,   252,   263, 0x0,                              STR_RESIZE_BUTTON },
   605 
   613 
   606 {   WIDGETS_END},
   614 {   WIDGETS_END},
   607 };
   615 };
   608 
   616 
   609 static const WindowDesc _network_game_window_desc = {
   617 static const WindowDesc _network_game_window_desc = {
   615 };
   623 };
   616 
   624 
   617 void ShowNetworkGameWindow()
   625 void ShowNetworkGameWindow()
   618 {
   626 {
   619 	static bool first = true;
   627 	static bool first = true;
   620 	Window *w;
       
   621 	DeleteWindowById(WC_NETWORK_WINDOW, 0);
   628 	DeleteWindowById(WC_NETWORK_WINDOW, 0);
   622 
   629 
   623 	/* Only show once */
   630 	/* Only show once */
   624 	if (first) {
   631 	if (first) {
   625 		char* const *srv;
   632 		char * const *srv;
   626 
   633 
   627 		first = false;
   634 		first = false;
   628 		// add all servers from the config file to our list
   635 		// add all servers from the config file to our list
   629 		for (srv = &_network_host_list[0]; srv != endof(_network_host_list) && *srv != NULL; srv++) {
   636 		for (srv = &_network_host_list[0]; srv != endof(_network_host_list) && *srv != NULL; srv++) {
   630 			NetworkAddServer(*srv);
   637 			NetworkAddServer(*srv);
   632 
   639 
   633 		_ng_sorting.criteria = 2; // sort default by collectivity (green-dots on top)
   640 		_ng_sorting.criteria = 2; // sort default by collectivity (green-dots on top)
   634 		_ng_sorting.order = 0;    // sort ascending by default
   641 		_ng_sorting.order = 0;    // sort ascending by default
   635 	}
   642 	}
   636 
   643 
   637 	w = AllocateWindowDesc(&_network_game_window_desc);
   644 	Window *w = AllocateWindowDesc(&_network_game_window_desc);
   638 	if (w != NULL) {
   645 	if (w != NULL) {
   639 		querystr_d *querystr = &WP(w, network_ql_d).q;
   646 		querystr_d *querystr = &WP(w, network_ql_d).q;
   640 
   647 
   641 		ttd_strlcpy(_edit_str_net_buf, _network_player_name, lengthof(_edit_str_net_buf));
   648 		ttd_strlcpy(_edit_str_net_buf, _network_player_name, lengthof(_edit_str_net_buf));
   642 		querystr->afilter = CS_ALPHANUMERAL;
   649 		querystr->afilter = CS_ALPHANUMERAL;
   685 static void NetworkStartServerWindowWndProc(Window *w, WindowEvent *e)
   692 static void NetworkStartServerWindowWndProc(Window *w, WindowEvent *e)
   686 {
   693 {
   687 	network_d *nd = &WP(w, network_ql_d).n;
   694 	network_d *nd = &WP(w, network_ql_d).n;
   688 
   695 
   689 	switch (e->event) {
   696 	switch (e->event) {
   690 	case WE_CREATE: // focus input box
   697 		case WE_CREATE: // focus input box
   691 		nd->field = NSSW_GAMENAME;
   698 			nd->field = NSSW_GAMENAME;
   692 		_network_game_info.use_password = (_network_server_password[0] != '\0');
   699 			_network_game_info.use_password = (_network_server_password[0] != '\0');
   693 		break;
   700 			break;
   694 
   701 
   695 	case WE_PAINT: {
   702 		case WE_PAINT: {
   696 		int y = NSSWND_START, pos;
   703 			int y = NSSWND_START, pos;
   697 		const FiosItem *item;
   704 			const FiosItem *item;
   698 
   705 
   699 		/* draw basic widgets */
   706 			/* draw basic widgets */
   700 		SetDParam(1, _connection_types_dropdown[_network_advertise]);
   707 			SetDParam(1, _connection_types_dropdown[_network_advertise]);
   701 		SetDParam(2, _network_game_info.clients_max);
   708 			SetDParam(2, _network_game_info.clients_max);
   702 		SetDParam(3, _network_game_info.companies_max);
   709 			SetDParam(3, _network_game_info.companies_max);
   703 		SetDParam(4, _network_game_info.spectators_max);
   710 			SetDParam(4, _network_game_info.spectators_max);
   704 		SetDParam(5, STR_NETWORK_LANG_ANY + _network_game_info.server_lang);
   711 			SetDParam(5, STR_NETWORK_LANG_ANY + _network_game_info.server_lang);
   705 		DrawWindowWidgets(w);
   712 			DrawWindowWidgets(w);
   706 
   713 
   707 		/* editbox to set game name */
   714 			/* editbox to set game name */
   708 		DrawEditBox(w, &WP(w, network_ql_d).q, NSSW_GAMENAME);
   715 			DrawEditBox(w, &WP(w, network_ql_d).q, NSSW_GAMENAME);
   709 
   716 
   710 		/* if password is set, draw red '*' next to 'Set password' button */
   717 			/* if password is set, draw red '*' next to 'Set password' button */
   711 		if (_network_game_info.use_password) DoDrawString("*", 408, 23, TC_RED);
   718 			if (_network_game_info.use_password) DoDrawString("*", 408, 23, TC_RED);
   712 
   719 
   713 		/* draw list of maps */
   720 			/* draw list of maps */
   714 		GfxFillRect(11, 63, 258, 215, 0xD7);  // black background of maps list
   721 			GfxFillRect(11, 63, 258, 215, 0xD7);  // black background of maps list
   715 
   722 
   716 		pos = w->vscroll.pos;
   723 			pos = w->vscroll.pos;
   717 		while (pos < _fios_num + 1) {
   724 			while (pos < _fios_num + 1) {
   718 			item = _fios_list + pos - 1;
   725 				item = _fios_list + pos - 1;
   719 			if (item == nd->map || (pos == 0 && nd->map == NULL))
   726 				if (item == nd->map || (pos == 0 && nd->map == NULL))
   720 				GfxFillRect(11, y - 1, 258, y + 10, 155); // show highlighted item with a different colour
   727 					GfxFillRect(11, y - 1, 258, y + 10, 155); // show highlighted item with a different colour
   721 
   728 
   722 			if (pos == 0) {
   729 				if (pos == 0) {
   723 				DrawString(14, y, STR_4010_GENERATE_RANDOM_NEW_GAME, TC_DARK_GREEN);
   730 					DrawString(14, y, STR_4010_GENERATE_RANDOM_NEW_GAME, TC_DARK_GREEN);
       
   731 				} else {
       
   732 					DoDrawString(item->title, 14, y, _fios_colors[item->type] );
       
   733 				}
       
   734 				pos++;
       
   735 				y += NSSWND_ROWSIZE;
       
   736 
       
   737 				if (y >= w->vscroll.cap * NSSWND_ROWSIZE + NSSWND_START) break;
       
   738 			}
       
   739 		} break;
       
   740 
       
   741 		case WE_CLICK:
       
   742 			if (e->we.click.widget != NSSW_CONNTYPE_BTN && e->we.click.widget != NSSW_LANGUAGE_BTN) HideDropDownMenu(w);
       
   743 			nd->field = e->we.click.widget;
       
   744 			switch (e->we.click.widget) {
       
   745 				case NSSW_CLOSE:  // Close 'X'
       
   746 				case NSSW_CANCEL: // Cancel button
       
   747 					ShowNetworkGameWindow();
       
   748 					break;
       
   749 
       
   750 				case NSSW_GAMENAME:
       
   751 					ShowOnScreenKeyboard(w, &WP(w, network_ql_d).q,  NSSW_GAMENAME, 0, 0);
       
   752 					break;
       
   753 
       
   754 				case NSSW_SETPWD: // Set password button
       
   755 					nd->widget_id = NSSW_SETPWD;
       
   756 					ShowQueryString(BindCString(_network_server_password), STR_NETWORK_SET_PASSWORD, 20, 250, w, CS_ALPHANUMERAL);
       
   757 					break;
       
   758 
       
   759 				case NSSW_SELMAP: { // Select map
       
   760 					int y = (e->we.click.pt.y - NSSWND_START) / NSSWND_ROWSIZE;
       
   761 
       
   762 					y += w->vscroll.pos;
       
   763 					if (y >= w->vscroll.count) return;
       
   764 
       
   765 					nd->map = (y == 0) ? NULL : _fios_list + y - 1;
       
   766 					SetWindowDirty(w);
       
   767 				} break;
       
   768 
       
   769 				case NSSW_CONNTYPE_BTN: // Connection type
       
   770 					ShowDropDownMenu(w, _connection_types_dropdown, _network_advertise, NSSW_CONNTYPE_BTN, 0, 0); // do it for widget NSSW_CONNTYPE_BTN
       
   771 					break;
       
   772 
       
   773 				case NSSW_CLIENTS_BTND:    case NSSW_CLIENTS_BTNU:    // Click on up/down button for number of clients
       
   774 				case NSSW_COMPANIES_BTND:  case NSSW_COMPANIES_BTNU:  // Click on up/down button for number of companies
       
   775 				case NSSW_SPECTATORS_BTND: case NSSW_SPECTATORS_BTNU: // Click on up/down button for number of spectators
       
   776 					/* Don't allow too fast scrolling */
       
   777 					if ((w->flags4 & WF_TIMEOUT_MASK) <= 2 << WF_TIMEOUT_SHL) {
       
   778 						w->HandleButtonClick(e->we.click.widget);
       
   779 						SetWindowDirty(w);
       
   780 						switch (e->we.click.widget) {
       
   781 							default: NOT_REACHED();
       
   782 							case NSSW_CLIENTS_BTND: case NSSW_CLIENTS_BTNU:
       
   783 								_network_game_info.clients_max    = Clamp(_network_game_info.clients_max    + e->we.click.widget - NSSW_CLIENTS_TXT,    2, MAX_CLIENTS);
       
   784 								break;
       
   785 							case NSSW_COMPANIES_BTND: case NSSW_COMPANIES_BTNU:
       
   786 								_network_game_info.companies_max  = Clamp(_network_game_info.companies_max  + e->we.click.widget - NSSW_COMPANIES_TXT,  1, MAX_PLAYERS);
       
   787 								break;
       
   788 							case NSSW_SPECTATORS_BTND: case NSSW_SPECTATORS_BTNU:
       
   789 								_network_game_info.spectators_max = Clamp(_network_game_info.spectators_max + e->we.click.widget - NSSW_SPECTATORS_TXT, 0, MAX_CLIENTS);
       
   790 								break;
       
   791 						}
       
   792 					}
       
   793 					_left_button_clicked = false;
       
   794 					break;
       
   795 
       
   796 				case NSSW_CLIENTS_TXT:    // Click on number of players
       
   797 					nd->widget_id = NSSW_CLIENTS_TXT;
       
   798 					SetDParam(0, _network_game_info.clients_max);
       
   799 					ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_NETWORK_NUMBER_OF_CLIENTS,    3, 50, w, CS_NUMERAL);
       
   800 					break;
       
   801 
       
   802 				case NSSW_COMPANIES_TXT:  // Click on number of companies
       
   803 					nd->widget_id = NSSW_COMPANIES_TXT;
       
   804 					SetDParam(0, _network_game_info.companies_max);
       
   805 					ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_NETWORK_NUMBER_OF_COMPANIES,  3, 50, w, CS_NUMERAL);
       
   806 					break;
       
   807 
       
   808 				case NSSW_SPECTATORS_TXT: // Click on number of spectators
       
   809 					nd->widget_id = NSSW_SPECTATORS_TXT;
       
   810 					SetDParam(0, _network_game_info.spectators_max);
       
   811 					ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_NETWORK_NUMBER_OF_SPECTATORS, 3, 50, w, CS_NUMERAL);
       
   812 					break;
       
   813 
       
   814 				case NSSW_LANGUAGE_BTN: { // Language
       
   815 					uint sel = 0;
       
   816 					for (uint i = 0; i < lengthof(_language_dropdown) - 1; i++) {
       
   817 						if (_language_dropdown[i] == STR_NETWORK_LANG_ANY + _network_game_info.server_lang) {
       
   818 							sel = i;
       
   819 							break;
       
   820 						}
       
   821 					}
       
   822 					ShowDropDownMenu(w, _language_dropdown, sel, NSSW_LANGUAGE_BTN, 0, 0);
       
   823 				} break;
       
   824 
       
   825 				case NSSW_START: // Start game
       
   826 					_is_network_server = true;
       
   827 
       
   828 					if (nd->map == NULL) { // start random new game
       
   829 						ShowGenerateLandscape();
       
   830 					} else { // load a scenario
       
   831 						char *name = FiosBrowseTo(nd->map);
       
   832 						if (name != NULL) {
       
   833 							SetFiosType(nd->map->type);
       
   834 							_file_to_saveload.filetype = FT_SCENARIO;
       
   835 							ttd_strlcpy(_file_to_saveload.name, name, sizeof(_file_to_saveload.name));
       
   836 							ttd_strlcpy(_file_to_saveload.title, nd->map->title, sizeof(_file_to_saveload.title));
       
   837 
       
   838 							DeleteWindow(w);
       
   839 							SwitchMode(SM_START_SCENARIO);
       
   840 						}
       
   841 					}
       
   842 					break;
       
   843 
       
   844 				case NSSW_LOAD: // Load game
       
   845 					_is_network_server = true;
       
   846 					/* XXX - WC_NETWORK_WINDOW (this window) should stay, but if it stays, it gets
       
   847 					* copied all the elements of 'load game' and upon closing that, it segfaults */
       
   848 					DeleteWindow(w);
       
   849 					ShowSaveLoadDialog(SLD_LOAD_GAME);
       
   850 					break;
       
   851 			}
       
   852 			break;
       
   853 
       
   854 		case WE_DROPDOWN_SELECT: // we have selected a dropdown item in the list
       
   855 			switch (e->we.dropdown.button) {
       
   856 				case NSSW_CONNTYPE_BTN:
       
   857 					_network_advertise = (e->we.dropdown.index != 0);
       
   858 					break;
       
   859 				case NSSW_LANGUAGE_BTN:
       
   860 					_network_game_info.server_lang = _language_dropdown[e->we.dropdown.index] - STR_NETWORK_LANG_ANY;
       
   861 					break;
       
   862 				default:
       
   863 					NOT_REACHED();
       
   864 			}
       
   865 
       
   866 			SetWindowDirty(w);
       
   867 			break;
       
   868 
       
   869 		case WE_MOUSELOOP:
       
   870 			if (nd->field == NSSW_GAMENAME) HandleEditBox(w, &WP(w, network_ql_d).q, NSSW_GAMENAME);
       
   871 			break;
       
   872 
       
   873 		case WE_KEYPRESS:
       
   874 			if (nd->field == NSSW_GAMENAME) {
       
   875 				if (HandleEditBoxKey(w, &WP(w, network_ql_d).q, NSSW_GAMENAME, e) == 1) break; // enter pressed
       
   876 
       
   877 				ttd_strlcpy(_network_server_name, WP(w, network_ql_d).q.text.buf, sizeof(_network_server_name));
       
   878 			}
       
   879 			break;
       
   880 
       
   881 		case WE_ON_EDIT_TEXT:
       
   882 			if (e->we.edittext.str == NULL) break;
       
   883 
       
   884 			if (nd->widget_id == NSSW_SETPWD) {
       
   885 				ttd_strlcpy(_network_server_password, e->we.edittext.str, lengthof(_network_server_password));
       
   886 				_network_game_info.use_password = (_network_server_password[0] != '\0');
   724 			} else {
   887 			} else {
   725 				DoDrawString(item->title, 14, y, _fios_colors[item->type] );
   888 				int32 value = atoi(e->we.edittext.str);
   726 			}
   889 				w->InvalidateWidget(nd->widget_id);
   727 			pos++;
   890 				switch (nd->widget_id) {
   728 			y += NSSWND_ROWSIZE;
   891 					default: NOT_REACHED();
   729 
   892 					case NSSW_CLIENTS_TXT:    _network_game_info.clients_max    = Clamp(value, 2, MAX_CLIENTS); break;
   730 			if (y >= w->vscroll.cap * NSSWND_ROWSIZE + NSSWND_START) break;
   893 					case NSSW_COMPANIES_TXT:  _network_game_info.companies_max  = Clamp(value, 1, MAX_PLAYERS); break;
   731 		}
   894 					case NSSW_SPECTATORS_TXT: _network_game_info.spectators_max = Clamp(value, 0, MAX_CLIENTS); break;
   732 	} break;
   895 				}
   733 
   896 			}
   734 	case WE_CLICK:
   897 
   735 		if (e->we.click.widget != NSSW_CONNTYPE_BTN && e->we.click.widget != NSSW_LANGUAGE_BTN) HideDropDownMenu(w);
       
   736 		nd->field = e->we.click.widget;
       
   737 		switch (e->we.click.widget) {
       
   738 		case NSSW_CLOSE:  // Close 'X'
       
   739 		case NSSW_CANCEL: // Cancel button
       
   740 			ShowNetworkGameWindow();
       
   741 			break;
       
   742 		case NSSW_GAMENAME:
       
   743 			ShowOnScreenKeyboard(w, &WP(w, network_ql_d).q,  NSSW_GAMENAME, 0, 0);
       
   744 			break;
       
   745 		case NSSW_SETPWD: // Set password button
       
   746 			nd->widget_id = NSSW_SETPWD;
       
   747 			ShowQueryString(BindCString(_network_server_password), STR_NETWORK_SET_PASSWORD, 20, 250, w, CS_ALPHANUMERAL);
       
   748 			break;
       
   749 
       
   750 		case NSSW_SELMAP: { // Select map
       
   751 			int y = (e->we.click.pt.y - NSSWND_START) / NSSWND_ROWSIZE;
       
   752 
       
   753 			y += w->vscroll.pos;
       
   754 			if (y >= w->vscroll.count) return;
       
   755 
       
   756 			nd->map = (y == 0) ? NULL : _fios_list + y - 1;
       
   757 			SetWindowDirty(w);
   898 			SetWindowDirty(w);
   758 			} break;
   899 			break;
   759 		case NSSW_CONNTYPE_BTN: // Connection type
       
   760 			ShowDropDownMenu(w, _connection_types_dropdown, _network_advertise, NSSW_CONNTYPE_BTN, 0, 0); // do it for widget NSSW_CONNTYPE_BTN
       
   761 			break;
       
   762 		case NSSW_CLIENTS_BTND:    case NSSW_CLIENTS_BTNU:    // Click on up/down button for number of clients
       
   763 		case NSSW_COMPANIES_BTND:  case NSSW_COMPANIES_BTNU:  // Click on up/down button for number of companies
       
   764 		case NSSW_SPECTATORS_BTND: case NSSW_SPECTATORS_BTNU: // Click on up/down button for number of spectators
       
   765 			/* Don't allow too fast scrolling */
       
   766 			if ((w->flags4 & WF_TIMEOUT_MASK) <= 2 << WF_TIMEOUT_SHL) {
       
   767 				w->HandleButtonClick(e->we.click.widget);
       
   768 				SetWindowDirty(w);
       
   769 				switch (e->we.click.widget) {
       
   770 					default: NOT_REACHED();
       
   771 					case NSSW_CLIENTS_BTND: case NSSW_CLIENTS_BTNU:
       
   772 						_network_game_info.clients_max    = Clamp(_network_game_info.clients_max    + e->we.click.widget - NSSW_CLIENTS_TXT,    2, MAX_CLIENTS);
       
   773 						break;
       
   774 					case NSSW_COMPANIES_BTND: case NSSW_COMPANIES_BTNU:
       
   775 						_network_game_info.companies_max  = Clamp(_network_game_info.companies_max  + e->we.click.widget - NSSW_COMPANIES_TXT,  1, MAX_PLAYERS);
       
   776 						break;
       
   777 					case NSSW_SPECTATORS_BTND: case NSSW_SPECTATORS_BTNU:
       
   778 						_network_game_info.spectators_max = Clamp(_network_game_info.spectators_max + e->we.click.widget - NSSW_SPECTATORS_TXT, 0, MAX_CLIENTS);
       
   779 						break;
       
   780 				}
       
   781 			}
       
   782 			_left_button_clicked = false;
       
   783 			break;
       
   784 		case NSSW_CLIENTS_TXT:    // Click on number of players
       
   785 			nd->widget_id = NSSW_CLIENTS_TXT;
       
   786 			SetDParam(0, _network_game_info.clients_max);
       
   787 			ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_NETWORK_NUMBER_OF_CLIENTS,    3, 50, w, CS_NUMERAL);
       
   788 			break;
       
   789 		case NSSW_COMPANIES_TXT:  // Click on number of companies
       
   790 			nd->widget_id = NSSW_COMPANIES_TXT;
       
   791 			SetDParam(0, _network_game_info.companies_max);
       
   792 			ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_NETWORK_NUMBER_OF_COMPANIES,  3, 50, w, CS_NUMERAL);
       
   793 			break;
       
   794 		case NSSW_SPECTATORS_TXT: // Click on number of spectators
       
   795 			nd->widget_id = NSSW_SPECTATORS_TXT;
       
   796 			SetDParam(0, _network_game_info.spectators_max);
       
   797 			ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_NETWORK_NUMBER_OF_SPECTATORS, 3, 50, w, CS_NUMERAL);
       
   798 			break;
       
   799 		case NSSW_LANGUAGE_BTN: { // Language
       
   800 			uint sel = 0;
       
   801 			for (uint i = 0; i < lengthof(_language_dropdown) - 1; i++) {
       
   802 				if (_language_dropdown[i] == STR_NETWORK_LANG_ANY + _network_game_info.server_lang) {
       
   803 					sel = i;
       
   804 					break;
       
   805 				}
       
   806 			}
       
   807 			ShowDropDownMenu(w, _language_dropdown, sel, NSSW_LANGUAGE_BTN, 0, 0);
       
   808 			break;
       
   809 		}
       
   810 		case NSSW_START: // Start game
       
   811 			_is_network_server = true;
       
   812 
       
   813 			if (nd->map == NULL) { // start random new game
       
   814 				ShowGenerateLandscape();
       
   815 			} else { // load a scenario
       
   816 				char *name = FiosBrowseTo(nd->map);
       
   817 				if (name != NULL) {
       
   818 					SetFiosType(nd->map->type);
       
   819 					_file_to_saveload.filetype = FT_SCENARIO;
       
   820 					ttd_strlcpy(_file_to_saveload.name, name, sizeof(_file_to_saveload.name));
       
   821 					ttd_strlcpy(_file_to_saveload.title, nd->map->title, sizeof(_file_to_saveload.title));
       
   822 
       
   823 					DeleteWindow(w);
       
   824 					SwitchMode(SM_START_SCENARIO);
       
   825 				}
       
   826 			}
       
   827 			break;
       
   828 		case NSSW_LOAD: // Load game
       
   829 			_is_network_server = true;
       
   830 			/* XXX - WC_NETWORK_WINDOW (this window) should stay, but if it stays, it gets
       
   831 			 * copied all the elements of 'load game' and upon closing that, it segfaults */
       
   832 			DeleteWindow(w);
       
   833 			ShowSaveLoadDialog(SLD_LOAD_GAME);
       
   834 			break;
       
   835 		}
       
   836 		break;
       
   837 
       
   838 	case WE_DROPDOWN_SELECT: // we have selected a dropdown item in the list
       
   839 		switch (e->we.dropdown.button) {
       
   840 			case NSSW_CONNTYPE_BTN:
       
   841 				_network_advertise = (e->we.dropdown.index != 0);
       
   842 				break;
       
   843 			case NSSW_LANGUAGE_BTN:
       
   844 				_network_game_info.server_lang = _language_dropdown[e->we.dropdown.index] - STR_NETWORK_LANG_ANY;
       
   845 				break;
       
   846 			default:
       
   847 				NOT_REACHED();
       
   848 		}
       
   849 
       
   850 		SetWindowDirty(w);
       
   851 		break;
       
   852 
       
   853 	case WE_MOUSELOOP:
       
   854 		if (nd->field == NSSW_GAMENAME) HandleEditBox(w, &WP(w, network_ql_d).q, NSSW_GAMENAME);
       
   855 		break;
       
   856 
       
   857 	case WE_KEYPRESS:
       
   858 		if (nd->field == NSSW_GAMENAME) {
       
   859 			if (HandleEditBoxKey(w, &WP(w, network_ql_d).q, NSSW_GAMENAME, e) == 1) break; // enter pressed
       
   860 
       
   861 			ttd_strlcpy(_network_server_name, WP(w, network_ql_d).q.text.buf, sizeof(_network_server_name));
       
   862 		}
       
   863 		break;
       
   864 
       
   865 	case WE_ON_EDIT_TEXT:
       
   866 		if (e->we.edittext.str == NULL) break;
       
   867 
       
   868 		if (nd->widget_id == NSSW_SETPWD) {
       
   869 			ttd_strlcpy(_network_server_password, e->we.edittext.str, lengthof(_network_server_password));
       
   870 			_network_game_info.use_password = (_network_server_password[0] != '\0');
       
   871 		} else {
       
   872 			int32 value = atoi(e->we.edittext.str);
       
   873 			w->InvalidateWidget(nd->widget_id);
       
   874 			switch (nd->widget_id) {
       
   875 				default: NOT_REACHED();
       
   876 				case NSSW_CLIENTS_TXT:    _network_game_info.clients_max    = Clamp(value, 2, MAX_CLIENTS); break;
       
   877 				case NSSW_COMPANIES_TXT:  _network_game_info.companies_max  = Clamp(value, 1, MAX_PLAYERS); break;
       
   878 				case NSSW_SPECTATORS_TXT: _network_game_info.spectators_max = Clamp(value, 0, MAX_CLIENTS); break;
       
   879 			}
       
   880 		}
       
   881 
       
   882 		SetWindowDirty(w);
       
   883 		break;
       
   884 	}
   900 	}
   885 }
   901 }
   886 
   902 
   887 static const Widget _network_start_server_window_widgets[] = {
   903 static const Widget _network_start_server_window_widgets[] = {
   888 /* Window decoration and background panel */
   904 /* Window decoration and background panel */
   889 {   WWT_CLOSEBOX,   RESIZE_NONE,   BGC,     0,    10,     0,    13, STR_00C5,                         STR_018B_CLOSE_WINDOW },               // NSSW_CLOSE
   905 {   WWT_CLOSEBOX,   RESIZE_NONE,   BGC,     0,    10,     0,    13, STR_00C5,                           STR_018B_CLOSE_WINDOW },               // NSSW_CLOSE
   890 {    WWT_CAPTION,   RESIZE_NONE,   BGC,    11,   419,     0,    13, STR_NETWORK_START_GAME_WINDOW,    STR_NULL},
   906 {    WWT_CAPTION,   RESIZE_NONE,   BGC,    11,   419,     0,    13, STR_NETWORK_START_GAME_WINDOW,      STR_NULL},
   891 {      WWT_PANEL,   RESIZE_NONE,   BGC,     0,   419,    14,   243, 0x0,                              STR_NULL},
   907 {      WWT_PANEL,   RESIZE_NONE,   BGC,     0,   419,    14,   243, 0x0,                                STR_NULL},
   892 
   908 
   893 /* Set game name and password widgets */
   909 /* Set game name and password widgets */
   894 {       WWT_TEXT,   RESIZE_NONE,   BGC,    10,    90,    22,    34, STR_NETWORK_NEW_GAME_NAME,        STR_NULL},
   910 {       WWT_TEXT,   RESIZE_NONE,   BGC,    10,    90,    22,    34, STR_NETWORK_NEW_GAME_NAME,          STR_NULL},
   895 {    WWT_EDITBOX,   RESIZE_NONE,   BGC,   100,   272,    22,    33, STR_NETWORK_NEW_GAME_NAME_OSKTITLE, STR_NETWORK_NEW_GAME_NAME_TIP},        // NSSW_GAMENAME
   911 {    WWT_EDITBOX,   RESIZE_NONE,   BGC,   100,   272,    22,    33, STR_NETWORK_NEW_GAME_NAME_OSKTITLE, STR_NETWORK_NEW_GAME_NAME_TIP},        // NSSW_GAMENAME
   896 { WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,   285,   405,    22,    33, STR_NETWORK_SET_PASSWORD,         STR_NETWORK_PASSWORD_TIP},             // NSSW_SETPWD
   912 { WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,   285,   405,    22,    33, STR_NETWORK_SET_PASSWORD,           STR_NETWORK_PASSWORD_TIP},             // NSSW_SETPWD
   897 
   913 
   898 /* List of playable scenarios */
   914 /* List of playable scenarios */
   899 {       WWT_TEXT,   RESIZE_NONE,   BGC,    10,   110,    43,    55, STR_NETWORK_SELECT_MAP,           STR_NULL},
   915 {       WWT_TEXT,   RESIZE_NONE,   BGC,    10,   110,    43,    55, STR_NETWORK_SELECT_MAP,             STR_NULL},
   900 {      WWT_INSET,   RESIZE_NONE,   BGC,    10,   271,    62,   216, STR_NULL,                         STR_NETWORK_SELECT_MAP_TIP},           // NSSW_SELMAP
   916 {      WWT_INSET,   RESIZE_NONE,   BGC,    10,   271,    62,   216, STR_NULL,                           STR_NETWORK_SELECT_MAP_TIP},           // NSSW_SELMAP
   901 {  WWT_SCROLLBAR,   RESIZE_NONE,   BGC,   259,   270,    63,   215, 0x0,                              STR_0190_SCROLL_BAR_SCROLLS_LIST},
   917 {  WWT_SCROLLBAR,   RESIZE_NONE,   BGC,   259,   270,    63,   215, 0x0,                                STR_0190_SCROLL_BAR_SCROLLS_LIST},
   902 
   918 
   903 /* Combo/selection boxes to control Connection Type / Max Clients / Max Companies / Max Observers / Language */
   919 /* Combo/selection boxes to control Connection Type / Max Clients / Max Companies / Max Observers / Language */
   904 {       WWT_TEXT,   RESIZE_NONE,   BGC,   280,   419,    63,    75, STR_NETWORK_CONNECTION,           STR_NULL},
   920 {       WWT_TEXT,   RESIZE_NONE,   BGC,   280,   419,    63,    75, STR_NETWORK_CONNECTION,             STR_NULL},
   905 { WWT_DROPDOWNIN,   RESIZE_NONE,   BGC,   280,   410,    77,    88, STR_NETWORK_LAN_INTERNET_COMBO,   STR_NETWORK_CONNECTION_TIP},           // NSSW_CONNTYPE_BTN
   921 { WWT_DROPDOWNIN,   RESIZE_NONE,   BGC,   280,   410,    77,    88, STR_NETWORK_LAN_INTERNET_COMBO,     STR_NETWORK_CONNECTION_TIP},           // NSSW_CONNTYPE_BTN
   906 
   922 
   907 {       WWT_TEXT,   RESIZE_NONE,   BGC,   280,   419,    95,   107, STR_NETWORK_NUMBER_OF_CLIENTS,    STR_NULL},
   923 {       WWT_TEXT,   RESIZE_NONE,   BGC,   280,   419,    95,   107, STR_NETWORK_NUMBER_OF_CLIENTS,      STR_NULL},
   908 {     WWT_IMGBTN,   RESIZE_NONE,   BGC,   280,   291,   109,   120, SPR_ARROW_DOWN,                   STR_NETWORK_NUMBER_OF_CLIENTS_TIP},    // NSSW_CLIENTS_BTND
   924 {     WWT_IMGBTN,   RESIZE_NONE,   BGC,   280,   291,   109,   120, SPR_ARROW_DOWN,                     STR_NETWORK_NUMBER_OF_CLIENTS_TIP},    // NSSW_CLIENTS_BTND
   909 { WWT_PUSHTXTBTN,   RESIZE_NONE,   BGC,   292,   397,   109,   120, STR_NETWORK_CLIENTS_SELECT,       STR_NETWORK_NUMBER_OF_CLIENTS_TIP},    // NSSW_CLIENTS_TXT
   925 { WWT_PUSHTXTBTN,   RESIZE_NONE,   BGC,   292,   397,   109,   120, STR_NETWORK_CLIENTS_SELECT,         STR_NETWORK_NUMBER_OF_CLIENTS_TIP},    // NSSW_CLIENTS_TXT
   910 {     WWT_IMGBTN,   RESIZE_NONE,   BGC,   398,   410,   109,   120, SPR_ARROW_UP,                     STR_NETWORK_NUMBER_OF_CLIENTS_TIP},    // NSSW_CLIENTS_BTNU
   926 {     WWT_IMGBTN,   RESIZE_NONE,   BGC,   398,   410,   109,   120, SPR_ARROW_UP,                       STR_NETWORK_NUMBER_OF_CLIENTS_TIP},    // NSSW_CLIENTS_BTNU
   911 
   927 
   912 {       WWT_TEXT,   RESIZE_NONE,   BGC,   280,   419,   127,   139, STR_NETWORK_NUMBER_OF_COMPANIES,  STR_NULL},
   928 {       WWT_TEXT,   RESIZE_NONE,   BGC,   280,   419,   127,   139, STR_NETWORK_NUMBER_OF_COMPANIES,    STR_NULL},
   913 {     WWT_IMGBTN,   RESIZE_NONE,   BGC,   280,   291,   141,   152, SPR_ARROW_DOWN,                   STR_NETWORK_NUMBER_OF_COMPANIES_TIP},  // NSSW_COMPANIES_BTND
   929 {     WWT_IMGBTN,   RESIZE_NONE,   BGC,   280,   291,   141,   152, SPR_ARROW_DOWN,                     STR_NETWORK_NUMBER_OF_COMPANIES_TIP},  // NSSW_COMPANIES_BTND
   914 { WWT_PUSHTXTBTN,   RESIZE_NONE,   BGC,   292,   397,   141,   152, STR_NETWORK_COMPANIES_SELECT,     STR_NETWORK_NUMBER_OF_COMPANIES_TIP},  // NSSW_COMPANIES_TXT
   930 { WWT_PUSHTXTBTN,   RESIZE_NONE,   BGC,   292,   397,   141,   152, STR_NETWORK_COMPANIES_SELECT,       STR_NETWORK_NUMBER_OF_COMPANIES_TIP},  // NSSW_COMPANIES_TXT
   915 {     WWT_IMGBTN,   RESIZE_NONE,   BGC,   398,   410,   141,   152, SPR_ARROW_UP,                     STR_NETWORK_NUMBER_OF_COMPANIES_TIP},  // NSSW_COMPANIES_BTNU
   931 {     WWT_IMGBTN,   RESIZE_NONE,   BGC,   398,   410,   141,   152, SPR_ARROW_UP,                       STR_NETWORK_NUMBER_OF_COMPANIES_TIP},  // NSSW_COMPANIES_BTNU
   916 
   932 
   917 {       WWT_TEXT,   RESIZE_NONE,   BGC,   280,   419,   159,   171, STR_NETWORK_NUMBER_OF_SPECTATORS, STR_NULL},
   933 {       WWT_TEXT,   RESIZE_NONE,   BGC,   280,   419,   159,   171, STR_NETWORK_NUMBER_OF_SPECTATORS,   STR_NULL},
   918 {     WWT_IMGBTN,   RESIZE_NONE,   BGC,   280,   291,   173,   184, SPR_ARROW_DOWN,                   STR_NETWORK_NUMBER_OF_SPECTATORS_TIP}, // NSSW_SPECTATORS_BTND
   934 {     WWT_IMGBTN,   RESIZE_NONE,   BGC,   280,   291,   173,   184, SPR_ARROW_DOWN,                     STR_NETWORK_NUMBER_OF_SPECTATORS_TIP}, // NSSW_SPECTATORS_BTND
   919 { WWT_PUSHTXTBTN,   RESIZE_NONE,   BGC,   292,   397,   173,   184, STR_NETWORK_SPECTATORS_SELECT,    STR_NETWORK_NUMBER_OF_SPECTATORS_TIP}, // NSSW_SPECTATORS_TXT
   935 { WWT_PUSHTXTBTN,   RESIZE_NONE,   BGC,   292,   397,   173,   184, STR_NETWORK_SPECTATORS_SELECT,      STR_NETWORK_NUMBER_OF_SPECTATORS_TIP}, // NSSW_SPECTATORS_TXT
   920 {     WWT_IMGBTN,   RESIZE_NONE,   BGC,   398,   410,   173,   184, SPR_ARROW_UP,                     STR_NETWORK_NUMBER_OF_SPECTATORS_TIP}, // NSSW_SPECTATORS_BTNU
   936 {     WWT_IMGBTN,   RESIZE_NONE,   BGC,   398,   410,   173,   184, SPR_ARROW_UP,                       STR_NETWORK_NUMBER_OF_SPECTATORS_TIP}, // NSSW_SPECTATORS_BTNU
   921 
   937 
   922 {       WWT_TEXT,   RESIZE_NONE,   BGC,   280,   419,   191,   203, STR_NETWORK_LANGUAGE_SPOKEN,      STR_NULL},
   938 {       WWT_TEXT,   RESIZE_NONE,   BGC,   280,   419,   191,   203, STR_NETWORK_LANGUAGE_SPOKEN,        STR_NULL},
   923 { WWT_DROPDOWNIN,   RESIZE_NONE,   BGC,   280,   410,   205,   216, STR_NETWORK_LANGUAGE_COMBO,       STR_NETWORK_LANGUAGE_TIP},             // NSSW_LANGUAGE_BTN
   939 { WWT_DROPDOWNIN,   RESIZE_NONE,   BGC,   280,   410,   205,   216, STR_NETWORK_LANGUAGE_COMBO,         STR_NETWORK_LANGUAGE_TIP},             // NSSW_LANGUAGE_BTN
   924 
   940 
   925 /* Buttons Start / Load / Cancel */
   941 /* Buttons Start / Load / Cancel */
   926 { WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,    40,   140,   224,   235, STR_NETWORK_START_GAME,           STR_NETWORK_START_GAME_TIP},           // NSSW_START
   942 { WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,    40,   140,   224,   235, STR_NETWORK_START_GAME,             STR_NETWORK_START_GAME_TIP},           // NSSW_START
   927 { WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,   150,   250,   224,   235, STR_NETWORK_LOAD_GAME,            STR_NETWORK_LOAD_GAME_TIP},            // NSSW_LOAD
   943 { WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,   150,   250,   224,   235, STR_NETWORK_LOAD_GAME,              STR_NETWORK_LOAD_GAME_TIP},            // NSSW_LOAD
   928 { WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,   260,   360,   224,   235, STR_012E_CANCEL,                  STR_NULL},                             // NSSW_CANCEL
   944 { WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,   260,   360,   224,   235, STR_012E_CANCEL,                    STR_NULL},                             // NSSW_CANCEL
   929 
   945 
   930 {   WIDGETS_END},
   946 {   WIDGETS_END},
   931 };
   947 };
   932 
   948 
   933 static const WindowDesc _network_start_server_window_desc = {
   949 static const WindowDesc _network_start_server_window_desc = {
   938 	NetworkStartServerWindowWndProc,
   954 	NetworkStartServerWindowWndProc,
   939 };
   955 };
   940 
   956 
   941 static void ShowNetworkStartServerWindow()
   957 static void ShowNetworkStartServerWindow()
   942 {
   958 {
   943 	Window *w;
       
   944 	DeleteWindowById(WC_NETWORK_WINDOW, 0);
   959 	DeleteWindowById(WC_NETWORK_WINDOW, 0);
   945 
   960 
   946 	w = AllocateWindowDesc(&_network_start_server_window_desc);
   961 	Window *w = AllocateWindowDesc(&_network_start_server_window_desc);
   947 	ttd_strlcpy(_edit_str_net_buf, _network_server_name, lengthof(_edit_str_net_buf));
   962 	ttd_strlcpy(_edit_str_net_buf, _network_server_name, lengthof(_edit_str_net_buf));
   948 
   963 
   949 	_saveload_mode = SLD_NEW_GAME;
   964 	_saveload_mode = SLD_NEW_GAME;
   950 	BuildFileList();
   965 	BuildFileList();
   951 	w->vscroll.cap = 12;
   966 	w->vscroll.cap = 12;
   955 	InitializeTextBuffer(&WP(w, network_ql_d).q.text, _edit_str_net_buf, lengthof(_edit_str_net_buf), 160);
   970 	InitializeTextBuffer(&WP(w, network_ql_d).q.text, _edit_str_net_buf, lengthof(_edit_str_net_buf), 160);
   956 }
   971 }
   957 
   972 
   958 static PlayerID NetworkLobbyFindCompanyIndex(byte pos)
   973 static PlayerID NetworkLobbyFindCompanyIndex(byte pos)
   959 {
   974 {
   960 	PlayerID i;
   975 	/* Scroll through all _network_player_info and get the 'pos' item that is not empty */
   961 
   976 	for (PlayerID i = PLAYER_FIRST; i < MAX_PLAYERS; i++) {
   962 	/* Scroll through all _network_player_info and get the 'pos' item
       
   963 	    that is not empty */
       
   964 	for (i = PLAYER_FIRST; i < MAX_PLAYERS; i++) {
       
   965 		if (_network_player_info[i].company_name[0] != '\0') {
   977 		if (_network_player_info[i].company_name[0] != '\0') {
   966 			if (pos-- == 0) return i;
   978 			if (pos-- == 0) return i;
   967 		}
   979 		}
   968 	}
   980 	}
   969 
   981 
   994 static void NetworkLobbyWindowWndProc(Window *w, WindowEvent *e)
  1006 static void NetworkLobbyWindowWndProc(Window *w, WindowEvent *e)
   995 {
  1007 {
   996 	network_d *nd = &WP(w, network_d);
  1008 	network_d *nd = &WP(w, network_d);
   997 
  1009 
   998 	switch (e->event) {
  1010 	switch (e->event) {
   999 	case WE_CREATE:
  1011 		case WE_CREATE:
  1000 		nd->company = INVALID_PLAYER;
  1012 			nd->company = INVALID_PLAYER;
  1001 		break;
  1013 			break;
  1002 
  1014 
  1003 	case WE_PAINT: {
  1015 		case WE_PAINT: {
  1004 		const NetworkGameInfo *gi = &nd->server->info;
  1016 			const NetworkGameInfo *gi = &nd->server->info;
  1005 		int y = NET_PRC__OFFSET_TOP_WIDGET_COMPANY, pos;
  1017 			int y = NET_PRC__OFFSET_TOP_WIDGET_COMPANY, pos;
  1006 
  1018 
  1007 		/* Join button is disabled when no company is selected */
  1019 			/* Join button is disabled when no company is selected */
  1008 		w->SetWidgetDisabledState(NLWW_JOIN, nd->company == INVALID_PLAYER);
  1020 			w->SetWidgetDisabledState(NLWW_JOIN, nd->company == INVALID_PLAYER);
  1009 		/* Cannot start new company if there are too many */
  1021 			/* Cannot start new company if there are too many */
  1010 		w->SetWidgetDisabledState(NLWW_NEW, gi->companies_on >= gi->companies_max);
  1022 			w->SetWidgetDisabledState(NLWW_NEW, gi->companies_on >= gi->companies_max);
  1011 		/* Cannot spectate if there are too many spectators */
  1023 			/* Cannot spectate if there are too many spectators */
  1012 		w->SetWidgetDisabledState(NLWW_SPECTATE, gi->spectators_on >= gi->spectators_max);
  1024 			w->SetWidgetDisabledState(NLWW_SPECTATE, gi->spectators_on >= gi->spectators_max);
  1013 
  1025 
  1014 		/* Draw window widgets */
  1026 			/* Draw window widgets */
  1015 		SetDParamStr(0, gi->server_name);
  1027 			SetDParamStr(0, gi->server_name);
  1016 		DrawWindowWidgets(w);
  1028 			DrawWindowWidgets(w);
  1017 
  1029 
  1018 		/* Draw company list */
  1030 			/* Draw company list */
  1019 		pos = w->vscroll.pos;
  1031 			pos = w->vscroll.pos;
  1020 		while (pos < gi->companies_on) {
  1032 			while (pos < gi->companies_on) {
  1021 			byte company = NetworkLobbyFindCompanyIndex(pos);
  1033 				byte company = NetworkLobbyFindCompanyIndex(pos);
  1022 			bool income = false;
  1034 				bool income = false;
  1023 			if (nd->company == company)
  1035 				if (nd->company == company)
  1024 				GfxFillRect(11, y - 1, 154, y + 10, 10); // show highlighted item with a different colour
  1036 					GfxFillRect(11, y - 1, 154, y + 10, 10); // show highlighted item with a different colour
  1025 
  1037 
  1026 			DoDrawStringTruncated(_network_player_info[company].company_name, 13, y, TC_BLACK, 135 - 13);
  1038 				DoDrawStringTruncated(_network_player_info[company].company_name, 13, y, TC_BLACK, 135 - 13);
  1027 			if (_network_player_info[company].use_password != 0) DrawSprite(SPR_LOCK, PAL_NONE, 135, y);
  1039 				if (_network_player_info[company].use_password != 0) DrawSprite(SPR_LOCK, PAL_NONE, 135, y);
  1028 
  1040 
  1029 			/* If the company's income was positive puts a green dot else a red dot */
  1041 				/* If the company's income was positive puts a green dot else a red dot */
  1030 			if (_network_player_info[company].income >= 0) income = true;
  1042 				if (_network_player_info[company].income >= 0) income = true;
  1031 			DrawSprite(SPR_BLOT, income ? PALETTE_TO_GREEN : PALETTE_TO_RED, 145, y);
  1043 				DrawSprite(SPR_BLOT, income ? PALETTE_TO_GREEN : PALETTE_TO_RED, 145, y);
  1032 
  1044 
  1033 			pos++;
  1045 				pos++;
  1034 			y += NET_PRC__SIZE_OF_ROW;
  1046 				y += NET_PRC__SIZE_OF_ROW;
  1035 			if (pos >= w->vscroll.cap) break;
  1047 				if (pos >= w->vscroll.cap) break;
  1036 		}
  1048 			}
  1037 
  1049 
  1038 		/* Draw info about selected company when it is selected in the left window */
  1050 			/* Draw info about selected company when it is selected in the left window */
  1039 		GfxFillRect(174, 39, 403, 75, 157);
  1051 			GfxFillRect(174, 39, 403, 75, 157);
  1040 		DrawStringCentered(290, 50, STR_NETWORK_COMPANY_INFO, TC_FROMSTRING);
  1052 			DrawStringCentered(290, 50, STR_NETWORK_COMPANY_INFO, TC_FROMSTRING);
  1041 		if (nd->company != INVALID_PLAYER) {
  1053 			if (nd->company != INVALID_PLAYER) {
  1042 			const uint x = 183;
  1054 				const uint x = 183;
  1043 			const uint trunc_width = w->widget[NLWW_DETAILS].right - x;
  1055 				const uint trunc_width = w->widget[NLWW_DETAILS].right - x;
  1044 			y = 80;
  1056 				y = 80;
  1045 
  1057 
  1046 			SetDParam(0, nd->server->info.clients_on);
  1058 				SetDParam(0, nd->server->info.clients_on);
  1047 			SetDParam(1, nd->server->info.clients_max);
  1059 				SetDParam(1, nd->server->info.clients_max);
  1048 			SetDParam(2, nd->server->info.companies_on);
  1060 				SetDParam(2, nd->server->info.companies_on);
  1049 			SetDParam(3, nd->server->info.companies_max);
  1061 				SetDParam(3, nd->server->info.companies_max);
  1050 			DrawString(x, y, STR_NETWORK_CLIENTS, TC_GOLD);
  1062 				DrawString(x, y, STR_NETWORK_CLIENTS, TC_GOLD);
  1051 			y += 10;
  1063 				y += 10;
  1052 
  1064 
  1053 			SetDParamStr(0, _network_player_info[nd->company].company_name);
  1065 				SetDParamStr(0, _network_player_info[nd->company].company_name);
  1054 			DrawStringTruncated(x, y, STR_NETWORK_COMPANY_NAME, TC_GOLD, trunc_width);
  1066 				DrawStringTruncated(x, y, STR_NETWORK_COMPANY_NAME, TC_GOLD, trunc_width);
  1055 			y += 10;
  1067 				y += 10;
  1056 
  1068 
  1057 			SetDParam(0, _network_player_info[nd->company].inaugurated_year);
  1069 				SetDParam(0, _network_player_info[nd->company].inaugurated_year);
  1058 			DrawString(x, y, STR_NETWORK_INAUGURATION_YEAR, TC_GOLD); // inauguration year
  1070 				DrawString(x, y, STR_NETWORK_INAUGURATION_YEAR, TC_GOLD); // inauguration year
  1059 			y += 10;
  1071 				y += 10;
  1060 
  1072 
  1061 			SetDParam(0, _network_player_info[nd->company].company_value);
  1073 				SetDParam(0, _network_player_info[nd->company].company_value);
  1062 			DrawString(x, y, STR_NETWORK_VALUE, TC_GOLD); // company value
  1074 				DrawString(x, y, STR_NETWORK_VALUE, TC_GOLD); // company value
  1063 			y += 10;
  1075 				y += 10;
  1064 
  1076 
  1065 			SetDParam(0, _network_player_info[nd->company].money);
  1077 				SetDParam(0, _network_player_info[nd->company].money);
  1066 			DrawString(x, y, STR_NETWORK_CURRENT_BALANCE, TC_GOLD); // current balance
  1078 				DrawString(x, y, STR_NETWORK_CURRENT_BALANCE, TC_GOLD); // current balance
  1067 			y += 10;
  1079 				y += 10;
  1068 
  1080 
  1069 			SetDParam(0, _network_player_info[nd->company].income);
  1081 				SetDParam(0, _network_player_info[nd->company].income);
  1070 			DrawString(x, y, STR_NETWORK_LAST_YEARS_INCOME, TC_GOLD); // last year's income
  1082 				DrawString(x, y, STR_NETWORK_LAST_YEARS_INCOME, TC_GOLD); // last year's income
  1071 			y += 10;
  1083 				y += 10;
  1072 
  1084 
  1073 			SetDParam(0, _network_player_info[nd->company].performance);
  1085 				SetDParam(0, _network_player_info[nd->company].performance);
  1074 			DrawString(x, y, STR_NETWORK_PERFORMANCE, TC_GOLD); // performance
  1086 				DrawString(x, y, STR_NETWORK_PERFORMANCE, TC_GOLD); // performance
  1075 			y += 10;
  1087 				y += 10;
  1076 
  1088 
  1077 			SetDParam(0, _network_player_info[nd->company].num_vehicle[0]);
  1089 				SetDParam(0, _network_player_info[nd->company].num_vehicle[0]);
  1078 			SetDParam(1, _network_player_info[nd->company].num_vehicle[1]);
  1090 				SetDParam(1, _network_player_info[nd->company].num_vehicle[1]);
  1079 			SetDParam(2, _network_player_info[nd->company].num_vehicle[2]);
  1091 				SetDParam(2, _network_player_info[nd->company].num_vehicle[2]);
  1080 			SetDParam(3, _network_player_info[nd->company].num_vehicle[3]);
  1092 				SetDParam(3, _network_player_info[nd->company].num_vehicle[3]);
  1081 			SetDParam(4, _network_player_info[nd->company].num_vehicle[4]);
  1093 				SetDParam(4, _network_player_info[nd->company].num_vehicle[4]);
  1082 			DrawString(x, y, STR_NETWORK_VEHICLES, TC_GOLD); // vehicles
  1094 				DrawString(x, y, STR_NETWORK_VEHICLES, TC_GOLD); // vehicles
  1083 			y += 10;
  1095 				y += 10;
  1084 
  1096 
  1085 			SetDParam(0, _network_player_info[nd->company].num_station[0]);
  1097 				SetDParam(0, _network_player_info[nd->company].num_station[0]);
  1086 			SetDParam(1, _network_player_info[nd->company].num_station[1]);
  1098 				SetDParam(1, _network_player_info[nd->company].num_station[1]);
  1087 			SetDParam(2, _network_player_info[nd->company].num_station[2]);
  1099 				SetDParam(2, _network_player_info[nd->company].num_station[2]);
  1088 			SetDParam(3, _network_player_info[nd->company].num_station[3]);
  1100 				SetDParam(3, _network_player_info[nd->company].num_station[3]);
  1089 			SetDParam(4, _network_player_info[nd->company].num_station[4]);
  1101 				SetDParam(4, _network_player_info[nd->company].num_station[4]);
  1090 			DrawString(x, y, STR_NETWORK_STATIONS, TC_GOLD); // stations
  1102 				DrawString(x, y, STR_NETWORK_STATIONS, TC_GOLD); // stations
  1091 			y += 10;
  1103 				y += 10;
  1092 
  1104 
  1093 			SetDParamStr(0, _network_player_info[nd->company].players);
  1105 				SetDParamStr(0, _network_player_info[nd->company].players);
  1094 			DrawStringTruncated(x, y, STR_NETWORK_PLAYERS, TC_GOLD, trunc_width); // players
  1106 				DrawStringTruncated(x, y, STR_NETWORK_PLAYERS, TC_GOLD, trunc_width); // players
  1095 		}
  1107 			}
  1096 	} break;
  1108 		} break;
  1097 
  1109 
  1098 	case WE_CLICK:
  1110 		case WE_CLICK:
  1099 		switch (e->we.click.widget) {
  1111 			switch (e->we.click.widget) {
  1100 		case NLWW_CLOSE:    // Close 'X'
  1112 				case NLWW_CLOSE:    // Close 'X'
  1101 		case NLWW_CANCEL:   // Cancel button
  1113 				case NLWW_CANCEL:   // Cancel button
  1102 			ShowNetworkGameWindow();
  1114 					ShowNetworkGameWindow();
  1103 			break;
  1115 					break;
  1104 		case NLWW_MATRIX: { // Company list
  1116 
  1105 			uint32 id_v = (e->we.click.pt.y - NET_PRC__OFFSET_TOP_WIDGET_COMPANY) / NET_PRC__SIZE_OF_ROW;
  1117 				case NLWW_MATRIX: { // Company list
  1106 
  1118 					uint32 id_v = (e->we.click.pt.y - NET_PRC__OFFSET_TOP_WIDGET_COMPANY) / NET_PRC__SIZE_OF_ROW;
  1107 			if (id_v >= w->vscroll.cap) break;
  1119 
  1108 
  1120 					if (id_v >= w->vscroll.cap) break;
  1109 			id_v += w->vscroll.pos;
  1121 
  1110 			nd->company = (id_v >= nd->server->info.companies_on) ? INVALID_PLAYER : NetworkLobbyFindCompanyIndex(id_v);
  1122 					id_v += w->vscroll.pos;
       
  1123 					nd->company = (id_v >= nd->server->info.companies_on) ? INVALID_PLAYER : NetworkLobbyFindCompanyIndex(id_v);
       
  1124 					SetWindowDirty(w);
       
  1125 				} break;
       
  1126 
       
  1127 				case NLWW_JOIN:     // Join company
       
  1128 					/* Button can be clicked only when it is enabled */
       
  1129 					_network_playas = nd->company;
       
  1130 					NetworkClientConnectGame(_network_last_host, _network_last_port);
       
  1131 					break;
       
  1132 
       
  1133 				case NLWW_NEW:      // New company
       
  1134 					_network_playas = PLAYER_NEW_COMPANY;
       
  1135 					NetworkClientConnectGame(_network_last_host, _network_last_port);
       
  1136 					break;
       
  1137 
       
  1138 				case NLWW_SPECTATE: // Spectate game
       
  1139 					_network_playas = PLAYER_SPECTATOR;
       
  1140 					NetworkClientConnectGame(_network_last_host, _network_last_port);
       
  1141 					break;
       
  1142 
       
  1143 				case NLWW_REFRESH:  // Refresh
       
  1144 					NetworkTCPQueryServer(_network_last_host, _network_last_port); // company info
       
  1145 					NetworkUDPQueryServer(_network_last_host, _network_last_port); // general data
       
  1146 					break;
       
  1147 			}
       
  1148 			break;
       
  1149 
       
  1150 		case WE_MESSAGE:
  1111 			SetWindowDirty(w);
  1151 			SetWindowDirty(w);
  1112 		} break;
  1152 			break;
  1113 		case NLWW_JOIN:     // Join company
       
  1114 			/* Button can be clicked only when it is enabled */
       
  1115 			_network_playas = nd->company;
       
  1116 			NetworkClientConnectGame(_network_last_host, _network_last_port);
       
  1117 			break;
       
  1118 		case NLWW_NEW:      // New company
       
  1119 			_network_playas = PLAYER_NEW_COMPANY;
       
  1120 			NetworkClientConnectGame(_network_last_host, _network_last_port);
       
  1121 			break;
       
  1122 		case NLWW_SPECTATE: // Spectate game
       
  1123 			_network_playas = PLAYER_SPECTATOR;
       
  1124 			NetworkClientConnectGame(_network_last_host, _network_last_port);
       
  1125 			break;
       
  1126 		case NLWW_REFRESH:  // Refresh
       
  1127 			NetworkTCPQueryServer(_network_last_host, _network_last_port); // company info
       
  1128 			NetworkUDPQueryServer(_network_last_host, _network_last_port); // general data
       
  1129 			break;
       
  1130 		} break;
       
  1131 
       
  1132 	case WE_MESSAGE:
       
  1133 		SetWindowDirty(w);
       
  1134 		break;
       
  1135 	}
  1153 	}
  1136 }
  1154 }
  1137 
  1155 
  1138 static const Widget _network_lobby_window_widgets[] = {
  1156 static const Widget _network_lobby_window_widgets[] = {
  1139 {   WWT_CLOSEBOX,   RESIZE_NONE,   BGC,     0,    10,     0,    13, STR_00C5,                    STR_018B_CLOSE_WINDOW },           // NLWW_CLOSE
  1157 {   WWT_CLOSEBOX,   RESIZE_NONE,   BGC,     0,    10,     0,    13, STR_00C5,                    STR_018B_CLOSE_WINDOW },           // NLWW_CLOSE
  1169 
  1187 
  1170 /* Show the networklobbywindow with the selected server
  1188 /* Show the networklobbywindow with the selected server
  1171  * @param ngl Selected game pointer which is passed to the new window */
  1189  * @param ngl Selected game pointer which is passed to the new window */
  1172 static void ShowNetworkLobbyWindow(NetworkGameList *ngl)
  1190 static void ShowNetworkLobbyWindow(NetworkGameList *ngl)
  1173 {
  1191 {
  1174 	Window *w;
       
  1175 	DeleteWindowById(WC_NETWORK_WINDOW, 0);
  1192 	DeleteWindowById(WC_NETWORK_WINDOW, 0);
  1176 
  1193 
  1177 	NetworkTCPQueryServer(_network_last_host, _network_last_port); // company info
  1194 	NetworkTCPQueryServer(_network_last_host, _network_last_port); // company info
  1178 	NetworkUDPQueryServer(_network_last_host, _network_last_port); // general data
  1195 	NetworkUDPQueryServer(_network_last_host, _network_last_port); // general data
  1179 
  1196 
  1180 	w = AllocateWindowDesc(&_network_lobby_window_desc);
  1197 	Window *w = AllocateWindowDesc(&_network_lobby_window_desc);
  1181 	if (w != NULL) {
  1198 	if (w != NULL) {
  1182 		WP(w, network_ql_d).n.server = ngl;
  1199 		WP(w, network_ql_d).n.server = ngl;
  1183 		strcpy(_edit_str_net_buf, "");
  1200 		strcpy(_edit_str_net_buf, "");
  1184 		w->vscroll.cap = 10;
  1201 		w->vscroll.cap = 10;
  1185 	}
  1202 	}
  1252 		SEND_COMMAND(PACKET_SERVER_ERROR)(DEREF_CLIENT(client_no), NETWORK_ERROR_KICKED);
  1269 		SEND_COMMAND(PACKET_SERVER_ERROR)(DEREF_CLIENT(client_no), NETWORK_ERROR_KICKED);
  1253 }
  1270 }
  1254 
  1271 
  1255 static void ClientList_Ban(byte client_no)
  1272 static void ClientList_Ban(byte client_no)
  1256 {
  1273 {
  1257 	uint i;
       
  1258 	uint32 ip = NetworkFindClientInfo(client_no)->client_ip;
  1274 	uint32 ip = NetworkFindClientInfo(client_no)->client_ip;
  1259 
  1275 
  1260 	for (i = 0; i < lengthof(_network_ban_list); i++) {
  1276 	for (uint i = 0; i < lengthof(_network_ban_list); i++) {
  1261 		if (_network_ban_list[i] == NULL) {
  1277 		if (_network_ban_list[i] == NULL) {
  1262 			_network_ban_list[i] = strdup(inet_ntoa(*(struct in_addr *)&ip));
  1278 			_network_ban_list[i] = strdup(inet_ntoa(*(struct in_addr *)&ip));
  1263 			break;
  1279 			break;
  1264 		}
  1280 		}
  1265 	}
  1281 	}
  1266 
  1282 
  1267 	if (client_no < MAX_PLAYERS)
  1283 	if (client_no < MAX_PLAYERS) {
  1268 		SEND_COMMAND(PACKET_SERVER_ERROR)(DEREF_CLIENT(client_no), NETWORK_ERROR_KICKED);
  1284 		SEND_COMMAND(PACKET_SERVER_ERROR)(DEREF_CLIENT(client_no), NETWORK_ERROR_KICKED);
       
  1285 	}
  1269 }
  1286 }
  1270 
  1287 
  1271 static void ClientList_GiveMoney(byte client_no)
  1288 static void ClientList_GiveMoney(byte client_no)
  1272 {
  1289 {
  1273 	if (NetworkFindClientInfo(client_no) != NULL)
  1290 	if (NetworkFindClientInfo(client_no) != NULL) {
  1274 		ShowNetworkGiveMoneyWindow(NetworkFindClientInfo(client_no)->client_playas);
  1291 		ShowNetworkGiveMoneyWindow(NetworkFindClientInfo(client_no)->client_playas);
       
  1292 	}
  1275 }
  1293 }
  1276 
  1294 
  1277 static void ClientList_SpeakToClient(byte client_no)
  1295 static void ClientList_SpeakToClient(byte client_no)
  1278 {
  1296 {
  1279 	if (NetworkFindClientInfo(client_no) != NULL)
  1297 	if (NetworkFindClientInfo(client_no) != NULL) {
  1280 		ShowNetworkChatQueryWindow(DESTTYPE_CLIENT, NetworkFindClientInfo(client_no)->client_index);
  1298 		ShowNetworkChatQueryWindow(DESTTYPE_CLIENT, NetworkFindClientInfo(client_no)->client_index);
       
  1299 	}
  1281 }
  1300 }
  1282 
  1301 
  1283 static void ClientList_SpeakToCompany(byte client_no)
  1302 static void ClientList_SpeakToCompany(byte client_no)
  1284 {
  1303 {
  1285 	if (NetworkFindClientInfo(client_no) != NULL)
  1304 	if (NetworkFindClientInfo(client_no) != NULL) {
  1286 		ShowNetworkChatQueryWindow(DESTTYPE_TEAM, NetworkFindClientInfo(client_no)->client_playas);
  1305 		ShowNetworkChatQueryWindow(DESTTYPE_TEAM, NetworkFindClientInfo(client_no)->client_playas);
       
  1306 	}
  1287 }
  1307 }
  1288 
  1308 
  1289 static void ClientList_SpeakToAll(byte client_no)
  1309 static void ClientList_SpeakToAll(byte client_no)
  1290 {
  1310 {
  1291 	ShowNetworkChatQueryWindow(DESTTYPE_BROADCAST, 0);
  1311 	ShowNetworkChatQueryWindow(DESTTYPE_BROADCAST, 0);
  1292 }
  1312 }
  1293 
  1313 
  1294 static void ClientList_None(byte client_no)
  1314 static void ClientList_None(byte client_no)
  1295 {
  1315 {
  1296 	// No action ;)
  1316 	/* No action ;) */
  1297 }
  1317 }
  1298 
  1318 
  1299 
  1319 
  1300 
  1320 
  1301 // Help, a action is clicked! What do we do?
  1321 /**
       
  1322  * An action is clicked! What do we do?
       
  1323  */
  1302 static void HandleClientListPopupClick(byte index, byte clientno)
  1324 static void HandleClientListPopupClick(byte index, byte clientno)
  1303 {
  1325 {
  1304 	// A click on the Popup of the ClientList.. handle the command
  1326 	/* A click on the Popup of the ClientList.. handle the command */
  1305 	if (index < MAX_CLIENTLIST_ACTION && _clientlist_proc[index] != NULL) {
  1327 	if (index < MAX_CLIENTLIST_ACTION && _clientlist_proc[index] != NULL) {
  1306 		_clientlist_proc[index](clientno);
  1328 		_clientlist_proc[index](clientno);
  1307 	}
  1329 	}
  1308 }
  1330 }
  1309 
  1331 
  1310 // Finds the amount of clients and set the height correct
  1332 /**
       
  1333  * Finds the amount of clients and set the height correct
       
  1334  */
  1311 static bool CheckClientListHeight(Window *w)
  1335 static bool CheckClientListHeight(Window *w)
  1312 {
  1336 {
  1313 	int num = 0;
  1337 	int num = 0;
  1314 	const NetworkClientInfo *ci;
  1338 	const NetworkClientInfo *ci;
  1315 
  1339 
  1316 	// Should be replaced with a loop through all clients
  1340 	/* Should be replaced with a loop through all clients */
  1317 	FOR_ALL_ACTIVE_CLIENT_INFOS(ci) {
  1341 	FOR_ALL_ACTIVE_CLIENT_INFOS(ci) {
  1318 		num++;
  1342 		num++;
  1319 	}
  1343 	}
  1320 
  1344 
  1321 	num *= CLNWND_ROWSIZE;
  1345 	num *= CLNWND_ROWSIZE;
  1322 
  1346 
  1323 	// If height is changed
  1347 	/* If height is changed */
  1324 	if (w->height != CLNWND_OFFSET + num + 1) {
  1348 	if (w->height != CLNWND_OFFSET + num + 1) {
  1325 		// XXX - magic unfortunately; (num + 2) has to be one bigger than heigh (num + 1)
  1349 		// XXX - magic unfortunately; (num + 2) has to be one bigger than heigh (num + 1)
  1326 		SetWindowDirty(w);
  1350 		SetWindowDirty(w);
  1327 		w->widget[3].bottom = w->widget[3].top + num + 2;
  1351 		w->widget[3].bottom = w->widget[3].top + num + 2;
  1328 		w->height = CLNWND_OFFSET + num + 1;
  1352 		w->height = CLNWND_OFFSET + num + 1;
  1330 		return false;
  1354 		return false;
  1331 	}
  1355 	}
  1332 	return true;
  1356 	return true;
  1333 }
  1357 }
  1334 
  1358 
  1335 // Finds the amount of actions in the popup and set the height correct
  1359 /**
       
  1360  * Finds the amount of actions in the popup and set the height correct
       
  1361  */
  1336 static uint ClientListPopupHeight()
  1362 static uint ClientListPopupHeight()
  1337 {
  1363 {
  1338 	int i, num = 0;
  1364 	int num = 0;
  1339 
  1365 
  1340 	// Find the amount of actions
  1366 	// Find the amount of actions
  1341 	for (i = 0; i < MAX_CLIENTLIST_ACTION; i++) {
  1367 	for (int i = 0; i < MAX_CLIENTLIST_ACTION; i++) {
  1342 		if (_clientlist_action[i][0] == '\0') continue;
  1368 		if (_clientlist_action[i][0] == '\0') continue;
  1343 		if (_clientlist_proc[i] == NULL) continue;
  1369 		if (_clientlist_proc[i] == NULL) continue;
  1344 		num++;
  1370 		num++;
  1345 	}
  1371 	}
  1346 
  1372 
  1347 	num *= CLNWND_ROWSIZE;
  1373 	num *= CLNWND_ROWSIZE;
  1348 
  1374 
  1349 	return num + 1;
  1375 	return num + 1;
  1350 }
  1376 }
  1351 
  1377 
  1352 // Show the popup (action list)
  1378 /**
       
  1379  * Show the popup (action list)
       
  1380  */
  1353 static Window *PopupClientList(Window *w, int client_no, int x, int y)
  1381 static Window *PopupClientList(Window *w, int client_no, int x, int y)
  1354 {
  1382 {
  1355 	int i, h;
  1383 	int i;
  1356 	const NetworkClientInfo *ci;
  1384 	const NetworkClientInfo *ci;
  1357 	DeleteWindowById(WC_TOOLBAR_MENU, 0);
  1385 	DeleteWindowById(WC_TOOLBAR_MENU, 0);
  1358 
  1386 
  1359 	// Clean the current actions
  1387 	/* Clean the current actions */
  1360 	for (i = 0; i < MAX_CLIENTLIST_ACTION; i++) {
  1388 	for (i = 0; i < MAX_CLIENTLIST_ACTION; i++) {
  1361 		_clientlist_action[i][0] = '\0';
  1389 		_clientlist_action[i][0] = '\0';
  1362 		_clientlist_proc[i] = NULL;
  1390 		_clientlist_proc[i] = NULL;
  1363 	}
  1391 	}
  1364 
  1392 
  1365 	// Fill the actions this client has
  1393 	/*
  1366 	// Watch is, max 50 chars long!
  1394 	 * Fill the actions this client has.
       
  1395 	 * Watch is, max 50 chars long!
       
  1396 	 */
  1367 
  1397 
  1368 	ci = NetworkFindClientInfo(client_no);
  1398 	ci = NetworkFindClientInfo(client_no);
  1369 	if (ci == NULL) return NULL;
  1399 	if (ci == NULL) return NULL;
  1370 
  1400 
  1371 	i = 0;
  1401 	i = 0;
  1387 			GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_GIVE_MONEY, lastof(_clientlist_action[i]));
  1417 			GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_GIVE_MONEY, lastof(_clientlist_action[i]));
  1388 			_clientlist_proc[i++] = &ClientList_GiveMoney;
  1418 			_clientlist_proc[i++] = &ClientList_GiveMoney;
  1389 		}
  1419 		}
  1390 	}
  1420 	}
  1391 
  1421 
  1392 	// A server can kick clients (but not himself)
  1422 	/* A server can kick clients (but not himself) */
  1393 	if (_network_server && _network_own_client_index != ci->client_index) {
  1423 	if (_network_server && _network_own_client_index != ci->client_index) {
  1394 		GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_KICK, lastof(_clientlist_action[i]));
  1424 		GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_KICK, lastof(_clientlist_action[i]));
  1395 		_clientlist_proc[i++] = &ClientList_Kick;
  1425 		_clientlist_proc[i++] = &ClientList_Kick;
  1396 
  1426 
  1397 		sprintf(_clientlist_action[i],"Ban"); // XXX GetString?
  1427 		sprintf(_clientlist_action[i],"Ban"); // XXX GetString?
  1402 		GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_NONE, lastof(_clientlist_action[i]));
  1432 		GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_NONE, lastof(_clientlist_action[i]));
  1403 		_clientlist_proc[i++] = &ClientList_None;
  1433 		_clientlist_proc[i++] = &ClientList_None;
  1404 	}
  1434 	}
  1405 
  1435 
  1406 	/* Calculate the height */
  1436 	/* Calculate the height */
  1407 	h = ClientListPopupHeight();
  1437 	int h = ClientListPopupHeight();
  1408 
  1438 
  1409 	// Allocate the popup
  1439 	/* Allocate the popup */
  1410 	w = AllocateWindow(x, y, 150, h + 1, ClientListPopupWndProc, WC_TOOLBAR_MENU, _client_list_popup_widgets);
  1440 	w = AllocateWindow(x, y, 150, h + 1, ClientListPopupWndProc, WC_TOOLBAR_MENU, _client_list_popup_widgets);
  1411 	w->widget[0].bottom = w->widget[0].top + h;
  1441 	w->widget[0].bottom = w->widget[0].top + h;
  1412 	w->widget[0].right = w->widget[0].left + 150;
  1442 	w->widget[0].right = w->widget[0].left + 150;
  1413 
  1443 
  1414 	w->flags4 &= ~WF_WHITE_BORDER_MASK;
  1444 	w->flags4 &= ~WF_WHITE_BORDER_MASK;
  1425 /** Main handle for the client popup list
  1455 /** Main handle for the client popup list
  1426  * uses menu_d WP macro */
  1456  * uses menu_d WP macro */
  1427 static void ClientListPopupWndProc(Window *w, WindowEvent *e)
  1457 static void ClientListPopupWndProc(Window *w, WindowEvent *e)
  1428 {
  1458 {
  1429 	switch (e->event) {
  1459 	switch (e->event) {
  1430 	case WE_PAINT: {
  1460 		case WE_PAINT: {
  1431 		int i, y, sel;
  1461 			DrawWindowWidgets(w);
  1432 		TextColour colour;
  1462 
  1433 		DrawWindowWidgets(w);
  1463 			/* Draw the actions */
  1434 
  1464 			int sel = WP(w, menu_d).sel_index;
  1435 		// Draw the actions
  1465 			int y = 1;
  1436 		sel = WP(w, menu_d).sel_index;
  1466 			for (int i = 0; i < MAX_CLIENTLIST_ACTION; i++, y += CLNWND_ROWSIZE) {
  1437 		y = 1;
  1467 				if (_clientlist_action[i][0] == '\0') continue;
  1438 		for (i = 0; i < MAX_CLIENTLIST_ACTION; i++, y += CLNWND_ROWSIZE) {
  1468 				if (_clientlist_proc[i] == NULL) continue;
  1439 			if (_clientlist_action[i][0] == '\0') continue;
  1469 
  1440 			if (_clientlist_proc[i] == NULL) continue;
  1470 				TextColour colour;
  1441 
  1471 				if (sel-- == 0) { // Selected item, highlight it
  1442 			if (sel-- == 0) { // Selected item, highlight it
  1472 					GfxFillRect(1, y, 150 - 2, y + CLNWND_ROWSIZE - 1, 0);
  1443 				GfxFillRect(1, y, 150 - 2, y + CLNWND_ROWSIZE - 1, 0);
  1473 					colour = TC_WHITE;
  1444 				colour = TC_WHITE;
  1474 				} else {
       
  1475 					colour = TC_BLACK;
       
  1476 				}
       
  1477 
       
  1478 				DoDrawString(_clientlist_action[i], 4, y, colour);
       
  1479 			}
       
  1480 		} break;
       
  1481 
       
  1482 		case WE_POPUPMENU_SELECT: {
       
  1483 			/* We selected an action */
       
  1484 			int index = (e->we.popupmenu.pt.y - w->top) / CLNWND_ROWSIZE;
       
  1485 
       
  1486 			if (index >= 0 && e->we.popupmenu.pt.y >= w->top) {
       
  1487 				HandleClientListPopupClick(index, WP(w, menu_d).main_button);
       
  1488 			}
       
  1489 
       
  1490 			DeleteWindowById(WC_TOOLBAR_MENU, 0);
       
  1491 		} break;
       
  1492 
       
  1493 		case WE_POPUPMENU_OVER: {
       
  1494 			/* Our mouse hoovers over an action? Select it! */
       
  1495 			int index = (e->we.popupmenu.pt.y - w->top) / CLNWND_ROWSIZE;
       
  1496 
       
  1497 			if (index == -1 || index == WP(w, menu_d).sel_index) return;
       
  1498 
       
  1499 			WP(w, menu_d).sel_index = index;
       
  1500 			SetWindowDirty(w);
       
  1501 		} break;
       
  1502 	}
       
  1503 }
       
  1504 
       
  1505 /**
       
  1506  * Main handle for clientlist
       
  1507  */
       
  1508 static void ClientListWndProc(Window *w, WindowEvent *e)
       
  1509 {
       
  1510 	switch (e->event) {
       
  1511 		case WE_PAINT: {
       
  1512 			NetworkClientInfo *ci;
       
  1513 			int i = 0;
       
  1514 
       
  1515 			/* Check if we need to reset the height */
       
  1516 			if (!CheckClientListHeight(w)) break;
       
  1517 
       
  1518 			DrawWindowWidgets(w);
       
  1519 
       
  1520 			int y = CLNWND_OFFSET;
       
  1521 
       
  1522 			FOR_ALL_ACTIVE_CLIENT_INFOS(ci) {
       
  1523 				TextColour colour;
       
  1524 				if (_selected_clientlist_item == i++) { // Selected item, highlight it
       
  1525 					GfxFillRect(1, y, 248, y + CLNWND_ROWSIZE - 1, 0);
       
  1526 					colour = TC_WHITE;
       
  1527 				} else {
       
  1528 					colour = TC_BLACK;
       
  1529 				}
       
  1530 
       
  1531 				if (ci->client_index == NETWORK_SERVER_INDEX) {
       
  1532 					DrawString(4, y, STR_NETWORK_SERVER, colour);
       
  1533 				} else {
       
  1534 					DrawString(4, y, STR_NETWORK_CLIENT, colour);
       
  1535 				}
       
  1536 
       
  1537 				/* Filter out spectators */
       
  1538 				if (IsValidPlayer(ci->client_playas)) DrawPlayerIcon(ci->client_playas, 64, y + 1);
       
  1539 
       
  1540 				DoDrawString(ci->client_name, 81, y, colour);
       
  1541 
       
  1542 				y += CLNWND_ROWSIZE;
       
  1543 			}
       
  1544 		} break;
       
  1545 
       
  1546 		case WE_CLICK:
       
  1547 			/* Show the popup with option */
       
  1548 			if (_selected_clientlist_item != 255) {
       
  1549 				PopupClientList(w, _selected_clientlist_item, e->we.click.pt.x + w->left, e->we.click.pt.y + w->top);
       
  1550 			}
       
  1551 			break;
       
  1552 
       
  1553 		case WE_MOUSEOVER:
       
  1554 			/* -1 means we left the current window */
       
  1555 			if (e->we.mouseover.pt.y == -1) {
       
  1556 				_selected_clientlist_y = 0;
       
  1557 				_selected_clientlist_item = 255;
       
  1558 				SetWindowDirty(w);
       
  1559 				break;
       
  1560 			}
       
  1561 			/* It did not change.. no update! */
       
  1562 			if (e->we.mouseover.pt.y == _selected_clientlist_y) break;
       
  1563 
       
  1564 			/* Find the new selected item (if any) */
       
  1565 			_selected_clientlist_y = e->we.mouseover.pt.y;
       
  1566 			if (e->we.mouseover.pt.y > CLNWND_OFFSET) {
       
  1567 				_selected_clientlist_item = (e->we.mouseover.pt.y - CLNWND_OFFSET) / CLNWND_ROWSIZE;
  1445 			} else {
  1568 			} else {
  1446 				colour = TC_BLACK;
  1569 				_selected_clientlist_item = 255;
  1447 			}
  1570 			}
  1448 
  1571 
  1449 			DoDrawString(_clientlist_action[i], 4, y, colour);
  1572 			/* Repaint */
  1450 		}
  1573 			SetWindowDirty(w);
  1451 	} break;
  1574 			break;
  1452 
  1575 
  1453 	case WE_POPUPMENU_SELECT: {
  1576 		case WE_DESTROY: case WE_CREATE:
  1454 		// We selected an action
  1577 			/* When created or destroyed, data is reset */
  1455 		int index = (e->we.popupmenu.pt.y - w->top) / CLNWND_ROWSIZE;
  1578 			_selected_clientlist_item = 255;
  1456 
       
  1457 		if (index >= 0 && e->we.popupmenu.pt.y >= w->top)
       
  1458 			HandleClientListPopupClick(index, WP(w, menu_d).main_button);
       
  1459 
       
  1460 		DeleteWindowById(WC_TOOLBAR_MENU, 0);
       
  1461 	} break;
       
  1462 
       
  1463 	case WE_POPUPMENU_OVER: {
       
  1464 		// Our mouse hoovers over an action? Select it!
       
  1465 		int index = (e->we.popupmenu.pt.y - w->top) / CLNWND_ROWSIZE;
       
  1466 
       
  1467 		if (index == -1 || index == WP(w, menu_d).sel_index) return;
       
  1468 
       
  1469 		WP(w, menu_d).sel_index = index;
       
  1470 		SetWindowDirty(w);
       
  1471 	} break;
       
  1472 
       
  1473 	}
       
  1474 }
       
  1475 
       
  1476 // Main handle for clientlist
       
  1477 static void ClientListWndProc(Window *w, WindowEvent *e)
       
  1478 {
       
  1479 	switch (e->event) {
       
  1480 	case WE_PAINT: {
       
  1481 		NetworkClientInfo *ci;
       
  1482 		int y, i = 0;
       
  1483 		TextColour colour;
       
  1484 
       
  1485 		// Check if we need to reset the height
       
  1486 		if (!CheckClientListHeight(w)) break;
       
  1487 
       
  1488 		DrawWindowWidgets(w);
       
  1489 
       
  1490 		y = CLNWND_OFFSET;
       
  1491 
       
  1492 		FOR_ALL_ACTIVE_CLIENT_INFOS(ci) {
       
  1493 			if (_selected_clientlist_item == i++) { // Selected item, highlight it
       
  1494 				GfxFillRect(1, y, 248, y + CLNWND_ROWSIZE - 1, 0);
       
  1495 				colour = TC_WHITE;
       
  1496 			} else {
       
  1497 				colour = TC_BLACK;
       
  1498 			}
       
  1499 
       
  1500 			if (ci->client_index == NETWORK_SERVER_INDEX) {
       
  1501 				DrawString(4, y, STR_NETWORK_SERVER, colour);
       
  1502 			} else {
       
  1503 				DrawString(4, y, STR_NETWORK_CLIENT, colour);
       
  1504 			}
       
  1505 
       
  1506 			// Filter out spectators
       
  1507 			if (IsValidPlayer(ci->client_playas)) DrawPlayerIcon(ci->client_playas, 64, y + 1);
       
  1508 
       
  1509 			DoDrawString(ci->client_name, 81, y, colour);
       
  1510 
       
  1511 			y += CLNWND_ROWSIZE;
       
  1512 		}
       
  1513 	} break;
       
  1514 
       
  1515 	case WE_CLICK:
       
  1516 		// Show the popup with option
       
  1517 		if (_selected_clientlist_item != 255) {
       
  1518 			PopupClientList(w, _selected_clientlist_item, e->we.click.pt.x + w->left, e->we.click.pt.y + w->top);
       
  1519 		}
       
  1520 
       
  1521 		break;
       
  1522 
       
  1523 	case WE_MOUSEOVER:
       
  1524 		// -1 means we left the current window
       
  1525 		if (e->we.mouseover.pt.y == -1) {
       
  1526 			_selected_clientlist_y = 0;
  1579 			_selected_clientlist_y = 0;
  1527 			_selected_clientlist_item = 255;
  1580 			break;
  1528 			SetWindowDirty(w);
       
  1529 			break;
       
  1530 		}
       
  1531 		// It did not change.. no update!
       
  1532 		if (e->we.mouseover.pt.y == _selected_clientlist_y) break;
       
  1533 
       
  1534 		// Find the new selected item (if any)
       
  1535 		_selected_clientlist_y = e->we.mouseover.pt.y;
       
  1536 		if (e->we.mouseover.pt.y > CLNWND_OFFSET) {
       
  1537 			_selected_clientlist_item = (e->we.mouseover.pt.y - CLNWND_OFFSET) / CLNWND_ROWSIZE;
       
  1538 		} else {
       
  1539 			_selected_clientlist_item = 255;
       
  1540 		}
       
  1541 
       
  1542 		// Repaint
       
  1543 		SetWindowDirty(w);
       
  1544 		break;
       
  1545 
       
  1546 	case WE_DESTROY: case WE_CREATE:
       
  1547 		// When created or destroyed, data is reset
       
  1548 		_selected_clientlist_item = 255;
       
  1549 		_selected_clientlist_y = 0;
       
  1550 		break;
       
  1551 	}
  1581 	}
  1552 }
  1582 }
  1553 
  1583 
  1554 void ShowClientList()
  1584 void ShowClientList()
  1555 {
  1585 {
  1575 
  1605 
  1576 
  1606 
  1577 static void NetworkJoinStatusWindowWndProc(Window *w, WindowEvent *e)
  1607 static void NetworkJoinStatusWindowWndProc(Window *w, WindowEvent *e)
  1578 {
  1608 {
  1579 	switch (e->event) {
  1609 	switch (e->event) {
  1580 	case WE_PAINT: {
  1610 		case WE_PAINT: {
  1581 		uint8 progress; // used for progress bar
  1611 			uint8 progress; // used for progress bar
  1582 		DrawWindowWidgets(w);
  1612 			DrawWindowWidgets(w);
  1583 
  1613 
  1584 		DrawStringCentered(125, 35, STR_NETWORK_CONNECTING_1 + _network_join_status, TC_GREY);
  1614 			DrawStringCentered(125, 35, STR_NETWORK_CONNECTING_1 + _network_join_status, TC_GREY);
  1585 		switch (_network_join_status) {
  1615 			switch (_network_join_status) {
  1586 			case NETWORK_JOIN_STATUS_CONNECTING: case NETWORK_JOIN_STATUS_AUTHORIZING:
  1616 				case NETWORK_JOIN_STATUS_CONNECTING: case NETWORK_JOIN_STATUS_AUTHORIZING:
  1587 			case NETWORK_JOIN_STATUS_GETTING_COMPANY_INFO:
  1617 				case NETWORK_JOIN_STATUS_GETTING_COMPANY_INFO:
  1588 				progress = 10; // first two stages 10%
  1618 					progress = 10; // first two stages 10%
  1589 				break;
  1619 					break;
  1590 			case NETWORK_JOIN_STATUS_WAITING:
  1620 				case NETWORK_JOIN_STATUS_WAITING:
  1591 				SetDParam(0, _network_join_waiting);
  1621 					SetDParam(0, _network_join_waiting);
  1592 				DrawStringCentered(125, 46, STR_NETWORK_CONNECTING_WAITING, TC_GREY);
  1622 					DrawStringCentered(125, 46, STR_NETWORK_CONNECTING_WAITING, TC_GREY);
  1593 				progress = 15; // third stage is 15%
  1623 					progress = 15; // third stage is 15%
  1594 				break;
  1624 					break;
  1595 			case NETWORK_JOIN_STATUS_DOWNLOADING:
  1625 				case NETWORK_JOIN_STATUS_DOWNLOADING:
  1596 				SetDParam(0, _network_join_kbytes);
  1626 					SetDParam(0, _network_join_kbytes);
  1597 				SetDParam(1, _network_join_kbytes_total);
  1627 					SetDParam(1, _network_join_kbytes_total);
  1598 				DrawStringCentered(125, 46, STR_NETWORK_CONNECTING_DOWNLOADING, TC_GREY);
  1628 					DrawStringCentered(125, 46, STR_NETWORK_CONNECTING_DOWNLOADING, TC_GREY);
  1599 				/* Fallthrough */
  1629 					/* Fallthrough */
  1600 			default: /* Waiting is 15%, so the resting receivement of map is maximum 70% */
  1630 				default: /* Waiting is 15%, so the resting receivement of map is maximum 70% */
  1601 				progress = 15 + _network_join_kbytes * (100 - 15) / _network_join_kbytes_total;
  1631 					progress = 15 + _network_join_kbytes * (100 - 15) / _network_join_kbytes_total;
  1602 		}
  1632 			}
  1603 
  1633 
  1604 		/* Draw nice progress bar :) */
  1634 			/* Draw nice progress bar :) */
  1605 		DrawFrameRect(20, 18, (int)((w->width - 20) * progress / 100), 28, 10, FR_NONE);
  1635 			DrawFrameRect(20, 18, (int)((w->width - 20) * progress / 100), 28, 10, FR_NONE);
  1606 	} break;
  1636 		} break;
  1607 
  1637 
  1608 	case WE_CLICK:
  1638 		case WE_CLICK:
  1609 		switch (e->we.click.widget) {
  1639 			if (e->we.click.widget == 2) { //Disconnect button
  1610 			case 2: /* Disconnect button */
       
  1611 				NetworkDisconnect();
  1640 				NetworkDisconnect();
  1612 				DeleteWindow(w);
  1641 				DeleteWindow(w);
  1613 				SwitchMode(SM_MENU);
  1642 				SwitchMode(SM_MENU);
  1614 				ShowNetworkGameWindow();
  1643 				ShowNetworkGameWindow();
       
  1644 			}
       
  1645 			break;
       
  1646 
       
  1647 			/* If the server asks for a password, we need to fill it in */
       
  1648 			case WE_ON_EDIT_TEXT_CANCEL:
       
  1649 				NetworkDisconnect();
       
  1650 				ShowNetworkGameWindow();
  1615 				break;
  1651 				break;
  1616 		}
  1652 
  1617 		break;
  1653 			case WE_ON_EDIT_TEXT:
  1618 
  1654 				SEND_COMMAND(PACKET_CLIENT_PASSWORD)(pw_type, e->we.edittext.str);
  1619 		/* If the server asks for a password, we need to fill it in */
  1655 				break;
  1620 		case WE_ON_EDIT_TEXT_CANCEL:
       
  1621 			NetworkDisconnect();
       
  1622 			ShowNetworkGameWindow();
       
  1623 			break;
       
  1624 
       
  1625 		case WE_ON_EDIT_TEXT:
       
  1626 			SEND_COMMAND(PACKET_CLIENT_PASSWORD)(pw_type, e->we.edittext.str);
       
  1627 			break;
       
  1628 	}
  1656 	}
  1629 }
  1657 }
  1630 
  1658 
  1631 static const Widget _network_join_status_window_widget[] = {
  1659 static const Widget _network_join_status_window_widget[] = {
  1632 {    WWT_CAPTION,   RESIZE_NONE,    14,     0,   249,     0,    13, STR_NETWORK_CONNECTING, STR_018C_WINDOW_TITLE_DRAG_THIS},
  1660 {    WWT_CAPTION,   RESIZE_NONE,    14,     0,   249,     0,    13, STR_NETWORK_CONNECTING, STR_018C_WINDOW_TITLE_DRAG_THIS},
  1643 	NetworkJoinStatusWindowWndProc,
  1671 	NetworkJoinStatusWindowWndProc,
  1644 };
  1672 };
  1645 
  1673 
  1646 void ShowJoinStatusWindow()
  1674 void ShowJoinStatusWindow()
  1647 {
  1675 {
  1648 	Window *w;
       
  1649 	DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
  1676 	DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
  1650 	w = AllocateWindowDesc(&_network_join_status_window_desc);
  1677 	Window *w = AllocateWindowDesc(&_network_join_status_window_desc);
  1651 	/* Parent the status window to the lobby */
  1678 	/* Parent the status window to the lobby */
  1652 	if (w != NULL) w->parent = FindWindowById(WC_NETWORK_WINDOW, 0);
  1679 	if (w != NULL) w->parent = FindWindowById(WC_NETWORK_WINDOW, 0);
  1653 }
  1680 }
  1654 
  1681 
  1655 static void SendChat(const char *buf, DestType type, int dest)
  1682 static void SendChat(const char *buf, DestType type, int dest)
  1800  * uses chatquerystr_d->dtype to store type of chat message (Private/Team/All)
  1827  * uses chatquerystr_d->dtype to store type of chat message (Private/Team/All)
  1801  */
  1828  */
  1802 static void ChatWindowWndProc(Window *w, WindowEvent *e)
  1829 static void ChatWindowWndProc(Window *w, WindowEvent *e)
  1803 {
  1830 {
  1804 	switch (e->event) {
  1831 	switch (e->event) {
  1805 	case WE_CREATE:
  1832 		case WE_CREATE:
  1806 		SendWindowMessage(WC_NEWS_WINDOW, 0, WE_CREATE, w->height, 0);
  1833 			SendWindowMessage(WC_NEWS_WINDOW, 0, WE_CREATE, w->height, 0);
  1807 		SetBit(_no_scroll, SCROLL_CHAT); // do not scroll the game with the arrow-keys
  1834 			SetBit(_no_scroll, SCROLL_CHAT); // do not scroll the game with the arrow-keys
  1808 		break;
  1835 			break;
  1809 
  1836 
  1810 	case WE_PAINT: {
  1837 		case WE_PAINT: {
  1811 		static const StringID chat_captions[] = {
  1838 			static const StringID chat_captions[] = {
  1812 			STR_NETWORK_CHAT_ALL_CAPTION,
  1839 				STR_NETWORK_CHAT_ALL_CAPTION,
  1813 			STR_NETWORK_CHAT_COMPANY_CAPTION,
  1840 				STR_NETWORK_CHAT_COMPANY_CAPTION,
  1814 			STR_NETWORK_CHAT_CLIENT_CAPTION
  1841 				STR_NETWORK_CHAT_CLIENT_CAPTION
  1815 		};
  1842 			};
  1816 
  1843 
  1817 		DrawWindowWidgets(w);
  1844 			DrawWindowWidgets(w);
  1818 
  1845 
  1819 		assert((uint)WP(w, chatquerystr_d).dtype < lengthof(chat_captions));
  1846 			assert((uint)WP(w, chatquerystr_d).dtype < lengthof(chat_captions));
  1820 		DrawStringRightAligned(w->widget[2].left - 2, w->widget[2].top + 1, chat_captions[WP(w, chatquerystr_d).dtype], TC_BLACK);
  1847 			DrawStringRightAligned(w->widget[2].left - 2, w->widget[2].top + 1, chat_captions[WP(w, chatquerystr_d).dtype], TC_BLACK);
  1821 		DrawEditBox(w, &WP(w, chatquerystr_d), 2);
  1848 			DrawEditBox(w, &WP(w, chatquerystr_d), 2);
  1822 	} break;
  1849 		} break;
  1823 
  1850 
  1824 	case WE_CLICK:
  1851 		case WE_CLICK:
  1825 		switch (e->we.click.widget) {
  1852 			switch (e->we.click.widget) {
  1826 			case 2:
  1853 				case 2:
  1827 				ShowOnScreenKeyboard(w, &WP(w, chatquerystr_d), 2, 0, 3);
  1854 					ShowOnScreenKeyboard(w, &WP(w, chatquerystr_d), 2, 0, 3);
  1828 				break;
  1855 					break;
  1829 
  1856 
  1830 			case 3: /* Send */
  1857 				case 3: /* Send */
  1831 				SendChat(WP(w, chatquerystr_d).text.buf, WP(w, chatquerystr_d).dtype, WP(w, chatquerystr_d).dest);
       
  1832 			/* FALLTHROUGH */
       
  1833 			case 0: /* Cancel */ DeleteWindow(w); break;
       
  1834 		}
       
  1835 		break;
       
  1836 
       
  1837 	case WE_MOUSELOOP:
       
  1838 		HandleEditBox(w, &WP(w, chatquerystr_d), 2);
       
  1839 		break;
       
  1840 
       
  1841 	case WE_KEYPRESS:
       
  1842 		if (e->we.keypress.keycode == WKC_TAB) {
       
  1843 			ChatTabCompletion(w);
       
  1844 		} else {
       
  1845 			_chat_tab_completion_active = false;
       
  1846 			switch (HandleEditBoxKey(w, &WP(w, chatquerystr_d), 2, e)) {
       
  1847 				case 1: /* Return */
       
  1848 					SendChat(WP(w, chatquerystr_d).text.buf, WP(w, chatquerystr_d).dtype, WP(w, chatquerystr_d).dest);
  1858 					SendChat(WP(w, chatquerystr_d).text.buf, WP(w, chatquerystr_d).dtype, WP(w, chatquerystr_d).dest);
  1849 				/* FALLTHROUGH */
  1859 				/* FALLTHROUGH */
  1850 				case 2: /* Escape */ DeleteWindow(w); break;
  1860 				case 0: /* Cancel */ DeleteWindow(w); break;
  1851 			}
  1861 			}
  1852 		}
  1862 			break;
  1853 		break;
  1863 
  1854 
  1864 		case WE_MOUSELOOP:
  1855 	case WE_DESTROY:
  1865 			HandleEditBox(w, &WP(w, chatquerystr_d), 2);
  1856 		SendWindowMessage(WC_NEWS_WINDOW, 0, WE_DESTROY, 0, 0);
  1866 			break;
  1857 		ClrBit(_no_scroll, SCROLL_CHAT);
  1867 
  1858 		break;
  1868 		case WE_KEYPRESS:
       
  1869 			if (e->we.keypress.keycode == WKC_TAB) {
       
  1870 				ChatTabCompletion(w);
       
  1871 			} else {
       
  1872 				_chat_tab_completion_active = false;
       
  1873 				switch (HandleEditBoxKey(w, &WP(w, chatquerystr_d), 2, e)) {
       
  1874 					case 1: /* Return */
       
  1875 						SendChat(WP(w, chatquerystr_d).text.buf, WP(w, chatquerystr_d).dtype, WP(w, chatquerystr_d).dest);
       
  1876 					/* FALLTHROUGH */
       
  1877 					case 2: /* Escape */ DeleteWindow(w); break;
       
  1878 				}
       
  1879 			}
       
  1880 			break;
       
  1881 
       
  1882 		case WE_DESTROY:
       
  1883 			SendWindowMessage(WC_NEWS_WINDOW, 0, WE_DESTROY, 0, 0);
       
  1884 			ClrBit(_no_scroll, SCROLL_CHAT);
       
  1885 			break;
  1859 	}
  1886 	}
  1860 }
  1887 }
  1861 
  1888 
  1862 static const Widget _chat_window_widgets[] = {
  1889 static const Widget _chat_window_widgets[] = {
  1863 {   WWT_CLOSEBOX, RESIZE_NONE,  14,   0,  10,  0, 13, STR_00C5,                  STR_018B_CLOSE_WINDOW},
  1890 {   WWT_CLOSEBOX, RESIZE_NONE,  14,   0,  10,  0, 13, STR_00C5,                  STR_018B_CLOSE_WINDOW},
  1875 	ChatWindowWndProc
  1902 	ChatWindowWndProc
  1876 };
  1903 };
  1877 
  1904 
  1878 void ShowNetworkChatQueryWindow(DestType type, int dest)
  1905 void ShowNetworkChatQueryWindow(DestType type, int dest)
  1879 {
  1906 {
  1880 	Window *w;
       
  1881 
       
  1882 	DeleteWindowById(WC_SEND_NETWORK_MSG, 0);
  1907 	DeleteWindowById(WC_SEND_NETWORK_MSG, 0);
  1883 
  1908 
  1884 	_edit_str_net_buf[0] = '\0';
  1909 	_edit_str_net_buf[0] = '\0';
  1885 	_chat_tab_completion_active = false;
  1910 	_chat_tab_completion_active = false;
  1886 
  1911 
  1887 	w = AllocateWindowDesc(&_chat_window_desc);
  1912 	Window *w = AllocateWindowDesc(&_chat_window_desc);
  1888 
  1913 
  1889 	w->LowerWidget(2);
  1914 	w->LowerWidget(2);
  1890 	WP(w, chatquerystr_d).dtype   = type;
  1915 	WP(w, chatquerystr_d).dtype   = type;
  1891 	WP(w, chatquerystr_d).dest    = dest;
  1916 	WP(w, chatquerystr_d).dest    = dest;
  1892 	WP(w, chatquerystr_d).afilter = CS_ALPHANUMERAL;
  1917 	WP(w, chatquerystr_d).afilter = CS_ALPHANUMERAL;