1/*
2 * LegacyClonk
3 *
4 * Copyright (c) RedWolf Design
5 * Copyright (c) 2008, Sven2
6 * Copyright (c) 2017-2020, The LegacyClonk Team and contributors
7 *
8 * Distributed under the terms of the ISC license; see accompanying file
9 * "COPYING" for details.
10 *
11 * "Clonk" is a registered trademark of Matthes Bender, used with permission.
12 * See accompanying file "TRADEMARK" for details.
13 *
14 * To redistribute this file separately, substitute the full license texts
15 * for the above references.
16 */
17
18// player listbox used in lobby and game over dlg
19
20#pragma once
21
22#include "C4Gui.h"
23#include "C4GuiListBox.h"
24
25#include "C4Scenario.h"
26#include "C4Network2Res.h"
27#include "C4GameLobby.h"
28
29class C4Team;
30
31class C4PlayerInfoListBox : public C4GUI::ListBox
32{
33public:
34 enum Spacings
35 {
36 // some spacings
37 IconLabelSpacing = 2, // space between an icon and its text
38 ClientListBoxSpacing = 8, // space between two clients in the list
39 PlayerListBoxIndent = 3, // indent of player list box items
40
41 SoundIconShowTime = 1, // seconds. min time a sound icon is shown
42 };
43
44 // list box mode
45 enum Mode
46 {
47 PILBM_LobbyClientSort,
48 PILBM_LobbyTeamSort,
49 PILBM_Evaluation,
50 PILBM_EvaluationNoWinners,
51 };
52
53private:
54 // generic player list item
55 class ListItem : public C4GUI::Window
56 {
57 protected:
58 C4PlayerInfoListBox *pList;
59 uint32_t dwBackground; // not drawn if 0
60
61 public:
62 struct ID
63 {
64 enum IDType
65 {
66 PLI_NONE = 0,
67 PLI_SCRIPTPLR, // script player caption (ID=0) - script players themselbed are regular PLI_PLAYER
68 PLI_SAVEGAMEPLR, // restore savegame player (ID>0), or caption (ID=0)
69 PLI_PLAYER, // player
70 PLI_CLIENT, // client label
71 PLI_TEAM, // team label
72 PLI_REPLAY, // replay player (ID>0), or caption (ID=0)
73 } idType;
74
75 int32_t id; // player file ID or team ID or client ID
76
77 ID() : idType(PLI_NONE), id(0) {}
78 ID(IDType eType, int32_t id) : idType(eType), id(id) {}
79
80 inline bool operator==(const ID &r2) const
81 {
82 return idType == r2.idType && id == r2.id;
83 }
84 };
85
86 ID idListItemID;
87
88 C4GameLobby::MainDlg *GetLobby() const;
89 virtual void Update() {} // periodic update callback
90
91 protected:
92 virtual void DrawElement(C4FacetEx &cgo) override; // draw background
93 bool CanLocalChooseTeams(int32_t idPlayer = 0) const; // whether the local client can change any teams
94
95 public:
96 ListItem(C4PlayerInfoListBox *pList) : pList(pList), dwBackground(0), C4GUI::Window() {}
97 };
98
99 // lobby information and display of joined players
100 class PlayerListItem : public ListItem
101 {
102 private:
103 // subcomponents
104 C4GUI::Icon *pIcon; // player icon
105 C4GUI::Label *pNameLabel; // label indicating player name
106 C4GUI::Label *pScoreLabel; // label showing some player score (league)
107 C4GUI::Label *pTimeLabel; // evaluation only: label showing total playing time
108 C4GUI::Label *pExtraLabel; // evaluation only: label showing extra data set by script
109 C4GUI::Icon *pRankIcon; // league rank icon
110 C4GUI::ComboBox *pTeamCombo; // team selection combo - nullptr for no-team-scens
111 C4GUI::Picture *pTeamPic; // evaluation only: Team icon spec
112
113 bool fIconSet; // whether custom icon has been set
114 bool fJoinedInfoSet; // join info for savegame recreation
115 uint32_t dwJoinClr, dwPlrClr; // colors currently reflected in icon
116
117 protected:
118 int32_t idClient, idPlayer; // referenced IDs
119 bool fFreeSavegamePlayer; // if set, the player is an (unassociated) savegame player
120 bool fShownCollapsed; // true if small view is shown
121
122 protected:
123 virtual void UpdateOwnPos() override; // recalculate item positioning
124 virtual int32_t GetListItemTopSpacing() override;
125
126 public:
127 PlayerListItem(C4PlayerInfoListBox *pForListBox, int32_t idClient, int32_t idPlayer, bool fSavegamePlayer, C4GUI::Element *pInsertBeforeElement);
128 ~PlayerListItem() {}
129
130 void UpdateIcon(C4PlayerInfo *pInfo, C4PlayerInfo *pJoinedInfo); // update player icon
131 void UpdateTeam();
132 void UpdateScoreLabel(C4PlayerInfo *pInfo); // update league score labels and icons
133 void UpdateCollapsed();
134
135 public:
136 C4GUI::ContextMenu *OnContext(C4GUI::Element *pListItem, int32_t iX, int32_t iY); // open context menu
137 C4GUI::ContextMenu *OnContextTakeOver(C4GUI::Element *pListItem, int32_t iX, int32_t iY); // takeover savegame player submenu
138 void OnCtxTakeOver(C4GUI::Element *pListItem, const int32_t &idPlayer);
139 void OnCtxRemove(C4GUI::Element *pListItem);
140 void OnCtxNewColor(C4GUI::Element *pListItem);
141
142 void OnTeamComboFill(C4GUI::ComboBox_FillCB *pFiller);
143 bool OnTeamComboSelChange(C4GUI::ComboBox *pForCombo, int32_t idNewSelection);
144
145 virtual void Update() override; // update icon and team
146
147 C4Network2Client *GetNetClient() const; // return associated network client
148 C4PlayerInfo *GetPlayerInfo() const;
149
150 C4PlayerInfo *GetJoinedInfo() const; // if this player is joined or associated to a joined info, return the joined info
151
152 bool IsLocalClientPlayer() const; // whether this player is going to join locally
153 bool CanLocalChooseTeam() const; // whether the local client can change team for this player
154 };
155
156 // lobby information and display of connected clients
157 class ClientListItem : public ListItem
158 {
159 private:
160 // subcomponents
161 C4GUI::Icon *pStatusIcon; // icon indicating client status (host, etc.)
162 C4GUI::Label *pNameLabel; // label indicating client name
163 C4GUI::Label *pPingLabel; // label indicating ping to client - may be nullptr
164
165 protected:
166 int32_t idClient; // associated network interface ID
167 uint32_t dwClientClr; // client color used for chatting
168
169 bool fIsShownActive; // whether client was active in last update
170 time_t tLastSoundTime; // now() when the client last issued a sound (display as sound icon). 0 for no sound.
171
172 public:
173 ClientListItem(C4PlayerInfoListBox *pForListBox, const C4ClientCore &rClientInfo, ListItem *pInsertBefore);
174 ~ClientListItem() {}
175
176 void SetColor(uint32_t dwToClr) // update color of client name label
177 {
178 pNameLabel->SetColor(dwToClr: (dwClientClr = dwToClr) | C4GUI_MessageFontAlpha);
179 }
180
181 void SetStatus(C4GUI::Icons icoNewStatus) // set new status
182 {
183 pStatusIcon->SetIcon(icoNewStatus);
184 }
185
186 void SetPing(int32_t iToPing); // update ping label; iToPing=-1 removes the label
187 void SetSoundIcon(); // sets the sound icon as current icon and schedules reset after some time
188
189 // spacing inserted between two client list items
190 virtual int32_t GetListItemTopSpacing() override { return ClientListBoxSpacing; }
191 virtual bool GetListItemTopSpacingBar() override { return true; }
192
193 public:
194 void UpdateInfo(); // update for changed player info
195
196 uint32_t GetColor() const { return dwClientClr; } // client chat color
197 C4Client *GetClient() const; // get client associated with this list item
198 bool IsLocalClientPlayer() const; // whether this player is going to join locally
199 C4GUI::Icons GetCurrentStatusIcon(); // get status icon that shows the current client state
200 class C4Network2Client *GetNetClient() const; // return assicuated network client; nullptr for local
201
202 virtual void Update() override { UpdatePing(); UpdateInfo(); }
203 void UpdatePing(); // update ping label
204
205 C4GUI::ContextMenu *OnContext(C4GUI::Element *pListItem, int32_t iX, int32_t iY); // open context menu
206 void OnCtxKick(C4GUI::Element *pListItem); // kick item selected in client ctx menu
207 void OnCtxActivate(C4GUI::Element *pListItem); // toggle player/observer
208 void OnCtxInfo(C4GUI::Element *pListItem); // show info dlg (modal)
209 void OnCtxToggleMute(C4GUI::Element *pListItem); // toggle /sound mute/unmute
210 void OnBtnAddPlr(C4GUI::Control *btn);
211 };
212
213 // team label
214 class TeamListItem : public ListItem
215 {
216 private:
217 // subcomponents
218 C4GUI::Icon *pIcon;
219 C4GUI::Label *pNameLabel;
220
221 int32_t idTeam; // team ID
222
223 protected:
224 virtual void MouseInput(C4GUI::CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, uint32_t dwKeyParam) override; // input: mouse movement or buttons
225 virtual void UpdateOwnPos() override; // recalculate item positioning
226
227 public:
228 TeamListItem(C4PlayerInfoListBox *pForListBox, int32_t idTeam, ListItem *pInsertBefore);
229
230 // spacing inserted between of those list items; usually this is top anyway...
231 virtual bool GetListItemTopSpacingBar() override { return true; }
232 virtual int32_t GetListItemTopSpacing() override { return ClientListBoxSpacing; }
233
234 virtual void Update() override;
235
236 private:
237 void MoveLocalPlayersIntoTeam(); // move all local players into team marked by this label
238 };
239
240 // list of unassigned savegame recreation players
241 class FreeSavegamePlayersListItem : public ListItem
242 {
243 private:
244 // subcomponents
245 C4GUI::Icon *pIcon;
246 C4GUI::Label *pNameLabel;
247
248 public:
249 FreeSavegamePlayersListItem(C4PlayerInfoListBox *pForListBox, ListItem *pInsertBefore);
250
251 // spacing inserted between of those list items; usually this is top anyway...
252 virtual bool ListItemTopSpacingBar() { return true; }
253 virtual int32_t GetListItemTopSpacing() override { return ClientListBoxSpacing; }
254
255 public:
256 virtual void Update() override;
257 };
258
259 // list of script players (both savegame recreation and regular)
260 class ScriptPlayersListItem : public ListItem
261 {
262 private:
263 // subcomponents
264 C4GUI::Icon *pIcon;
265 C4GUI::Label *pNameLabel;
266 C4GUI::IconButton *btnAddPlayer;
267
268 public:
269 ScriptPlayersListItem(C4PlayerInfoListBox *pForListBox, ListItem *pInsertBefore);
270
271 // spacing inserted between of those list items; usually this is top anyway...
272 virtual bool ListItemTopSpacingBar() { return true; }
273 virtual int32_t GetListItemTopSpacing() override { return ClientListBoxSpacing; }
274
275 protected:
276 void OnBtnAddPlr(C4GUI::Control *btn);
277
278 public:
279 virtual void Update() override;
280 };
281
282 // list of players in record (currently not used, because replays in network are not allowed :C)
283 class ReplayPlayersListItem : public ListItem
284 {
285 private:
286 // subcomponents
287 C4GUI::Icon *pIcon;
288 C4GUI::Label *pNameLabel;
289
290 public:
291 ReplayPlayersListItem(C4PlayerInfoListBox *pForListBox, ListItem *pInsertBefore);
292
293 // spacing inserted between of those list items; usually this is top anyway...
294 virtual bool GetListItemTopSpacingBar() override { return true; }
295 virtual int32_t GetListItemTopSpacing() override { return ClientListBoxSpacing; }
296 };
297
298private:
299 Mode eMode;
300 int32_t iMaxUncollapsedPlayers; // maximum number of players that can be displayed without collapse - valid only if fIsCollapsed
301 bool fIsCollapsed;
302 int32_t iTeamFilter; // if nonzero, only playeers of this team are shown in the listbox
303
304 uint32_t dwTextColor;
305 CStdFont *pCustomFont;
306
307 enum AddMode
308 {
309 AM_Winners,
310 AM_Losers,
311 AM_All,
312 };
313
314 void UpdateSavegamePlayers(ListItem **ppCurrInList);
315 void UpdateReplayPlayers(ListItem **ppCurrInList);
316 void UpdateScriptPlayers(ListItem **ppCurrInList);
317 void UpdatePlayersByTeam(ListItem **ppCurrInList);
318 void UpdatePlayersByRandomTeam(ListItem **ppCurrInList);
319 void UpdatePlayersByClient(ListItem **ppCurrInList);
320 void UpdatePlayersByEvaluation(ListItem **ppCurrInList, bool fShowWinners);
321 void UpdatePlayersByEvaluation(ListItem **ppCurrInList, C4Team *pTeam, AddMode eAddMode);
322
323 ListItem *GetPlayerListItem(ListItem::ID::IDType eType, int32_t id); // search for a player list item
324 bool PlrListItemUpdate(ListItem::ID::IDType eType, int32_t id, class ListItem **pEnsurePos); // search for player list item with given ID in the list starting at ensurepos; ensure it's positioned at given pos; update and return true if found
325
326 bool IsEvaluation() const { return eMode == PILBM_Evaluation || eMode == PILBM_EvaluationNoWinners; }
327 bool IsLobby() const { return eMode == PILBM_LobbyClientSort || eMode == PILBM_LobbyTeamSort; }
328 bool IsTeamFilter() const { return !!iTeamFilter; }
329
330protected:
331 bool IsPlayerItemCollapsed(PlayerListItem *pItem); // CB from list item: return true if it should be shown small
332 void OnPlrListSelChange(class C4GUI::Element *pEl) { Update(); }
333
334 uint32_t GetTextColor() const { return dwTextColor; }
335 CStdFont *GetCustomFont() const { return pCustomFont; }
336
337public:
338 C4PlayerInfoListBox(const C4Rect &rcBounds, Mode eMode, int32_t iTeamFilter = 0);
339 virtual ~C4PlayerInfoListBox() {}
340
341 void Update(); // update player list
342 void SetClientSoundIcon(int32_t iForClientID);
343 void SetMode(Mode eNewMode);
344
345 Mode GetMode() const { return eMode; }
346
347 friend class PlayerListItem;
348 friend class TeamListItem;
349};
350