1 // ----------------------------------------------------------------------------
3 // ----------------------------------------------------------------------------
5 #include "MainGameLoop.h"
7 // static char *VB_Name = "modMainGameLoop";
13 int LeadOutCounter, EnterRepeatCounter;
18 boolean AutoScrollFlag;
20 // ==========================================================================
23 // ==========================================================================
25 int subMainGameLoop_Init()
32 TickCountObject Clock;
39 printf("::: playing demo ...\n");
42 // EP set level success byte: demo, not game
44 EP_GameDemoVar0DAA = 0; // demo
49 printf("::: playing game ...\n");
52 // EP set level success byte: game, not demo
54 EP_GameDemoVar0DAA = 1; // game
58 // If RecordDemoFlag = 1 Then
59 // RecordDemoFlag = 0 ' clear Demo Recording flag
60 // Call subDisplayPlayingTime ' playing time on screen
61 // ' Record key still pressed?' >= (Ctrl-)F1 and <= (Ctrl-)F10
62 // While &H3B <= KeyScanCode7 And KeyScanCode7 <= &H44
63 // ' yes -> wait until released
64 // ' should we DoEvents here???? ... depends on how ... but yes!
65 // ' ...or we can rather poll the keyboardstate inside this loop???
67 // Call subInitGameConditions ' Init game conditions (vars)
68 // If MusicOnFlag = 0 Then Call subMusicInit
69 // WasDemoFlag = 0 ' no demo anymore
70 // EP_GameDemoVar0DAA = 1 ' force game
73 // This was a bug in the original Supaplex: sometimes red disks could not
74 // be released. This happened If Murphy was killed DURING a red disk release
75 // and the next try started.
77 RedDiskReleasePhase = 0; // (re-)enable red disk release
82 return subMainGameLoop;
85 int subMainGameLoop_Main(byte action, boolean warp_mode)
90 // ----------------------------------------------------------------------------
91 // --------------------- START OF GAME-BUSY LOOP ------------------------------
92 // ----------------------------------------------------------------------------
95 locRepeatMainGameLoop: // start repeating game loop
98 // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
100 while (PauseMode != 0)
107 DoEvents(); // user may klick on menus or move the window here ...
112 while (Clock.TickDiffUS(LastFrame) < DeltaT); // wait till its time for the next frame
115 // never any additional code between here!
117 LastFrame = Clock.TickNow(); // store the frame time
119 // never any additional code between here!
124 if (! NoDisplayFlag) // copy the BackBuffer(=Stage) to visible screen
130 // FS end of synchronization
131 // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
135 // (should never happen)
137 // printf("::: EndFlag == True\n");
139 goto locExitMainGameLoop;
143 goto locExitMainGameLoop;
146 // If DemoFlag = 0 Then Call subCheckJoystick ' check joystick
147 // bx = subCheckRightMouseButton() ' check (right) mouse button
148 // If bx = 2 And LeadOutCounter < 1 Then KillMurphyFlag = 1 ' lead-out busy after quit? -> kill Murphy!
150 // If DebugVersionFlag <> 0 Then ' debug mode on?
151 // If Data_SubRest <> 0 Then Data_SubRest = Data_SubRest - 1
152 // If keyEnter <> 0 Then GoTo loc_g_186F ' Was it the Enter key? -> yes--skip! No mouse!
153 // ' fixes ENTER bug If no mouse driver!
154 // If bx <> 1 Then GoTo loc_g_186F ' Left button=Init game field
155 // ' Also Enter If no mouse!
156 // If Data_SubRest <> 0 Then GoTo loc_g_186F
158 // Call subRestoreFancy
159 // Call subDisplayLevel ' Paint (Init) game field
160 // Call subConvertToEasySymbols ' Convert to easy symbols
165 subProcessKeyboardInput(action); // Check keyboard, act on keys
168 // TimerVar = TimerVar + 1
172 // If RecordDemoFlag = 1 Then GoTo RestartGameLoop
174 // ----------------------------------------------------------------------------
178 printf("::: >>>>>>>>>> MainGameLoop.c: subDoGameStuff() START\n");
181 subDoGameStuff(); // do all game stuff
184 printf("::: <<<<<<<<<< MainGameLoop.c: subDoGameStuff() END\n");
188 // ----------------------------------------------------------------------------
190 // Call subDisplayPlayingTime ' playing time on screen
192 subCheckRestoreRedDiskCountDisplay(); // Restore panel: red-disk hole
194 subRedDiskReleaseExplosion(); // Red Disk release and explode
195 subFollowUpExplosions(); // every explosion may cause up to 8 following explosions
197 bx = subCalculateScreenScrollPos(); // calculate screen start addrs
201 // Now new X and new Y are calculated, and bx = screen position = ScreenPosition
202 data_h_Ytmp = ScreenScrollYPos; // copy Y for next soft scroll
203 data_h_Xtmp = ScreenScrollXPos; // copy X for next soft scroll
204 if ((! UserDragFlag) && AutoScrollFlag)
207 printf("::: MainGameLoop.c: subMainGameLoop(): %d, %d\n", ScreenScrollXPos, ScreenScrollYPos);
210 ScrollTowards(ScreenScrollXPos, ScreenScrollYPos);
214 if (ForcedExitFlag != 0) // Forced Exit?' yes--exit!
216 // (should never happen)
218 // printf("::: ForcedExitFlag == True\n");
220 goto locExitMainGameLoop;
223 if (ForcedExitFlag != 0) // Forced Exit?' yes--exit!
224 goto locExitMainGameLoop;
227 TimerVar = TimerVar + 1;
231 MainForm.SaveSnapshot(TimerVar);
234 // If Not NoDisplayFlag Then
235 // With MainForm.lblFrameCount
236 // .Caption = TimerVar
242 if (ExitToMenuFlag == 1)
244 // happens when demo ends or when Murphy enters exit (to be checked)
247 printf("::: ExitToMenuFlag == True\n");
251 goto locExitMainGameLoop;
255 if (ExitToMenuFlag == 1)
256 goto locExitMainGameLoop;
260 if (LeadOutCounter == 0) // no lead-out: game busy
261 return subMainGameLoop;
263 if (LeadOutCounter == 0) // no lead-out: game busy
264 goto locRepeatMainGameLoop;
267 // ----------------------------------------------------------------------------
268 // ---------------------- END OF GAME-BUSY LOOP -------------------------------
269 // ----------------------------------------------------------------------------
270 LeadOutCounter = LeadOutCounter - 1; // do more lead-out after quit
273 printf("::: LeadOutCounter == %d\n", LeadOutCounter);
277 if (LeadOutCounter != 0) // lead-out not ready: more
278 return subMainGameLoop;
280 if (LeadOutCounter != 0) // lead-out not ready: more
281 goto locRepeatMainGameLoop;
284 // lead-out done: exit now
285 // ---------------------- END OF GAME-BUSY LOOP (including lead-out) ----------
290 printf("::: locExitMainGameLoop reached [%d]\n", LeadOutCounter);
291 printf("::: [KillMurphyFlag == %d]\n", KillMurphyFlag);
295 /* if the game is not won when reaching this point, then it is lost */
296 if (!game_sp_info.LevelSolved)
297 game_sp_info.GameOver = TRUE;
301 return subMainGameLoop;
308 DoEvents(); // user may klick on menus or move the window here ...
313 while (Clock.TickDiffUS(LastFrame) < DeltaT); // wait till its time for the next frame
316 Stage.Blt(); // blit the last frame
320 MainForm.menStop_Click();
321 MainForm.PanelVisible = True;
324 // If DemoRecordingFlag <> 0 Then Call subCloseDemoRecordingFile ' Demo recording on? -> close opened demo file (w)
325 if (SavedGameFlag != 0) // after savegame: no update!
328 return subMainGameLoop;
332 if (UpdateTimeFlag == 0) // update time?
333 return subMainGameLoop;
335 if (UpdatedFlag == 0) // update playing time
336 subUpdatePlayingTime();
338 return subMainGameLoop;
343 int subMainGameLoop()
350 TickCountObject Clock;
357 printf("::: playing demo ...\n");
360 // EP set level success byte: demo, not game
362 EP_GameDemoVar0DAA = 0; // demo
367 printf("::: playing game ...\n");
370 // EP set level success byte: game, not demo
372 EP_GameDemoVar0DAA = 1; // game
376 // If RecordDemoFlag = 1 Then
377 // RecordDemoFlag = 0 ' clear Demo Recording flag
378 // Call subDisplayPlayingTime ' playing time on screen
379 // ' Record key still pressed?' >= (Ctrl-)F1 and <= (Ctrl-)F10
380 // While &H3B <= KeyScanCode7 And KeyScanCode7 <= &H44
381 // ' yes -> wait until released
382 // ' should we DoEvents here???? ... depends on how ... but yes!
383 // ' ...or we can rather poll the keyboardstate inside this loop???
385 // Call subInitGameConditions ' Init game conditions (vars)
386 // If MusicOnFlag = 0 Then Call subMusicInit
387 // WasDemoFlag = 0 ' no demo anymore
388 // EP_GameDemoVar0DAA = 1 ' force game
391 // This was a bug in the original Supaplex: sometimes red disks could not
392 // be released. This happened If Murphy was killed DURING a red disk release
393 // and the next try started.
395 RedDiskReleasePhase = 0; // (re-)enable red disk release
400 // ----------------------------------------------------------------------------
401 // --------------------- START OF GAME-BUSY LOOP ------------------------------
402 // ----------------------------------------------------------------------------
404 locRepeatMainGameLoop: // start repeating game loop
406 // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
407 // FS synchronization
408 while (PauseMode != 0)
415 DoEvents(); // user may klick on menus or move the window here ...
420 while (Clock.TickDiffUS(LastFrame) < DeltaT); // wait till its time for the next frame
423 // never any additional code between here!
425 LastFrame = Clock.TickNow(); // store the frame time
427 // never any additional code between here!
428 if (! NoDisplayFlag) // copy the BackBuffer(=Stage) to visible screen
431 // FS end of synchronization
432 // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
434 goto locExitMainGameLoop;
436 // If DemoFlag = 0 Then Call subCheckJoystick ' check joystick
437 // bx = subCheckRightMouseButton() ' check (right) mouse button
438 // If bx = 2 And LeadOutCounter < 1 Then KillMurphyFlag = 1 ' lead-out busy after quit? -> kill Murphy!
440 // If DebugVersionFlag <> 0 Then ' debug mode on?
441 // If Data_SubRest <> 0 Then Data_SubRest = Data_SubRest - 1
442 // If keyEnter <> 0 Then GoTo loc_g_186F ' Was it the Enter key? -> yes--skip! No mouse!
443 // ' fixes ENTER bug If no mouse driver!
444 // If bx <> 1 Then GoTo loc_g_186F ' Left button=Init game field
445 // ' Also Enter If no mouse!
446 // If Data_SubRest <> 0 Then GoTo loc_g_186F
448 // Call subRestoreFancy
449 // Call subDisplayLevel ' Paint (Init) game field
450 // Call subConvertToEasySymbols ' Convert to easy symbols
455 subProcessKeyboardInput(); // Check keyboard, act on keys
458 // TimerVar = TimerVar + 1
462 // If RecordDemoFlag = 1 Then GoTo RestartGameLoop
464 // ----------------------------------------------------------------------------
468 printf("::: >>>>>>>>>> MainGameLoop.c: subDoGameStuff() START\n");
471 subDoGameStuff(); // do all game stuff
474 printf("::: <<<<<<<<<< MainGameLoop.c: subDoGameStuff() END\n");
478 // ----------------------------------------------------------------------------
480 // Call subDisplayPlayingTime ' playing time on screen
482 subCheckRestoreRedDiskCountDisplay(); // Restore panel: red-disk hole
484 subRedDiskReleaseExplosion(); // Red Disk release and explode
485 subFollowUpExplosions(); // every explosion may cause up to 8 following explosions
487 bx = subCalculateScreenScrollPos(); // calculate screen start addrs
491 // Now new X and new Y are calculated, and bx = screen position = ScreenPosition
492 data_h_Ytmp = ScreenScrollYPos; // copy Y for next soft scroll
493 data_h_Xtmp = ScreenScrollXPos; // copy X for next soft scroll
494 if ((! UserDragFlag) && AutoScrollFlag)
497 printf("::: MainGameLoop.c: subMainGameLoop(): %d, %d\n", ScreenScrollXPos, ScreenScrollYPos);
500 ScrollTowards(ScreenScrollXPos, ScreenScrollYPos);
503 if (ForcedExitFlag != 0) // Forced Exit?' yes--exit!
504 goto locExitMainGameLoop;
506 TimerVar = TimerVar + 1;
510 MainForm.SaveSnapshot(TimerVar);
513 // If Not NoDisplayFlag Then
514 // With MainForm.lblFrameCount
515 // .Caption = TimerVar
519 if (ExitToMenuFlag == 1)
520 goto locExitMainGameLoop;
522 if (LeadOutCounter == 0) // no lead-out: game busy
523 goto locRepeatMainGameLoop;
525 // ----------------------------------------------------------------------------
526 // ---------------------- END OF GAME-BUSY LOOP -------------------------------
527 // ----------------------------------------------------------------------------
528 LeadOutCounter = LeadOutCounter - 1; // do more lead-out after quit
529 if (LeadOutCounter != 0) // lead-out not ready: more
530 goto locRepeatMainGameLoop;
532 // lead-out done: exit now
533 // ---------------------- END OF GAME-BUSY LOOP (including lead-out) ----------
538 DoEvents(); // user may klick on menus or move the window here ...
543 while (Clock.TickDiffUS(LastFrame) < DeltaT); // wait till its time for the next frame
546 Stage.Blt(); // blit the last frame
550 MainForm.menStop_Click();
551 MainForm.PanelVisible = True;
554 // If DemoRecordingFlag <> 0 Then Call subCloseDemoRecordingFile ' Demo recording on? -> close opened demo file (w)
555 if (SavedGameFlag != 0) // after savegame: no update!
558 return subMainGameLoop;
562 if (UpdateTimeFlag == 0) // update time?
563 return subMainGameLoop;
565 if (UpdatedFlag == 0) // update playing time
566 subUpdatePlayingTime();
569 return subMainGameLoop;
574 void subUpdatePlayingTime()
578 int subCalculateScreenScrollPos()
580 int subCalculateScreenScrollPos;
585 int jump_pos = TILEX / 2;
587 if (MurphyScreenXPos < -jump_pos)
589 MurphyScreenXPos = FieldWidth * TILEX + MurphyScreenXPos;
590 MurphyScreenYPos -= TILEY;
592 else if (MurphyScreenXPos >= FieldWidth * TILEX - jump_pos)
594 MurphyScreenXPos = MurphyScreenXPos - FieldWidth * TILEX;
595 MurphyScreenYPos += TILEY;
599 if (ExplosionShake != 0)
601 subGetRandomNumber();
603 // printf("::: ExplosionShake [%d]\n", FrameCounter);
607 ax = MainForm.picPane.Width / 2;
608 Ay = MainForm.picPane.Height / 2;
612 ScreenScrollXPos = Stretch * (MurphyScreenXPos + 16) - ax;
613 ScreenScrollYPos = Stretch * (MurphyScreenYPos + 16) - Ay;
615 ScreenScrollXPos = Stretch * (MurphyScreenXPos + 8) - ax;
616 ScreenScrollYPos = Stretch * (MurphyScreenYPos + 8) - Ay;
620 printf("::: MainGameLoop.c: subCalculateScreenScrollPos(): %d, %d [%d, %d] -> %d, %d\n",
621 MainForm.picPane.Width, MainForm.picPane.Height,
622 MurphyScreenXPos, MurphyScreenYPos,
623 ScreenScrollXPos, ScreenScrollYPos);
626 return subCalculateScreenScrollPos;