]> git.mxchange.org Git - quix0rs-blobwars.git/blob - src/game.cpp
Prevent a segmentation fault when using the -map option without specifying a map.
[quix0rs-blobwars.git] / src / game.cpp
1 /*
2 Copyright (C) 2004-2011 Parallel Realities
3 Copyright (C) 2011-2015 Perpendicular Dimensions
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
14 See the GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19
20 */
21
22 #include "game.h"
23
24 void newGame()
25 {
26         game.clear();
27         gameData.clear();
28         map.persistantList.clear();
29         engine.practice = false;
30
31         game.skill = engine.skill;
32 }
33
34 void showInGameOptions()
35 {
36         if (!engine.loadWidgets(_("data/inGameWidgets")))
37         {
38                 graphics.showErrorAndExit(ERR_FILE, _("data/inGameWidgets"));
39         }
40
41         graphics.drawRect(120, 100, 400, 300, graphics.black, graphics.white, graphics.screen);
42
43         int cont, options, escape, quit, escapeyes, escapeno, warnno, warnyes, quitno, quityes, train, trainno, trainyes, restart, restartno, restartyes;
44         cont = options = escape = quit = escapeyes = escapeno = warnno = warnyes = quitno = quityes = train = trainno = trainyes = restart = restartno = restartyes = 0;
45
46         engine.setWidgetVariable("continue", &cont);
47         engine.setWidgetVariable("options", &options);
48         engine.setWidgetVariable("escape", &escape);
49         engine.setWidgetVariable("restart", &restart);
50         engine.setWidgetVariable("quit", &quit);
51         engine.setWidgetVariable("train", &train);
52
53         engine.setWidgetVariable("warnno", &warnno);
54         engine.setWidgetVariable("warnyes", &warnyes);
55         
56         engine.setWidgetVariable("restartno", &restartno);
57         engine.setWidgetVariable("restartyes", &restartyes);
58
59         engine.setWidgetVariable("quitno", &quitno);
60         engine.setWidgetVariable("quityes", &quityes);
61         
62         engine.setWidgetVariable("trainno", &quitno);
63         engine.setWidgetVariable("trainyes", &quityes);
64         
65         engine.setWidgetVariable("escapeno", &escapeno);
66         engine.setWidgetVariable("escapeyes", &escapeyes);
67
68         engine.showWidgetGroup("warning", false);
69         engine.showWidgetGroup("restartconf", false);
70         engine.showWidgetGroup("escapeconf", false);
71         engine.showWidgetGroup("quitconf", false);
72         engine.showWidgetGroup("trainconf", false);
73         
74         if ((map.isBossMission) || (engine.practice) || (strcmp(map.name, "Space Station") == 0))
75         {
76                 engine.enableWidget("escape", false);
77                 engine.enableWidget("restart", false);
78         }
79                 
80         if (!engine.practice)
81         {
82                 engine.showWidget("train", false);
83         }
84         else
85         {
86                 engine.showWidget("quit", false);
87         }
88
89         engine.flushInput();
90         engine.clearInput();
91
92         drawWidgets();
93         audio.playMenuSound(2);
94         
95         int menuSound = -1;
96
97         while (true)
98         {
99                 graphics.updateScreen();                
100                 engine.getInput();
101                 config.populate();
102
103                 if ((config.isControl(CONTROL::PAUSE)) || (engine.keyState[SDL_SCANCODE_ESCAPE]))
104                 {
105                         engine.keyState[SDL_SCANCODE_ESCAPE] = 0;
106                         config.resetControl(CONTROL::PAUSE);
107                         break;
108                 }
109                 
110                 menuSound = engine.processWidgets();
111
112                 if (menuSound)
113                 {
114                         graphics.drawRect(120, 100, 400, 300, graphics.black, graphics.white, graphics.screen);
115                         drawWidgets();
116                         audio.playMenuSound(menuSound);
117                 }
118
119                 if (cont)
120                 {
121                         break;
122                 }
123
124                 if (escape)
125                 {
126                         engine.showWidgetGroup("options", false);
127
128                         if (!gameData.stagePreviouslyCleared(game.stageName))
129                         {
130                                 engine.showWidgetGroup("warning", true);
131                                 engine.highlightWidget("warnno");
132                         }
133                         else
134                         {
135                                 engine.showWidgetGroup("escapeconf", true);
136                                 engine.highlightWidget("escapeno");
137                         }
138
139                         graphics.drawRect(120, 100, 400, 300, graphics.black, graphics.white, graphics.screen);
140                         drawWidgets();
141                         escape = 0;
142                 }
143
144                 if ((escapeyes) || (warnyes))
145                 {
146                         audio.stopMusic();
147                         audio.stopAmbiance();
148                         addTeleportParticles(player.x, player.y, 50, SND_TELEPORT3);
149                         dropCarriedItems();
150                         game.setMissionOver(MIS_PLAYERESCAPE);
151                         break;
152                 }
153
154                 if (options)
155                 {
156                         showOptions();
157                         break;
158                 }
159
160                 if ((warnno) || (quitno) || (escapeno) || (trainno) || (restartno))
161                 {
162                         engine.highlightWidget("continue");
163                         engine.showWidgetGroup("options", true);
164                         engine.showWidgetGroup("warning", false);
165                         engine.showWidgetGroup("trainconf", false);
166                         engine.showWidgetGroup("escapeconf", false);
167                         engine.showWidgetGroup("quitconf", false);
168                         engine.showWidgetGroup("restartconf", false);
169                         
170                         if (!engine.practice)
171                         {
172                                 engine.showWidget("train", false);
173                         }
174                         else
175                         {
176                                 engine.showWidget("quit", false);
177                         }
178                         
179                         graphics.drawRect(120, 100, 400, 300, graphics.black, graphics.white, graphics.screen);
180                         drawWidgets();
181                         quitno = trainno = warnno = escapeno = restartno = 0;
182                 }
183
184                 if (quit)
185                 {
186                         engine.showWidgetGroup("options", false);
187                         engine.showWidgetGroup("quitconf", true);
188                         engine.highlightWidget("quitno");
189
190                         graphics.drawRect(120, 100, 400, 300, graphics.black, graphics.white, graphics.screen);
191                         drawWidgets();
192                         quit = 0;
193                 }
194                 
195                 if (train)
196                 {
197                         engine.showWidgetGroup("options", false);
198                         engine.showWidgetGroup("trainconf", true);
199                         engine.highlightWidget("trainno");
200
201                         graphics.drawRect(120, 100, 400, 300, graphics.black, graphics.white, graphics.screen);
202                         drawWidgets();
203                         train = 0;
204                 }
205                 
206                 if (restart)
207                 {
208                         engine.showWidgetGroup("options", false);
209                         engine.showWidgetGroup("restartconf", true);
210                         engine.highlightWidget("restartno");
211
212                         graphics.drawRect(120, 100, 400, 300, graphics.black, graphics.white, graphics.screen);
213                         drawWidgets();
214                         restart = 0;
215                 }
216
217                 if ((quityes) || (trainyes))
218                 {
219                         game.setMissionOver(MIS_PLAYERQUIT);
220                         break;
221                 }
222                 
223                 if (restartyes)
224                 {
225                         game.setMissionOver(MIS_PLAYERRESTART);
226                         SDL_FillRect(graphics.screen, NULL, graphics.black);
227                         audio.stopMusic();
228                         audio.stopAmbiance();
229                         graphics.delay(500);
230                         break;
231                 }
232
233                 SDL_Delay(16);
234         }
235 }
236
237 void doGameStuff()
238 {
239         engine.getInput();
240         config.populate();
241         replayData.read(config.command);
242         
243         if (game.missionOverReason == MIS_INPROGRESS)
244         {
245                 config.doPause();
246         }
247
248         engine.doFrameLoop();
249
250         graphics.updateScreen();
251         graphics.animateSprites();
252         graphics.drawBackground();
253
254         doEffects();
255         doTrains();
256         doTraps();
257         drawMap();
258         doLineDefs();
259         doSwitches();
260         doItems();
261         doBullets();
262         doMIAs();
263         
264         if (map.isBossMission)
265         {
266                 doBosses();
267         }
268         
269         doEnemies();
270         doObstacles();
271         doTeleporters();
272         
273         if (map.isBlizzardLevel)
274         {
275                 doWind();
276         }
277         
278         doParticles();
279         
280         replayData.set(config.command); 
281         replayData.commit();
282 }
283
284 int gameover()
285 {
286         audio.stopMusic();
287         audio.stopAmbiance();
288         
289         if (!engine.loadWidgets(_("data/gameOverWidgets")))
290         {
291                 graphics.showErrorAndExit(ERR_FILE, _("data/gameOverWidgets"));
292         }
293
294         SDL_Surface *gameover = graphics.quickSprite("Game Over", graphics.loadImage("gfx/main/gameover.png"));
295         graphics.setTransparent(gameover);
296
297         audio.loadGameOverMusic();
298         audio.playMusic();
299
300         engine.flushInput();
301         engine.clearInput();
302
303         unsigned int frameLimit = SDL_GetTicks() + 16;
304
305         bool showGameOverOptions = false;
306         int cont, quit, menuSound;
307         cont = quit = menuSound = 0;
308
309         engine.setWidgetVariable("gameOverNo", &cont);
310         engine.setWidgetVariable("gameOverYes", &quit);
311         
312         if (game.canContinue > 1)
313         {
314                 Widget *widget = engine.getWidgetByName("gameOverNo");
315                 char postfix[100];
316                 snprintf(postfix, sizeof postfix, " (%d)", game.canContinue);
317                 strlcat(widget->label, postfix, sizeof widget->label);
318         }
319
320         while (true)
321         {
322                 if (menuSound)
323                         audio.playMenuSound(menuSound);
324
325                 doGameStuff();
326                 drawMapTopLayer();
327
328                 graphics.blit(gameover, 320, 240, graphics.screen, true);
329
330                 if (engine.userAccepts())
331                 {
332                         if (!showGameOverOptions)
333                         {
334                                 showGameOverOptions = true;
335                                 engine.showWidgetGroup("gameover", true);
336                                 engine.highlightWidget("gameOverNo");
337                                 engine.flushInput();
338                                 engine.clearInput();
339                         }
340
341                         // Can't continue on a boss mission or if no checkpoints reached!
342                         if ((map.isBossMission) || (!game.canContinue))
343                         {
344                                 engine.showWidgetGroup("gameover", false);
345                                 quit = 1;
346                         }
347                 }
348                 
349                 if (showGameOverOptions)
350                 {
351                         drawWidgets();
352                         menuSound = engine.processWidgets();
353                 }
354
355                 if ((cont) || (quit))
356                         break;
357
358                 engine.delay(frameLimit);
359                 frameLimit = SDL_GetTicks() + 16;
360         }
361
362         if (quit)
363         {
364                 audio.fadeMusic();
365                 graphics.fadeToBlack();
366                 map.clear();
367                 
368                 return SECTION_TITLE;
369         }
370
371         game.continueFromCheckPoint = true;
372         audio.stopMusic();
373         audio.reloadLevelMusic();
374
375         return SECTION_GAME;
376 }
377
378 void showMissionInformation()
379 {
380         SDL_FillRect(graphics.screen, NULL, graphics.black);
381         graphics.updateScreen();
382
383         SDL_Surface *panel = graphics.createSurface(400, 300);
384         SDL_Surface *panelBack = graphics.alphaRect(400, 300, 0x00, 0x00, 0x00);
385         SDL_SetColorKey(panel, SDL_TRUE, SDL_MapRGB(panel->format, 0, 0, 0));
386
387         graphics.drawRect(1, 1, 398, 298, graphics.black, graphics.white, panelBack);
388
389         char message[256];
390         int col1 = 25;
391         int col2 = 375;
392         int y = 30;
393
394         Objective *objective;
395
396         graphics.setFontSize(0);
397
398         graphics.setFontSize(3);
399         graphics.setFontColor(0xff, 0xff, 0xff, 0x00, 0x00, 0x00);
400         graphics.drawString(_(game.stageName), 200, 20, TXT_CENTERED, panel);
401
402         graphics.setFontSize(0);
403
404         y += 20;
405
406         if (map.totalMIAs > 0)
407         {
408                 graphics.setFontColor(0xff, 0xff, 0xff, 0x00, 0x00, 0x00);
409                 snprintf(message, sizeof message, _("Rescue %d MIAs"), map.requiredMIAs);
410                 graphics.drawString(message, col1, y, TXT_LEFT, panel);
411
412                 if (map.foundMIAs < map.requiredMIAs)
413                 {
414                         graphics.setFontColor(0xff, 0x00, 0x00, 0x00, 0x00, 0x00);
415                         snprintf(message, sizeof message, "%d / %d", map.foundMIAs, map.requiredMIAs);
416                         graphics.drawString(message, col2, y, TXT_RIGHT, panel);
417                 }
418                 else
419                 {
420                         graphics.setFontColor(0x00, 0xff, 0x00, 0x00, 0x00, 0x00);
421                         graphics.drawString(_("Completed"), col2, y, TXT_RIGHT, panel);
422                 }
423         }
424
425         objective = (Objective*)map.objectiveList.getHead();
426
427         while (objective->next != NULL)
428         {
429                 objective = (Objective*)objective->next;
430
431                 y += 20;
432
433                 graphics.setFontColor(0xff, 0xff, 0xff, 0x00, 0x00, 0x00);
434                 
435                 if ((game.skill < 3) &&  (strstr(objective->description, "L.R.T.S.")) && (!gameData.completedWorld))
436                 {
437                         graphics.drawString(_("???? ???????? ????"), col1, y, TXT_LEFT, panel);
438                 }
439                 else
440                 {
441                         graphics.drawString(_(objective->description), col1, y, TXT_LEFT, panel);
442                 }
443                 
444                 // this is a fake objective (for the 4th Ancient Tomb)
445                 if (objective->targetValue == -1)
446                 {
447                         graphics.setFontColor(0xff, 0x00, 0x00, 0x00, 0x00, 0x00);
448                         graphics.drawString(_("Incomplete"), col2, y, TXT_RIGHT, panel);
449                 }
450                 else if (objective->currentValue < objective->targetValue)
451                 {
452                         graphics.setFontColor(0xff, 0x00, 0x00, 0x00, 0x00, 0x00);
453                         if (objective->targetValue == 1)
454                         {
455                                 graphics.drawString(_("Incomplete"), col2, y, TXT_RIGHT, panel);
456                         }
457                         else
458                         {
459                                 snprintf(message, sizeof message, "%d / %d", objective->currentValue, objective->targetValue);
460                                 graphics.drawString(message, col2, y, TXT_RIGHT, panel);
461                         }
462                 }
463                 else
464                 {
465                         graphics.setFontColor(0x00, 0xff, 0x00, 0x00, 0x00, 0x00);
466                         graphics.drawString(_("Completed"), col2, y, TXT_RIGHT, panel);
467                 }
468         }
469         
470         if (game.skill == 3)
471         {
472                 graphics.setFontColor(0xff, 0xff, 0x00, 0x00, 0x00, 0x00);
473                 snprintf(message, sizeof message, _("Time Limit - %d:%.2d Minutes"), map.remainingMinutes, map.remainingSeconds);
474                 graphics.drawString(message, 200, 260, TXT_CENTERED, panel);
475         }
476         
477         graphics.setFontColor(0xff, 0xff, 0xff, 0x00, 0x00, 0x00);
478         graphics.drawString(_("Press Fire to Continue"), 200, 280, TXT_CENTERED, panel);
479
480         engine.flushInput();
481         engine.clearInput();
482
483         int px, py;
484
485         map.getRandomEntityPosition(&px, &py);
486         map.getRandomEntityPosition(&player.tx, &player.ty);
487
488         player.x = px;
489         player.y = py;
490
491         unsigned int frameLimit = SDL_GetTicks() + 16;
492                 
493         while (true)
494         {
495                 if ((int)player.x < player.tx) player.x += 2;
496                 if ((int)player.x > player.tx) player.x -= 2;
497                 if ((int)player.y < player.ty) player.y += 2;
498                 if ((int)player.y > player.ty) player.y -= 2;
499
500                 if (Collision::collision(player.x, player.y, 5, 5, player.tx, player.ty, 5, 5))
501                         map.getRandomEntityPosition(&player.tx, &player.ty);
502
503                 engine.setPlayerPosition((int)player.x, (int)player.y, map.limitLeft, map.limitRight, map.limitUp, map.limitDown);
504
505                 doGameStuff();
506                 drawMapTopLayer();
507                 graphics.blit(panelBack, 320, 220, graphics.screen, true);
508                 graphics.blit(panel, 320, 220, graphics.screen, true);
509
510                 engine.delay(frameLimit);
511                 frameLimit = SDL_GetTicks() + 16;
512
513                 if (engine.userAccepts())
514                         break;
515         }
516
517         SDL_FreeSurface(panel);
518         SDL_FreeSurface(panelBack);
519
520         SDL_FillRect(graphics.screen, NULL, graphics.black);
521         graphics.delay(1000);
522 }
523
524 void beamInPlayer()
525 {
526         game.getCheckPoint(&player.x, &player.y);
527         
528         int beamInTime = 180;
529         
530         unsigned int frameLimit = SDL_GetTicks() + 16;
531         
532         audio.playSound(SND_TELEPORT1, CH_ANY);
533         
534         engine.setPlayerPosition((int)player.x, (int)player.y, map.limitLeft, map.limitRight, map.limitUp, map.limitDown);
535         
536         while (beamInTime > 0)
537         {
538                 engine.delay(frameLimit);
539                 frameLimit = SDL_GetTicks() + 16;
540                 
541                 doGameStuff();
542                 drawMapTopLayer();
543                 
544                 if ((beamInTime % 10) == 0)
545                         addTeleportParticles(player.x + 10, player.y + 10, 50, -1);
546                 
547                 beamInTime--;
548         }
549         
550         game.getCheckPoint(&player.x, &player.y);
551         
552         player.dx = 0;
553         player.dy = 0;
554         player.immune = 120;
555         player.environment = ENV_AIR;
556         player.oxygen = 7;
557         player.fuel = 7;
558         Math::removeBit(&player.flags, ENT_FLIES);
559 }
560
561 int doGame()
562 {
563         graphics.setFontSize(0);
564
565         SDL_FillRect(graphics.screen, NULL, graphics.black);
566         graphics.delay(1000);
567
568         Uint32 then, frames, frameLimit, millis;
569         Uint32 start, cur;
570
571         #if DEBUG
572         Uint32 now, frameCounter;
573         char fps[10];
574         strlcpy(fps, "fps", sizeof fps);
575         #endif
576
577         engine.messageTime = -1;
578         engine.messagePriority = -1;
579
580         audio.playMusic();
581         audio.playAmbiance();
582
583         if (!game.continueFromCheckPoint)
584         {
585                 player.health = -99;
586
587                 if ((!map.isBossMission) && (replayData.replayMode == REPLAY_MODE::NONE))
588                 {
589                         showMissionInformation();
590                 }
591
592                 game.levelsStarted++;
593         }
594         else
595         {
596                 game.useObjectiveCheckPoint();
597         }
598
599         player.setVelocity(0, 1);
600         player.baseThink = 60;
601         player.health = MAX_HEALTH;
602
603         if (game.continueFromCheckPoint)
604         {
605                 player.health = (MAX_HEALTH / 2);
606                 player.setSprites(graphics.getSprite("BobRight", true), graphics.getSprite("BobLeft", true), graphics.getSprite("BobSpin", true));
607         }
608         else
609         {
610                 player.currentWeapon = &weapon[WP_PISTOL];
611         }
612
613         game.resetMissionOver();
614
615         frameLimit = SDL_GetTicks() + 16;
616         frames = millis = 0;
617         start = then = SDL_GetTicks();
618 #ifdef DEBUG
619         frameCounter = SDL_GetTicks();
620 #endif
621
622         if ((strcmp(map.name, "Space Station") == 0) && (!game.continueFromCheckPoint))
623         {
624                 beamInPlayer();
625         }
626         else
627         {
628                 resetPlayer();
629         }
630
631         engine.flushInput();
632         engine.clearInput();
633
634         debug(("Map Clipping is %d %d %d %d\n", map.limitLeft, map.limitRight, map.limitUp, map.limitDown));
635
636         game.continueFromCheckPoint = false;
637
638         engine.paused = false;
639
640         while (true)
641         {
642                 ++frames;
643                 ++millis;
644                 cur = SDL_GetTicks();
645
646                 if (game.missionOverReason != MIS_PLAYEROUT)
647                 {
648                         engine.setPlayerPosition((int)player.x, (int)player.y, map.limitLeft, map.limitRight, map.limitUp, map.limitDown);
649                 }
650
651                 doSpawnPoints();
652                 doGameStuff();
653
654                 doPlayer();
655                 raiseWaterLevel();
656
657                 if ((player.environment == ENV_SLIME) || (player.environment == ENV_LAVA) || (player.health < 1))
658                 {
659                         if (player.health < 1)
660                         {
661                                 game.setMissionOver(MIS_PLAYERDEAD);
662                                 audio.fadeMusic();
663                                 audio.stopAmbiance();
664                         }
665                         else
666                         {
667                                 game.setMissionOver(MIS_PLAYEROUT);
668                                 player.immune = 130;
669                         }
670                 }
671
672                 if (config.isControl(CONTROL::MAP))
673                 {
674                         if (!map.isBossMission)
675                         {
676                                 showMap((int)(player.x / 32), (int)(player.y / 32));
677                         }
678                         else
679                         {
680                                 engine.setInfoMessage("Automap is not available!", 1, INFO_HINT);
681                         }
682                 }
683
684                 drawMapTopLayer();
685                 doStatusBar();
686                 doMusicInfo(cur - start);
687
688                 if ((engine.keyState[SDL_SCANCODE_ESCAPE]) && (game.missionOver == 0))
689                 {
690                         if (replayData.replayMode == REPLAY_MODE::NONE)
691                         {
692                                 showInGameOptions();
693                         }
694                         else
695                         {
696                                 exit(0);
697                         }
698                 }
699
700                 if (allObjectivesCompleted())
701                 {
702                         if (game.missionOver == 0)
703                         {
704                                 if (map.isBossMission)
705                                 {
706                                         map.killAllEnemies();
707                                 }
708                                 
709                                 audio.stopMusic();
710                                 audio.stopAmbiance();
711
712                                 game.setMissionOver(MIS_COMPLETE);
713                                 engine.setInfoMessage("All Required Objectives Met - Mission Complete", 10, INFO_OBJECTIVE);
714                         }
715                 }
716
717                 if (game.missionOver > 0)
718                 {
719                         game.missionOver--;
720                 
721                         if (game.missionOver == 0)
722                         {
723                                 if (game.missionOverReason == MIS_PLAYEROUT)
724                                 {
725                                         SDL_FillRect(graphics.screen, NULL, graphics.black);
726                                         graphics.updateScreen();
727                                         graphics.delay(1000);
728                                         engine.flushInput();
729                                         engine.clearInput();
730                                         resetPlayer();
731                                         game.resetMissionOver();
732                                 }
733                                 else
734                                 {
735                                         if (game.missionOverReason == MIS_COMPLETE)
736                                         {
737                                                 game.missionOver = MAX_FPS * 2;
738                                                 
739                                                 if (strcmp(map.name, "Space Station") != 0)
740                                                 {
741                                                         addTeleportParticles(player.x, player.y, 50, SND_TELEPORT3);
742                                                         dropCarriedItems();
743                                                         game.missionOverReason = MIS_PLAYERESCAPE;
744                                                 }
745                                                 else
746                                                 {
747                                                         break;
748                                                 }
749                                         }
750                                         else if (game.missionOverReason == MIS_GAMECOMPLETE)
751                                         {
752                                                 addTeleportParticles(player.x, player.y, 50, SND_TELEPORT3);
753                                                 game.missionOverReason = MIS_PLAYERESCAPE;
754                                                 game.missionOver = MAX_FPS * 4;
755                                         }
756                                         else
757                                         {
758                                                 if (replayData.replayMode != REPLAY_MODE::NONE)
759                                                 {
760                                                         exit(0);
761                                                 }
762                                         
763                                                 break;
764                                         }
765                                 }
766                         }
767                 }
768
769                 Math::limitInt(&(--game.lastComboTime), 0, 60);
770
771                 if (millis >= 60)
772                 {
773                         millis = 0;
774                         
775                         if ((game.missionOverReason == MIS_INPROGRESS) || (game.missionOverReason == MIS_PLAYEROUT))
776                         {
777                                 game.incrementMissionTime();
778                                 
779                                 if (game.skill == 3)
780                                 {
781                                         doTimeRemaining();
782                                 }
783                         }
784                 }
785
786                 if (engine.paused)
787                 {
788                         doPauseInfo();
789                         audio.pause();
790                 }
791
792                 while (engine.paused)
793                 {
794                         engine.getInput();
795                         config.populate();
796                         config.doPause();
797                         graphics.updateScreen();
798                         then = SDL_GetTicks();
799                         frames = 0;
800
801                         if (!engine.paused)
802                         {
803                                 audio.resume();
804                         }
805
806                         SDL_Delay(16);
807                 }
808                 
809                 if ((engine.keyState[SDL_SCANCODE_F3]) && (engine.cheatSkipLevel))
810                 {
811                         autoCompleteAllObjectives(true);
812                         engine.keyState[SDL_SCANCODE_F3] = 0;
813                         engine.setInfoMessage("Skipping Mission...", 2, INFO_OBJECTIVE);
814                 }
815                 
816                 #if DEBUG
817                 if (engine.keyState[SDL_SCANCODE_F1])
818                 {
819                         autoCompleteAllObjectives(false);
820                 }               
821                 #endif
822                 
823                 if (replayData.replayMode != REPLAY_MODE::PLAYBACK)
824                 {
825                         engine.delay(frameLimit);
826                 }
827                 else if (!replayData.fast)
828                 {
829                         engine.delay(frameLimit);
830                 }
831                 
832                 if (engine.keyState[SDL_SCANCODE_F5])
833                 {
834                         replayData.fast = !replayData.fast;
835                         engine.keyState[SDL_SCANCODE_F5] = 0;
836                 }
837                 
838                 frameLimit = SDL_GetTicks()  + 16;
839                 
840                 if (game.missionOverReason == MIS_GAMECOMPLETE)
841                         frameLimit = SDL_GetTicks() + 64;
842
843                 #if DEBUG
844                 static Graphics::SurfaceCache fpsCache;
845                 graphics.drawString(fps, 600, 30, true, graphics.screen, fpsCache);
846
847                 if (SDL_GetTicks() > frameCounter + 500)
848                 {
849                         now = SDL_GetTicks();
850                         snprintf(fps, sizeof fps, "%2.2f fps", ((double)frames*1000)/(now - then));
851                         then = frameCounter = SDL_GetTicks();
852                         frames = 0;
853                 }
854                 #endif
855         }
856
857         if (allObjectivesCompleted())
858         {
859                 if (strcmp(map.name, "Final Battle") == 0)
860                 {
861                         game.missionOverReason = MIS_GAMECOMPLETE;
862                 }
863                 else
864                 {
865                         game.missionOverReason = MIS_COMPLETE;
866                 }
867         }
868
869         switch (game.missionOverReason)
870         {
871                 case MIS_COMPLETE:
872                         if (strcmp(map.name, "Space Station"))
873                         {
874                                 graphics.delay(1000);
875                                 audio.loadMusic("music/grasslands");
876                                 audio.playMusic();
877                                 graphics.fadeToBlack();
878                                 
879                                 bool previouslyCompleted = gameData.stagePreviouslyCleared(game.stageName);
880                                 
881                                 showMissionClear();
882                                 
883                                 if (engine.practice)
884                                 {
885                                         return SECTION_TITLE;
886                                 }
887                                 
888                                 if (!previouslyCompleted)
889                                 {
890                                         checkEndCutscene();
891                                 }
892                                 return SECTION_HUB;
893                         }
894                         else
895                         {
896                                 graphics.fadeToBlack();
897                                 processPostMissionData();
898                                 saveGame();
899                                 game.setMapName("data/finalBattle");
900                                 game.setStageName("Final Battle");
901                                 return SECTION_GAME;
902                         }
903                         break;
904                         
905                 case MIS_GAMECOMPLETE:
906                         SDL_FillRect(graphics.screen, NULL, graphics.white);
907                         graphics.updateScreen();
908                         graphics.fadeToBlack();
909                         
910                         // we've finished the game. Extreme mode is now available! :)
911                         engine.extremeAvailable = true;
912                         map.clear();
913                         graphics.free();
914                         audio.free();
915                         checkEndCutscene();
916                         return SECTION_CREDITS;
917                         break;
918
919                 case MIS_TIMEUP:
920                         game.canContinue = 0;
921                 case MIS_PLAYERDEAD:
922                         if (player.health > -60)
923                         {
924                                 player.health = -99;
925                                 gibPlayer();
926                         }
927                         return SECTION_GAMEOVER;
928                         break;
929
930                 case MIS_PLAYERESCAPE:
931                         game.escapes++;
932                         if (gameData.stagePreviouslyCleared(game.stageName))
933                         {
934                                 processPostMissionData();
935                                 saveGame();
936                         }
937                         return SECTION_HUB;
938                         break;
939                         
940                 case MIS_PLAYERRESTART:
941                         clearAllMissionData();
942                         return SECTION_GAME;
943                         break;
944
945                 default:
946                         return SECTION_TITLE;
947                         break;
948         }
949
950         return SECTION_TITLE;
951 }