38f76fc7f6a1f7b760f5f1fd3a96ba4122f27171
[rocksndiamonds.git] / src / game_sp / MainGameLoop.c
1 // ----------------------------------------------------------------------------
2 // MainGameLoop.c
3 // ----------------------------------------------------------------------------
4
5 #include "MainGameLoop.h"
6
7 // static char *VB_Name = "modMainGameLoop";
8
9 // --- Option Explicit
10
11 int GameLoopRunning;
12 boolean bPlaying;
13 int LeadOutCounter, EnterRepeatCounter;
14 int ForcedExitFlag;
15 int ExitToMenuFlag;
16 int SavedGameFlag;
17 boolean UserDragFlag;
18 boolean AutoScrollFlag;
19
20 // ==========================================================================
21 //                              SUBROUTINE
22 // Play a game/demo
23 // ==========================================================================
24
25 int subMainGameLoop_Init()
26 {
27   int subMainGameLoop;
28
29   // int al, bx;
30   // int bx;
31 #if 0
32   TickCountObject Clock;
33   currency LastFrame;
34 #endif
35
36   if (DemoFlag != 0)
37   {
38 #if 0
39     printf("::: playing demo ...\n");
40 #endif
41
42     // EP set level success byte: demo, not game
43     WasDemoFlag = 1;
44     EP_GameDemoVar0DAA = 0; // demo
45   }
46   else // loc_g_1836:
47   {
48 #if 0
49     printf("::: playing game ...\n");
50 #endif
51
52     // EP set level success byte: game, not demo
53     WasDemoFlag = 0;
54     EP_GameDemoVar0DAA = 1; // game
55   }
56
57   // RestartGameLoop:
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???
66   //    Wend
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
71   //  End If
72
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.
76
77   RedDiskReleasePhase = 0; // (re-)enable red disk release
78   UpdatedFlag = 0;
79   GameLoopRunning = 1;
80   LevelStatus = 0;
81
82   return subMainGameLoop;
83 }
84
85 int subMainGameLoop_Main(byte action, boolean warp_mode)
86 {
87   int subMainGameLoop;
88   int bx;
89
90   // ----------------------------------------------------------------------------
91   // --------------------- START OF GAME-BUSY LOOP ------------------------------
92   // ----------------------------------------------------------------------------
93
94 #if 0
95 locRepeatMainGameLoop:                           // start repeating game loop
96 #endif
97
98   // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
99   // FS   synchronization
100   while (PauseMode != 0)
101   {
102     DoEvents();
103   }
104
105   do
106   {
107     DoEvents(); // user may klick on menus or move the window here ...
108   }
109 #if 1
110   while (0);
111 #else
112   while (Clock.TickDiffUS(LastFrame) < DeltaT); // wait till its time for the next frame
113 #endif
114
115   //   never any additional code between here!
116 #if 0
117   LastFrame = Clock.TickNow(); // store the frame time
118 #endif
119   //   never any additional code between here!
120
121
122
123 #if 0
124   if (! NoDisplayFlag) // copy the BackBuffer(=Stage) to visible screen
125     Stage.Blt();
126 #endif
127
128
129
130   // FS   end of synchronization
131   // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
132 #if 1
133   if (EndFlag)
134   {
135     // (should never happen)
136
137     // printf("::: EndFlag == True\n");
138
139     goto locExitMainGameLoop;
140   }
141 #else
142   if (EndFlag)
143     goto locExitMainGameLoop;
144 #endif
145
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!
149
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
157   //    Data_SubRest = 10
158   //    Call subRestoreFancy
159   //    Call subDisplayLevel         ' Paint (Init) game field
160   //    Call subConvertToEasySymbols ' Convert to easy symbols
161   //  End If
162
163   // loc_g_186F:
164
165   subProcessKeyboardInput(action);              // Check keyboard, act on keys
166
167   // 'HACK:
168   //  TimerVar = TimerVar + 1
169   //  DoEvents
170   //  GoTo loc_g_186F
171   // 'END HACK
172   // If RecordDemoFlag = 1 Then GoTo RestartGameLoop
173
174   // ----------------------------------------------------------------------------
175   //
176
177 #if 0
178   printf("::: >>>>>>>>>> MainGameLoop.c: subDoGameStuff() START\n");
179 #endif
180
181   subDoGameStuff();                 // do all game stuff
182
183 #if 0
184   printf("::: <<<<<<<<<< MainGameLoop.c: subDoGameStuff() END\n");
185 #endif
186
187   //
188   // ----------------------------------------------------------------------------
189
190   //  Call subDisplayPlayingTime                 ' playing time on screen
191
192   subCheckRestoreRedDiskCountDisplay();    // Restore panel: red-disk hole
193
194   subRedDiskReleaseExplosion();       // Red Disk release and explode
195   subFollowUpExplosions();  // every explosion may cause up to 8 following explosions
196
197   bx = subCalculateScreenScrollPos();     // calculate screen start addrs
198
199   ScreenPosition = bx;
200
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)
205   {
206 #if 0
207     printf("::: MainGameLoop.c: subMainGameLoop(): %d, %d\n", ScreenScrollXPos, ScreenScrollYPos);
208 #endif
209
210     ScrollTowards(ScreenScrollXPos, ScreenScrollYPos);
211   }
212
213 #if 1
214   if (ForcedExitFlag != 0) // Forced Exit?' yes--exit!
215   {
216     // (should never happen)
217
218     // printf("::: ForcedExitFlag == True\n");
219
220     goto locExitMainGameLoop;
221   }
222 #else
223   if (ForcedExitFlag != 0) // Forced Exit?' yes--exit!
224     goto locExitMainGameLoop;
225 #endif
226
227   TimerVar = TimerVar + 1;
228
229 #if 0
230   if (bCapturePane)
231     MainForm.SaveSnapshot(TimerVar);
232 #endif
233
234   //  If Not NoDisplayFlag Then
235   //    With MainForm.lblFrameCount
236   //      .Caption = TimerVar
237   //      .Refresh
238   //    End With
239   //  End If
240
241 #if 1
242   if (ExitToMenuFlag == 1)
243   {
244     // happens when demo ends or when Murphy enters exit (to be checked)
245
246 #if 0
247     printf("::: ExitToMenuFlag == True\n");
248 #endif
249
250 #if 0
251     goto locExitMainGameLoop;
252 #endif
253   }
254 #else
255   if (ExitToMenuFlag == 1)
256     goto locExitMainGameLoop;
257 #endif
258
259 #if 1
260   if (LeadOutCounter == 0) // no lead-out: game busy
261     return subMainGameLoop;
262 #else
263   if (LeadOutCounter == 0) // no lead-out: game busy
264     goto locRepeatMainGameLoop;
265 #endif
266
267   // ----------------------------------------------------------------------------
268   // ---------------------- END OF GAME-BUSY LOOP -------------------------------
269   // ----------------------------------------------------------------------------
270   LeadOutCounter = LeadOutCounter - 1;             // do more lead-out after quit
271
272 #if 0
273   printf("::: LeadOutCounter == %d\n", LeadOutCounter);
274 #endif
275
276 #if 1
277   if (LeadOutCounter != 0) // lead-out not ready: more
278     return subMainGameLoop;
279 #else
280   if (LeadOutCounter != 0) // lead-out not ready: more
281     goto locRepeatMainGameLoop;
282 #endif
283
284   // lead-out done: exit now
285   // ---------------------- END OF GAME-BUSY LOOP (including lead-out) ----------
286
287 locExitMainGameLoop:
288
289 #if 1
290   printf("::: locExitMainGameLoop reached [%d]\n", LeadOutCounter);
291   printf("::: [KillMurphyFlag == %d]\n", KillMurphyFlag);
292 #endif
293
294 #if 1
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;
298 #endif
299
300 #if 1
301   return subMainGameLoop;
302 #endif
303
304
305
306   do
307   {
308     DoEvents(); // user may klick on menus or move the window here ...
309   }
310 #if 1
311   while (0);
312 #else
313   while (Clock.TickDiffUS(LastFrame) < DeltaT); // wait till its time for the next frame
314 #endif
315
316   Stage.Blt(); // blit the last frame
317   GameLoopRunning = 0;
318
319 #if 0
320   MainForm.menStop_Click();
321   MainForm.PanelVisible = True;
322 #endif
323
324   // If DemoRecordingFlag <> 0 Then Call subCloseDemoRecordingFile ' Demo recording on? -> close opened demo file (w)
325   if (SavedGameFlag != 0) // after savegame: no update!
326   {
327     SavedGameFlag = 0;
328     return subMainGameLoop;
329   }
330
331   SavedGameFlag = 0;
332   if (UpdateTimeFlag == 0) // update time?
333     return subMainGameLoop;
334
335   if (UpdatedFlag == 0) // update playing time
336     subUpdatePlayingTime();
337
338   return subMainGameLoop;
339 } // subMainGameLoop
340
341 #if 0
342
343 int subMainGameLoop()
344 {
345   int subMainGameLoop;
346
347   // int al, bx;
348   int bx;
349 #if 0
350   TickCountObject Clock;
351   currency LastFrame;
352 #endif
353
354   if (DemoFlag != 0)
355   {
356 #if 1
357     printf("::: playing demo ...\n");
358 #endif
359
360     // EP set level success byte: demo, not game
361     WasDemoFlag = 1;
362     EP_GameDemoVar0DAA = 0; // demo
363   }
364   else // loc_g_1836:
365   {
366 #if 1
367     printf("::: playing game ...\n");
368 #endif
369
370     // EP set level success byte: game, not demo
371     WasDemoFlag = 0;
372     EP_GameDemoVar0DAA = 1; // game
373   }
374
375   // RestartGameLoop:
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???
384   //    Wend
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
389   //  End If
390
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.
394
395   RedDiskReleasePhase = 0; // (re-)enable red disk release
396   UpdatedFlag = 0;
397   GameLoopRunning = 1;
398   LevelStatus = 0;
399
400   // ----------------------------------------------------------------------------
401   // --------------------- START OF GAME-BUSY LOOP ------------------------------
402   // ----------------------------------------------------------------------------
403
404 locRepeatMainGameLoop:                           // start repeating game loop
405
406   // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
407   // FS   synchronization
408   while (PauseMode != 0)
409   {
410     DoEvents();
411   }
412
413   do
414   {
415     DoEvents(); // user may klick on menus or move the window here ...
416   }
417 #if 1
418   while (0);
419 #else
420   while (Clock.TickDiffUS(LastFrame) < DeltaT); // wait till its time for the next frame
421 #endif
422
423   //   never any additional code between here!
424 #if 0
425   LastFrame = Clock.TickNow(); // store the frame time
426 #endif
427   //   never any additional code between here!
428   if (! NoDisplayFlag) // copy the BackBuffer(=Stage) to visible screen
429     Stage.Blt();
430
431   // FS   end of synchronization
432   // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
433   if (EndFlag)
434     goto locExitMainGameLoop;
435
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!
439
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
447   //    Data_SubRest = 10
448   //    Call subRestoreFancy
449   //    Call subDisplayLevel         ' Paint (Init) game field
450   //    Call subConvertToEasySymbols ' Convert to easy symbols
451   //  End If
452
453   // loc_g_186F:
454
455   subProcessKeyboardInput();                 // Check keyboard, act on keys
456
457   // 'HACK:
458   //  TimerVar = TimerVar + 1
459   //  DoEvents
460   //  GoTo loc_g_186F
461   // 'END HACK
462   // If RecordDemoFlag = 1 Then GoTo RestartGameLoop
463
464   // ----------------------------------------------------------------------------
465   //
466
467 #if 0
468   printf("::: >>>>>>>>>> MainGameLoop.c: subDoGameStuff() START\n");
469 #endif
470
471   subDoGameStuff();                 // do all game stuff
472
473 #if 0
474   printf("::: <<<<<<<<<< MainGameLoop.c: subDoGameStuff() END\n");
475 #endif
476
477   //
478   // ----------------------------------------------------------------------------
479
480   //  Call subDisplayPlayingTime                 ' playing time on screen
481
482   subCheckRestoreRedDiskCountDisplay();    // Restore panel: red-disk hole
483
484   subRedDiskReleaseExplosion();       // Red Disk release and explode
485   subFollowUpExplosions();  // every explosion may cause up to 8 following explosions
486
487   bx = subCalculateScreenScrollPos();     // calculate screen start addrs
488
489   ScreenPosition = bx;
490
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)
495   {
496 #if 0
497     printf("::: MainGameLoop.c: subMainGameLoop(): %d, %d\n", ScreenScrollXPos, ScreenScrollYPos);
498 #endif
499
500     ScrollTowards(ScreenScrollXPos, ScreenScrollYPos);
501   }
502
503   if (ForcedExitFlag != 0) // Forced Exit?' yes--exit!
504     goto locExitMainGameLoop;
505
506   TimerVar = TimerVar + 1;
507
508 #if 0
509   if (bCapturePane)
510     MainForm.SaveSnapshot(TimerVar);
511 #endif
512
513   //  If Not NoDisplayFlag Then
514   //    With MainForm.lblFrameCount
515   //      .Caption = TimerVar
516   //      .Refresh
517   //    End With
518   //  End If
519   if (ExitToMenuFlag == 1)
520     goto locExitMainGameLoop;
521
522   if (LeadOutCounter == 0) // no lead-out: game busy
523     goto locRepeatMainGameLoop;
524
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;
531
532   // lead-out done: exit now
533   // ---------------------- END OF GAME-BUSY LOOP (including lead-out) ----------
534
535 locExitMainGameLoop:
536   do
537   {
538     DoEvents(); // user may klick on menus or move the window here ...
539   }
540 #if 1
541   while (0);
542 #else
543   while (Clock.TickDiffUS(LastFrame) < DeltaT); // wait till its time for the next frame
544 #endif
545
546   Stage.Blt(); // blit the last frame
547   GameLoopRunning = 0;
548
549 #if 0
550   MainForm.menStop_Click();
551   MainForm.PanelVisible = True;
552 #endif
553
554   // If DemoRecordingFlag <> 0 Then Call subCloseDemoRecordingFile ' Demo recording on? -> close opened demo file (w)
555   if (SavedGameFlag != 0) // after savegame: no update!
556   {
557     SavedGameFlag = 0;
558     return subMainGameLoop;
559   }
560
561   SavedGameFlag = 0;
562   if (UpdateTimeFlag == 0) // update time?
563     return subMainGameLoop;
564
565   if (UpdatedFlag == 0) // update playing time
566     subUpdatePlayingTime();
567
568
569   return subMainGameLoop;
570 } // subMainGameLoop
571
572 #endif
573
574 void subUpdatePlayingTime()
575 {
576 }
577
578 int subCalculateScreenScrollPos()
579 {
580   int subCalculateScreenScrollPos;
581
582   int ax, Ay;
583
584 #if 1
585   int jump_pos = TILEX / 2;
586
587   if (MurphyScreenXPos < -jump_pos)
588   {
589     MurphyScreenXPos = FieldWidth * TILEX + MurphyScreenXPos;
590     MurphyScreenYPos -= TILEY;
591   }
592   else if (MurphyScreenXPos >= FieldWidth * TILEX - jump_pos)
593   {
594     MurphyScreenXPos = MurphyScreenXPos - FieldWidth * TILEX;
595     MurphyScreenYPos += TILEY;
596   }
597 #endif
598
599   if (ExplosionShake != 0)
600   {
601     subGetRandomNumber();
602   }
603
604   {
605     ax = MainForm.picPane.Width / 2;
606     Ay = MainForm.picPane.Height / 2;
607   }
608
609 #if 1
610   ScreenScrollXPos = Stretch * (MurphyScreenXPos + 16) - ax;
611   ScreenScrollYPos = Stretch * (MurphyScreenYPos + 16) - Ay;
612 #else
613   ScreenScrollXPos = Stretch * (MurphyScreenXPos + 8) - ax;
614   ScreenScrollYPos = Stretch * (MurphyScreenYPos + 8) - Ay;
615 #endif
616
617 #if 0
618   printf("::: MainGameLoop.c: subCalculateScreenScrollPos(): %d, %d [%d, %d] -> %d, %d\n",
619          MainForm.picPane.Width, MainForm.picPane.Height,
620          MurphyScreenXPos, MurphyScreenYPos,
621          ScreenScrollXPos, ScreenScrollYPos);
622 #endif
623
624   return subCalculateScreenScrollPos;
625 }