]> 4ch.mooo.com Git - 16.git/blob - 16/keen456/KEEN4-6/CK_GAME.C
extrcted keen code remake
[16.git] / 16 / keen456 / KEEN4-6 / CK_GAME.C
1 /* Reconstructed Commander Keen 4-6 Source Code\r
2  * Copyright (C) 2021 K1n9_Duk3\r
3  *\r
4  * This file is loosely based on:\r
5  * Keen Dreams Source Code\r
6  * Copyright (C) 2014 Javier M. Chavez\r
7  *\r
8  * This program is free software; you can redistribute it and/or modify\r
9  * it under the terms of the GNU General Public License as published by\r
10  * the Free Software Foundation; either version 2 of the License, or\r
11  * (at your option) any later version.\r
12  *\r
13  * This program is distributed in the hope that it will be useful,\r
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
16  * GNU General Public License for more details.\r
17  *\r
18  * You should have received a copy of the GNU General Public License along\r
19  * with this program; if not, write to the Free Software Foundation, Inc.,\r
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
21  */\r
22 \r
23 #include "CK_DEF.H"\r
24 \r
25 /*\r
26 =============================================================================\r
27 \r
28                                                  GLOBAL VARIABLES\r
29 \r
30 =============================================================================\r
31 */\r
32 \r
33 Uint16 fadecount;\r
34 Sint16 levelcompleted;\r
35 Sint32 chunkcount, chunkmax, handpic;\r
36 \r
37 /*\r
38 =============================================================================\r
39 \r
40                                                  LOCAL VARIABLES\r
41 \r
42 =============================================================================\r
43 */\r
44 \r
45 void FadeAndUnhook(void);\r
46 \r
47 //===========================================================================\r
48 \r
49 /*\r
50 ============================\r
51 =\r
52 = FreeGraphics\r
53 =\r
54 ============================\r
55 */\r
56 \r
57 void FreeGraphics(void)\r
58 {\r
59         Sint16 i;\r
60         for (i=STARTSPRITES; i<STARTSPRITES+NUMSPRITES; i++)\r
61         {\r
62                 if (grsegs[i])\r
63                 {\r
64                         MM_SetPurge(&grsegs[i], PURGE_LAST);\r
65                 }\r
66         }\r
67         for (i=STARTTILE16; i<STARTEXTERNS; i++)\r
68         {\r
69                 if (grsegs[i])\r
70                 {\r
71                         MM_SetPurge(&grsegs[i], PURGE_LAST);\r
72                 }\r
73         }\r
74 }\r
75 \r
76 //===========================================================================\r
77 \r
78 /*\r
79 =====================\r
80 =\r
81 = NewGame\r
82 =\r
83 = Set up new game to start from the beginning\r
84 =\r
85 =====================\r
86 */\r
87 \r
88 void NewGame(void)\r
89 {\r
90         memset(&gamestate, 0, sizeof(gamestate));\r
91         gamestate.nextextra = 20000;\r
92         gamestate.lives = 3;\r
93         gamestate.ammo = 5;\r
94 }\r
95 \r
96 //===========================================================================\r
97 \r
98 #ifndef KEEN5\r
99 /*\r
100 ============================\r
101 =\r
102 = GameOver\r
103 =\r
104 ============================\r
105 */\r
106 \r
107 void GameOver(void)\r
108 {\r
109         VW_FixRefreshBuffer();\r
110         US_CenterWindow(16, 3);\r
111         US_PrintCentered("Game Over!");\r
112         VW_UpdateScreen();\r
113         IN_ClearKeysDown();\r
114         IN_UserInput(4*TickBase, false);\r
115 }\r
116 #endif\r
117 \r
118 //===========================================================================\r
119 \r
120 /*\r
121 ============================\r
122 =\r
123 = SaveTheGame\r
124 =\r
125 ============================\r
126 */\r
127 \r
128 #define RLETAG 0xABCD\r
129 \r
130 boolean SaveTheGame(Sint16 handle)\r
131 {\r
132         Uint16  i,compressed,expanded;\r
133         objtype *ob;\r
134         memptr  bigbuffer;\r
135 \r
136         gamestate.riding = NULL;\r
137 \r
138         if (!CA_FarWrite(handle, (byte far *)&gamestate, sizeof(gamestate)))\r
139                 return false;\r
140 \r
141         expanded = mapwidth * mapheight * 2;\r
142         MM_GetPtr(&bigbuffer, expanded);\r
143 \r
144         for (i = 0; i < 3; i++)\r
145         {\r
146                 compressed = CA_RLEWCompress(mapsegs[i], expanded, (Uint16 huge *)bigbuffer+1, RLETAG);\r
147                 *(Uint16 huge *)bigbuffer = compressed;\r
148                 if (!CA_FarWrite(handle, bigbuffer, compressed+2))\r
149                 {\r
150                         MM_FreePtr(&bigbuffer);\r
151                         return false;\r
152                 }\r
153         }\r
154         for (ob = player; ob; ob=ob->next)\r
155         {\r
156                 if (!CA_FarWrite(handle, (byte far *)ob, sizeof(objtype)))\r
157                 {\r
158                         MM_FreePtr(&bigbuffer);\r
159                         return false;\r
160                 }\r
161         }\r
162         MM_FreePtr(&bigbuffer);\r
163         return true;\r
164 }\r
165 \r
166 //===========================================================================\r
167 \r
168 /*\r
169 ============================\r
170 =\r
171 = LoadTheGame\r
172 =\r
173 ============================\r
174 */\r
175 \r
176 boolean LoadTheGame(Sint16 handle)\r
177 {\r
178         Uint16  i;\r
179         objtype *prev,*next,*followed;\r
180         Uint16  compressed,expanded;\r
181         memptr  bigbuffer;\r
182 #ifdef KEEN5\r
183         Sint16  numfuses;\r
184 #endif\r
185 \r
186         if (!CA_FarRead(handle, (byte far *)&gamestate, sizeof(gamestate)))\r
187                 return false;\r
188 \r
189 #ifdef KEEN5\r
190         //\r
191         // remember the fuses value for later - SetupGameLevel calls\r
192         // ScanInfoPlane, which resets this part of the gamestate\r
193         //\r
194         numfuses = gamestate.numfuses;\r
195 #endif\r
196 \r
197         ca_levelbit >>= 1;\r
198         ca_levelnum--;\r
199         SetupGameLevel(false);\r
200         if (mmerror)\r
201         {\r
202                 mmerror = false;\r
203                 US_CenterWindow(20, 8);\r
204                 PrintY += 20;\r
205                 US_CPrint("Not enough memory\nto load game!");\r
206                 VW_UpdateScreen();\r
207                 IN_Ack();\r
208                 return false;\r
209         }\r
210         ca_levelbit <<= 1;\r
211         ca_levelnum++;\r
212 \r
213         expanded = mapwidth * mapheight * 2;\r
214         MM_BombOnError(true);   //BUG: this should use false to avoid an instant crash\r
215         MM_GetPtr(&bigbuffer, expanded);\r
216         MM_BombOnError(false);  //BUG: this should use true to force an instant crash\r
217         if (mmerror)\r
218         {\r
219                 mmerror = false;\r
220                 US_CenterWindow(20, 8);\r
221                 PrintY += 20;\r
222                 US_CPrint("Not enough memory\nto load game!");\r
223                 VW_UpdateScreen();\r
224                 IN_Ack();\r
225                 return false;\r
226         }\r
227         for (i = 0; i < 3; i++)\r
228         {\r
229                 if (!CA_FarRead(handle, (byte far *)&compressed, sizeof(compressed)))\r
230                 {\r
231                         MM_FreePtr(&bigbuffer);\r
232                         return false;\r
233                 }\r
234                 if (!CA_FarRead(handle, (byte far *)bigbuffer, compressed))\r
235                 {\r
236                         MM_FreePtr(&bigbuffer);\r
237                         return false;\r
238                 }\r
239                 CA_RLEWexpand(bigbuffer, mapsegs[i], expanded, RLETAG);\r
240         }\r
241         MM_FreePtr(&bigbuffer);\r
242 \r
243         InitObjArray();\r
244         new = player;\r
245         prev = new->prev;\r
246         next = new->next;\r
247         if (!CA_FarRead(handle, (byte far *)new, sizeof(objtype)))\r
248         {\r
249                 return false;\r
250         }\r
251         new->prev = prev;\r
252         new->next = next;\r
253         new->needtoreact = true;\r
254         new->sprite = NULL;\r
255         new = scoreobj;\r
256         while (true)\r
257         {\r
258                 prev = new->prev;\r
259                 next = new->next;\r
260                 if (!CA_FarRead(handle, (byte far *)new, sizeof(objtype)))\r
261                 {\r
262                         return false;\r
263                 }\r
264                 followed = new->next;\r
265                 new->prev = prev;\r
266                 new->next = next;\r
267                 new->needtoreact = true;\r
268                 new->sprite = NULL;\r
269                 if (new->obclass == stunnedobj)\r
270                 {\r
271                         new->temp3 = 0; //clear sprite ptr for the stars\r
272                 }\r
273 #if defined KEEN4\r
274                 else if (new->obclass == platformobj)\r
275                 {\r
276                         new->temp2 = new->temp3 = 0;    //clear sprite ptrs\r
277                 }\r
278 #elif defined KEEN5\r
279                 else if (new->obclass == mineobj)\r
280                 {\r
281                         new->temp4 = 0; //clear sprite ptr\r
282                 }\r
283                 else if (new->obclass == spherefulobj)\r
284                 {\r
285                         new->temp1 = new->temp2 = new->temp3 = new->temp4 = 0;  //clear sprite ptrs\r
286                 }\r
287 #elif defined KEEN6\r
288                 else if (new->obclass == platformobj)\r
289                 {\r
290                         new->temp3 = 0; //clear sprite ptr\r
291                 }\r
292 #endif\r
293                 if (followed)\r
294                 {\r
295                         GetNewObj(false);\r
296                 }\r
297                 else\r
298                 {\r
299                         break;\r
300                 }\r
301         }\r
302         scoreobj->temp2 = -1;\r
303         scoreobj->temp1 = -1;\r
304         scoreobj->temp3 = -1;\r
305         scoreobj->temp4 = -1;\r
306 #ifdef KEEN5\r
307         gamestate.numfuses = numfuses;  // put value from saved game back in place \r
308 #endif\r
309         return true;\r
310 }\r
311 \r
312 //===========================================================================\r
313 \r
314 /*\r
315 ============================\r
316 =\r
317 = ResetGame\r
318 =\r
319 ============================\r
320 */\r
321 \r
322 void ResetGame(void)\r
323 {\r
324         NewGame();\r
325         ca_levelnum--;\r
326         ca_levelbit >>= 1;\r
327         CA_ClearMarks();\r
328         ca_levelbit <<= 1;\r
329         ca_levelnum++;\r
330 }\r
331 \r
332 //===========================================================================\r
333 \r
334 \r
335 /*\r
336 ==========================\r
337 =\r
338 = PatchWorldMap\r
339 =\r
340 = Takes out blocking squares and spawns flags\r
341 =\r
342 ==========================\r
343 */\r
344 \r
345 void PatchWorldMap(void)\r
346 {\r
347         Uint16 x, y, planeoff, info, level, tag;\r
348         Uint16 far *infoptr;\r
349 \r
350         planeoff = 0;\r
351         infoptr = mapsegs[2];\r
352         for (y = 0; y < mapheight; y++)\r
353         {\r
354                 for (x = 0; x < mapwidth; x++, infoptr++, planeoff++)\r
355                 {\r
356                         info = *infoptr;\r
357                         level = info & 0xFF;\r
358                         if (level >= MINDONELEVEL && level <= MAXDONELEVEL && gamestate.leveldone[level])\r
359                         {\r
360                                 tag = info >> 8;\r
361                                 *infoptr = 0;   // BUG: infoplane value should only be set to 0 if tag == 0xC0\r
362                                 if (tag == 0xD0)\r
363                                 {\r
364                                         mapsegs[1][planeoff] = 0;\r
365                                 }\r
366                                 else if (tag == 0xF0)\r
367                                 {\r
368 #ifdef KEEN5\r
369                                         SpawnFlag(x, y);\r
370 #else\r
371                                         if (levelcompleted == level)\r
372                                         {\r
373                                                 SpawnThrowFlag(x, y);\r
374                                         }\r
375                                         else\r
376                                         {\r
377                                                 SpawnFlag(x, y);\r
378                                         }\r
379 #endif\r
380                                 }\r
381                         }\r
382                 }\r
383         }\r
384 }\r
385 \r
386 //===========================================================================\r
387 \r
388 /*\r
389 ==========================\r
390 =\r
391 = DelayedFade\r
392 =\r
393 = Fades out and latches FadeAndUnhook onto the refresh\r
394 =\r
395 ==========================\r
396 */\r
397 \r
398 void DelayedFade(void)\r
399 {\r
400         VW_FadeOut();\r
401         fadecount = 0;\r
402         RF_SetRefreshHook(&FadeAndUnhook);\r
403 }\r
404 \r
405 /*\r
406 ==========================\r
407 =\r
408 = FadeAndUnhook\r
409 =\r
410 = Latch this onto the refresh so the screen only gets faded in after two\r
411 = refreshes.  This lets all actors draw themselves to both pages before\r
412 = fading the screen in.\r
413 =\r
414 ==========================\r
415 */\r
416 \r
417 void FadeAndUnhook(void)\r
418 {\r
419         if (++fadecount == 2)\r
420         {\r
421                 VW_FadeIn();\r
422                 RF_SetRefreshHook(NULL);\r
423                 TimeCount = lasttimecount;      // don't adaptively time the fade\r
424         }\r
425 }\r
426 \r
427 //===========================================================================\r
428 \r
429 \r
430 /*\r
431 ==========================\r
432 =\r
433 = SetupGameLevel\r
434 =\r
435 = Load in map mapon and cache everything needed for it\r
436 =\r
437 ==========================\r
438 */\r
439 \r
440 void SetupGameLevel(boolean loadnow)\r
441 {\r
442 //\r
443 // randomize if not a demo\r
444 //\r
445         if (DemoMode)\r
446         {\r
447                 US_InitRndT(false);\r
448                 gamestate.difficulty = gd_Normal;\r
449         }\r
450         else\r
451         {\r
452                 US_InitRndT(true);\r
453         }\r
454 \r
455 //\r
456 // load the level header and three map planes\r
457 //\r
458         CA_CacheMap(gamestate.mapon);\r
459 \r
460 //\r
461 // let the refresh manager set up some variables\r
462 //\r
463         RF_NewMap();\r
464 \r
465 //\r
466 // decide which graphics are needed and spawn actors\r
467 //\r
468         CA_ClearMarks();\r
469         ScanInfoPlane();\r
470         if (mapon == 0)\r
471         {\r
472                 PatchWorldMap();\r
473         }\r
474         RF_MarkTileGraphics();\r
475 \r
476 //\r
477 // have the caching manager load and purge stuff to make sure all marks\r
478 // are in memory\r
479 //\r
480         MM_BombOnError(false);\r
481         CA_LoadAllSounds();\r
482         if (loadnow)\r
483         {\r
484                 if (scorescreenkludge)\r
485                 {\r
486                         CA_CacheMarks(NULL);\r
487                 }\r
488                 else if (DemoMode)\r
489                 {\r
490                         CA_CacheMarks("DEMO");\r
491                 }\r
492 #ifdef KEEN5\r
493                 else if (mapon == 0 && player->tiletop > 100)\r
494                 {\r
495                         CA_CacheMarks("Keen steps out\nonto Korath III");\r
496                 }\r
497 #endif\r
498                 else\r
499                 {\r
500                         _fstrcpy(str, levelenter[mapon]);\r
501                         CA_CacheMarks(str);\r
502                 }\r
503         }\r
504         MM_BombOnError(true);\r
505 \r
506         if (!mmerror && loadnow)\r
507         {\r
508                 DelayedFade();\r
509         }\r
510 }\r
511 \r
512 //===========================================================================\r
513 \r
514 \r
515 /*\r
516 ==========================\r
517 =\r
518 = DialogDraw\r
519 =\r
520 ==========================\r
521 */\r
522 \r
523 void DialogDraw(char *title, Uint16 numcache)\r
524 {\r
525         Sint16 i;\r
526         Uint16 width, height;\r
527         Sint32 totalfree;\r
528 \r
529         totalfree = MM_TotalFree();\r
530         if (totalfree < 2048)\r
531         {\r
532                 handpic = 5;\r
533         }\r
534         else\r
535         {\r
536                 handpic = 0;\r
537                 for (i = 0; i < 6; i++)\r
538                 {\r
539                         CA_CacheGrChunk(i+KEENCOUNT1PIC);\r
540                         CA_UnmarkGrChunk(i+KEENCOUNT1PIC);\r
541                         if (grsegs[i+KEENCOUNT1PIC])\r
542                         {\r
543                                 MM_SetPurge(&grsegs[i+KEENCOUNT1PIC], PURGE_FIRST);\r
544                         }\r
545                         else\r
546                         {\r
547                                 mmerror = false;\r
548                                 handpic = 5;\r
549                                 break;\r
550                         }\r
551                 }\r
552         }\r
553         US_CenterWindow(26, 8);\r
554         if (grsegs[KEENCOUNT1PIC])\r
555         {\r
556                 VWB_DrawPic(WindowX, WindowY, KEENCOUNT1PIC);\r
557         }\r
558         else\r
559         {\r
560                 handpic = 5;\r
561         }\r
562         CA_UnmarkGrChunk(KEENCOUNT1PIC);        //redundant\r
563         WindowW -= 48;\r
564         WindowX += 48;\r
565         SizeText(title, &width, &height);\r
566         PrintY += (WindowH-height)/2 - 4;\r
567         US_CPrint(title);\r
568         VW_UpdateScreen();\r
569         chunkmax = chunkcount = numcache / 6;\r
570         if (!chunkmax && !handpic)\r
571         {\r
572                 handpic = 5;\r
573                 if (grsegs[KEENCOUNT6PIC])\r
574                         VWB_DrawPic(WindowX-24, WindowY+40, KEENCOUNT6PIC);\r
575                 VW_UpdateScreen();\r
576         }\r
577 }\r
578 \r
579 /*\r
580 ==========================\r
581 =\r
582 = DialogUpdate\r
583 =\r
584 ==========================\r
585 */\r
586 \r
587 void DialogUpdate(void)\r
588 {\r
589         if (--chunkcount || handpic > 4)\r
590                 return;\r
591 \r
592         chunkcount = chunkmax;\r
593         if (grsegs[handpic+KEENCOUNT2PIC])\r
594         {\r
595                 VWB_DrawPic(WindowX-24, WindowY+40, handpic+KEENCOUNT2PIC);\r
596         }\r
597         VW_UpdateScreen();\r
598         handpic++;\r
599 }\r
600 \r
601 /*\r
602 ==========================\r
603 =\r
604 = DialogFinish\r
605 =\r
606 ==========================\r
607 */\r
608 \r
609 void DialogFinish(void)\r
610 {\r
611         //this is empty\r
612 }\r
613 \r
614 //==========================================================================\r
615 \r
616 /*\r
617 ==================\r
618 =\r
619 = StartDemoRecord\r
620 =\r
621 ==================\r
622 */\r
623 \r
624 void StartDemoRecord(void)\r
625 {\r
626         Sint16 level;\r
627         boolean esc;\r
628 \r
629         VW_FixRefreshBuffer();\r
630         US_CenterWindow(30, 3);\r
631         PrintY += 6;\r
632         US_Print("  Record a demo from level(0-21):");\r
633         VW_UpdateScreen();\r
634         esc = !US_LineInput(px, py, str, NULL, true, 2, 0);\r
635         if (!esc)\r
636         {\r
637                 level = atoi(str);\r
638                 if (level >= 0 && level <= 21)\r
639                 {\r
640                         gamestate.mapon = level;\r
641                         playstate = ex_warped;\r
642                         IN_StartDemoRecord(0x1000);\r
643                 }\r
644         }\r
645 }\r
646 \r
647 /*\r
648 ==================\r
649 =\r
650 = EndDemoRecord\r
651 =\r
652 ==================\r
653 */\r
654 \r
655 void EndDemoRecord(void)\r
656 {\r
657         Sint16 handle;\r
658         boolean esc;\r
659         char filename[] = "DEMO?."EXTENSION;\r
660 \r
661         IN_StopDemo();\r
662         VW_FixRefreshBuffer();\r
663         US_CenterWindow(22, 3);\r
664         PrintY += 6;\r
665         US_Print("  Save as demo #(0-9):");\r
666         VW_UpdateScreen();\r
667         esc = !US_LineInput(px, py, str, NULL, true, 2, 0);\r
668         if (!esc && str[0] >= '0' && str[0] <= '9')\r
669         {\r
670                 filename[4] = str[0];\r
671                 handle = open(filename, O_BINARY|O_WRONLY|O_CREAT, S_IFREG|S_IREAD|S_IWRITE);\r
672                 if (handle == -1)\r
673                 {\r
674                         Quit("EndDemoRecord:  Cannot write demo file!");\r
675                 }\r
676                 write(handle, &mapon, sizeof(mapon));\r
677                 write(handle, &DemoOffset, sizeof(DemoOffset));\r
678                 CA_FarWrite(handle, DemoBuffer, DemoOffset);\r
679                 close(handle);\r
680         }\r
681         IN_FreeDemoBuffer();\r
682 }\r
683 \r
684 //==========================================================================\r
685 \r
686 /*\r
687 ==========================\r
688 =\r
689 = HandleDeath\r
690 =\r
691 ==========================\r
692 */\r
693 \r
694 void HandleDeath(void)\r
695 {\r
696         Uint16 y, color, top, bottom, selection, w, h;\r
697 \r
698         _fstrcpy(str, levelnames[mapon]);\r
699         SizeText(str, &w, &h);\r
700 \r
701         memset(gamestate.keys, 0, sizeof(gamestate.keys));\r
702         gamestate.lives--;\r
703         if (gamestate.lives >= 0)\r
704         {\r
705                 VW_FixRefreshBuffer();\r
706                 US_CenterWindow(20, 8);\r
707                 PrintY += 3;\r
708                 US_CPrint("You didn't make it past");\r
709                 top = PrintY+22;\r
710                 if (h < 15)\r
711                         PrintY += 4;\r
712                 US_CPrint(str);\r
713                 PrintY = top+2;\r
714                 US_CPrint("Try Again");\r
715                 PrintY += 4;\r
716                 bottom = PrintY-2;\r
717                 US_CPrint("Exit to "WORLDMAPNAME);\r
718 \r
719                 IN_ClearKeysDown();\r
720                 selection = 0;\r
721                 while (true)\r
722                 {\r
723                         if (selection)\r
724                         {\r
725                                 y = bottom;\r
726                         }\r
727                         else\r
728                         {\r
729                                 y = top;\r
730                         }\r
731 \r
732 // draw select bar\r
733                         if ((TimeCount / 16) & 1)\r
734                         {\r
735                                 color = SECONDCOLOR;\r
736                         }\r
737                         else\r
738                         {\r
739                                 color = FIRSTCOLOR;\r
740                         }\r
741                         VWB_Hlin(WindowX+4, WindowX+WindowW-4, y, color);\r
742                         VWB_Hlin(WindowX+4, WindowX+WindowW-4, y+1, color);\r
743                         VWB_Hlin(WindowX+4, WindowX+WindowW-4, y+12, color);\r
744                         VWB_Hlin(WindowX+4, WindowX+WindowW-4, y+13, color);\r
745                         VWB_Vlin(y+1, y+11, WindowX+4, color);\r
746                         VWB_Vlin(y+1, y+11, WindowX+5, color);\r
747                         VWB_Vlin(y+1, y+11, WindowX+WindowW-4, color);\r
748                         VWB_Vlin(y+1, y+11, WindowX+WindowW-5, color);\r
749 \r
750                         VW_UpdateScreen();\r
751 \r
752 // erase select bar\r
753                         VWB_Hlin(WindowX+4, WindowX+WindowW-4, y, WHITE);\r
754                         VWB_Hlin(WindowX+4, WindowX+WindowW-4, y+1, WHITE);\r
755                         VWB_Hlin(WindowX+4, WindowX+WindowW-4, y+12, WHITE);\r
756                         VWB_Hlin(WindowX+4, WindowX+WindowW-4, y+13, WHITE);\r
757                         VWB_Vlin(y+1, y+11, WindowX+4, WHITE);\r
758                         VWB_Vlin(y+1, y+11, WindowX+5, WHITE);\r
759                         VWB_Vlin(y+1, y+11, WindowX+WindowW-4, WHITE);\r
760                         VWB_Vlin(y+1, y+11, WindowX+WindowW-5, WHITE);\r
761 \r
762                         if (LastScan == sc_Escape)\r
763                         {\r
764                                 gamestate.mapon = 0;            // exit to world map\r
765                                 IN_ClearKeysDown();\r
766                                 return;\r
767                         }\r
768 \r
769                         IN_ReadControl(0, &c);\r
770                         if (c.button0 || c.button1 || LastScan == sc_Return || LastScan == sc_Space)\r
771                         {\r
772                                 if (selection)\r
773                                         gamestate.mapon = 0;            // exit to world map\r
774                                 return;\r
775                         }\r
776                         if (c.yaxis == -1 || LastScan == sc_UpArrow)\r
777                         {\r
778                                 selection = 0;\r
779                         }\r
780                         else if (c.yaxis == 1 || LastScan == sc_DownArrow)\r
781                         {\r
782                                 selection = 1;\r
783                         }\r
784                 }\r
785         }\r
786 }\r
787 \r
788 //==========================================================================\r
789 \r
790 /*\r
791 ============================\r
792 =\r
793 = GameLoop\r
794 =\r
795 = A game has just started (after the cinematic or load game)\r
796 =\r
797 ============================\r
798 */\r
799 \r
800 void GameLoop(void)\r
801 {\r
802         Uint16 temp;\r
803 #ifdef KEEN6\r
804         Uint16 i;\r
805 #endif\r
806 \r
807 #ifdef KEEN6\r
808         if (!storedemo)\r
809         {\r
810                 if (!US_ManualCheck())\r
811                 {\r
812                         loadedgame = false;\r
813                         restartgame = gd_Continue;\r
814                         return;\r
815                 }\r
816         }\r
817 #endif\r
818 \r
819         if (playstate == ex_loadedgame)\r
820         {\r
821                 goto loaded;\r
822         }\r
823 reset:\r
824         gamestate.difficulty = restartgame;\r
825         restartgame = gd_Continue;\r
826         do\r
827         {\r
828 startlevel:\r
829                 SetupGameLevel(true);\r
830                 if (mmerror)\r
831                 {\r
832                         if (gamestate.mapon != 0)\r
833                         {\r
834                                 mmerror = false;\r
835                                 US_CenterWindow(20, 8);\r
836                                 PrintY += 20;\r
837                                 US_CPrint("Insufficient memory\nto load level!");\r
838                                 VW_UpdateScreen();\r
839                                 IN_Ack();\r
840                                 gamestate.mapon = 0;            // exit to world map\r
841                                 SetupGameLevel(true);\r
842                         }\r
843                         if (mmerror)\r
844                         {\r
845                                 Quit("GameLoop: Insufficient memory to load world map!");\r
846                         }\r
847                 }\r
848 loaded:\r
849                 keenkilled = false;\r
850                 SD_WaitSoundDone();\r
851 \r
852                 PlayLoop();\r
853 \r
854                 if (playstate != ex_loadedgame)\r
855                 {\r
856                         memset(gamestate.keys, 0, sizeof(gamestate.keys));\r
857 #ifdef KEEN5\r
858                         gamestate.keycard = false;\r
859 #endif\r
860                 }\r
861                 VW_FixRefreshBuffer();\r
862 \r
863                 if (tedlevel)\r
864                 {\r
865                         if (playstate == ex_loadedgame)\r
866                         {\r
867                                 goto loaded;\r
868                         }\r
869                         else if (playstate == ex_died)\r
870                         {\r
871                                 goto startlevel;\r
872                         }\r
873                         else\r
874                         {\r
875                                 TEDDeath();\r
876                         }\r
877                 }\r
878 \r
879                 levelcompleted = -1;\r
880                 switch (playstate)\r
881                 {\r
882                 case ex_resetgame:\r
883                         goto reset;\r
884 \r
885                 case ex_loadedgame:\r
886                         goto loaded;\r
887 \r
888                 case ex_died:\r
889                         HandleDeath();\r
890                         break;\r
891 \r
892 #if defined KEEN4\r
893                 case ex_rescued:\r
894                         if (mapon != 0)\r
895                         {\r
896                                 SD_PlaySound(SND_LEVELDONE);\r
897                         }\r
898                         levelcompleted = mapon;\r
899                         gamestate.leveldone[mapon] = true;\r
900                         RescuedMember();\r
901                         if (gamestate.rescued != 8)\r
902                         {\r
903                                 gamestate.mapon = 0;\r
904                         }\r
905                         else\r
906                         {\r
907                                 FreeGraphics();\r
908                                 RF_FixOfs();\r
909                                 VW_FixRefreshBuffer();\r
910                                 FinaleLayout();\r
911                                 CheckHighScore(gamestate.score, gamestate.rescued);\r
912                                 return;\r
913                         }\r
914                         break;\r
915 \r
916 #elif defined KEEN5\r
917                 case ex_fusebroke:\r
918                         SD_PlaySound(SND_LEVELDONE);\r
919                         levelcompleted = mapon;\r
920                         gamestate.leveldone[mapon] = ex_fusebroke;\r
921                         FinishedFuse();\r
922                         gamestate.mapon = 0;\r
923                         break;\r
924 \r
925                 case ex_qedbroke:\r
926                         FreeGraphics();\r
927                         RF_FixOfs();\r
928                         VW_FixRefreshBuffer();\r
929                         FinaleLayout();\r
930                         CheckHighScore(gamestate.score, 0);\r
931                         return;\r
932 \r
933 #elif defined KEEN6\r
934                 case ex_hook:\r
935                         GotHook();\r
936                         goto completed;\r
937 \r
938                 case ex_sandwich:\r
939                         GotSandwich();\r
940                         goto completed;\r
941 \r
942                 case ex_card:\r
943                         GotPasscard();\r
944                         goto completed;\r
945 \r
946                 case ex_molly:\r
947                         FreeGraphics();\r
948                         RF_FixOfs();\r
949                         VW_FixRefreshBuffer();\r
950                         FinaleLayout();\r
951                         goto check_score;\r
952 \r
953 #endif\r
954                 case ex_completed:\r
955                 case ex_foot:\r
956                 case ex_portout:\r
957 completed:\r
958                         if (mapon != 0)\r
959                         {\r
960                                 SD_PlaySound(SND_LEVELDONE);\r
961                                 gamestate.mapon = 0;\r
962                                 levelcompleted = mapon;\r
963                                 gamestate.leveldone[mapon] = true;\r
964                                 if (storedemo && mapon == 2)\r
965                                 {\r
966                                         IN_ClearKeysDown();\r
967                                         return;\r
968                                 }\r
969                         }\r
970                         else\r
971                         {\r
972 #if GRMODE != CGAGR\r
973                                 temp = bufferofs;\r
974                                 bufferofs = displayofs;\r
975 #endif\r
976                                 US_CenterWindow(26, 8);\r
977                                 PrintY += 25;\r
978                                 US_CPrint("One moment");\r
979 #if GRMODE == CGAGR\r
980                                 VW_UpdateScreen();\r
981 #else\r
982                                 bufferofs = temp;\r
983 #endif\r
984                         }\r
985                         break;\r
986 \r
987                 case ex_abortgame:\r
988                         IN_ClearKeysDown();\r
989                         return;\r
990                 }\r
991         } while (gamestate.lives >= 0);\r
992 \r
993         GameOver();\r
994 \r
995 check_score:\r
996 #if defined KEEN4\r
997         CheckHighScore(gamestate.score, gamestate.rescued);\r
998 #else\r
999         temp = 0;\r
1000 #if defined KEEN6\r
1001         for (i = 0; i < GAMELEVELS; i++)\r
1002         {\r
1003                 if (gamestate.leveldone[i])\r
1004                         temp++;\r
1005         }\r
1006 #endif\r
1007         CheckHighScore(gamestate.score, temp);\r
1008 #endif\r
1009 }