Feature: rework in-game Online Players GUI

The GUI now more clearly shows some basic information about the
server you joined, your client name (and the ability to change it),
and what players are in which company.

It also contains useful buttons to press to join companies, chat
with other people, and for admins to kick/ban people.

Additionally, renamed "advertised" to "visibility"; this has to
do with future additions, but also because it is more clear in
wording.
This commit is contained in:
Patric Stout 2021-04-18 09:54:47 +02:00 committed by Patric Stout
parent aca20092aa
commit 5266359424
12 changed files with 573 additions and 175 deletions

Binary file not shown.

View File

@ -4,7 +4,7 @@
// See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
//
-1 * 0 0C "OpenTTD GUI graphics"
-1 * 3 05 15 \b 186 // OPENTTD_SPRITE_COUNT
-1 * 3 05 15 \b 189 // OPENTTD_SPRITE_COUNT
-1 sprites/openttdgui.png 8bpp 66 8 64 31 -31 7 normal
-1 sprites/openttdgui.png 8bpp 146 8 64 31 -31 7 normal
-1 sprites/openttdgui.png 8bpp 226 8 64 31 -31 7 normal
@ -191,3 +191,6 @@
-1 sprites/openttdgui_convert_tram.png 8bpp 24 0 32 32 0 0 normal
-1 sprites/openttdgui.png 8bpp 513 440 10 10 0 0 normal
-1 sprites/openttdgui.png 8bpp 526 440 10 10 0 0 normal
-1 sprites/openttdgui.png 8bpp 539 440 12 10 0 0 normal
-1 sprites/openttdgui.png 8bpp 553 440 12 10 0 0 normal
-1 sprites/openttdgui.png 8bpp 567 440 12 10 0 0 normal

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 43 KiB

View File

@ -571,8 +571,8 @@ Company *DoStartupNewCompany(bool is_ai, CompanyID company = INVALID_COMPANY)
GeneratePresidentName(c);
SetWindowDirty(WC_GRAPH_LEGEND, 0);
SetWindowClassesDirty(WC_CLIENT_LIST_POPUP);
SetWindowDirty(WC_CLIENT_LIST, 0);
InvalidateWindowClassesData(WC_CLIENT_LIST_POPUP);
InvalidateWindowData(WC_CLIENT_LIST, 0);
InvalidateWindowData(WC_LINKGRAPH_LEGEND, 0);
BuildOwnerLegend();
InvalidateWindowData(WC_SMALLMAP, 0, 1);

View File

@ -1991,6 +1991,9 @@ STR_FACE_TIE :Tie:
STR_FACE_EARRING :Earring:
STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Change tie or earring
STR_NETWORK_SERVER_VISIBILITY_PRIVATE :Private
STR_NETWORK_SERVER_VISIBILITY_PUBLIC :Public
# Network server list
STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Multiplayer
STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Player name:
@ -2053,10 +2056,8 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}The game
STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Set password
STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Protect your game with a password if you don't want it to be publicly accessible
STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Advertised
STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Choose between an advertised (internet) and a not advertised (Local Area Network, LAN) game
STR_NETWORK_START_SERVER_UNADVERTISED :No
STR_NETWORK_START_SERVER_ADVERTISED :Yes
STR_NETWORK_START_SERVER_VISIBILITY_LABEL :{BLACK}Visibility
STR_NETWORK_START_SERVER_VISIBILITY_TOOLTIP :{BLACK}Whether other people can see your server in the public listing
STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} client{P "" s}
STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Maximum number of clients:
STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Choose the maximum number of clients. Not all slots need to be filled
@ -2118,19 +2119,37 @@ STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Disconne
STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Server is protected. Enter password
STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Company is protected. Enter password
STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION :{WHITE}Client list
# Network company list added strings
STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Client list
STR_NETWORK_COMPANY_LIST_SPECTATE :Spectate
STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Online players
STR_NETWORK_COMPANY_LIST_NEW_COMPANY :New company
# Network client list
# Network client list popup for clients
STR_NETWORK_CLIENTLIST_KICK :Kick
STR_NETWORK_CLIENTLIST_BAN :Ban
STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Speak to all
STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Speak to company
STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Private message
# Network client list
STR_NETWORK_CLIENT_LIST_CAPTION :{WHITE}Multiplayer
STR_NETWORK_CLIENT_LIST_SERVER :{BLACK}Server
STR_NETWORK_CLIENT_LIST_SERVER_NAME :{BLACK}Name
STR_NETWORK_CLIENT_LIST_SERVER_NAME_TOOLTIP :{BLACK}Name of the server you are playing on
STR_NETWORK_CLIENT_LIST_SERVER_NAME_EDIT_TOOLTIP :{BLACK}Edit the name of your server
STR_NETWORK_CLIENT_LIST_SERVER_NAME_QUERY_CAPTION :Name of the server
STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY :{BLACK}Visibility
STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY_TOOLTIP :{BLACK}Whether other people can see your server in the public listing
STR_NETWORK_CLIENT_LIST_PLAYER :{BLACK}Player
STR_NETWORK_CLIENT_LIST_PLAYER_NAME :{BLACK}Name
STR_NETWORK_CLIENT_LIST_PLAYER_NAME_TOOLTIP :{BLACK}Your player name
STR_NETWORK_CLIENT_LIST_PLAYER_NAME_EDIT_TOOLTIP :{BLACK}Edit your player name
STR_NETWORK_CLIENT_LIST_PLAYER_NAME_QUERY_CAPTION :Your player name
STR_NETWORK_CLIENT_LIST_PLAYER_HOST :{WHITE}(host) {BLACK}{RAW_STRING}
STR_NETWORK_CLIENT_LIST_PLAYER_SELF :{WHITE}(you) {BLACK}{RAW_STRING}
STR_NETWORK_CLIENT_LIST_ADMIN_TOOLTIP :{BLACK}Administrative actions to perform for this client
STR_NETWORK_CLIENT_LIST_JOIN_TOOLTIP :{BLACK}Join this company
STR_NETWORK_CLIENT_LIST_CHAT_CLIENT_TOOLTIP :{BLACK}Send a message to this player
STR_NETWORK_CLIENT_LIST_CHAT_COMPANY_TOOLTIP :{BLACK}Send a message to all players of this company
STR_NETWORK_CLIENT_LIST_CHAT_SPECTATOR_TOOLTIP :{BLACK}Send a message to all spectators
STR_NETWORK_CLIENT_LIST_SPECTATORS :Spectators
STR_NETWORK_SERVER :Server
STR_NETWORK_CLIENT :Client

View File

@ -522,9 +522,10 @@ void ParseGameConnectionString(const char **company, const char **port, char *co
/* Register the login */
_network_clients_connected++;
SetWindowDirty(WC_CLIENT_LIST, 0);
ServerNetworkGameSocketHandler *cs = new ServerNetworkGameSocketHandler(s);
cs->client_address = address; // Save the IP of the client
InvalidateWindowData(WC_CLIENT_LIST, 0);
}
/**
@ -713,7 +714,7 @@ void NetworkClientConnectGame(NetworkAddress address, CompanyID join_as, const c
static void NetworkInitGameInfo()
{
if (StrEmpty(_settings_client.network.server_name)) {
seprintf(_settings_client.network.server_name, lastof(_settings_client.network.server_name), "Unnamed Server");
strecpy(_settings_client.network.server_name, "Unnamed Server", lastof(_settings_client.network.server_name));
}
/* The server is a client too */

View File

@ -647,7 +647,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CLIENT_INFO(Pac
ci->client_playas = playas;
strecpy(ci->client_name, name, lastof(ci->client_name));
SetWindowDirty(WC_CLIENT_LIST, 0);
InvalidateWindowData(WC_CLIENT_LIST, 0);
return NETWORK_RECV_STATUS_OKAY;
}
@ -666,7 +666,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CLIENT_INFO(Pac
strecpy(ci->client_name, name, lastof(ci->client_name));
SetWindowDirty(WC_CLIENT_LIST, 0);
InvalidateWindowData(WC_CLIENT_LIST, 0);
return NETWORK_RECV_STATUS_OKAY;
}
@ -1043,7 +1043,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_ERROR_QUIT(Pack
delete ci;
}
SetWindowDirty(WC_CLIENT_LIST, 0);
InvalidateWindowData(WC_CLIENT_LIST, 0);
return NETWORK_RECV_STATUS_OKAY;
}
@ -1062,7 +1062,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_QUIT(Packet *p)
DEBUG(net, 0, "Unknown client (%d) is leaving the game", client_id);
}
SetWindowDirty(WC_CLIENT_LIST, 0);
InvalidateWindowData(WC_CLIENT_LIST, 0);
/* If we come here it means we could not locate the client.. strange :s */
return NETWORK_RECV_STATUS_OKAY;
@ -1079,7 +1079,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_JOIN(Packet *p)
NetworkTextMessage(NETWORK_ACTION_JOIN, CC_DEFAULT, false, ci->client_name);
}
SetWindowDirty(WC_CLIENT_LIST, 0);
InvalidateWindowData(WC_CLIENT_LIST, 0);
return NETWORK_RECV_STATUS_OKAY;
}

View File

@ -21,6 +21,7 @@
#include "network_udp.h"
#include "../window_func.h"
#include "../gfx_func.h"
#include "../widgets/dropdown_type.h"
#include "../widgets/dropdown_func.h"
#include "../querystring_gui.h"
#include "../sortlist_type.h"
@ -30,6 +31,8 @@
#include "../map_type.h"
#include "../guitimer_func.h"
#include "../zoom_func.h"
#include "../sprite.h"
#include "../settings_internal.h"
#include "../widgets/network_widget.h"
@ -38,21 +41,24 @@
#include "../stringfilter_type.h"
#include "../safeguards.h"
#ifdef __EMSCRIPTEN__
# include <emscripten.h>
#endif
#include <map>
#include "../safeguards.h"
static void ShowNetworkStartServerWindow();
static void ShowNetworkLobbyWindow(NetworkGameList *ngl);
/**
* Advertisement options in the start server window
* Visibility of the server. Public servers advertise, where private servers
* do not.
*/
static const StringID _connection_types_dropdown[] = {
STR_NETWORK_START_SERVER_UNADVERTISED,
STR_NETWORK_START_SERVER_ADVERTISED,
static const StringID _server_visibility_dropdown[] = {
STR_NETWORK_SERVER_VISIBILITY_PRIVATE,
STR_NETWORK_SERVER_VISIBILITY_PUBLIC,
INVALID_STRING_ID
};
@ -985,7 +991,7 @@ struct NetworkStartServerWindow : public Window {
{
switch (widget) {
case WID_NSS_CONNTYPE_BTN:
SetDParam(0, _connection_types_dropdown[_settings_client.network.server_advertise]);
SetDParam(0, _server_visibility_dropdown[_settings_client.network.server_advertise]);
break;
case WID_NSS_CLIENTS_TXT:
@ -1006,7 +1012,7 @@ struct NetworkStartServerWindow : public Window {
{
switch (widget) {
case WID_NSS_CONNTYPE_BTN:
*size = maxdim(GetStringBoundingBox(_connection_types_dropdown[0]), GetStringBoundingBox(_connection_types_dropdown[1]));
*size = maxdim(GetStringBoundingBox(_server_visibility_dropdown[0]), GetStringBoundingBox(_server_visibility_dropdown[1]));
size->width += padding.width;
size->height += padding.height;
break;
@ -1036,7 +1042,7 @@ struct NetworkStartServerWindow : public Window {
break;
case WID_NSS_CONNTYPE_BTN: // Connection type
ShowDropDownMenu(this, _connection_types_dropdown, _settings_client.network.server_advertise, WID_NSS_CONNTYPE_BTN, 0, 0); // do it for widget WID_NSS_CONNTYPE_BTN
ShowDropDownMenu(this, _server_visibility_dropdown, _settings_client.network.server_advertise, WID_NSS_CONNTYPE_BTN, 0, 0); // do it for widget WID_NSS_CONNTYPE_BTN
break;
case WID_NSS_CLIENTS_BTND: case WID_NSS_CLIENTS_BTNU: // Click on up/down button for number of clients
@ -1175,8 +1181,8 @@ static const NWidgetPart _nested_network_start_server_window_widgets[] = {
NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(10, 6, 10),
NWidget(NWID_VERTICAL), SetPIP(0, 1, 0),
NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NSS_CONNTYPE_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_ADVERTISED_LABEL, STR_NULL),
NWidget(WWT_DROPDOWN, COLOUR_LIGHT_BLUE, WID_NSS_CONNTYPE_BTN), SetFill(1, 0), SetDataTip(STR_BLACK_STRING, STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP),
NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NSS_CONNTYPE_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_VISIBILITY_LABEL, STR_NULL),
NWidget(WWT_DROPDOWN, COLOUR_LIGHT_BLUE, WID_NSS_CONNTYPE_BTN), SetFill(1, 0), SetDataTip(STR_BLACK_STRING, STR_NETWORK_START_SERVER_VISIBILITY_TOOLTIP),
EndContainer(),
NWidget(NWID_VERTICAL), SetPIP(0, 1, 0),
NWidget(NWID_SPACER), SetFill(1, 1),
@ -1592,21 +1598,6 @@ static void ClientList_Ban(const NetworkClientInfo *ci)
NetworkServerKickOrBanIP(ci->client_id, true, nullptr);
}
static void ClientList_SpeakToClient(const NetworkClientInfo *ci)
{
ShowNetworkChatQueryWindow(DESTTYPE_CLIENT, ci->client_id);
}
static void ClientList_SpeakToCompany(const NetworkClientInfo *ci)
{
ShowNetworkChatQueryWindow(DESTTYPE_TEAM, ci->client_playas);
}
static void ClientList_SpeakToAll(const NetworkClientInfo *ci)
{
ShowNetworkChatQueryWindow(DESTTYPE_BROADCAST, 0);
}
/** Popup selection window to chose an action to perform */
struct NetworkClientListPopupWindow : Window {
/** Container for actions that can be executed. */
@ -1639,15 +1630,6 @@ struct NetworkClientListPopupWindow : Window {
const NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id);
if (_network_own_client_id != ci->client_id) {
this->AddAction(STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT, &ClientList_SpeakToClient);
}
if (Company::IsValidID(ci->client_playas) || ci->client_playas == COMPANY_SPECTATOR) {
this->AddAction(STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY, &ClientList_SpeakToCompany);
}
this->AddAction(STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL, &ClientList_SpeakToAll);
/* A server can kick clients (but not himself). */
if (_network_server && _network_own_client_id != ci->client_id) {
this->AddAction(STR_NETWORK_CLIENTLIST_KICK, &ClientList_Kick);
@ -1671,7 +1653,7 @@ struct NetworkClientListPopupWindow : Window {
}
d.height *= (uint)this->actions.size();
d.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
d.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT + 4 + 4; // Give the list a bit of padding on both sides.
d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
*size = d;
}
@ -1690,7 +1672,7 @@ struct NetworkClientListPopupWindow : Window {
colour = TC_BLACK;
}
DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, action.name, colour);
DrawString(r.left + WD_FRAMERECT_LEFT + 4, r.right - WD_FRAMERECT_RIGHT - 4, y, action.name, colour);
y += FONT_HEIGHT_NORMAL;
}
}
@ -1731,167 +1713,554 @@ static void PopupClientList(ClientID client_id, int x, int y)
static const NWidgetPart _nested_client_list_widgets[] = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_NETWORK_CLIENT_LIST_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
NWidget(WWT_STICKYBOX, COLOUR_GREY),
EndContainer(),
NWidget(WWT_PANEL, COLOUR_GREY, WID_CL_PANEL), SetMinimalSize(250, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM), SetResize(1, 1), EndContainer(),
NWidget(WWT_PANEL, COLOUR_GREY),
NWidget(NWID_SELECTION, INVALID_COLOUR, WID_CL_SERVER_SELECTOR),
NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_NETWORK_CLIENT_LIST_SERVER, STR_NULL), SetPadding(4, 4, 0, 4), SetPIP(0, 2, 0),
NWidget(NWID_HORIZONTAL), SetPIP(0, 3, 0),
NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalTextLines(1, 0), SetDataTip(STR_NETWORK_CLIENT_LIST_SERVER_NAME, STR_NULL),
NWidget(NWID_SPACER), SetMinimalSize(20, 0),
NWidget(WWT_TEXT, COLOUR_GREY, WID_CL_SERVER_NAME), SetFill(1, 0), SetMinimalTextLines(1, 0), SetResize(1, 0), SetDataTip(STR_BLACK_RAW_STRING, STR_NETWORK_CLIENT_LIST_SERVER_NAME_TOOLTIP), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_CL_SERVER_NAME_EDIT), SetMinimalSize(12, 14), SetDataTip(SPR_RENAME, STR_NETWORK_CLIENT_LIST_SERVER_NAME_EDIT_TOOLTIP),
EndContainer(),
NWidget(NWID_HORIZONTAL), SetPIP(0, 3, 0),
NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalTextLines(1, 0), SetDataTip(STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY, STR_NULL),
NWidget(NWID_SPACER), SetMinimalSize(20, 0), SetFill(1, 0), SetResize(1, 0),
NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_CL_SERVER_VISIBILITY), SetDataTip(STR_BLACK_STRING, STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY_TOOLTIP),
EndContainer(),
EndContainer(),
EndContainer(),
NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_NETWORK_CLIENT_LIST_PLAYER, STR_NULL), SetPadding(4, 4, 4, 4), SetPIP(0, 2, 0),
NWidget(NWID_HORIZONTAL), SetPIP(0, 3, 0),
NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalTextLines(1, 0), SetDataTip(STR_NETWORK_CLIENT_LIST_PLAYER_NAME, STR_NULL),
NWidget(NWID_SPACER), SetMinimalSize(20, 0),
NWidget(WWT_TEXT, COLOUR_GREY, WID_CL_CLIENT_NAME), SetFill(1, 0), SetMinimalTextLines(1, 0), SetResize(1, 0), SetDataTip(STR_BLACK_RAW_STRING, STR_NETWORK_CLIENT_LIST_PLAYER_NAME_TOOLTIP), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_CL_CLIENT_NAME_EDIT), SetMinimalSize(12, 14), SetDataTip(SPR_RENAME, STR_NETWORK_CLIENT_LIST_PLAYER_NAME_EDIT_TOOLTIP),
EndContainer(),
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_MATRIX, COLOUR_GREY, WID_CL_MATRIX), SetMinimalSize(180, 0), SetResize(1, 1), SetFill(1, 1), SetMatrixDataTip(1, 0, STR_NULL), SetScrollbar(WID_CL_SCROLLBAR),
NWidget(NWID_VERTICAL),
NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_CL_SCROLLBAR),
NWidget(WWT_RESIZEBOX, COLOUR_GREY),
EndContainer(),
EndContainer(),
EndContainer(),
};
static WindowDesc _client_list_desc(
WDP_AUTO, "list_clients", 0, 0,
WDP_AUTO, "list_clients", 220, 300,
WC_CLIENT_LIST, WC_NONE,
0,
_nested_client_list_widgets, lengthof(_nested_client_list_widgets)
);
/**
* Button shown for either a company or client in the client-list.
*
* These buttons are dynamic and strongly depends on which company/client
* what buttons are available. This class allows dynamically creating them
* as the current Widget system does not.
*/
class ButtonCommon {
public:
SpriteID sprite; ///< The sprite to use on the button.
StringID tooltip; ///< The tooltip of the button.
Colours colour; ///< The colour of the button.
bool disabled; ///< Is the button disabled?
uint height; ///< Calculated height of the button.
uint width; ///< Calculated width of the button.
ButtonCommon(SpriteID sprite, StringID tooltip, Colours colour) :
sprite(sprite),
tooltip(tooltip),
colour(colour),
disabled(false)
{
Dimension d = GetSpriteSize(sprite);
this->height = d.height + ScaleGUITrad(WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM);
this->width = d.width + ScaleGUITrad(WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT);
}
virtual ~ButtonCommon() {}
/**
* OnClick handler for when the button is pressed.
*/
virtual void OnClick(struct NetworkClientListWindow *w, Point pt) = 0;
};
/**
* Template version of Button, with callback support.
*/
template<typename T>
class Button : public ButtonCommon {
private:
typedef void (*ButtonCallback)(struct NetworkClientListWindow *w, Point pt, T id); ///< Callback function to call on click.
T id; ///< ID this button belongs to.
ButtonCallback proc; ///< Callback proc to call when button is pressed.
public:
Button(SpriteID sprite, StringID tooltip, Colours colour, T id, ButtonCallback proc) :
ButtonCommon(sprite, tooltip, colour),
id(id),
proc(proc)
{
assert(proc != nullptr);
}
void OnClick(struct NetworkClientListWindow *w, Point pt) override
{
if (this->disabled) return;
this->proc(w, pt, this->id);
}
};
using CompanyButton = Button<CompanyID>;
using ClientButton = Button<ClientID>;
/**
* Main handle for clientlist
*/
struct NetworkClientListWindow : Window {
int selected_item;
private:
ClientListWidgets query_widget; ///< During a query this tracks what widget caused the query.
CompanyID join_company; ///< During query for company password, this stores what company we wanted to join.
uint server_client_width;
uint line_height;
Scrollbar *vscroll; ///< Vertical scrollbar of this window.
uint line_height; ///< Current lineheight of each entry in the matrix.
uint line_count; ///< Amount of lines in the matrix.
Dimension icon_size;
std::map<uint, std::vector<std::unique_ptr<ButtonCommon>>> buttons; ///< Per line which buttons are available.
NetworkClientListWindow(WindowDesc *desc, WindowNumber window_number) :
Window(desc),
selected_item(-1)
static const int CLIENT_OFFSET_LEFT = 12; ///< Offset of client entries compared to company entries.
/**
* Chat button on a Company is clicked.
* @param w The instance of this window.
* @param pt The point where this button was clicked.
* @param company_id The company this button was assigned to.
*/
static void OnClickCompanyChat(NetworkClientListWindow *w, Point pt, CompanyID company_id)
{
this->InitNested(window_number);
ShowNetworkChatQueryWindow(DESTTYPE_TEAM, company_id);
}
/**
* Finds the amount of clients and set the height correct
* Join button on a Company is clicked.
* @param w The instance of this window.
* @param pt The point where this button was clicked.
* @param company_id The company this button was assigned to.
*/
bool CheckClientListHeight()
static void OnClickCompanyJoin(NetworkClientListWindow *w, Point pt, CompanyID company_id)
{
int num = 0;
if (_network_server) {
NetworkServerDoMove(CLIENT_ID_SERVER, company_id);
MarkWholeScreenDirty();
} else if (NetworkCompanyIsPassworded(company_id)) {
w->query_widget = WID_CL_COMPANY_JOIN;
w->join_company = company_id;
ShowQueryString(STR_EMPTY, STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION, NETWORK_PASSWORD_LENGTH, w, CS_ALPHANUMERAL, QSF_PASSWORD);
} else {
NetworkClientRequestMove(company_id);
}
}
/* Should be replaced with a loop through all clients */
/**
* Admin button on a Client is clicked.
* @param w The instance of this window.
* @param pt The point where this button was clicked.
* @param client_id The client this button was assigned to.
*/
static void OnClickClientAdmin(NetworkClientListWindow *w, Point pt, ClientID client_id)
{
PopupClientList(client_id, pt.x + w->left, pt.y + w->top);
}
/**
* Chat button on a Client is clicked.
* @param w The instance of this window.
* @param pt The point where this button was clicked.
* @param client_id The client this button was assigned to.
*/
static void OnClickClientChat(NetworkClientListWindow *w, Point pt, ClientID client_id)
{
ShowNetworkChatQueryWindow(DESTTYPE_CLIENT, client_id);
}
/**
* Part of RebuildList() to create the information for a single company.
* @param company_id The company to build the list for.
* @param own_ci The NetworkClientInfo of the client itself.
*/
void RebuildListCompany(CompanyID company_id, const NetworkClientInfo *own_ci)
{
ButtonCommon *chat_button = new CompanyButton(SPR_CHAT, company_id == COMPANY_SPECTATOR ? STR_NETWORK_CLIENT_LIST_CHAT_SPECTATOR_TOOLTIP : STR_NETWORK_CLIENT_LIST_CHAT_COMPANY_TOOLTIP, COLOUR_ORANGE, company_id, &NetworkClientListWindow::OnClickCompanyChat);
this->buttons[line_count].emplace_back(chat_button);
if (own_ci->client_playas != company_id) this->buttons[line_count].emplace_back(new CompanyButton(SPR_JOIN, STR_NETWORK_CLIENT_LIST_JOIN_TOOLTIP, COLOUR_ORANGE, company_id, &NetworkClientListWindow::OnClickCompanyJoin));
this->line_count += 1;
bool has_players = false;
for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
if (ci->client_playas != COMPANY_INACTIVE_CLIENT) num++;
if (ci->client_playas != company_id) continue;
has_players = true;
if (_network_own_client_id != ci->client_id) this->buttons[line_count].emplace_back(new ClientButton(SPR_CHAT, STR_NETWORK_CLIENT_LIST_CHAT_CLIENT_TOOLTIP, COLOUR_ORANGE, ci->client_id, &NetworkClientListWindow::OnClickClientChat));
if (_network_server && _network_own_client_id != ci->client_id) this->buttons[line_count].emplace_back(new ClientButton(SPR_ADMIN, STR_NETWORK_CLIENT_LIST_ADMIN_TOOLTIP, COLOUR_RED, ci->client_id, &NetworkClientListWindow::OnClickClientAdmin));
this->line_count += 1;
}
num *= this->line_height;
chat_button->disabled = !has_players;
}
int diff = (num + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM) - (this->GetWidget<NWidgetBase>(WID_CL_PANEL)->current_y);
/* If height is changed */
if (diff != 0) {
ResizeWindow(this, 0, diff, false);
return false;
/**
* Rebuild the list, meaning: calculate the lines needed and what buttons go on which line.
*/
void RebuildList()
{
const NetworkClientInfo *own_ci = NetworkClientInfo::GetByClientID(_network_own_client_id);
this->buttons.clear();
this->line_count = 0;
/* Companies */
for (const Company *c : Company::Iterate()) {
this->RebuildListCompany(c->index, own_ci);
}
return true;
/* Spectators */
this->RebuildListCompany(COMPANY_SPECTATOR, own_ci);
this->vscroll->SetCount(this->line_count);
}
/**
* Get the button at a specific point on the WID_CL_MATRIX.
* @param pt The point to look for a button.
* @return The button or a nullptr if there was none.
*/
ButtonCommon *GetButtonAtPoint(Point pt)
{
uint index = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_CL_MATRIX);
NWidgetBase *widget_matrix = this->GetWidget<NWidgetBase>(WID_CL_MATRIX);
bool rtl = _current_text_dir == TD_RTL;
uint x = rtl ? (uint)widget_matrix->pos_x + WD_FRAMERECT_LEFT : widget_matrix->current_x - WD_FRAMERECT_RIGHT;
/* Find the buttons for this row. */
auto button_find = this->buttons.find(index);
if (button_find == this->buttons.end()) return nullptr;
/* Check if we want to display a tooltip for any of the buttons. */
for (auto &button : button_find->second) {
uint left = rtl ? x : x - button->width;
uint right = rtl ? x + button->width : x;
if (IsInsideMM(pt.x, left, right)) {
return button.get();
}
int width = button->width + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
x += rtl ? width : -width;
}
return nullptr;
}
public:
NetworkClientListWindow(WindowDesc *desc, WindowNumber window_number) :
Window(desc)
{
this->CreateNestedTree();
this->vscroll = this->GetScrollbar(WID_CL_SCROLLBAR);
this->OnInvalidateData();
this->FinishInitNested(window_number);
}
void OnInvalidateData(int data = 0, bool gui_scope = true) override
{
this->RebuildList();
/* Currently server information is not sync'd to clients, so we cannot show it on clients. */
this->GetWidget<NWidgetStacked>(WID_CL_SERVER_SELECTOR)->SetDisplayedPlane(_network_server ? 0 : SZSP_HORIZONTAL);
}
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
{
if (widget != WID_CL_PANEL) return;
switch (widget) {
case WID_CL_SERVER_VISIBILITY:
*size = maxdim(GetStringBoundingBox(_server_visibility_dropdown[0]), GetStringBoundingBox(_server_visibility_dropdown[1]));
size->width += padding.width;
size->height += padding.height;
break;
this->server_client_width = std::max(GetStringBoundingBox(STR_NETWORK_SERVER).width, GetStringBoundingBox(STR_NETWORK_CLIENT).width) + WD_FRAMERECT_RIGHT;
this->icon_size = GetSpriteSize(SPR_COMPANY_ICON);
this->line_height = std::max(this->icon_size.height + 2U, (uint)FONT_HEIGHT_NORMAL);
case WID_CL_MATRIX: {
uint height = std::max({GetSpriteSize(SPR_COMPANY_ICON).height, GetSpriteSize(SPR_JOIN).height, GetSpriteSize(SPR_ADMIN).height, GetSpriteSize(SPR_CHAT).height});
height += ScaleGUITrad(WD_FRAMERECT_TOP) + ScaleGUITrad(WD_FRAMERECT_BOTTOM);
this->line_height = std::max(height, (uint)FONT_HEIGHT_NORMAL) + ScaleGUITrad(WD_MATRIX_TOP + WD_MATRIX_BOTTOM);
uint width = 100; // Default width
for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
width = std::max(width, GetStringBoundingBox(ci->client_name).width);
resize->width = 1;
resize->height = this->line_height;
fill->height = this->line_height;
size->height = std::max(size->height, 5 * this->line_height);
break;
}
}
size->width = WD_FRAMERECT_LEFT + this->server_client_width + this->icon_size.width + WD_FRAMERECT_LEFT + width + WD_FRAMERECT_RIGHT;
}
void OnPaint() override
void OnResize() override
{
/* Check if we need to reset the height */
if (!this->CheckClientListHeight()) return;
this->DrawWidgets();
this->vscroll->SetCapacityFromWidget(this, WID_CL_MATRIX);
}
void DrawWidget(const Rect &r, int widget) const override
void SetStringParameters(int widget) const override
{
if (widget != WID_CL_PANEL) return;
switch (widget) {
case WID_CL_SERVER_NAME:
SetDParamStr(0, _settings_client.network.server_name);
break;
bool rtl = _current_text_dir == TD_RTL;
int icon_offset = (this->line_height - icon_size.height) / 2;
int text_offset = (this->line_height - FONT_HEIGHT_NORMAL) / 2;
case WID_CL_SERVER_VISIBILITY:
SetDParam(0, _server_visibility_dropdown[_settings_client.network.server_advertise]);
break;
uint y = r.top + WD_FRAMERECT_TOP;
uint left = r.left + WD_FRAMERECT_LEFT;
uint right = r.right - WD_FRAMERECT_RIGHT;
uint type_icon_width = this->server_client_width + this->icon_size.width + WD_FRAMERECT_LEFT;
uint type_left = rtl ? right - this->server_client_width : left;
uint type_right = rtl ? right : left + this->server_client_width - 1;
uint icon_left = rtl ? right - type_icon_width + WD_FRAMERECT_LEFT : left + this->server_client_width;
uint name_left = rtl ? left : left + type_icon_width;
uint name_right = rtl ? right - type_icon_width : right;
int i = 0;
for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
TextColour colour;
if (this->selected_item == i++) { // Selected item, highlight it
GfxFillRect(r.left + 1, y, r.right - 1, y + this->line_height - 1, PC_BLACK);
colour = TC_WHITE;
} else {
colour = TC_BLACK;
}
if (ci->client_id == CLIENT_ID_SERVER) {
DrawString(type_left, type_right, y + text_offset, STR_NETWORK_SERVER, colour);
} else {
DrawString(type_left, type_right, y + text_offset, STR_NETWORK_CLIENT, colour);
}
/* Filter out spectators */
if (Company::IsValidID(ci->client_playas)) DrawCompanyIcon(ci->client_playas, icon_left, y + icon_offset);
DrawString(name_left, name_right, y + text_offset, ci->client_name, colour);
y += line_height;
case WID_CL_CLIENT_NAME:
SetDParamStr(0, _settings_client.network.client_name);
break;
}
}
void OnClick(Point pt, int widget, int click_count) override
{
/* Show the popup with option */
if (this->selected_item != -1) {
int client_no = this->selected_item;
for (NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
if (client_no == 0) {
PopupClientList(ci->client_id, pt.x + this->left, pt.y + this->top);
break;
}
client_no--;
switch (widget) {
case WID_CL_SERVER_NAME_EDIT:
if (!_network_server) break;
this->query_widget = WID_CL_SERVER_NAME_EDIT;
SetDParamStr(0, _settings_client.network.server_name);
ShowQueryString(STR_JUST_RAW_STRING, STR_NETWORK_CLIENT_LIST_SERVER_NAME_QUERY_CAPTION, NETWORK_NAME_LENGTH, this, CS_ALPHANUMERAL, QSF_LEN_IN_CHARS);
break;
case WID_CL_CLIENT_NAME_EDIT:
this->query_widget = WID_CL_CLIENT_NAME_EDIT;
SetDParamStr(0, _settings_client.network.client_name);
ShowQueryString(STR_JUST_RAW_STRING, STR_NETWORK_CLIENT_LIST_PLAYER_NAME_QUERY_CAPTION, NETWORK_CLIENT_NAME_LENGTH, this, CS_ALPHANUMERAL, QSF_LEN_IN_CHARS);
break;
case WID_CL_SERVER_VISIBILITY:
if (!_network_server) break;
ShowDropDownMenu(this, _server_visibility_dropdown, _settings_client.network.server_advertise, WID_CL_SERVER_VISIBILITY, 0, 0);
break;
case WID_CL_MATRIX: {
ButtonCommon *button = this->GetButtonAtPoint(pt);
if (button == nullptr) break;
button->OnClick(this, pt);
break;
}
}
}
void OnMouseOver(Point pt, int widget) override
bool OnTooltip(Point pt, int widget, TooltipCloseCondition close_cond) override
{
/* -1 means we left the current window */
if (pt.y == -1) {
this->selected_item = -1;
this->SetDirty();
return;
switch (widget) {
case WID_CL_MATRIX: {
ButtonCommon *button = this->GetButtonAtPoint(pt);
if (button == nullptr) return false;
GuiShowTooltips(this, button->tooltip, 0, nullptr, close_cond);
return true;
};
}
/* Find the new selected item (if any) */
pt.y -= this->GetWidget<NWidgetBase>(WID_CL_PANEL)->pos_y;
int item = -1;
if (IsInsideMM(pt.y, WD_FRAMERECT_TOP, this->GetWidget<NWidgetBase>(WID_CL_PANEL)->current_y - WD_FRAMERECT_BOTTOM)) {
item = (pt.y - WD_FRAMERECT_TOP) / this->line_height;
return false;
}
void OnDropdownSelect(int widget, int index) override
{
switch (widget) {
case WID_CL_SERVER_VISIBILITY:
if (!_network_server) break;
_settings_client.network.server_advertise = (index != 0);
break;
default:
NOT_REACHED();
}
/* It did not change.. no update! */
if (item == this->selected_item) return;
this->selected_item = item;
/* Repaint */
this->SetDirty();
}
void OnQueryTextFinished(char *str) override
{
if (str == nullptr) return;
switch (this->query_widget) {
default: NOT_REACHED();
case WID_CL_SERVER_NAME_EDIT: {
if (!_network_server) break;
uint index;
GetSettingFromName("network.server_name", &index);
SetSettingValue(index, StrEmpty(str) ? "Unnamed Server" : str);
this->InvalidateData();
break;
}
case WID_CL_CLIENT_NAME_EDIT: {
if (!NetworkValidateClientName(str)) break;
uint index;
GetSettingFromName("network.client_name", &index);
SetSettingValue(index, str);
this->InvalidateData();
break;
}
case WID_CL_COMPANY_JOIN:
NetworkClientRequestMove(this->join_company, str);
break;
}
}
/**
* Draw the buttons for a single line in the matrix.
*
* The x-position in RTL is the most left or otherwise the most right pixel
* we can draw the buttons from.
*
* @param x The x-position to start with the buttons. Updated during this function.
* @param y The y-position to start with the buttons.
* @param buttons The buttons to draw.
*/
void DrawButtons(uint &x, uint y, const std::vector<std::unique_ptr<ButtonCommon>> &buttons) const
{
for (auto &button : buttons) {
bool rtl = _current_text_dir == TD_RTL;
uint left = rtl ? x : x - button->width;
uint right = rtl ? x + button->width : x;
int offset = std::max(0, ((int)(this->line_height + 1) - (int)button->height) / 2);
DrawFrameRect(left, y + offset, right, y + offset + button->height, button->colour, FR_NONE);
DrawSprite(button->sprite, PAL_NONE, left + ScaleGUITrad(WD_FRAMERECT_LEFT), y + offset + ScaleGUITrad(WD_FRAMERECT_TOP));
if (button->disabled) {
GfxFillRect(left + 1, y + offset + 1, right - 1, y + offset + button->height - 1, _colour_gradient[button->colour & 0xF][2], FILLRECT_CHECKER);
}
int width = button->width + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
x += rtl ? width : -width;
}
}
/**
* Draw a company and its clients on the matrix.
* @param c The company to draw.
* @param left The most left pixel of the line.
* @param right The most right pixel of the line.
* @param top The top of the first line.
* @param line The Nth line we are drawing. Updated during this function.
*/
void DrawCompany(const Company *c, uint left, uint right, uint top, uint &line) const
{
bool rtl = _current_text_dir == TD_RTL;
int text_y_offset = std::max(0, ((int)(this->line_height + 1) - (int)FONT_HEIGHT_NORMAL) / 2) + WD_MATRIX_BOTTOM;
Dimension d = GetSpriteSize(SPR_COMPANY_ICON);
int offset = std::max(0, ((int)(this->line_height + 1) - (int)d.height) / 2);
uint text_left = left + (rtl ? (uint)WD_FRAMERECT_LEFT : d.width + 8);
uint text_right = right - (rtl ? d.width + 8 : (uint)WD_FRAMERECT_RIGHT);
uint line_start = this->vscroll->GetPosition();
uint line_end = line_start + this->vscroll->GetCapacity();
uint y = top + (this->line_height * (line - line_start));
/* Draw the company line (if in range of scrollbar). */
if (IsInsideMM(line, line_start, line_end)) {
uint x = rtl ? text_left : text_right;
/* If there are buttons for this company, draw them. */
auto button_find = this->buttons.find(line);
if (button_find != this->buttons.end()) {
this->DrawButtons(x, y, button_find->second);
}
if (c == nullptr) {
DrawSprite(SPR_COMPANY_ICON, PALETTE_TO_GREY, rtl ? right - d.width - 4 : left + 4, y + offset);
DrawString(rtl ? x : text_left, rtl ? text_right : x, y + text_y_offset, STR_NETWORK_CLIENT_LIST_SPECTATORS, TC_SILVER);
} else {
DrawCompanyIcon(c->index, rtl ? right - d.width - 4 : left + 4, y + offset);
SetDParam(0, c->index);
SetDParam(1, c->index);
DrawString(rtl ? x : text_left, rtl ? text_right : x, y + text_y_offset, STR_COMPANY_NAME, TC_SILVER);
}
}
y += this->line_height;
line++;
for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
if (c != nullptr && ci->client_playas != c->index) continue;
if (c == nullptr && ci->client_playas != COMPANY_SPECTATOR) continue;
/* Draw the player line (if in range of scrollbar). */
if (IsInsideMM(line, line_start, line_end)) {
uint x = rtl ? text_left : text_right;
/* If there are buttons for this client, draw them. */
auto button_find = this->buttons.find(line);
if (button_find != this->buttons.end()) {
this->DrawButtons(x, y, button_find->second);
}
StringID client_string = STR_JUST_RAW_STRING;
if (ci->client_id == CLIENT_ID_SERVER) {
client_string = STR_NETWORK_CLIENT_LIST_PLAYER_HOST;
}
if (ci->client_id == _network_own_client_id) {
client_string = STR_NETWORK_CLIENT_LIST_PLAYER_SELF;
}
SetDParamStr(0, ci->client_name);
DrawString(rtl ? x : text_left + CLIENT_OFFSET_LEFT, rtl ? text_right - CLIENT_OFFSET_LEFT : x, y + text_y_offset, client_string, TC_BLACK);
}
y += this->line_height;
line++;
}
}
void DrawWidget(const Rect &r, int widget) const override
{
switch (widget) {
case WID_CL_MATRIX: {
uint line = 0;
for (const Company *c : Company::Iterate()) {
this->DrawCompany(c, r.left, r.right, r.top, line);
}
/* Specators */
this->DrawCompany(nullptr, r.left, r.right, r.top, line);
break;
}
}
}
};
void ShowClientList()

View File

@ -288,13 +288,14 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::CloseConnection(NetworkRecvSta
_network_clients_connected--;
DeleteWindowById(WC_CLIENT_LIST_POPUP, this->client_id);
SetWindowDirty(WC_CLIENT_LIST, 0);
this->SendPackets(true);
delete this->GetInfo();
delete this;
InvalidateWindowData(WC_CLIENT_LIST, 0);
return status;
}
@ -1043,6 +1044,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_MAP_OK(Packet *
this->GetClientName(client_name, lastof(client_name));
NetworkTextMessage(NETWORK_ACTION_JOIN, CC_DEFAULT, false, client_name, nullptr, this->client_id);
InvalidateWindowData(WC_CLIENT_LIST, 0);
/* Mark the client as pre-active, and wait for an ACK
* so we know he is done loading and in sync with us */
@ -2061,6 +2063,9 @@ void NetworkServerDoMove(ClientID client_id, CompanyID company_id)
NetworkAction action = (company_id == COMPANY_SPECTATOR) ? NETWORK_ACTION_COMPANY_SPECTATOR : NETWORK_ACTION_COMPANY_JOIN;
NetworkServerSendChat(action, DESTTYPE_BROADCAST, 0, "", client_id, company_id + 1);
InvalidateWindowClassesData(WC_CLIENT_LIST_POPUP);
InvalidateWindowData(WC_CLIENT_LIST, 0);
}
/**

View File

@ -54,7 +54,7 @@ static const SpriteID SPR_LARGE_SMALL_WINDOW = 682;
/** Extra graphic spritenumbers */
static const SpriteID SPR_OPENTTD_BASE = 4896;
static const uint16 OPENTTD_SPRITE_COUNT = 186;
static const uint16 OPENTTD_SPRITE_COUNT = 189;
/* Halftile-selection sprites */
static const SpriteID SPR_HALFTILE_SELECTION_FLAT = SPR_OPENTTD_BASE;
@ -166,6 +166,10 @@ static const SpriteID SPR_WINDOW_DEFSIZE = SPR_OPENTTD_BASE + 168;
static const SpriteID SPR_RENAME = SPR_OPENTTD_BASE + 184;
static const SpriteID SPR_GOTO_LOCATION = SPR_OPENTTD_BASE + 185;
static const SpriteID SPR_CHAT = SPR_OPENTTD_BASE + 186;
static const SpriteID SPR_ADMIN = SPR_OPENTTD_BASE + 187;
static const SpriteID SPR_JOIN = SPR_OPENTTD_BASE + 188;
static const SpriteID SPR_IMG_CARGOFLOW = SPR_OPENTTD_BASE + 174;
static const SpriteID SPR_SIGNALS_BASE = SPR_OPENTTD_BASE + OPENTTD_SPRITE_COUNT;

View File

@ -205,8 +205,7 @@ static void PopupMainToolbMenu(Window *w, int widget, StringID string, int count
/** Enum for the Company Toolbar's network related buttons */
static const int CTMN_CLIENT_LIST = -1; ///< Show the client list
static const int CTMN_NEW_COMPANY = -2; ///< Create a new company
static const int CTMN_SPECTATE = -3; ///< Become spectator
static const int CTMN_SPECTATOR = -4; ///< Show a company window as spectator
static const int CTMN_SPECTATOR = -3; ///< Show a company window as spectator
/**
* Pop up a generic company list menu.
@ -227,8 +226,6 @@ static void PopupMainCompanyToolbMenu(Window *w, int widget, int grey = 0)
if (_local_company == COMPANY_SPECTATOR) {
list.emplace_back(new DropDownListStringItem(STR_NETWORK_COMPANY_LIST_NEW_COMPANY, CTMN_NEW_COMPANY, NetworkMaxCompaniesReached()));
} else {
list.emplace_back(new DropDownListStringItem(STR_NETWORK_COMPANY_LIST_SPECTATE, CTMN_SPECTATE, NetworkMaxSpectatorsReached()));
}
break;
@ -619,15 +616,6 @@ static CallBackFunction MenuClickCompany(int index)
NetworkSendCommand(0, CCA_NEW, 0, CMD_COMPANY_CTRL, nullptr, nullptr, _local_company);
}
return CBF_NONE;
case CTMN_SPECTATE:
if (_network_server) {
NetworkServerDoMove(CLIENT_ID_SERVER, COMPANY_SPECTATOR);
MarkWholeScreenDirty();
} else {
NetworkClientRequestMove(COMPANY_SPECTATOR);
}
return CBF_NONE;
}
}
ShowCompany((CompanyID)index);

View File

@ -96,7 +96,16 @@ enum NetworkLobbyWidgets {
/** Widgets of the #NetworkClientListWindow class. */
enum ClientListWidgets {
WID_CL_PANEL, ///< Panel of the window.
WID_CL_PANEL, ///< Panel of the window.
WID_CL_SERVER_SELECTOR, ///< Selector to hide the server frame.
WID_CL_SERVER_NAME, ///< Server name.
WID_CL_SERVER_NAME_EDIT, ///< Edit button for server name.
WID_CL_SERVER_VISIBILITY, ///< Server visibility.
WID_CL_CLIENT_NAME, ///< Client name.
WID_CL_CLIENT_NAME_EDIT, ///< Edit button for client name.
WID_CL_MATRIX, ///< Company/client list.
WID_CL_SCROLLBAR, ///< Scrollbar for company/client list.
WID_CL_COMPANY_JOIN, ///< Used for QueryWindow when a company has a password.
};
/** Widgets of the #NetworkClientListPopupWindow class. */