| 1 | /* |
| 2 | * LegacyClonk |
| 3 | * |
| 4 | * Copyright (c) RedWolf Design |
| 5 | * Copyright (c) 2008, Sven2 |
| 6 | * Copyright (c) 2017-2021, 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 | // game over dialog showing winners and losers |
| 19 | |
| 20 | #include "C4GuiResource.h" |
| 21 | #include <C4Include.h> |
| 22 | #include <C4GameOverDlg.h> |
| 23 | |
| 24 | #include <C4Game.h> |
| 25 | #include <C4FullScreen.h> |
| 26 | #include <C4Player.h> |
| 27 | #include <C4PlayerInfo.h> |
| 28 | #include <C4PlayerInfoListBox.h> |
| 29 | |
| 30 | #include <format> |
| 31 | |
| 32 | // C4GoalDisplay |
| 33 | |
| 34 | C4GoalDisplay::GoalPicture::GoalPicture(const C4Rect &rcBounds, C4ID idGoal, bool fFulfilled) |
| 35 | : idGoal(idGoal), fFulfilled(fFulfilled), C4GUI::Window() |
| 36 | { |
| 37 | // bounds |
| 38 | SetBounds(rcBounds); |
| 39 | // can't get specialized desc from object at the moment because of potential script callbacks! |
| 40 | StdStrBuf strGoalName, strGoalDesc; |
| 41 | // just get desc from def |
| 42 | C4Def *pGoalDef = Game.Defs.ID2Def(id: idGoal); |
| 43 | if (pGoalDef) |
| 44 | { |
| 45 | strGoalName.Copy(pnData: pGoalDef->GetName()); |
| 46 | strGoalDesc.Copy(pnData: pGoalDef->GetDesc()); |
| 47 | } |
| 48 | // get tooltip |
| 49 | const std::string toolTip{LoadResStrChoice(condition: fFulfilled, ifTrue: C4ResStrTableKey::IDS_DESC_GOALFULFILLED, ifFalse: C4ResStrTableKey::IDS_DESC_GOALNOTFULFILLED, args: strGoalName.getData(), args: strGoalDesc.getData())}; |
| 50 | SetToolTip(toolTip.c_str()); |
| 51 | // create buffered picture of goal definition |
| 52 | C4Def *pDrawDef = Game.Defs.ID2Def(id: idGoal); |
| 53 | if (pDrawDef) |
| 54 | { |
| 55 | Picture.Create(iWdt: C4PictureSize, iHgt: C4PictureSize); |
| 56 | // get an object instance to draw (optional; may be zero) |
| 57 | C4Object *pGoalObj = Game.Objects.FindInternal(id: idGoal); |
| 58 | // draw goal def! |
| 59 | pDrawDef->Draw(cgo&: Picture, fSelected: false, iColor: 0, pObj: pGoalObj); |
| 60 | } |
| 61 | // unfulfilled goal: grey out picture |
| 62 | if (!fFulfilled) |
| 63 | Picture.Grayscale(iOffset: 30); |
| 64 | } |
| 65 | |
| 66 | void C4GoalDisplay::GoalPicture::DrawElement(C4FacetEx &cgo) |
| 67 | { |
| 68 | // draw area |
| 69 | C4Facet cgoDraw; |
| 70 | cgoDraw.Set(nsfc: cgo.Surface, nx: cgo.X + rcBounds.x + cgo.TargetX, ny: cgo.Y + rcBounds.y + cgo.TargetY, nwdt: rcBounds.Wdt, nhgt: rcBounds.Hgt); |
| 71 | // draw buffered picture |
| 72 | Picture.Draw(cgo&: cgoDraw); |
| 73 | // draw star symbol if fulfilled |
| 74 | if (fFulfilled) |
| 75 | { |
| 76 | cgoDraw.Set(nsfc: cgoDraw.Surface, nx: cgoDraw.X + cgoDraw.Wdt * 1 / 2, ny: cgoDraw.Y + cgoDraw.Hgt * 1 / 2, nwdt: cgoDraw.Wdt / 2, nhgt: cgoDraw.Hgt / 2); |
| 77 | C4GUI::Icon::GetIconFacet(icoIconIndex: C4GUI::Ico_Star).Draw(cgo&: cgoDraw); |
| 78 | } |
| 79 | } |
| 80 | |
| 81 | void C4GoalDisplay::SetGoals(const C4IDList &rAllGoals, const C4IDList &rFulfilledGoals, int32_t iGoalSymbolHeight) |
| 82 | { |
| 83 | // clear previous |
| 84 | ClearChildren(); |
| 85 | // determine goal display area by goal count |
| 86 | int32_t iGoalSymbolMargin = C4GUI_DefDlgSmallIndent; |
| 87 | int32_t iGoalSymbolAreaHeight = 2 * iGoalSymbolMargin + iGoalSymbolHeight; |
| 88 | int32_t iGoalAreaWdt = GetClientRect().Wdt; |
| 89 | int32_t iGoalsPerRow = std::max<int32_t>(a: 1, b: iGoalAreaWdt / iGoalSymbolAreaHeight); |
| 90 | int32_t iGoalCount = rAllGoals.GetNumberOfIDs(); |
| 91 | int32_t iRowCount = (iGoalCount - 1) / iGoalsPerRow + 1; |
| 92 | C4Rect rcNewBounds = GetBounds(); |
| 93 | rcNewBounds.Hgt = GetMarginTop() + GetMarginBottom() + iRowCount * iGoalSymbolAreaHeight; |
| 94 | SetBounds(rcNewBounds); |
| 95 | C4GUI::ComponentAligner caAll(GetClientRect(), 0, 0, true); |
| 96 | // place goal symbols in this area |
| 97 | int32_t iGoal = 0; |
| 98 | for (int32_t iRow = 0; iRow < iRowCount; ++iRow) |
| 99 | { |
| 100 | int32_t iColCount = std::min<int32_t>(a: iGoalCount - iGoal, b: iGoalsPerRow); |
| 101 | C4GUI::ComponentAligner caGoalArea(caAll.GetFromTop(iHgt: iGoalSymbolAreaHeight, iWdt: iColCount * iGoalSymbolAreaHeight), iGoalSymbolMargin, iGoalSymbolMargin, false); |
| 102 | for (int32_t iCol = 0; iCol < iColCount; ++iCol, ++iGoal) |
| 103 | { |
| 104 | C4ID idGoal = rAllGoals.GetID(index: iGoal); |
| 105 | bool fFulfilled = !!rFulfilledGoals.GetIDCount(id: idGoal, zeroDefVal: 1); |
| 106 | AddElement(pChild: new GoalPicture(caGoalArea.GetGridCell(iSectX: iCol, iSectXMax: iColCount, iSectY: iRow, iSectYMax: iRowCount), idGoal, fFulfilled)); |
| 107 | } |
| 108 | } |
| 109 | } |
| 110 | |
| 111 | // C4GameOverDlg |
| 112 | |
| 113 | bool C4GameOverDlg::is_shown = false; |
| 114 | |
| 115 | C4GameOverDlg::C4GameOverDlg() : C4GUI::Dialog((C4GUI::GetScreenWdt() < 800) ? (C4GUI::GetScreenWdt() - 10) : std::min<int32_t>(a: C4GUI::GetScreenWdt() - 150, b: 800), |
| 116 | (C4GUI::GetScreenHgt() < 600) ? (C4GUI::GetScreenHgt() - 10) : std::min<int32_t>(a: C4GUI::GetScreenHgt() - 150, b: 600), |
| 117 | LoadResStr(id: C4ResStrTableKey::IDS_TEXT_EVALUATION), |
| 118 | false), pNetResultLabel(nullptr), fIsNetDone(false), fIsQuitBtnVisible(false) |
| 119 | { |
| 120 | is_shown = true; // assume dlg will be shown, soon |
| 121 | |
| 122 | pBtnRestart = nullptr; |
| 123 | pBtnNextMission = nullptr; |
| 124 | |
| 125 | bool hideRestart = false; |
| 126 | int32_t buttonCount = 2; |
| 127 | if (Game.Control.isCtrlHost() || (Game.C4S.Head.Film == 2)) |
| 128 | { |
| 129 | ++buttonCount; |
| 130 | if (Game.NextMission) |
| 131 | { |
| 132 | if (C4GUI::GetScreenWdt() < 1280) |
| 133 | { |
| 134 | hideRestart = true; |
| 135 | } |
| 136 | else |
| 137 | { |
| 138 | ++buttonCount; |
| 139 | } |
| 140 | } |
| 141 | SetBounds(C4Rect(0, 0, (C4GUI::GetScreenWdt() < 1280) ? (C4GUI::GetScreenWdt() - 10) : std::min<int32_t>(a: C4GUI::GetScreenWdt() - 150, b: 1280), (C4GUI::GetScreenHgt() < 720) ? (C4GUI::GetScreenHgt() - 10) : std::min<int32_t>(a: C4GUI::GetScreenHgt() - 150, b: 720))); |
| 142 | } |
| 143 | |
| 144 | UpdateOwnPos(); |
| 145 | |
| 146 | // indents / sizes |
| 147 | int32_t iDefBtnHeight = 32; |
| 148 | int32_t iIndentX1 = 10; |
| 149 | int32_t iIndentY1 = 6, iIndentY2 = 0; |
| 150 | // main screen components |
| 151 | C4GUI::ComponentAligner caMain(GetClientRect(), 0, iIndentY1, true); |
| 152 | int32_t iMainTextWidth = caMain.GetWidth() - 6 * iIndentX1; |
| 153 | caMain.GetFromBottom(iHgt: iIndentY2); |
| 154 | // lower button-area |
| 155 | C4GUI::ComponentAligner caBottom(caMain.GetFromBottom(iHgt: iDefBtnHeight + iIndentY1 * 2), iIndentX1, 0); |
| 156 | int32_t iBottomButtonSize = caBottom.GetInnerWidth(); |
| 157 | iBottomButtonSize = std::min<int32_t>(a: iBottomButtonSize / 2 - 2 * iIndentX1, b: C4GUI::GetRes()->CaptionFont.GetTextWidth(szText: "Quit it, baby! And some." ) * 13 / 10); |
| 158 | // goal display |
| 159 | const C4IDList &rGoals = Game.RoundResults.GetGoals(); |
| 160 | const C4IDList &rFulfilledGoals = Game.RoundResults.GetFulfilledGoals(); |
| 161 | if (rGoals.GetNumberOfIDs()) |
| 162 | { |
| 163 | C4GoalDisplay *pGoalDisplay = new C4GoalDisplay(caMain.GetFromTop(C4GUI_IconExHgt)); |
| 164 | pGoalDisplay->SetGoals(rAllGoals: rGoals, rFulfilledGoals, C4GUI_IconExHgt); |
| 165 | AddElement(pChild: pGoalDisplay); |
| 166 | // goal display may have resized itself; adjust component aligner |
| 167 | caMain.ExpandTop(C4GUI_IconExHgt - pGoalDisplay->GetBounds().Hgt); |
| 168 | } |
| 169 | // league/network result, present or pending |
| 170 | fIsNetDone = false; |
| 171 | bool fHasNetResult = Game.RoundResults.HasNetResult(); |
| 172 | const char *szNetResult = nullptr; |
| 173 | if (Game.Parameters.isLeague() || fHasNetResult) |
| 174 | { |
| 175 | if (fHasNetResult) |
| 176 | szNetResult = Game.RoundResults.GetNetResultString(); |
| 177 | else |
| 178 | szNetResult = LoadResStr(id: C4ResStrTableKey::IDS_TEXT_LEAGUEWAITINGFOREVALUATIO); |
| 179 | pNetResultLabel = new C4GUI::Label("" , caMain.GetFromTop(iHgt: C4GUI::GetRes()->TextFont.GetLineHeight() * 2, iWdt: iMainTextWidth), ACenter, C4GUI_Caption2FontClr, nullptr, false, false, true); |
| 180 | AddElement(pChild: pNetResultLabel); |
| 181 | // only add label - contents and fIsNetDone will be set in next update |
| 182 | } |
| 183 | else |
| 184 | { |
| 185 | // otherwise, network is always done |
| 186 | fIsNetDone = true; |
| 187 | } |
| 188 | // extra evaluation string area |
| 189 | const char *szCustomEvaluationStrings = Game.RoundResults.GetCustomEvaluationStrings(); |
| 190 | if (szCustomEvaluationStrings && *szCustomEvaluationStrings) |
| 191 | { |
| 192 | int32_t iMaxHgt = caMain.GetInnerHeight() / 3; // max 1/3rd of height for extra data |
| 193 | C4GUI::MultilineLabel *pCustomStrings = new C4GUI::MultilineLabel(caMain.GetFromTop(iHgt: 0 /* resized later*/, iWdt: iMainTextWidth), 0, 0, " " , true, true); |
| 194 | pCustomStrings->AddLine(szLine: szCustomEvaluationStrings, pFont: &C4GUI::GetRes()->TextFont, C4GUI_MessageFontClr, fDoUpdate: true, fMakeReadableOnBlack: false, pCaptionFont: nullptr); |
| 195 | C4Rect rcCustomStringBounds = pCustomStrings->GetBounds(); |
| 196 | if (rcCustomStringBounds.Hgt > iMaxHgt) |
| 197 | { |
| 198 | // Buffer too large: Use a scrollbox instead |
| 199 | delete pCustomStrings; |
| 200 | rcCustomStringBounds.Hgt = iMaxHgt; |
| 201 | C4GUI::TextWindow *pCustomStringsWin = new C4GUI::TextWindow(rcCustomStringBounds, 0, 0, 0, 0, 0, " " , true, nullptr, 0, true); |
| 202 | pCustomStringsWin->SetDecoration(fDrawBG: false, fDrawFrame: false, pToGfx: nullptr, fAutoScroll: false); |
| 203 | pCustomStringsWin->AddTextLine(szText: szCustomEvaluationStrings, pFont: &C4GUI::GetRes()->TextFont, C4GUI_MessageFontClr, fDoUpdate: true, fMakeReadableOnBlack: false, pCaptionFont: nullptr); |
| 204 | caMain.ExpandTop(iByHgt: -iMaxHgt); |
| 205 | AddElement(pChild: pCustomStringsWin); |
| 206 | } |
| 207 | else |
| 208 | { |
| 209 | // buffer size OK: Reserve required space |
| 210 | caMain.ExpandTop(iByHgt: -rcCustomStringBounds.Hgt); |
| 211 | AddElement(pChild: pCustomStrings); |
| 212 | } |
| 213 | } |
| 214 | // player list area |
| 215 | C4GUI::ComponentAligner caPlayerArea(caMain.GetAll(), iIndentX1, 0); |
| 216 | iPlrListCount = 1; bool fSepTeamLists = false; |
| 217 | if (Game.Teams.GetTeamCount() == 2 && !Game.Teams.IsAutoGenerateTeams()) |
| 218 | { |
| 219 | // exactly two predefined teams: Use two player list boxes; one for each team |
| 220 | iPlrListCount = 2; |
| 221 | fSepTeamLists = true; |
| 222 | } |
| 223 | ppPlayerLists = new C4PlayerInfoListBox *[iPlrListCount]; |
| 224 | for (int32_t i = 0; i < iPlrListCount; ++i) |
| 225 | { |
| 226 | ppPlayerLists[i] = new C4PlayerInfoListBox(caPlayerArea.GetGridCell(iSectX: i, iSectXMax: iPlrListCount, iSectY: 0, iSectYMax: 1), C4PlayerInfoListBox::PILBM_Evaluation, fSepTeamLists ? Game.Teams.GetTeamByIndex(iIndex: i)->GetID() : 0); |
| 227 | ppPlayerLists[i]->SetSelectionDiabled(true); |
| 228 | ppPlayerLists[i]->SetDecoration(fDrawBG: false, pToGfx: nullptr, fAutoScroll: true, fDrawBorder: false); |
| 229 | AddElement(pChild: ppPlayerLists[i]); |
| 230 | } |
| 231 | |
| 232 | // add buttons |
| 233 | pBtnExit = new C4GUI::CallbackButton<C4GameOverDlg>(LoadResStr(id: C4ResStrTableKey::IDS_BTN_ENDROUND), caBottom.GetGridCell(iSectX: 0, iSectXMax: buttonCount, iSectY: 0, iSectYMax: 1, iSectSizeX: iBottomButtonSize, iSectSizeY: -1, fCenterPos: true), &C4GameOverDlg::OnExitBtn); |
| 234 | pBtnExit->SetToolTip(LoadResStr(id: C4ResStrTableKey::IDS_DESC_ENDTHEROUND)); |
| 235 | AddElement(pChild: pBtnExit); |
| 236 | pBtnContinue = new C4GUI::CallbackButton<C4GameOverDlg>(LoadResStr(id: C4ResStrTableKey::IDS_BTN_CONTINUEGAME), caBottom.GetGridCell(iSectX: 1, iSectXMax: buttonCount, iSectY: 0, iSectYMax: 1, iSectSizeX: iBottomButtonSize, iSectSizeY: -1, fCenterPos: true), &C4GameOverDlg::OnContinueBtn); |
| 237 | pBtnContinue->SetToolTip(LoadResStr(id: C4ResStrTableKey::IDS_DESC_CONTINUETHEROUNDWITHNOFUR)); |
| 238 | AddElement(pChild: pBtnContinue); |
| 239 | |
| 240 | // not available for regular replay and network clients, obviously |
| 241 | // it is available for films though, so you can create cinematics for adventures |
| 242 | if (Game.Control.isCtrlHost() || (Game.C4S.Head.Film == 2)) |
| 243 | { |
| 244 | if (!hideRestart) |
| 245 | { |
| 246 | pBtnRestart = new C4GUI::CallbackButton<C4GameOverDlg>(LoadResStr(id: C4ResStrTableKey::IDS_BTN_RESTART), caBottom.GetGridCell(iSectX: 2, iSectXMax: buttonCount, iSectY: 0, iSectYMax: 1, iSectSizeX: iBottomButtonSize, iSectSizeY: -1, fCenterPos: true), &C4GameOverDlg::OnRestartBtn); |
| 247 | pBtnRestart->SetToolTip(LoadResStr(id: C4ResStrTableKey::IDS_DESC_RESTART)); |
| 248 | AddElement(pChild: pBtnRestart); |
| 249 | } |
| 250 | |
| 251 | // convert continue button to "next mission" button if available |
| 252 | if (Game.NextMission) |
| 253 | { |
| 254 | pBtnNextMission = new C4GUI::CallbackButton<C4GameOverDlg>(Game.NextMissionText.getData(), caBottom.GetGridCell(iSectX: 3 - hideRestart, iSectXMax: buttonCount, iSectY: 0, iSectYMax: 1, iSectSizeX: iBottomButtonSize, iSectSizeY: -1, fCenterPos: true), &C4GameOverDlg::OnNextMissionBtn); |
| 255 | pBtnNextMission->SetToolTip(Game.NextMissionDesc.getData()); |
| 256 | AddElement(pChild: pBtnNextMission); |
| 257 | } |
| 258 | } |
| 259 | // updates |
| 260 | pSec1Timer = new C4Sec1TimerCallback<C4GameOverDlg>(this); |
| 261 | Update(); |
| 262 | // initial focus on quit button if visible, so space/enter/low gamepad buttons quit |
| 263 | fIsQuitBtnVisible = fIsNetDone || !Game.Network.isHost(); |
| 264 | } |
| 265 | |
| 266 | C4GameOverDlg::~C4GameOverDlg() |
| 267 | { |
| 268 | pSec1Timer->Release(); |
| 269 | delete[] ppPlayerLists; |
| 270 | is_shown = false; |
| 271 | } |
| 272 | |
| 273 | void C4GameOverDlg::Update() |
| 274 | { |
| 275 | for (int32_t i = 0; i < iPlrListCount; ++i) ppPlayerLists[i]->Update(); |
| 276 | if (pNetResultLabel) |
| 277 | { |
| 278 | SetNetResult(szResultString: Game.RoundResults.GetNetResultString(), eResultType: Game.RoundResults.GetNetResult(), iPendingStreamingData: Game.Network.getPendingStreamData(), fIsStreaming: Game.Network.isStreaming()); |
| 279 | } |
| 280 | // exit/continue button only visible for host if league streaming finished |
| 281 | bool fBtnsVisible = fIsNetDone || !Game.Network.isHost(); |
| 282 | if (fBtnsVisible != fIsQuitBtnVisible) |
| 283 | { |
| 284 | fIsQuitBtnVisible = fBtnsVisible; |
| 285 | pBtnExit->SetVisibility(fBtnsVisible); |
| 286 | pBtnContinue->SetVisibility(fBtnsVisible); |
| 287 | } |
| 288 | } |
| 289 | |
| 290 | void C4GameOverDlg::SetNetResult(const char *szResultString, C4RoundResults::NetResult eResultType, size_t iPendingStreamingData, bool fIsStreaming) |
| 291 | { |
| 292 | // add info about pending streaming data |
| 293 | StdStrBuf sResult(szResultString, false); |
| 294 | if (fIsStreaming) |
| 295 | { |
| 296 | sResult.AppendChar(cChar: '|'); |
| 297 | sResult.Append(pnData: std::format(fmt: "[!]Transmitting record to league server... ({} kb remaining)" , args: iPendingStreamingData / 1024).c_str()); |
| 298 | } |
| 299 | // message linebreak into box |
| 300 | StdStrBuf sBrokenResult; |
| 301 | C4GUI::GetRes()->TextFont.BreakMessage(szMsg: sResult.getData(), iWdt: pNetResultLabel->GetBounds().Wdt, pOut: &sBrokenResult, fCheckMarkup: true); |
| 302 | pNetResultLabel->SetText(szText: sBrokenResult.getData(), fAllowHotkey: false); |
| 303 | // all done? |
| 304 | if (eResultType != C4RoundResults::NR_None && !fIsStreaming) |
| 305 | { |
| 306 | // a final result is determined and all streaming data has been transmitted |
| 307 | fIsNetDone = true; |
| 308 | } |
| 309 | // network error? |
| 310 | if (eResultType == C4RoundResults::NR_NetError) |
| 311 | { |
| 312 | // disconnected. Do not show winners/losers |
| 313 | for (int32_t i = 0; i < iPlrListCount; ++i) ppPlayerLists[i]->SetMode(C4PlayerInfoListBox::PILBM_EvaluationNoWinners); |
| 314 | } |
| 315 | } |
| 316 | |
| 317 | bool C4GameOverDlg::OnEnter() |
| 318 | { |
| 319 | Game.MessageInput.KeyStartTypeIn(mode: C4ChatInputDialog::All); |
| 320 | return true; |
| 321 | } |
| 322 | |
| 323 | void C4GameOverDlg::OnExitBtn(C4GUI::Control *btn) |
| 324 | { |
| 325 | // callback: exit button pressed. |
| 326 | Close(fOK: false); |
| 327 | } |
| 328 | |
| 329 | void C4GameOverDlg::OnContinueBtn(C4GUI::Control *btn) |
| 330 | { |
| 331 | // callback: continue button pressed |
| 332 | Close(fOK: true); |
| 333 | } |
| 334 | |
| 335 | void C4GameOverDlg::OnRestartBtn(C4GUI::Control *btn) |
| 336 | { |
| 337 | // callback: restart button pressed |
| 338 | nextMissionMode = Restart; |
| 339 | Close(fOK: true); |
| 340 | } |
| 341 | |
| 342 | void C4GameOverDlg::OnNextMissionBtn(C4GUI::Control *btn) |
| 343 | { |
| 344 | // callback: next mission button pressed |
| 345 | nextMissionMode = NextMission; |
| 346 | Close(fOK: true); |
| 347 | } |
| 348 | |
| 349 | void C4GameOverDlg::OnShown() |
| 350 | { |
| 351 | // close some other dialogs |
| 352 | Game.Scoreboard.HideDlg(); |
| 353 | FullScreen.CloseMenu(); |
| 354 | for (C4Player *plr = Game.Players.First; plr; plr = plr->Next) |
| 355 | plr->CloseMenu(); |
| 356 | // pause game when round results dlg is shown |
| 357 | Game.Pause(); |
| 358 | } |
| 359 | |
| 360 | void C4GameOverDlg::OnClosed(bool fOK) |
| 361 | { |
| 362 | typedef C4GUI::Dialog BaseClass; |
| 363 | auto _nextMissionMode = nextMissionMode; |
| 364 | BaseClass::OnClosed(fOK); // deletes this! |
| 365 | if (_nextMissionMode != Restart) |
| 366 | { |
| 367 | Game.RestartRestoreInfos.Clear(); |
| 368 | } |
| 369 | // continue round |
| 370 | if (fOK) |
| 371 | { |
| 372 | if (_nextMissionMode != None) |
| 373 | { |
| 374 | // switch to next mission if next mission button is pressed |
| 375 | Application.SetNextMission(_nextMissionMode == NextMission ? Game.NextMission.getData() : Game.ScenarioFilename); |
| 376 | Application.QuitGame(); |
| 377 | } |
| 378 | else |
| 379 | { |
| 380 | // unpause game when continue is pressed |
| 381 | Game.Unpause(); |
| 382 | } |
| 383 | } |
| 384 | // end round |
| 385 | else |
| 386 | { |
| 387 | Application.QuitGame(); |
| 388 | } |
| 389 | } |
| 390 | |