summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--console_cmds.c42
-rw-r--r--lang/english.txt41
-rw-r--r--network.c27
-rw-r--r--network.h41
-rw-r--r--network_client.c38
-rw-r--r--network_data.h3
-rw-r--r--network_gui.c239
-rw-r--r--network_server.c48
-rw-r--r--network_udp.c64
-rw-r--r--players.c7
10 files changed, 331 insertions, 219 deletions
diff --git a/console_cmds.c b/console_cmds.c
index 484925edc..971a4bfcd 100644
--- a/console_cmds.c
+++ b/console_cmds.c
@@ -381,7 +381,7 @@ DEF_CONSOLE_CMD(ConBan)
}
if (index == NETWORK_SERVER_INDEX) {
- IConsolePrint(_icolour_def, "Silly boy, you can not ban yourself!");
+ IConsoleError("Silly boy, you can not ban yourself!");
return true;
}
@@ -511,7 +511,7 @@ DEF_CONSOLE_CMD(ConStatus)
const NetworkClientState *cs;
if (argc == 0) {
- IConsoleHelp("List the status of all clients connected to the server: Usage 'status'");
+ IConsoleHelp("List the status of all clients connected to the server. Usage 'status'");
return true;
}
@@ -527,6 +527,35 @@ DEF_CONSOLE_CMD(ConStatus)
return true;
}
+DEF_CONSOLE_CMD(ConServerInfo)
+{
+ const NetworkGameInfo *gi;
+
+ if (argc == 0) {
+ IConsoleHelp("List current and maximum client/player limits. Usage 'server_info'");
+ IConsoleHelp("You can change these values by setting the variables 'max_clients', 'max_companies' and 'max_spectators'");
+ return true;
+ }
+
+ gi = &_network_game_info;
+ IConsolePrintF(_icolour_def, "Current/maximum clients: %2d/%2d", gi->clients_on, gi->clients_max);
+ IConsolePrintF(_icolour_def, "Current/maximum companies: %2d/%2d", gi->companies_on, gi->companies_max);
+ IConsolePrintF(_icolour_def, "Current/maximum spectators: %2d/%2d", gi->spectators_on, gi->spectators_max);
+
+ return true;
+}
+
+DEF_CONSOLE_HOOK(ConHookValidateMaxClientsCount) {
+ /* XXX - hardcoded, string limiation -- TrueLight
+ * XXX - also see network.c:NetworkStartup ~1343 */
+ if (_network_game_info.clients_max > 10) {
+ _network_game_info.clients_max = 10;
+ IConsoleError("Maximum clients is 10, truncating.");
+ }
+
+ return true;
+}
+
DEF_CONSOLE_CMD(ConKick)
{
NetworkClientInfo *ci;
@@ -549,7 +578,7 @@ DEF_CONSOLE_CMD(ConKick)
}
if (index == NETWORK_SERVER_INDEX) {
- IConsolePrint(_icolour_def, "Silly boy, you can not kick yourself!");
+ IConsoleError("Silly boy, you can not kick yourself!");
return true;
}
@@ -1405,6 +1434,13 @@ void IConsoleStdLibRegister(void)
IConsoleVarHookAdd("server_advertise", ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
IConsoleVarHookAdd("server_advertise", ICONSOLE_HOOK_POST_ACTION, ConHookServerAdvertise);
+ IConsoleVarRegister("max_clients", &_network_game_info.clients_max, ICONSOLE_VAR_BYTE, "Control the maximum amount of connected players during runtime. Default value: 10");
+ IConsoleVarHookAdd("max_clients", ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
+ IConsoleVarHookAdd("max_clients", ICONSOLE_HOOK_POST_ACTION, ConHookValidateMaxClientsCount);
+ IConsoleVarRegister("max_companies", &_network_game_info.companies_max, ICONSOLE_VAR_BYTE, "Control the maximum amount of active companies during runtime. Default value: 8");
+ IConsoleVarHookAdd("max_companies", ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
+ IConsoleVarRegister("max_spectators", &_network_game_info.spectators_max, ICONSOLE_VAR_BYTE, "Control the maximum amount of active spectators during runtime. Default value: 9");
+ IConsoleVarHookAdd("max_spectators", ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
IConsoleVarRegister("pause_on_join", &_network_pause_on_join, ICONSOLE_VAR_BOOLEAN, "Set if the server should pause gameplay while a client is joining. This might help slow users");
IConsoleVarHookAdd("pause_on_join", ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
diff --git a/lang/english.txt b/lang/english.txt
index 6b2c7ec75..d62fff336 100644
--- a/lang/english.txt
+++ b/lang/english.txt
@@ -1201,12 +1201,12 @@ STR_NETWORK_ADD_SERVER :{BLACK}Add serv
STR_NETWORK_ADD_SERVER_TIP :{BLACK}Adds a server to the list which will always be checked for running games.
STR_NETWORK_ENTER_IP :{BLACK}Enter the address of the host
-STR_NETWORK_CLIENTS_ONLINE :{BLACK}{COMMA}/{COMMA}
+STR_NETWORK_GENERAL_ONLINE :{BLACK}{COMMA}/{COMMA} - {COMMA}/{COMMA}
STR_NETWORK_CLIENTS_CAPTION :{BLACK}Clients
-STR_NETWORK_CLIENTS_CAPTION_TIP :{BLACK}Clients online / clients max
+STR_NETWORK_CLIENTS_CAPTION_TIP :{BLACK}Clients online / clients max{}Companies online / companies max
STR_NETWORK_GAME_INFO :{SILVER}GAME INFO
STR_ORANGE :{ORANGE}{STRING}
-STR_NETWORK_CLIENTS :{SILVER}Clients: {WHITE}{COMMA} / {COMMA}
+STR_NETWORK_CLIENTS :{SILVER}Clients: {WHITE}{COMMA} / {COMMA} - {COMMA} / {COMMA}
STR_NETWORK_LANGUAGE :{SILVER}Language: {WHITE}{STRING}
STR_NETWORK_TILESET :{SILVER}Tileset: {WHITE}{STRING}
STR_NETWORK_MAP_SIZE :{SILVER}Map size: {WHITE}{COMMA}x{COMMA}
@@ -1230,7 +1230,7 @@ STR_NETWORK_SET_PASSWORD :{BLACK}Set pass
STR_NETWORK_PASSWORD_TIP :{BLACK}Protect your game with a password if you don't want it to be publicly accessible
STR_NETWORK_SELECT_MAP :{BLACK}Select a map:
STR_NETWORK_SELECT_MAP_TIP :{BLACK}Which map do you want to play?
-STR_NETWORK_NUMBER_OF_CLIENTS :{BLACK}Maximum allowed clients:
+STR_NETWORK_NUMBER_OF_CLIENTS :{BLACK}Max clients:
STR_NETWORK_NUMBER_OF_CLIENTS_TIP :{BLACK}Choose the maximum number of clients. Not all slots need to be filled
STR_NETWORK_COMBO1 :{BLACK}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{STRING}
STR_NETWORK_LAN :LAN
@@ -1238,18 +1238,26 @@ STR_NETWORK_INTERNET :Internet
STR_NETWORK_LAN_INTERNET :LAN / Internet
STR_NETWORK_INTERNET_ADVERTISE :Internet (advertise)
STR_NETWORK_COMBO2 :{BLACK}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{STRING}
-STR_NETWORK_2_CLIENTS :2 clients
-STR_NETWORK_3_CLIENTS :3 clients
-STR_NETWORK_4_CLIENTS :4 clients
-STR_NETWORK_5_CLIENTS :5 clients
-STR_NETWORK_6_CLIENTS :6 clients
-STR_NETWORK_7_CLIENTS :7 clients
-STR_NETWORK_8_CLIENTS :8 clients
-STR_NETWORK_9_CLIENTS :9 clients
-STR_NETWORK_10_CLIENTS :10 clients
+STR_NETWORK_0_CLIENTS :0 players
+STR_NETWORK_1_CLIENTS :1 player
+STR_NETWORK_2_CLIENTS :2 players
+STR_NETWORK_3_CLIENTS :3 players
+STR_NETWORK_4_CLIENTS :4 players
+STR_NETWORK_5_CLIENTS :5 players
+STR_NETWORK_6_CLIENTS :6 players
+STR_NETWORK_7_CLIENTS :7 players
+STR_NETWORK_8_CLIENTS :8 players
+STR_NETWORK_9_CLIENTS :9 players
+STR_NETWORK_10_CLIENTS :10 players
+STR_NETWORK_NUMBER_OF_COMPANIES :{BLACK}Max companies:
+STR_NETWORK_NUMBER_OF_COMPANIES_TIP :{BLACK}Limit the server to a certain amount of companies
+STR_NETWORK_COMBO3 :{BLACK}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{STRING}
+STR_NETWORK_NUMBER_OF_SPECTATORS :{BLACK}Max spectators:
+STR_NETWORK_NUMBER_OF_SPECTATORS_TIP :{BLACK}Limit the server to a certain amount of spectators
+STR_NETWORK_COMBO4 :{BLACK}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{STRING}
STR_NETWORK_LANGUAGE_SPOKEN :{BLACK}Language spoken:
STR_NETWORK_LANGUAGE_TIP :{BLACK}Other players will know which language is spoken on the server
-STR_NETWORK_COMBO3 :{BLACK}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{STRING}
+STR_NETWORK_COMBO5 :{BLACK}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{STRING}
STR_NETWORK_START_GAME :{BLACK}Start Game
STR_NETWORK_START_GAME_TIP :{BLACK}Start a new network game from a random map, or scenario
STR_NETWORK_LOAD_GAME :{BLACK}Load Game
@@ -1336,14 +1344,15 @@ STR_NETWORK_ERR_CLIENT_DESYNC :desync error
STR_NETWORK_ERR_CLIENT_SAVEGAME :could not load map
STR_NETWORK_ERR_CLIENT_CONNECTION_LOST :connection lost
STR_NETWORK_ERR_CLIENT_PROTOCOL_ERROR :protocol error
-STR_NETWORK_ERR_CLIENT_NOT_AUTHORIZED :Not Authorised
+STR_NETWORK_ERR_CLIENT_NOT_AUTHORIZED :not authorized
STR_NETWORK_ERR_CLIENT_NOT_EXPECTED :received strange packet
STR_NETWORK_ERR_CLIENT_WRONG_REVISION :wrong revision
STR_NETWORK_ERR_CLIENT_NAME_IN_USE :name already in use
-STR_NETWORK_ERR_CLIENT_WRONG_PASSWORD :wrong game-password
+STR_NETWORK_ERR_CLIENT_WRONG_PASSWORD :wrong password
STR_NETWORK_ERR_CLIENT_PLAYER_MISMATCH :wrong player-id in DoCommand
STR_NETWORK_ERR_CLIENT_KICKED :kicked by server
STR_NETWORK_ERR_CLIENT_CHEATER :was trying to use a cheat
+STR_NETWORK_ERR_CLIENT_SERVER_FULL :server full
############ End of leave-in-this-order
STR_NETWORK_CLIENT_JOINED :has joined the game
STR_NETWORK_GIVE_MONEY :gave your company some money ({CURRENCY})
diff --git a/network.c b/network.c
index 444bf4d5f..7aa24a603 100644
--- a/network.c
+++ b/network.c
@@ -554,8 +554,11 @@ void NetworkCloseClient(NetworkClientState *cs)
if (_network_server) {
// We just lost one client :(
- if (cs->status > STATUS_INACTIVE)
+ if (cs->status > STATUS_INACTIVE) {
_network_game_info.clients_on--;
+ if (DEREF_CLIENT_INFO(cs)->client_playas == OWNER_SPECTATOR)
+ _network_game_info.spectators_on--;
+ }
_network_clients_connected--;
while ((cs + 1) != DEREF_CLIENT(MAX_CLIENTS) && (cs + 1)->socket != INVALID_SOCKET) {
@@ -784,9 +787,8 @@ static void NetworkInitialize(void)
}
// Clean the client_info memory
- memset(_network_client_info, 0, sizeof(_network_client_info));
- memset(_network_player_info, 0, sizeof(_network_player_info));
- _network_lobby_company_count = 0;
+ memset(&_network_client_info, 0, sizeof(_network_client_info));
+ memset(&_network_player_info, 0, sizeof(_network_player_info));
_sync_frame = 0;
_network_first_time = true;
@@ -914,16 +916,21 @@ static void NetworkInitGameInfo(void)
if (_network_game_info.server_name[0] == '\0')
snprintf(_network_game_info.server_name, sizeof(_network_game_info.server_name), "Unnamed Server");
+ ttd_strlcpy(_network_game_info.server_revision, _openttd_revision, sizeof(_network_game_info.server_revision));
+
// The server is a client too ;)
if (_network_dedicated) {
_network_game_info.clients_on = 0;
+ _network_game_info.companies_on = 0;
_network_game_info.dedicated = true;
} else {
_network_game_info.clients_on = 1;
+ _network_game_info.companies_on = 1;
_network_game_info.dedicated = false;
}
- ttd_strlcpy(_network_game_info.server_revision, _openttd_revision, sizeof(_network_game_info.server_revision));
+
_network_game_info.spectators_on = 0;
+
_network_game_info.game_date = _date;
_network_game_info.start_date = ConvertIntDate(_patches.starting_date);
_network_game_info.map_width = MapSizeX();
@@ -1332,14 +1339,12 @@ void NetworkStartUp(void)
snprintf(_network_server_bind_ip_host, sizeof(_network_server_bind_ip_host), "%s", inet_ntoa(*(struct in_addr *)&_network_server_bind_ip));
/* Generate an unique id when there is none yet */
- if (_network_unique_id[0] == '\0')
- NetworkGenerateUniqueId();
+ if (_network_unique_id[0] == '\0') NetworkGenerateUniqueId();
memset(&_network_game_info, 0, sizeof(_network_game_info));
-
- /* XXX - Hard number here, because the strings can currently handle no more
- than 10 clients -- TrueLight */
- _network_game_info.clients_max = 10;
+ _network_game_info.clients_max = 10; // XXX - hardcoded, string limiation -- TrueLight
+ _network_game_info.companies_max = MAX_PLAYERS;
+ _network_game_info.spectators_max = _network_game_info.clients_max;
// Let's load the network in windows
#if defined(WIN32)
diff --git a/network.h b/network.h
index e7adfd4ba..6bcfec530 100644
--- a/network.h
+++ b/network.h
@@ -61,25 +61,28 @@ enum {
// some fields will be empty on the client (like game_password) by default
// and only filled with data a player enters.
typedef struct NetworkGameInfo {
- char server_name[NETWORK_NAME_LENGTH]; // Server name
- char hostname[NETWORK_HOSTNAME_LENGTH]; // Hostname of the server (if any)
- char server_revision[NETWORK_REVISION_LENGTH]; // The SVN version number the server is using (e.g.: 'r304')
- // It even shows a SVN version in release-version, so
- // it is easy to compare if a server is of the correct version
- byte server_lang; // Language of the server (we should make a nice table for this)
- byte use_password; // Is set to != 0 if it uses a password
- char server_password[NETWORK_PASSWORD_LENGTH]; // On the server: the game password, on the client: != "" if server has password
- byte clients_max; // Max clients allowed on server
- byte clients_on; // Current count of clients on server
- byte spectators_on; // How many spectators do we have?
- uint16 game_date; // Current date
- uint16 start_date; // When the game started
- char map_name[NETWORK_NAME_LENGTH]; // Map which is played ["random" for a randomized map]
- uint16 map_width; // Map width
- uint16 map_height; // Map height
- byte map_set; // Graphical set
- bool dedicated; // Is this a dedicated server?
- char rcon_password[NETWORK_PASSWORD_LENGTH]; // RCon password for the server. "" if rcon is disabled
+ char server_name[NETWORK_NAME_LENGTH]; // Server name
+ char hostname[NETWORK_HOSTNAME_LENGTH]; // Hostname of the server (if any)
+ char server_revision[NETWORK_REVISION_LENGTH]; // The SVN version number the server is using (e.g.: 'r304')
+ // It even shows a SVN version in release-version, so
+ // it is easy to compare if a server is of the correct version
+ byte server_lang; // Language of the server (we should make a nice table for this)
+ byte use_password; // Is set to != 0 if it uses a password
+ char server_password[NETWORK_PASSWORD_LENGTH]; // On the server: the game password, on the client: != "" if server has password
+ byte clients_max; // Max clients allowed on server
+ byte clients_on; // Current count of clients on server
+ byte companies_max; // Max companies allowed on server
+ byte companies_on; // How many started companies do we have
+ byte spectators_max; // Max spectators allowed on server
+ byte spectators_on; // How many spectators do we have?
+ uint16 game_date; // Current date
+ uint16 start_date; // When the game started
+ char map_name[NETWORK_NAME_LENGTH]; // Map which is played ["random" for a randomized map]
+ uint16 map_width; // Map width
+ uint16 map_height; // Map height
+ byte map_set; // Graphical set
+ bool dedicated; // Is this a dedicated server?
+ char rcon_password[NETWORK_PASSWORD_LENGTH]; // RCon password for the server. "" if rcon is disabled
} NetworkGameInfo;
typedef struct NetworkPlayerInfo {
diff --git a/network_client.c b/network_client.c
index 060e230ea..a7452fd87 100644
--- a/network_client.c
+++ b/network_client.c
@@ -395,20 +395,30 @@ DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_ERROR)
{
NetworkErrorCode error = NetworkRecv_uint8(MY_CLIENT, p);
- if (error == NETWORK_ERROR_NOT_AUTHORIZED || error == NETWORK_ERROR_NOT_EXPECTED ||
- error == NETWORK_ERROR_PLAYER_MISMATCH) {
- // We made an error in the protocol, and our connection is closed.... :(
- _switch_mode_errorstr = STR_NETWORK_ERR_SERVER_ERROR;
- } else if (error == NETWORK_ERROR_WRONG_REVISION) {
- // Wrong revision :(
- _switch_mode_errorstr = STR_NETWORK_ERR_WRONG_REVISION;
- } else if (error == NETWORK_ERROR_WRONG_PASSWORD) {
- // Wrong password
- _switch_mode_errorstr = STR_NETWORK_ERR_WRONG_PASSWORD;
- } else if (error == NETWORK_ERROR_KICKED) {
- _switch_mode_errorstr = STR_NETWORK_ERR_KICKED;
- } else if (error == NETWORK_ERROR_CHEATER) {
- _switch_mode_errorstr = STR_NETWORK_ERR_CHEATER;
+ switch (error) {
+ /* We made an error in the protocol, and our connection is closed.... */
+ case NETWORK_ERROR_NOT_AUTHORIZED:
+ case NETWORK_ERROR_NOT_EXPECTED:
+ case NETWORK_ERROR_PLAYER_MISMATCH:
+ _switch_mode_errorstr = STR_NETWORK_ERR_SERVER_ERROR;
+ break;
+ case NETWORK_ERROR_FULL:
+ _switch_mode_errorstr = STR_NETWORK_ERR_SERVER_FULL;
+ break;
+ case NETWORK_ERROR_WRONG_REVISION:
+ _switch_mode_errorstr = STR_NETWORK_ERR_WRONG_REVISION;
+ break;
+ case NETWORK_ERROR_WRONG_PASSWORD:
+ _switch_mode_errorstr = STR_NETWORK_ERR_WRONG_PASSWORD;
+ break;
+ case NETWORK_ERROR_KICKED:
+ _switch_mode_errorstr = STR_NETWORK_ERR_KICKED;
+ break;
+ case NETWORK_ERROR_CHEATER:
+ _switch_mode_errorstr = STR_NETWORK_ERR_CHEATER;
+ break;
+ default:
+ _switch_mode_errorstr = STR_NETWORK_ERR_LOSTCONNECTION;
}
DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
diff --git a/network_data.h b/network_data.h
index 553680fc2..b8f6a0eef 100644
--- a/network_data.h
+++ b/network_data.h
@@ -18,7 +18,7 @@
#define NETWORK_EMPTY_INDEX 0
// What version of game-info do we use?
-#define NETWORK_GAME_INFO_VERSION 1
+#define NETWORK_GAME_INFO_VERSION 2
// What version of company info is this?
#define NETWORK_COMPANY_INFO_VERSION 3
// What version of master-server-protocol do we use?
@@ -92,6 +92,7 @@ typedef enum {
NETWORK_ERROR_PLAYER_MISMATCH, // Happens in CLIENT_COMMAND
NETWORK_ERROR_KICKED,
NETWORK_ERROR_CHEATER,
+ NETWORK_ERROR_FULL,
} NetworkErrorCode;
// Actions that can be used for NetworkTextMessage
diff --git a/network_gui.c b/network_gui.c
index e63811fcd..8021c8ee1 100644
--- a/network_gui.c
+++ b/network_gui.c
@@ -45,6 +45,29 @@ static const StringID _lan_internet_types_dropdown[] = {
INVALID_STRING_ID
};
+static const StringID _players_dropdown[] = {
+ STR_NETWORK_0_CLIENTS,
+ STR_NETWORK_1_CLIENTS,
+ STR_NETWORK_2_CLIENTS,
+ STR_NETWORK_3_CLIENTS,
+ STR_NETWORK_4_CLIENTS,
+ STR_NETWORK_5_CLIENTS,
+ STR_NETWORK_6_CLIENTS,
+ STR_NETWORK_7_CLIENTS,
+ STR_NETWORK_8_CLIENTS,
+ STR_NETWORK_9_CLIENTS,
+ STR_NETWORK_10_CLIENTS,
+ INVALID_STRING_ID
+};
+
+static const StringID _language_dropdown[] = {
+ STR_NETWORK_LANG_ANY,
+ STR_NETWORK_LANG_ENGLISH,
+ STR_NETWORK_LANG_GERMAN,
+ STR_NETWORK_LANG_FRENCH,
+ INVALID_STRING_ID
+};
+
enum {
NET_PRC__OFFSET_TOP_WIDGET = 74,
NET_PRC__OFFSET_TOP_WIDGET_COMPANY = 42,
@@ -88,8 +111,11 @@ static void NetworkGameWindowWndProc(Window *w, WindowEvent *e)
SETBIT(w->disabled_state, 17); SETBIT(w->disabled_state, 18);
} else if (!sel->online) {
SETBIT(w->disabled_state, 17); // Server offline, join button disabled
- } else if (sel->info.clients_on == sel->info.clients_max) {
+ } else if (sel->info.clients_on >= sel->info.clients_max) {
SETBIT(w->disabled_state, 17); // Server full, join button disabled
+ } else if (sel->info.companies_on >= sel->info.companies_max &&
+ sel->info.spectators_on >= sel->info.spectators_max) {
+ SETBIT(w->disabled_state, 17);
// revisions don't match, check if server has no revision; then allow connection
} else if (strncmp(sel->info.server_revision, _openttd_revision, NETWORK_REVISION_LENGTH - 1) != 0) {
@@ -106,9 +132,6 @@ static void NetworkGameWindowWndProc(Window *w, WindowEvent *e)
DrawString(9, 23, STR_NETWORK_PLAYER_NAME, 2);
DrawString(9, 43, STR_NETWORK_CONNECTION, 2);
- DrawString(15, 63, STR_NETWORK_GAME_NAME, 2);
- DrawString(135, 63, STR_NETWORK_CLIENTS_CAPTION, 2);
-
{ // draw list of games
uint16 y = NET_PRC__OFFSET_TOP_WIDGET + 3;
int32 n = 0;
@@ -133,7 +156,9 @@ static void NetworkGameWindowWndProc(Window *w, WindowEvent *e)
SetDParam(0, cur_item->info.clients_on);
SetDParam(1, cur_item->info.clients_max);
- DrawString(135, y, STR_NETWORK_CLIENTS_ONLINE, 2);
+ SetDParam(2, cur_item->info.companies_on);
+ SetDParam(3, cur_item->info.companies_max);
+ DrawString(135, y, STR_NETWORK_GENERAL_ONLINE, 2);
// only draw icons if the server is online
if (cur_item->online) {
@@ -176,10 +201,12 @@ static void NetworkGameWindowWndProc(Window *w, WindowEvent *e)
SetDParam(0, sel->info.clients_on);
SetDParam(1, sel->info.clients_max);
- DrawString(260, y, STR_NETWORK_CLIENTS, 2); // clients on the server / maximum slots
+ SetDParam(2, sel->info.companies_on);
+ SetDParam(3, sel->info.companies_max);
+ DrawString(260, y, STR_NETWORK_CLIENTS, 2);
y += 10;
- SetDParam(0, STR_NETWORK_LANG_ANY + sel->info.server_lang);
+ SetDParam(0, _language_dropdown[sel->info.server_lang]);
DrawString(260, y, STR_NETWORK_LANGUAGE, 2); // server language
y += 10;
@@ -339,40 +366,40 @@ static void NetworkGameWindowWndProc(Window *w, WindowEvent *e)
}
static const Widget _network_game_window_widgets[] = {
-{ WWT_CLOSEBOX, RESIZE_NONE, BGC, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
-{ WWT_CAPTION, RESIZE_NONE, BGC, 11, 489, 0, 13, STR_NETWORK_MULTIPLAYER, STR_NULL},
-{ WWT_IMGBTN, RESIZE_NONE, BGC, 0, 489, 14, 214, 0x0, STR_NULL},
+{ WWT_CLOSEBOX, RESIZE_NONE, BGC, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
+{ WWT_CAPTION, RESIZE_NONE, BGC, 11, 549, 0, 13, STR_NETWORK_MULTIPLAYER, STR_NULL},
+{ WWT_IMGBTN, RESIZE_NONE, BGC, 0, 549, 14, 214, STR_NULL, STR_NULL},
/* LEFT SIDE */
-{ WWT_IMGBTN, RESIZE_NONE, BGC, 90, 231, 22, 33, 0x0, STR_NETWORK_ENTER_NAME_TIP},
+{ WWT_IMGBTN, RESIZE_NONE, BGC, 90, 291, 22, 33, STR_NULL, STR_NETWORK_ENTER_NAME_TIP},
-{ WWT_6, RESIZE_NONE, BGC, 90, 231, 42, 53, STR_NETWORK_COMBO1, STR_NETWORK_CONNECTION_TIP},
-{ WWT_TEXTBTN, RESIZE_NONE, BGC, 220, 230, 43, 52, STR_0225, STR_NETWORK_CONNECTION_TIP},
+{ WWT_6, RESIZE_NONE, BGC, 90, 231, 42, 53, STR_NETWORK_COMBO1, STR_NETWORK_CONNECTION_TIP},
+{ WWT_TEXTBTN, RESIZE_NONE, BGC, 220, 230, 43, 52, STR_0225, STR_NETWORK_CONNECTION_TIP},
-{ WWT_IMGBTN, RESIZE_NONE, BTC, 10, 130, 62, 73, 0x0, STR_NETWORK_GAME_NAME_TIP },
-{ WWT_IMGBTN, RESIZE_NONE, BTC, 131, 180, 62, 73, 0x0, STR_NETWORK_CLIENTS_CAPTION_TIP },
-{ WWT_IMGBTN, RESIZE_NONE, BTC, 181, 219, 62, 73, 0x0, STR_NETWORK_INFO_ICONS_TIP },
+{ WWT_TEXTBTN, RESIZE_NONE, BTC, 10, 130, 62, 73, STR_NETWORK_GAME_NAME, STR_NETWORK_GAME_NAME_TIP},
+{ WWT_TEXTBTN, RESIZE_NONE, BTC, 131, 180, 62, 73, STR_NETWORK_CLIENTS_CAPTION,STR_NETWORK_CLIENTS_CAPTION_TIP},
+{ WWT_PANEL, RESIZE_NONE, BTC, 181, 219, 62, 73, 0, STR_NETWORK_INFO_ICONS_TIP},
-{ WWT_MATRIX, RESIZE_NONE, BGC, 10, 219, 74, 185, 0x801, STR_NETWORK_CLICK_GAME_TO_SELECT},
-{ WWT_SCROLLBAR, RESIZE_NONE, BGC, 220, 231, 62, 185, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
+{ WWT_MATRIX, RESIZE_NONE, BGC, 10, 219, 74, 185, 0x801, STR_NETWORK_CLICK_GAME_TO_SELECT},
+{ WWT_SCROLLBAR, RESIZE_NONE, BGC, 220, 231, 62, 185, STR_NULL, STR_0190_SCROLL_BAR_SCROLLS_LIST},
-{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 10, 115, 195, 206, STR_NETWORK_FIND_SERVER, STR_NETWORK_FIND_SERVER_TIP},
-{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 125, 231, 195, 206, STR_NETWORK_ADD_SERVER, STR_NETWORK_ADD_SERVER_TIP},
-{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 250, 360, 195, 206, STR_NETWORK_START_SERVER, STR_NETWORK_START_SERVER_TIP},
-{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 370, 480, 195, 206, STR_012E_CANCEL, STR_NULL},
+{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 10, 115, 195, 206, STR_NETWORK_FIND_SERVER, STR_NETWORK_FIND_SERVER_TIP},
+{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 125, 231, 195, 206, STR_NETWORK_ADD_SERVER, STR_NETWORK_ADD_SERVER_TIP},
+{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 250, 360, 195, 206, STR_NETWORK_START_SERVER, STR_NETWORK_START_SERVER_TIP},
+{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 370, 480, 195, 206, STR_012E_CANCEL, STR_NULL},
/* RIGHT SIDE */
-{ WWT_IMGBTN, RESIZE_NONE, BGC, 250, 480, 22, 185, 0x0, STR_NULL},
-{ WWT_6, RESIZE_NONE, BGC, 251, 479, 23, 184, 0x0, STR_NULL},
+{ WWT_IMGBTN, RESIZE_NONE, BGC, 250, 480, 22, 185, STR_NULL, STR_NULL},
+{ WWT_6, RESIZE_NONE, BGC, 251, 479, 23, 184, STR_NULL, STR_NULL},
-{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 257, 360, 164, 175, STR_NETWORK_JOIN_GAME, STR_NULL},
-{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 370, 473, 164, 175, STR_NETWORK_REFRESH, STR_NETWORK_REFRESH_TIP},
+{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 257, 360, 164, 175, STR_NETWORK_JOIN_GAME, STR_NULL},
+{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 370, 473, 164, 175, STR_NETWORK_REFRESH, STR_NETWORK_REFRESH_TIP},
{ WIDGETS_END},
};
static const WindowDesc _network_game_window_desc = {
- WDP_CENTER, WDP_CENTER, 490, 215,
+ WDP_CENTER, WDP_CENTER, 550, 215,
WC_NETWORK_WINDOW,0,
WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_network_game_window_widgets,
@@ -408,27 +435,6 @@ void ShowNetworkGameWindow(void)
UpdateNetworkGameWindow(true);
}
-static const StringID _players_dropdown[] = {
- STR_NETWORK_2_CLIENTS,
- STR_NETWORK_3_CLIENTS,
- STR_NETWORK_4_CLIENTS,
- STR_NETWORK_5_CLIENTS,
- STR_NETWORK_6_CLIENTS,
- STR_NETWORK_7_CLIENTS,
- STR_NETWORK_8_CLIENTS,
- STR_NETWORK_9_CLIENTS,
- STR_NETWORK_10_CLIENTS,
- INVALID_STRING_ID
-};
-
-static const StringID _language_dropdown[] = {
- STR_NETWORK_LANG_ANY,
- STR_NETWORK_LANG_ENGLISH,
- STR_NETWORK_LANG_GERMAN,
- STR_NETWORK_LANG_FRENCH,
- INVALID_STRING_ID
-};
-
enum {
NSSWND_START = 64,
NSSWND_ROWSIZE = 12
@@ -446,21 +452,25 @@ static void NetworkStartServerWindowWndProc(Window *w, WindowEvent *e)
int y = NSSWND_START, pos;
const FiosItem *item;
- SetDParam(7, STR_NETWORK_LAN_INTERNET + _network_advertise);
- SetDParam(9, STR_NETWORK_2_CLIENTS + _network_game_info.clients_max - 2);
- SetDParam(11, STR_NETWORK_LANG_ANY + _network_game_info.server_lang);
+ SetDParam( 7, _connection_types_dropdown[_network_advertise]);
+ SetDParam( 9, _players_dropdown[_network_game_info.clients_max]);
+ SetDParam(11, _players_dropdown[_network_game_info.companies_max]);
+ SetDParam(13, _players_dropdown[_network_game_info.spectators_max]);
+ SetDParam(15, _language_dropdown[_network_game_info.server_lang]);
DrawWindowWidgets(w);
- GfxFillRect(11, 63, 259, 171, 0xD7);
-
+ GfxFillRect(11, 63, 258, 215, 0xD7);
DrawEditBox(w, 3);
DrawString(10, 22, STR_NETWORK_NEW_GAME_NAME, 2);
DrawString(10, 43, STR_NETWORK_SELECT_MAP, 2);
- DrawString(280, 63, STR_NETWORK_CONNECTION, 2);
- DrawString(280, 95, STR_NETWORK_NUMBER_OF_CLIENTS, 2);
- DrawString(280, 127, STR_NETWORK_LANGUAGE_SPOKEN, 2);
+
+ DrawString(280, 63, STR_NETWORK_CONNECTION, 2);
+ DrawString(280, 95, STR_NETWORK_NUMBER_OF_CLIENTS, 2);
+ DrawString(280, 127, STR_NETWORK_NUMBER_OF_COMPANIES, 2);
+ DrawString(280, 159, STR_NETWORK_NUMBER_OF_SPECTATORS, 2);
+ DrawString(280, 191, STR_NETWORK_LANGUAGE_SPOKEN, 2);
if (_network_game_info.use_password) DoDrawString("*", 408, 23, 3);
@@ -469,7 +479,7 @@ static void NetworkStartServerWindowWndProc(Window *w, WindowEvent *e)
while (pos < _fios_num + 1) {
item = _fios_list + pos - 1;
if (item == _selected_map || (pos == 0 && _selected_map == NULL))
- GfxFillRect(11, y - 1, 259, y + 10, 155); // show highlighted item with a different colour
+ GfxFillRect(11, y - 1, 258, y + 10, 155); // show highlighted item with a different colour
if (pos == 0) DrawString(14, y, STR_4010_GENERATE_RANDOM_NEW_GAME, 9);
else DoDrawString(item->title, 14, y, _fios_colors[item->type] );
@@ -484,7 +494,7 @@ static void NetworkStartServerWindowWndProc(Window *w, WindowEvent *e)
_selected_field = e->click.widget;
switch (e->click.widget) {
case 0: /* Close 'X' */
- case 15: /* Cancel button */
+ case 19: /* Cancel button */
ShowNetworkGameWindow();
break;
@@ -505,13 +515,19 @@ static void NetworkStartServerWindowWndProc(Window *w, WindowEvent *e)
case 7: case 8: /* Connection type */
ShowDropDownMenu(w, _connection_types_dropdown, _network_advertise, 8, 0, 0); // do it for widget 8
break;
- case 9: case 10: /* Number of Players */
- ShowDropDownMenu(w, _players_dropdown, _network_game_info.clients_max - 2, 10, 0, 0); // do it for widget 10
- return;
- case 11: case 12: /* Language */
- ShowDropDownMenu(w, _language_dropdown, _network_game_info.server_lang, 12, 0, 0); // do it for widget 12
- return;
- case 13: /* Start game */
+ case 9: case 10: /* Number of Players (hide 0 and 1 players) */
+ ShowDropDownMenu(w, _players_dropdown, _network_game_info.clients_max, 10, 0, 3);
+ break;
+ case 11: case 12: /* Number of Companies (hide 0, 9 and 10 companies; max is 8) */
+ ShowDropDownMenu(w, _players_dropdown, _network_game_info.companies_max, 12, 0, 1537);
+ break;
+ case 13: case 14: /* Number of Spectators */
+ ShowDropDownMenu(w, _players_dropdown, _network_game_info.spectators_max, 14, 0, 0);
+ break;
+ case 15: case 16: /* Language */
+ ShowDropDownMenu(w, _language_dropdown, _network_game_info.server_lang, 16, 0, 0);
+ break;
+ case 17: /* Start game */
_is_network_server = true;
ttd_strlcpy(_network_server_name, WP(w, querystr_d).text.buf, sizeof(_network_server_name));
UpdateTextBufferSize(&WP(w, querystr_d).text);
@@ -529,7 +545,7 @@ static void NetworkStartServerWindowWndProc(Window *w, WindowEvent *e)
}
}
break;
- case 14: /* Load game */
+ case 18: /* Load game */
_is_network_server = true;
ttd_strlcpy(_network_server_name, WP(w, querystr_d).text.buf, sizeof(_network_server_name));
UpdateTextBufferSize(&WP(w, querystr_d).text);
@@ -543,15 +559,11 @@ static void NetworkStartServerWindowWndProc(Window *w, WindowEvent *e)
case WE_DROPDOWN_SELECT: /* we have selected a dropdown item in the list */
switch(e->dropdown.button) {
- case 8:
- _network_advertise = (e->dropdown.index != 0);
- break;
- case 10:
- _network_game_info.clients_max = e->dropdown.index + 2;
- break;
- case 12:
- _network_game_info.server_lang = e->dropdown.index;
- break;
+ case 8: _network_advertise = (e->dropdown.index != 0); break;
+ case 10: _network_game_info.clients_max = e->dropdown.index; break;
+ case 12: _network_game_info.companies_max = e->dropdown.index; break;
+ case 14: _network_game_info.spectators_max = e->dropdown.index; break;
+ case 16: _network_game_info.server_lang = e->dropdown.index; break;
}
SetWindowDirty(w);
@@ -574,33 +586,35 @@ static void NetworkStartServerWindowWndProc(Window *w, WindowEvent *e)
}
static const Widget _network_start_server_window_widgets[] = {
-{ WWT_CLOSEBOX, RESIZE_NONE, BGC, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW },
-{ WWT_CAPTION, RESIZE_NONE, BGC, 11, 419, 0, 13, STR_NETWORK_START_GAME_WINDOW, STR_NULL},
-{ WWT_IMGBTN, RESIZE_NONE, BGC, 0, 419, 14, 199, 0x0, STR_NULL},
-
-{ WWT_IMGBTN, RESIZE_NONE, BGC, 100, 272, 22, 33, 0x0, STR_NETWORK_NEW_GAME_NAME_TIP},
-{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 285, 405, 22, 33, STR_NETWORK_SET_PASSWORD, STR_NETWORK_PASSWORD_TIP},
-
-{ WWT_6, RESIZE_NONE, BGC, 10, 271, 62, 172, 0x0, STR_NETWORK_SELECT_MAP_TIP},
-{ WWT_SCROLLBAR, RESIZE_NONE, BGC, 260, 271, 63, 171, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
-
-{ WWT_6, RESIZE_NONE, BGC, 280, 410, 77, 88, STR_NETWORK_COMBO1, STR_NETWORK_CONNECTION_TIP},
-{ WWT_TEXTBTN, RESIZE_NONE, BGC, 399, 409, 78, 87, STR_0225, STR_NETWORK_CONNECTION_TIP},
-
-{ WWT_6, RESIZE_NONE, BGC, 280, 410, 109, 120, STR_NETWORK_COMBO2, STR_NETWORK_NUMBER_OF_CLIENTS_TIP},
-{ WWT_TEXTBTN, RESIZE_NONE, BGC, 399, 409, 110, 119, STR_0225, STR_NETWORK_NUMBER_OF_CLIENTS_TIP},
-
-{ WWT_6, RESIZE_NONE, BGC, 280, 410, 141, 152, STR_NETWORK_COMBO3, STR_NETWORK_LANGUAGE_TIP},
-{ WWT_TEXTBTN, RESIZE_NONE, BGC, 399, 409, 142, 151, STR_0225, STR_NETWORK_LANGUAGE_TIP},
-
-{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 40, 140, 180, 191, STR_NETWORK_START_GAME, STR_NETWORK_START_GAME_TIP},
-{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 150, 250, 180, 191, STR_NETWORK_LOAD_GAME, STR_NETWORK_LOAD_GAME_TIP},
-{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 260, 360, 180, 191, STR_012E_CANCEL, STR_NULL},
+{ WWT_CLOSEBOX, RESIZE_NONE, BGC, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW },
+{ WWT_CAPTION, RESIZE_NONE, BGC, 11, 419, 0, 13, STR_NETWORK_START_GAME_WINDOW, STR_NULL},
+{ WWT_IMGBTN, RESIZE_NONE, BGC, 0, 419, 14, 243, 0x0, STR_NULL},
+
+{ WWT_IMGBTN, RESIZE_NONE, BGC, 100, 272, 22, 33, 0x0, STR_NETWORK_NEW_GAME_NAME_TIP},
+{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 285, 405, 22, 33, STR_NETWORK_SET_PASSWORD, STR_NETWORK_PASSWORD_TIP},
+
+{ WWT_6, RESIZE_NONE, BGC, 10, 271, 62, 216, 0x0, STR_NETWORK_SELECT_MAP_TIP},
+{ WWT_SCROLLBAR, RESIZE_NONE, BGC, 259, 270, 63, 215, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
+/* Combo boxes to control Connection Type / Max Clients / Max Companies / Max Observers / Language */
+{ WWT_6, RESIZE_NONE, BGC, 280, 410, 77, 88, STR_NETWORK_COMBO1, STR_NETWORK_CONNECTION_TIP},
+{ WWT_TEXTBTN, RESIZE_NONE, BGC, 399, 409, 78, 87, STR_0225, STR_NETWORK_CONNECTION_TIP},
+{ WWT_6, RESIZE_NONE, BGC, 280, 410, 109, 120, STR_NETWORK_COMBO2, STR_NETWORK_NUMBER_OF_CLIENTS_TIP},
+{ WWT_TEXTBTN, RESIZE_NONE, BGC, 399, 409, 110, 119, STR_0225, STR_NETWORK_NUMBER_OF_CLIENTS_TIP},
+{ WWT_6, RESIZE_NONE, BGC, 280, 410, 141, 152, STR_NETWORK_COMBO3, STR_NETWORK_NUMBER_OF_COMPANIES_TIP},
+{ WWT_TEXTBTN, RESIZE_NONE, BGC, 399, 409, 142, 151, STR_0225, STR_NETWORK_NUMBER_OF_COMPANIES_TIP},
+{ WWT_6, RESIZE_NONE, BGC, 280, 410, 173, 184, STR_NETWORK_COMBO4, STR_NETWORK_NUMBER_OF_SPECTATORS_TIP},
+{ WWT_TEXTBTN, RESIZE_NONE, BGC, 399, 409, 174, 183, STR_0225, STR_NETWORK_NUMBER_OF_SPECTATORS_TIP},
+{ WWT_6, RESIZE_NONE, BGC, 280, 410, 205, 216, STR_NETWORK_COMBO5, STR_NETWORK_LANGUAGE_TIP},
+{ WWT_TEXTBTN, RESIZE_NONE, BGC, 399, 409, 206, 215, STR_0225, STR_NETWORK_LANGUAGE_TIP},
+
+{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 40, 140, 224, 235, STR_NETWORK_START_GAME, STR_NETWORK_START_GAME_TIP},
+{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 150, 250, 224, 235, STR_NETWORK_LOAD_GAME, STR_NETWORK_LOAD_GAME_TIP},
+{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 260, 360, 224, 235, STR_012E_CANCEL, STR_NULL},
{ WIDGETS_END},
};
static const WindowDesc _network_start_server_window_desc = {
- WDP_CENTER, WDP_CENTER, 420, 200,
+ WDP_CENTER, WDP_CENTER, 420, 244,
WC_NETWORK_WINDOW,0,
WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_network_start_server_window_widgets,
@@ -645,17 +659,22 @@ static byte NetworkLobbyFindCompanyIndex(byte pos)
static void NetworkLobbyWindowWndProc(Window *w, WindowEvent *e)
{
switch (e->event) {
+ case WE_CREATE:
+ _selected_company_item = -1;
+ break;
+
case WE_PAINT: {
+ const NetworkGameInfo *gi = &_network_game_info;
int y = NET_PRC__OFFSET_TOP_WIDGET_COMPANY, pos;
w->disabled_state = (_selected_company_item == -1) ? 1 << 7 : 0;
+ assert(_network_lobby_company_count == gi->companies_on);
- if (_network_lobby_company_count == MAX_PLAYERS)
- SETBIT(w->disabled_state, 8);
+ if (gi->companies_on == gi->companies_max) SETBIT(w->disabled_state, 8);
+ if (gi->spectators_on == gi->spectators_max) SETBIT(w->disabled_state, 9);
/* You can not join a server as spectator when it has no companies active..
- it causes some nasty crashes */
- if (_network_lobby_company_count == 0)
- SETBIT(w->disabled_state, 9);
+ * it causes some nasty crashes */
+ if (gi->companies_on == 0) SETBIT(w->disabled_state, 9);
DrawWindowWidgets(w);
@@ -665,13 +684,13 @@ static void NetworkLobbyWindowWndProc(Window *w, WindowEvent *e)
// draw company list
GfxFillRect(11, 41, 154, 165, 0xD7);
pos = w->vscroll.pos;
- while (pos < _network_lobby_company_count) {
+ while (pos < gi->companies_on) {
byte index = NetworkLobbyFindCompanyIndex(pos);
bool income = false;
if (_selected_company_item == index)
GfxFillRect(11, y - 1, 154, y + 10, 155); // show highlighted item with a different colour
- DoDrawString(_network_player_info[index].company_name, 13, y, 2);
+ DoDrawStringTruncated(_network_player_info[index].company_name, 13, y, 2, 135 - 13);
if (_network_player_info[index].use_password != 0)
DrawSprite(SPR_LOCK, 135, y);
@@ -690,10 +709,11 @@ static void NetworkLobbyWindowWndProc(Window *w, WindowEvent *e)
if (_selected_company_item != -1) { // if a company is selected...
// show company info
const uint x = 183;
+ const uint trunc_width = w->widget[6].right - x;
y = 65;
SetDParamStr(0, _network_player_info[_selected_company_item].company_name);
- DrawString(x, y, STR_NETWORK_COMPANY_NAME, 2);
+ DrawStringTruncated(x, y, STR_NETWORK_COMPANY_NAME, 2, trunc_width);
y += 10;
SetDParam(0, _network_player_info[_selected_company_item].inaugurated_year + MAX_YEAR_BEGIN_REAL);
@@ -733,7 +753,7 @@ static void NetworkLobbyWindowWndProc(Window *w, WindowEvent *e)
y += 10;
SetDParamStr(0, _network_player_info[_selected_company_item].players);
- DrawString(x, y, STR_NETWORK_PLAYERS, 2); // players
+ DrawStringTruncated(x, y, STR_NETWORK_PLAYERS, 2, trunc_width); // players
y += 10;
}
} break;
@@ -753,7 +773,7 @@ static void NetworkLobbyWindowWndProc(Window *w, WindowEvent *e)
return;
}
_selected_company_item += w->vscroll.pos;
- if (_selected_company_item >= _network_lobby_company_count) {
+ if (_selected_company_item >= _network_game_info.companies_on) {
_selected_company_item = -1;
SetWindowDirty(w);
return;
@@ -781,9 +801,6 @@ static void NetworkLobbyWindowWndProc(Window *w, WindowEvent *e)
NetworkQueryServer(_network_last_host, _network_last_port, false);
break;
} break;
-
- case WE_CREATE:
- _selected_company_item = -1;
}
}
diff --git a/network_server.c b/network_server.c
index ad0b42f26..8dd6c36c7 100644
--- a/network_server.c
+++ b/network_server.c
@@ -156,13 +156,13 @@ DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_ERROR)(NetworkClientState *cs, Netwo
NetworkSend_uint8(p, error);
NetworkSend_Packet(p, cs);
+ GetString(str, STR_NETWORK_ERR_CLIENT_GENERAL + error);
+
// Only send when the current client was in game
if (cs->status > STATUS_AUTH) {
NetworkGetClientName(client_name, sizeof(client_name), cs);
- GetString(str, STR_NETWORK_ERR_CLIENT_GENERAL + error);
-
- DEBUG(net, 2)("[NET] %s made an error (%s) and his connection is closed", client_name, str);
+ DEBUG(net, 2) ("[NET] '%s' made an error and has been disconnected. Reason: %s", client_name, str);
NetworkTextMessage(NETWORK_ACTION_LEAVE, 1, false, client_name, "%s", str);
@@ -177,7 +177,7 @@ DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_ERROR)(NetworkClientState *cs, Netwo
}
}
} else {
- DEBUG(net, 2)("[NET] Clientno %d has made an error and his connection is closed", cs->index);
+ DEBUG(net, 2) ("[NET] Client %d made an error and has been disconnected. Reason: %s", cs->index, str);
}
cs->quited = true;
@@ -213,14 +213,16 @@ DEF_SERVER_SEND_COMMAND(PACKET_SERVER_WELCOME)
//
Packet *p;
- NetworkClientState *new_cs;
+ const NetworkClientState *new_cs;
+ const NetworkClientInfo *ci = DEREF_CLIENT_INFO(cs);
// Invalid packet when status is AUTH or higher
- if (cs->status >= STATUS_AUTH)
- return;
+ if (cs->status >= STATUS_AUTH) return;
cs->status = STATUS_AUTH;
_network_game_info.clients_on++;
+ /* increment spectator; defer company addition for when player is actually created */
+ if (ci->client_playas == OWNER_SPECTATOR) _network_game_info.spectators_on++;
p = NetworkSend_Init(PACKET_SERVER_WELCOME);
NetworkSend_uint16(p, cs->index);
@@ -585,12 +587,10 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_JOIN)
char name[NETWORK_NAME_LENGTH];
char unique_id[NETWORK_NAME_LENGTH];
NetworkClientInfo *ci;
- char test_name[NETWORK_NAME_LENGTH];
byte playas;
NetworkLanguage client_lang;
char client_revision[NETWORK_REVISION_LENGTH];
-
NetworkRecv_string(cs, p, client_revision, sizeof(client_revision));
#if defined(WITH_REV) || defined(WITH_REV_HACK)
@@ -610,18 +610,28 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_JOIN)
client_lang = NetworkRecv_uint8(cs, p);
NetworkRecv_string(cs, p, unique_id, sizeof(unique_id));
- if (cs->quited)
- return;
-
- // Check if someone else already has that name
- snprintf(test_name, sizeof(test_name), "%s", name);
+ if (cs->quited) return;
- if (test_name[0] == '\0') {
- // We need a valid name.. make it Player
- snprintf(test_name, sizeof(test_name), "Player");
+ // join another company does not affect these values
+ switch (playas) {
+ case 0: /* New company */
+ if (_network_game_info.companies_max >= _network_game_info.companies_on) {
+ SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_FULL);
+ return;
+ }
+ break;
+ case OWNER_SPECTATOR: /* Spectator */
+ if (_network_game_info.spectators_on >= _network_game_info.spectators_max) {
+ SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_FULL);
+ return;
+ }
+ break;
}
- if (!NetworkFindName(test_name)) {
+ // We need a valid name.. make it Player
+ if (name[0] == '\0') snprintf(name, sizeof(name), "Player");
+
+ if (!NetworkFindName(name)) { // Change name if duplicate
// We could not create a name for this player
SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NAME_IN_USE);
return;
@@ -629,7 +639,7 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_JOIN)
ci = DEREF_CLIENT_INFO(cs);
- snprintf(ci->client_name, sizeof(ci->client_name), "%s", test_name);
+ snprintf(ci->client_name, sizeof(ci->client_name), "%s", name);
snprintf(ci->unique_id, sizeof(ci->unique_id), "%s", unique_id);
ci->client_playas = playas;
ci->client_lang = client_lang;
diff --git a/network_udp.c b/network_udp.c
index b4087c1e6..3248b98a1 100644
--- a/network_udp.c
+++ b/network_udp.c
@@ -61,6 +61,13 @@ DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_CLIENT_FIND_SERVER)
_network_game_info.map_set = _opt.landscape;
NetworkSend_uint8 (packet, NETWORK_GAME_INFO_VERSION);
+
+ /* NETWORK_GAME_INFO_VERSION = 2 */
+ NetworkSend_uint8 (packet, _network_game_info.companies_max);
+ NetworkSend_uint8 (packet, _network_game_info.companies_on);
+ NetworkSend_uint8 (packet, _network_game_info.spectators_max);
+
+ /* NETWORK_GAME_INFO_VERSION = 1 */
NetworkSend_string(packet, _network_game_info.server_name);
NetworkSend_string(packet, _network_game_info.server_revision);
NetworkSend_uint8 (packet, _network_game_info.server_lang);
@@ -103,30 +110,39 @@ DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_SERVER_RESPONSE)
// Find next item
item = NetworkGameListAddItem(inet_addr(inet_ntoa(client_addr->sin_addr)), ntohs(client_addr->sin_port));
- if (game_info_version == 1) {
- NetworkRecv_string(&_udp_cs, p, item->info.server_name, sizeof(item->info.server_name));
- NetworkRecv_string(&_udp_cs, p, item->info.server_revision, sizeof(item->info.server_revision));
- item->info.server_lang = NetworkRecv_uint8(&_udp_cs, p);
- item->info.use_password = NetworkRecv_uint8(&_udp_cs, p);
- item->info.clients_max = NetworkRecv_uint8(&_udp_cs, p);
- item->info.clients_on = NetworkRecv_uint8(&_udp_cs, p);
- item->info.spectators_on = NetworkRecv_uint8(&_udp_cs, p);
- item->info.game_date = NetworkRecv_uint16(&_udp_cs, p);
- item->info.start_date = NetworkRecv_uint16(&_udp_cs, p);
- NetworkRecv_string(&_udp_cs, p, item->info.map_name, sizeof(item->info.map_name));
- item->info.map_width = NetworkRecv_uint16(&_udp_cs, p);
- item->info.map_height = NetworkRecv_uint16(&_udp_cs, p);
- item->info.map_set = NetworkRecv_uint8(&_udp_cs, p);
- item->info.dedicated = NetworkRecv_uint8(&_udp_cs, p);
-
- str_validate(item->info.server_name);
- str_validate(item->info.server_revision);
- str_validate(item->info.map_name);
- if (item->info.server_lang >= NETWORK_NUM_LANGUAGES) item->info.server_lang = 0;
- if (item->info.map_set >= NUM_LANDSCAPE ) item->info.map_set = 0;
-
- if (item->info.hostname[0] == '\0')
- snprintf(item->info.hostname, sizeof(item->info.hostname), "%s", inet_ntoa(client_addr->sin_addr));
+ /* Please observe the order. In the order in which packets are sent
+ * they are to be received */
+ switch (game_info_version) {
+ case 2:
+ item->info.companies_max = NetworkRecv_uint8(&_udp_cs, p);
+ item->info.companies_on = NetworkRecv_uint8(&_udp_cs, p);
+ item->info.spectators_max = NetworkRecv_uint8(&_udp_cs, p);
+ /* Fallthrough */
+ case 1:
+ NetworkRecv_string(&_udp_cs, p, item->info.server_name, sizeof(item->info.server_name));
+ NetworkRecv_string(&_udp_cs, p, item->info.server_revision, sizeof(item->info.server_revision));
+ item->info.server_lang = NetworkRecv_uint8(&_udp_cs, p);
+ item->info.use_password = NetworkRecv_uint8(&_udp_cs, p);
+ item->info.clients_max = NetworkRecv_uint8(&_udp_cs, p);
+ item->info.clients_on = NetworkRecv_uint8(&_udp_cs, p);
+ item->info.spectators_on = NetworkRecv_uint8(&_udp_cs, p);
+ item->info.game_date = NetworkRecv_uint16(&_udp_cs, p);
+ item->info.start_date = NetworkRecv_uint16(&_udp_cs, p);
+ NetworkRecv_string(&_udp_cs, p, item->info.map_name, sizeof(item->info.map_name));
+ item->info.map_width = NetworkRecv_uint16(&_udp_cs, p);
+ item->info.map_height = NetworkRecv_uint16(&_udp_cs, p);
+ item->info.map_set = NetworkRecv_uint8(&_udp_cs, p);
+ item->info.dedicated = NetworkRecv_uint8(&_udp_cs, p);
+
+ str_validate(item->info.server_name);
+ str_validate(item->info.server_revision);
+ str_validate(item->info.map_name);
+ if (item->info.server_lang >= NETWORK_NUM_LANGUAGES) item->info.server_lang = 0;
+ if (item->info.map_set >= NUM_LANDSCAPE ) item->info.map_set = 0;
+
+ if (item->info.hostname[0] == '\0')
+ snprintf(item->info.hostname, sizeof(item->info.hostname), "%s", inet_ntoa(client_addr->sin_addr));
+ break;
}
item->online = true;
diff --git a/players.c b/players.c
index 2ea429994..34d458555 100644
--- a/players.c
+++ b/players.c
@@ -856,13 +856,15 @@ int32 CmdPlayerCtrl(int x, int y, uint32 flags, uint32 p1, uint32 p2)
_local_player = ci->client_playas - 1;
NetworkSend_Command(0, 0, 0, CMD_CHANGE_PRESIDENT_NAME, NULL);
_local_player = player_backup;
+ _network_game_info.companies_on++;
}
}
- } else if (_network_server) {
+ } else if (_network_server) { // Creating player failed, defer client to spectator
/* XXX - UGLY! p2 (pid) is mis-used to fetch the client-id, done at server-side
* in network_server.c:838, function DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMMAND) */
NetworkClientInfo *ci = &_network_client_info[pid];
ci->client_playas = OWNER_SPECTATOR;
+ _network_game_info.spectators_on++;
NetworkUpdateClientInfo(ci->client_index);
}
#else
@@ -901,6 +903,9 @@ int32 CmdPlayerCtrl(int x, int y, uint32 flags, uint32 p1, uint32 p2)
p->is_active = false;
}
RemoveAllEngineReplacementForPlayer(p);
+#ifdef ENABLE_NETWORK
+ _network_game_info.companies_on--;
+#endif /* ENABLE_NETWORK */
} break;