OpenClonk
C4GameOverDlg.cpp
Go to the documentation of this file.
1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 2008-2009, RedWolf Design GmbH, http://www.clonk.de/
5  * Copyright (c) 2009-2016, The OpenClonk Team and contributors
6  *
7  * Distributed under the terms of the ISC license; see accompanying file
8  * "COPYING" for details.
9  *
10  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11  * See accompanying file "TRADEMARK" for details.
12  *
13  * To redistribute this file separately, substitute the full license texts
14  * for the above references.
15  */
16 // game over dialog showing winners and losers
17 
18 #include "C4Include.h"
19 #include "gui/C4GameOverDlg.h"
20 
21 #include "control/C4GameControl.h"
22 #include "game/C4Application.h"
23 #include "game/C4FullScreen.h"
26 #include "object/C4Def.h"
27 #include "object/C4DefList.h"
28 #include "object/C4GameObjects.h"
29 #include "player/C4Player.h"
30 #include "player/C4PlayerList.h"
31 
32 // ---------------------------------------------------
33 // C4GoalDisplay
34 
35 C4GoalDisplay::GoalPicture::GoalPicture(const C4Rect &rcBounds, C4ID idGoal, bool fFulfilled)
36  : C4GUI::Window(), idGoal(idGoal), fFulfilled(fFulfilled)
37 {
38  // bounds
39  SetBounds(rcBounds);
40  // can't get specialized desc from object at the moment because of potential script callbacks!
41  StdStrBuf strGoalName;
42  // just get desc from def
43  C4Def *pGoalDef = ::Definitions.ID2Def(idGoal);
44  if (pGoalDef)
45  {
46  strGoalName.Copy(pGoalDef->GetName());
47  // strGoalDesc.Copy(pGoalDef->GetDesc());
48  }
49  // get tooltip
50  StdStrBuf sToolTip;
51  if (fFulfilled)
52  sToolTip.Format(LoadResStr("IDS_DESC_GOALFULFILLED"), strGoalName.getData());
53  else
54  sToolTip.Format(LoadResStr("IDS_DESC_GOALNOTFULFILLED"), strGoalName.getData());
55  SetToolTip(sToolTip.getData());
56  // create buffered picture of goal definition
57  C4Def *pDrawDef = ::Definitions.ID2Def(idGoal);
58  if (pDrawDef)
59  {
60  Picture.Create(C4PictureSize, C4PictureSize);
61  // get an object instance to draw (optional; may be zero)
62  C4Object *pGoalObj = ::Objects.Find(pDrawDef);
63  // draw goal def!
64  pDrawDef->Draw(Picture, false, 0, pGoalObj);
65  }
66  // unfulfilled goal: grey out picture
67  if (!fFulfilled)
68  Picture.Grayscale(30);
69 }
70 
71 void C4GoalDisplay::GoalPicture::DrawElement(C4TargetFacet &cgo)
72 {
73  // draw area
74  C4Facet cgoDraw;
75  cgoDraw.Set(cgo.Surface, cgo.X+rcBounds.x+cgo.TargetX, cgo.Y+rcBounds.y+cgo.TargetY, rcBounds.Wdt, rcBounds.Hgt);
76  // draw buffered picture
77  Picture.Draw(cgoDraw);
78  // draw star symbol if fulfilled
79  if (fFulfilled)
80  {
81  cgoDraw.Set(cgoDraw.Surface, cgoDraw.X+cgoDraw.Wdt*1/2, cgoDraw.Y+cgoDraw.Hgt*1/2, cgoDraw.Wdt/2, cgoDraw.Hgt/2);
83  }
84 }
85 
86 void C4GoalDisplay::SetGoals(const C4IDList &rAllGoals, const C4IDList &rFulfilledGoals, int32_t iGoalSymbolHeight)
87 {
88  // clear previous
89  ClearChildren();
90  // determine goal display area by goal count
91  int32_t iGoalSymbolMargin = C4GUI_DefDlgSmallIndent;
92  int32_t iGoalSymbolAreaHeight = 2*iGoalSymbolMargin + iGoalSymbolHeight;
93  int32_t iGoalAreaWdt = GetClientRect().Wdt;
94  int32_t iGoalsPerRow = std::max<int32_t>(1, iGoalAreaWdt / iGoalSymbolAreaHeight);
95  int32_t iGoalCount = rAllGoals.GetNumberOfIDs();
96  int32_t iRowCount = (iGoalCount-1) / iGoalsPerRow + 1;
97  C4Rect rcNewBounds = GetBounds();
98  rcNewBounds.Hgt = GetMarginTop()+GetMarginBottom()+iRowCount*iGoalSymbolAreaHeight;
99  SetBounds(rcNewBounds);
100  C4GUI::ComponentAligner caAll(GetClientRect(), 0,0, true);
101  // place goal symbols in this area
102  int32_t iGoal = 0;
103  for (int32_t iRow=0; iRow<iRowCount; ++iRow)
104  {
105  int32_t iColCount = std::min<int32_t>(iGoalCount - iGoal, iGoalsPerRow);
106  C4GUI::ComponentAligner caGoalArea(caAll.GetFromTop(iGoalSymbolAreaHeight, iColCount*iGoalSymbolAreaHeight), iGoalSymbolMargin,iGoalSymbolMargin, false);
107  for (int32_t iCol=0; iCol<iColCount; ++iCol,++iGoal)
108  {
109  C4ID idGoal = rAllGoals.GetID(iGoal);
110  bool fFulfilled = !!rFulfilledGoals.GetIDCount(idGoal, 1);
111  AddElement(new GoalPicture(caGoalArea.GetGridCell(iCol, iColCount, iRow, iRowCount), idGoal, fFulfilled));
112  }
113  }
114 }
115 
116 // ---------------------------------------------------
117 // C4GameOverDlg
118 
119 bool C4GameOverDlg::is_shown = false;
120 
121 C4GameOverDlg::C4GameOverDlg() : C4GUI::Dialog( (C4GUI::GetScreenWdt() < 800) ? (C4GUI::GetScreenWdt()-10) : std::min<int32_t>(C4GUI::GetScreenWdt()-150, 800),
122  (C4GUI::GetScreenHgt() < 600) ? (C4GUI::GetScreenHgt()-10) : std::min<int32_t>(C4GUI::GetScreenHgt()-150, 600),
123  LoadResStr("IDS_TEXT_EVALUATION"),
124  false)
125 {
126  is_shown = true; // assume dlg will be shown, soon
127  UpdateOwnPos();
128  // indents / sizes
129  int32_t iDefBtnHeight = 32;
130  int32_t iIndentX1=10;
131  int32_t iIndentY1=6, iIndentY2=0;
132  // main screen components
133  C4GUI::ComponentAligner caMain(GetClientRect(), 0,iIndentY1,true);
134  int32_t iMainTextWidth = caMain.GetWidth() - 6*iIndentX1;
135  caMain.GetFromBottom(iIndentY2);
136  // lower button-area
137  C4GUI::ComponentAligner caBottom(caMain.GetFromBottom(iDefBtnHeight+iIndentY1*2), iIndentX1,0);
138  int32_t iBottomButtonSize = caBottom.GetInnerWidth();
139  iBottomButtonSize = std::min<int32_t>(iBottomButtonSize/2-2*iIndentX1, ::GraphicsResource.CaptionFont.GetTextWidth("Quit it, baby! And some.")*2);
140  // goal display
141  const C4IDList &rGoals = Game.RoundResults.GetGoals();
142  const C4IDList &rFulfilledGoals = Game.RoundResults.GetFulfilledGoals();
143  if (rGoals.GetNumberOfIDs())
144  {
145  C4GoalDisplay *pGoalDisplay = new C4GoalDisplay(caMain.GetFromTop(C4GUI_IconExHgt));
146  pGoalDisplay->SetGoals(rGoals, rFulfilledGoals, C4GUI_IconExHgt);
147  AddElement(pGoalDisplay);
148  // goal display may have resized itself; adjust component aligner
149  caMain.ExpandTop(C4GUI_IconExHgt - pGoalDisplay->GetBounds().Hgt);
150  }
151  // league/network result, present or pending
152  fIsNetDone = false;
153  bool fHasNetResult = Game.RoundResults.HasNetResult();
154  const char *szNetResult = nullptr;
155  if (Game.Parameters.isLeague() || fHasNetResult)
156  {
157  if (fHasNetResult)
158  szNetResult = Game.RoundResults.GetNetResultString();
159  else
160  szNetResult = LoadResStr("IDS_TEXT_LEAGUEWAITINGFOREVALUATIO");
161  pNetResultLabel = new C4GUI::Label(szNetResult, caMain.GetFromTop(::GraphicsResource.TextFont.GetLineHeight()*2, iMainTextWidth), ACenter, C4GUI_Caption2FontClr, nullptr, false, false, true);
162  AddElement(pNetResultLabel);
163  // only add label - contents and fIsNetDone will be set in next update
164  }
165  else
166  {
167  // otherwise, network is always done
168  fIsNetDone = true;
169  }
170  // extra evaluation string area
171  const char *szCustomEvaluationStrings = Game.RoundResults.GetCustomEvaluationStrings();
172  if (szCustomEvaluationStrings && *szCustomEvaluationStrings)
173  {
174  int32_t iMaxHgt = caMain.GetInnerHeight() / 3; // max 1/3rd of height for extra data
175  C4GUI::MultilineLabel *pCustomStrings = new C4GUI::MultilineLabel(caMain.GetFromTop(0 /* resized later*/, iMainTextWidth), 0,0, " ", true, true);
176  pCustomStrings->AddLine(szCustomEvaluationStrings, &::GraphicsResource.TextFont, C4GUI_MessageFontClr, true, false, nullptr);
177  C4Rect rcCustomStringBounds = pCustomStrings->GetBounds();
178  if (rcCustomStringBounds.Hgt > iMaxHgt)
179  {
180  // Buffer too large: Use a scrollbox instead
181  delete pCustomStrings;
182  rcCustomStringBounds.Hgt = iMaxHgt;
183  C4GUI::TextWindow *pCustomStringsWin = new C4GUI::TextWindow(rcCustomStringBounds, 0,0,0, 0,0," ",true, nullptr,0, true);
184  pCustomStringsWin->SetDecoration(false, false, nullptr, false);
185  pCustomStringsWin->AddTextLine(szCustomEvaluationStrings, &::GraphicsResource.TextFont, C4GUI_MessageFontClr, true, false, nullptr);
186  caMain.ExpandTop(-iMaxHgt);
187  AddElement(pCustomStringsWin);
188  }
189  else
190  {
191  // buffer size OK: Reserve required space
192  caMain.ExpandTop(-rcCustomStringBounds.Hgt);
193  AddElement(pCustomStrings);
194  }
195  }
196  // player list area
197  C4GUI::ComponentAligner caPlayerArea(caMain.GetAll(), iIndentX1,0);
198  iPlrListCount = 1; bool fSepTeamLists = false;
200  {
201  // exactly two predefined teams: Use two player list boxes; one for each team
202  iPlrListCount = 2;
203  fSepTeamLists = true;
204  }
205  ppPlayerLists = new C4PlayerInfoListBox *[iPlrListCount];
206  for (int32_t i=0; i<iPlrListCount; ++i)
207  {
208  ppPlayerLists[i] = new C4PlayerInfoListBox(caPlayerArea.GetGridCell(i,iPlrListCount,0,1), C4PlayerInfoListBox::PILBM_Evaluation, fSepTeamLists ? Game.Teams.GetTeamByIndex(i)->GetID() : 0);
209  ppPlayerLists[i]->SetSelectionDiabled(true);
210  ppPlayerLists[i]->SetDecoration(false, nullptr, true, false);
211  AddElement(ppPlayerLists[i]);
212  }
213  // add buttons
215  pBtnExit = btnExit = new C4GUI::CallbackButton<C4GameOverDlg>(LoadResStr("IDS_BTN_ENDROUND"), caBottom.GetGridCell(0,2, 0,1, iBottomButtonSize, -1, true), &C4GameOverDlg::OnExitBtn);
216  btnExit->SetToolTip(LoadResStr("IDS_DESC_ENDTHEROUND"));
217  AddElement(btnExit);
219  pBtnContinue = btnContinue = new C4GUI::CallbackButton<C4GameOverDlg>(LoadResStr("IDS_BTN_CONTINUEGAME"), caBottom.GetGridCell(1,2, 0,1, iBottomButtonSize, -1, true), &C4GameOverDlg::OnContinueBtn);
220  btnContinue->SetToolTip(LoadResStr("IDS_DESC_CONTINUETHEROUNDWITHNOFUR"));
221  AddElement(btnContinue);
222  // convert continue button to "next mission" button if available
223  if (Game.NextMission)
224  {
225  // not available for regular replay and network clients, obviously
226  // it is available for films though, so you can create cinematics for adventures
227  if (::Control.isCtrlHost() || (Game.C4S.Head.Film == 2))
228  {
229  fHasNextMissionButton = true;
230  btnContinue->SetText(Game.NextMissionText.getData());
231  btnContinue->SetToolTip(Game.NextMissionDesc.getData());
232  }
233  }
234  fIsQuitBtnVisible = fIsNetDone || !::Network.isHost();
235  // updates
236  Application.Add(this);
237  Update();
238  // initial focus on quit button if visible, so space/enter/low gamepad buttons quit
239  if (fIsQuitBtnVisible) SetFocus(btnExit, false);
240 }
241 
243 {
244  Application.Remove(this);
245  delete[] ppPlayerLists;
246  is_shown = false;
247 }
248 
249 void C4GameOverDlg::Update()
250 {
251  for (int32_t i=0; i<iPlrListCount; ++i) ppPlayerLists[i]->Update();
252  if (pNetResultLabel)
253  {
255  }
256  // exit/continue button only visible for host if league streaming finished
257  bool fBtnsVisible = fIsNetDone || !::Network.isHost();
258  if (fBtnsVisible != fIsQuitBtnVisible)
259  {
260  fIsQuitBtnVisible = fBtnsVisible;
261  pBtnExit->SetVisibility(fBtnsVisible);
262  pBtnContinue->SetVisibility(fBtnsVisible);
263  if (fIsQuitBtnVisible) SetFocus(pBtnExit, false);
264  }
265 }
266 
267 void C4GameOverDlg::SetNetResult(const char *szResultString, C4RoundResults::NetResult eResultType, size_t iPendingStreamingData, bool fIsStreaming)
268 {
269  // add info about pending streaming data
270  StdStrBuf sResult(szResultString);
271  if (fIsStreaming)
272  {
273  sResult.AppendChar('|');
274  sResult.AppendFormat("[!]Transmitting record to league server... (%d kb remaining)", int(iPendingStreamingData/1024));
275  }
276  // message linebreak into box
277  StdStrBuf sBrokenResult;
278  ::GraphicsResource.TextFont.BreakMessage(sResult.getData(), pNetResultLabel->GetBounds().Wdt, &sBrokenResult, true);
279  pNetResultLabel->SetText(sBrokenResult.getData(), false);
280  // all done?
281  if (eResultType != C4RoundResults::NR_None && !fIsStreaming)
282  {
283  // a final result is determined and all streaming data has been transmitted
284  fIsNetDone = true;
285  }
286  // network error?
287  if (eResultType == C4RoundResults::NR_NetError)
288  {
289  // disconnected. Do not show winners/losers
290  for (int32_t i=0; i<iPlrListCount; ++i) ppPlayerLists[i]->SetMode(C4PlayerInfoListBox::PILBM_EvaluationNoWinners);
291  }
292 }
293 
294 void C4GameOverDlg::OnExitBtn(C4GUI::Control *btn)
295 {
296  // callback: exit button pressed.
298  Close(false);
299 }
300 
301 void C4GameOverDlg::OnContinueBtn(C4GUI::Control *btn)
302 {
303  // callback: continue button pressed
304  if (fHasNextMissionButton)
305  {
306  // switch to next mission if next mission button is pressed
309  }
310  Close(true); // unpauses and deletes this object
311 }
312 
314 {
315  // close some other dialogs
318  for (C4Player *plr = ::Players.First; plr; plr = plr->Next)
319  plr->CloseMenu();
320  // pause game when round results dlg is shown
321  Game.Pause();
322 }
323 
325 {
326  Game.Unpause();
327  typedef C4GUI::Dialog BaseClass;
328  BaseClass::OnClosed(fOK); // deletes this object!
329 }
const int C4PictureSize
Definition: C4Constants.h:60
C4GameControl Control
C4Game Game
Definition: C4Globals.cpp:52
C4Application Application
Definition: C4Globals.cpp:44
C4GameObjects Objects
Definition: C4Globals.cpp:48
C4DefList Definitions
Definition: C4Globals.cpp:49
C4Network2 Network
Definition: C4Globals.cpp:53
C4FullScreen FullScreen
Definition: C4Globals.cpp:46
C4GraphicsResource GraphicsResource
#define C4GUI_DefDlgSmallIndent
Definition: C4Gui.h:133
#define C4GUI_MessageFontClr
Definition: C4Gui.h:43
#define C4GUI_IconExHgt
Definition: C4Gui.h:96
#define C4GUI_Caption2FontClr
Definition: C4Gui.h:38
const char * LoadResStr(const char *id)
Definition: C4Language.h:83
C4PlayerList Players
const int ACenter
Definition: C4Surface.h:41
void SetNextMission(const char *szMissionFilename)
Definition: C4Def.h:99
void Draw(C4Facet &cgo, bool fSelected=false, DWORD iColor=0, C4Object *pObj=nullptr, int32_t iPhaseX=0, int32_t iPhaseY=0, C4DrawTransform *trans=nullptr, const char *graphicsName=nullptr)
Definition: C4Def.cpp:607
C4Def * ID2Def(C4ID id)
void Set(C4Surface &rSfc)
Definition: C4Facet.cpp:459
C4Surface * Surface
Definition: C4Facet.h:117
float Hgt
Definition: C4Facet.h:118
float Wdt
Definition: C4Facet.h:118
void Draw(C4Facet &cgo, bool fAspect=true, int32_t iPhaseX=0, int32_t iPhaseY=0, bool fTransparent=true)
Definition: C4Facet.cpp:154
float Y
Definition: C4Facet.h:118
float X
Definition: C4Facet.h:118
void SetText(const char *szToText)
Definition: C4GuiButton.cpp:55
int32_t GetWidth() const
Definition: C4Gui.h:2803
int32_t GetInnerHeight() const
Definition: C4Gui.h:2809
int32_t GetInnerWidth() const
Definition: C4Gui.h:2808
void ExpandTop(int32_t iByHgt)
Definition: C4Gui.h:2811
bool GetFromTop(int32_t iHgt, int32_t iWdt, C4Rect &rcOut)
Definition: C4Gui.cpp:1059
C4Rect & GetGridCell(int32_t iSectX, int32_t iSectXMax, int32_t iSectY, int32_t iSectYMax, int32_t iSectSizeX=-1, int32_t iSectSizeY=-1, bool fCenterPos=false, int32_t iSectNumX=1, int32_t iSectNumY=1)
Definition: C4Gui.cpp:1148
void GetAll(C4Rect &rcOut)
Definition: C4Gui.cpp:1125
bool GetFromBottom(int32_t iHgt, int32_t iWdt, C4Rect &rcOut)
Definition: C4Gui.cpp:1109
void AddElement(Element *pChild)
void SetVisibility(bool fToValue) override
void SetFocus(Control *pCtrl, bool fByMouse)
void Close(bool fOK)
bool fOK
Definition: C4Gui.h:2083
void SetBounds(const C4Rect &rcNewBound)
Definition: C4Gui.h:446
void SetToolTip(const char *szNewTooltip, bool is_immediate=false)
Definition: C4Gui.cpp:409
C4Rect & GetBounds()
Definition: C4Gui.h:445
static C4Facet GetIconFacet(Icons icoIconIndex)
void SetText(const char *szToText, bool fAllowHotkey=true)
Definition: C4GuiLabels.cpp:74
void SetDecoration(bool fDrawBG, ScrollBarFacets *pToGfx, bool fAutoScroll, bool fDrawBorder=false)
Definition: C4Gui.h:1567
void SetSelectionDiabled(bool fToVal=true)
Definition: C4Gui.h:1569
void AddLine(const char *szLine, CStdFont *pFont, DWORD dwClr, bool fDoUpdate, bool fMakeReadableOnBlack, CStdFont *pCaptionFont)
void SetDecoration(bool fDrawBG, bool fDrawFrame, ScrollBarFacets *pToGfx, bool fAutoScroll)
Definition: C4Gui.h:1753
void AddTextLine(const char *szText, CStdFont *pFont, DWORD dwClr, bool fDoUpdate, bool fMakeReadableOnBlack, CStdFont *pCaptionFont=nullptr)
Definition: C4Gui.h:1741
virtual int32_t GetMarginTop()
Definition: C4Gui.h:873
void UpdateOwnPos() override
C4Rect & GetClientRect() override
Definition: C4Gui.h:864
virtual int32_t GetMarginBottom()
Definition: C4Gui.h:876
bool isCtrlHost() const
Definition: C4GameControl.h:99
C4RoundResults & RoundResults
Definition: C4Game.h:73
C4TeamList & Teams
Definition: C4Game.h:70
C4Scenario C4S
Definition: C4Game.h:74
C4Scoreboard Scoreboard
Definition: C4Game.h:94
StdCopyStrBuf NextMissionText
Definition: C4Game.h:147
bool Pause()
Definition: C4Game.cpp:1171
StdCopyStrBuf NextMissionDesc
Definition: C4Game.h:147
C4GameParameters & Parameters
Definition: C4Game.h:67
bool Unpause()
Definition: C4Game.cpp:1203
StdCopyStrBuf NextMission
Definition: C4Game.h:147
~C4GameOverDlg() override
void OnClosed(bool fOK) override
void OnShown() override
bool isLeague() const
void SetGoals(const C4IDList &rAllGoals, const C4IDList &rFulfilledGoals, int32_t iGoalSymbolHeight)
Definition: C4Id.h:26
C4ID GetID(size_t index, int32_t *ipCount=nullptr) const
Definition: C4IDList.cpp:103
int32_t GetNumberOfIDs() const
Definition: C4IDList.cpp:231
int32_t GetIDCount(C4ID c_id, int32_t iZeroDefVal=0) const
Definition: stub-handle.cpp:67
bool isStreaming() const
size_t getPendingStreamData() const
Definition: C4Network2.h:300
bool isHost() const
Definition: C4Network2.h:209
C4Object * Find(C4Def *def, int owner=ANY_OWNER, DWORD dwOCF=OCF_All)
C4Player * Next
Definition: C4Player.h:142
C4Player * First
Definition: C4PlayerList.h:31
const char * GetName() const override
Definition: C4PropList.cpp:243
Definition: C4Rect.h:28
int32_t y
Definition: C4Rect.h:30
int32_t Hgt
Definition: C4Rect.h:30
int32_t Wdt
Definition: C4Rect.h:30
int32_t x
Definition: C4Rect.h:30
const char * GetNetResultString() const
bool HasNetResult() const
const char * GetCustomEvaluationStrings() const
const C4IDList & GetFulfilledGoals() const
const C4IDList & GetGoals() const
NetResult GetNetResult() const
int32_t Film
Definition: C4Scenario.h:73
C4SHead Head
Definition: C4Scenario.h:232
float TargetY
Definition: C4Facet.h:165
float TargetX
Definition: C4Facet.h:165
int32_t GetID() const
Definition: C4Teams.h:66
C4Team * GetTeamByIndex(int32_t iIndex) const
Definition: C4Teams.cpp:404
bool IsAutoGenerateTeams() const
Definition: C4Teams.h:172
int32_t GetTeamCount() const
Definition: C4Teams.h:158
int GetLineHeight() const
Definition: C4FontLoader.h:125
int32_t GetTextWidth(const char *szText, bool fCheckMarkup=true)
Definition: C4FontLoader.h:140
std::tuple< std::string, int > BreakMessage(const char *szMsg, int iWdt, bool fCheckMarkup, float fZoom=1.0f)
void Remove(StdSchedulerProc *pProc)
void Add(StdSchedulerProc *pProc)
const char * getData() const
Definition: StdBuf.h:442
void Copy()
Definition: StdBuf.h:467
void Format(const char *szFmt,...) GNUC_FORMAT_ATTRIBUTE_O
Definition: StdBuf.cpp:174
int32_t GetScreenHgt()
Definition: C4Gui.h:2825
int32_t GetScreenWdt()
Definition: C4Gui.h:2824
@ Ico_Star
Definition: C4Gui.h:692