| 1 | /* |
| 2 | * LegacyClonk |
| 3 | * |
| 4 | * Copyright (c) RedWolf Design |
| 5 | * Copyright (c) 2001, Sven2 |
| 6 | * Copyright (c) 2017-2022, 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 | // the ingame-lobby |
| 19 | |
| 20 | // TODO: Tab: NickCompletion - and can't do this here, because tab is used to cycle controls! |
| 21 | |
| 22 | #pragma once |
| 23 | |
| 24 | #include "C4Gui.h" |
| 25 | #include "C4GuiDialogs.h" |
| 26 | #include "C4Client.h" |
| 27 | #include "C4Cooldown.h" |
| 28 | #include "C4PlayerInfo.h" |
| 29 | |
| 30 | class C4PlayerInfo; |
| 31 | class C4PlayerInfoListBox; |
| 32 | class C4ClientPlayerInfos; |
| 33 | class C4Network2ResDlg; |
| 34 | class C4GameOptionsList; |
| 35 | class C4GameOptionButtons; |
| 36 | |
| 37 | namespace C4GameLobby |
| 38 | { |
| 39 | |
| 40 | class MainDlg; |
| 41 | |
| 42 | // countdown time from which the elevator sound starts and team selection becomes unavailable |
| 43 | const int32_t AlmostStartCountdownTime = 10; // seconds |
| 44 | |
| 45 | extern bool UserAbort; |
| 46 | |
| 47 | // * PID_LobbyCountdown |
| 48 | // initiates or aborts countdown |
| 49 | class C4PacketCountdown : public C4PacketBase |
| 50 | { |
| 51 | private: |
| 52 | int32_t iCountdown; // countdown timer, or zero for abort |
| 53 | |
| 54 | public: |
| 55 | enum { Abort = -1 }; |
| 56 | |
| 57 | C4PacketCountdown(int32_t iaCountdown) : iCountdown(iaCountdown) {} |
| 58 | C4PacketCountdown() : iCountdown(Abort) {} |
| 59 | |
| 60 | bool IsAbort() const { return iCountdown == Abort; } |
| 61 | int32_t GetCountdown() const { return iCountdown; } |
| 62 | std::string GetCountdownMsg(bool fInitialMsg = false) const; |
| 63 | |
| 64 | virtual void CompileFunc(StdCompiler *pComp) override; |
| 65 | }; |
| 66 | |
| 67 | // scneario info tab: displays scenario description |
| 68 | class ScenDesc : public C4GUI::Window |
| 69 | { |
| 70 | private: |
| 71 | C4GUI::Label *pTitle; // scenario title or warning label if unloaded |
| 72 | C4GUI::TextWindow *pDescBox; // scenario description box |
| 73 | bool fDescFinished; // if set, scenario resource has been loaded |
| 74 | |
| 75 | C4Sec1TimerCallback<ScenDesc> *pSec1Timer; // engine timer hook for updates |
| 76 | |
| 77 | void Update(); |
| 78 | |
| 79 | public: |
| 80 | ScenDesc(const C4Rect &rcBounds, bool fActive); |
| 81 | ~ScenDesc() { Deactivate(); } |
| 82 | |
| 83 | void OnSec1Timer() { Update(); } |
| 84 | // activate/deactivate periodic updates |
| 85 | void Activate(); |
| 86 | void Deactivate(); |
| 87 | }; |
| 88 | |
| 89 | class MainDlg : public C4GUI::FullscreenDialog |
| 90 | { |
| 91 | private: |
| 92 | C4Sec1TimerCallback<MainDlg> *pSec1Timer; // engine timer hook |
| 93 | enum CountdownState { CDS_None = 0, CDS_LongCountdown = 1, CDS_Countdown = 2, CDS_Start = 3 } eCountdownState; // nonzero when a packet was received that the game is about to start (starts elevator sound, etc.) |
| 94 | int32_t iBackBufferIndex; // chat message history index |
| 95 | C4KeyBinding *pKeyHistoryUp, *pKeyHistoryDown; // keys used to scroll through chat history |
| 96 | |
| 97 | enum { SheetIdx_PlayerList = 0, SheetIdx_Res = 1, SheetIdx_Options = 2, SheetIdx_Scenario = 3, }; |
| 98 | C4PlayerInfoListBox *pPlayerList; |
| 99 | C4Network2ResDlg *pResList; |
| 100 | C4GameOptionButtons *pGameOptionButtons; |
| 101 | C4GameOptionsList *pOptionsList; |
| 102 | ScenDesc *pScenarioInfo; |
| 103 | C4GUI::TextWindow *pChatBox; |
| 104 | C4GUI::Label *pRightTabLbl; |
| 105 | C4GUI::Tabular *pRightTab; |
| 106 | C4GUI::Edit *pEdt; // chat input |
| 107 | C4GUI::CallbackButton<MainDlg> *btnRun; // host only |
| 108 | C4GUI::CallbackButton<MainDlg, C4GUI::IconButton> *btnPlayers, *btnResources, *btnTeams, *btnOptions, *btnScenario, *btnChat; // right list sheet selection |
| 109 | C4GUI::CheckBox *checkReady; |
| 110 | C4GUI::CallbackButton<MainDlg> *btnPreload{nullptr}; |
| 111 | C4CooldownSeconds readyButtonCooldown{std::chrono::seconds{2}}; // not in C4Config as it is dependent on |
| 112 | bool resourcesLoaded{false}; |
| 113 | |
| 114 | protected: |
| 115 | void OnReadyCheck(C4GUI::Element *pCheckBox); // callback: checkbox ticked |
| 116 | void OnRunBtn(C4GUI::Control *btn); // callback: run button pressed |
| 117 | void OnExitBtn(C4GUI::Control *btn); // callback: exit button pressed |
| 118 | bool KeyHistoryUpDown(bool fUp); // key callback |
| 119 | C4GUI::InputResult OnChatInput(C4GUI::Edit *edt, bool fPasting, bool fPastingMore); // callback: chat input performed |
| 120 | |
| 121 | void OnClosed(bool fOK) override; // callback when dlg is closed |
| 122 | void OnSec1Timer(); // timer proc; update pings |
| 123 | |
| 124 | C4GUI::ContextMenu *OnRightTabContext(C4GUI::Element *pLabel, int32_t iX, int32_t iY); // open context menu |
| 125 | void OnCtxTabPlayers(C4GUI::Element *pListItem) { OnTabPlayers(btn: nullptr); } |
| 126 | void OnTabPlayers(C4GUI::Control *btn); |
| 127 | void OnCtxTabTeams(C4GUI::Element *pListItem) { OnTabTeams(btn: nullptr); } |
| 128 | void OnTabTeams(C4GUI::Control *btn); |
| 129 | void OnCtxTabRes(C4GUI::Element *pListItem) { OnTabRes(btn: nullptr); } |
| 130 | void OnTabRes(C4GUI::Control *btn); |
| 131 | void OnCtxTabOptions(C4GUI::Element *pListItem) { OnTabOptions(btn: nullptr); } |
| 132 | void OnTabOptions(C4GUI::Control *btn); |
| 133 | void OnTabScenario(C4GUI::Control *btn); |
| 134 | void UpdateRightTab(); // update label and tooltips for sheet change |
| 135 | void UpdateRightTabTitle(); |
| 136 | void OnBtnChat(C4GUI::Control *btn); |
| 137 | void OnBtnPreload(C4GUI::Control *); |
| 138 | |
| 139 | virtual class C4GUI::Control *GetDefaultControl() override; // def focus chat input |
| 140 | |
| 141 | private: |
| 142 | void SetCountdownState(CountdownState eToState, int32_t iTimer); |
| 143 | void Start(int32_t iCountdownTime); // host only: Do game start with specified countdown time (forwards to network system) |
| 144 | int32_t ValidatedCountdownTime(int32_t iTimeout); // correct invalid timeout settings |
| 145 | |
| 146 | void UpdatePlayerList(); |
| 147 | void UpdateResourceProgress(); |
| 148 | void UpdatePreloadingGUIState(bool isComplete); |
| 149 | bool Preload(); |
| 150 | |
| 151 | public: |
| 152 | MainDlg(bool fHost); |
| 153 | ~MainDlg(); |
| 154 | |
| 155 | // callback by network system |
| 156 | void OnClientJoin(C4Client *pNewClient); // called when a new client joined (connection not necessarily ready) |
| 157 | void OnClientConnect(C4Client *pClient, C4Network2IOConnection *pConn); // called when new clinet connection is established (notice of lobby status) |
| 158 | void OnClientPart(C4Client *pPartClient); // called when a client disconnects |
| 159 | bool OnMessage(C4Client *pOfClient, const char *szMessage); // display message in chat window |
| 160 | void OnClientSound(C4Client *pOfClient); // show that someone played a sound |
| 161 | void OnLog(const char *szLogMsg, uint32_t dwClr = C4GUI_LogFontClr); // log callback |
| 162 | void OnError(const char *szErrMsg); // error sound + log in red |
| 163 | void OnPlayersChange() { UpdatePlayerList(); } |
| 164 | void OnClientReadyStateChange(C4Client *client); |
| 165 | void OnClientAddPlayer(const char *szFilename, int32_t idClient); |
| 166 | // packet callbacks from C4Network2 |
| 167 | void HandlePacket(char cStatus, const C4PacketBase *pBasePkt, C4Network2Client *pClient); |
| 168 | void OnCountdownPacket(const C4PacketCountdown &Pkt); // called when a countdown packet is received: Update countdown state |
| 169 | |
| 170 | bool IsCountdown(); |
| 171 | bool IsLongCountdown() const; |
| 172 | void UpdateFairCrew(); |
| 173 | void UpdatePassword(); |
| 174 | void UpdatePlayerCountDisplay(); |
| 175 | void ClearLog(); |
| 176 | void RequestReadyCheck(); |
| 177 | void CheckReady(bool check); |
| 178 | bool CanBeReady() const { return resourcesLoaded; } |
| 179 | |
| 180 | friend class C4Sec1TimerCallback<MainDlg>; |
| 181 | }; |
| 182 | |
| 183 | // helper |
| 184 | void LobbyError(const char *szErrorMsg); |
| 185 | |
| 186 | // lobby countdown: Moves game from lobby to go state. Only created by host. |
| 187 | class Countdown |
| 188 | { |
| 189 | private: |
| 190 | C4Sec1TimerCallback<Countdown> *pSec1Timer; // engine timer hook |
| 191 | int32_t iStartTimer; // countdown timer for round start; 0 for not started, -1 for start overdue |
| 192 | |
| 193 | public: |
| 194 | void OnSec1Timer(); // timer proc; count down; send important countdown packets |
| 195 | |
| 196 | public: |
| 197 | Countdown(int32_t iStartTimer); // Init; sends initial countdown packet |
| 198 | ~Countdown(); |
| 199 | |
| 200 | void Abort(); |
| 201 | }; |
| 202 | |
| 203 | } |
| 204 | |