]> 4ch.mooo.com Git - 16.git/blob - 16/keen456/KEEN4-6/KEEN5/K5_SPEC.C
extrcted keen code remake
[16.git] / 16 / keen456 / KEEN4-6 / KEEN5 / K5_SPEC.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 /*\r
24 K5_SPEC.C\r
25 =========\r
26 \r
27 Contains (in this order):\r
28 \r
29 - lump definition\r
30 - "Star Wars" crawl text\r
31 - level names & messages\r
32 - Airlock opening & closing code\r
33 - ScanInfoPlane() - for spawning the level objects and marking required sprites\r
34 - game over animation\r
35 - messages for breaking fuses\r
36 */\r
37 \r
38 #include "CK_DEF.H"\r
39 \r
40 enum {\r
41         HELP_LUMP,        //  0\r
42         CONTROLS_LUMP,    //  1\r
43         KEENTALK_LUMP,    //  2\r
44         LOADING_LUMP,     //  3\r
45         PADDLE_LUMP,      //  4\r
46         KEEN_LUMP,        //  5\r
47         SUGAR1_LUMP,      //  6\r
48         SUGAR2_LUMP,      //  7\r
49         SUGAR3_LUMP,      //  8\r
50         SUGAR4_LUMP,      //  9\r
51         SUGAR5_LUMP,      // 10\r
52         SUGAR6_LUMP,      // 11\r
53         ONEUP_LUMP,       // 12\r
54         KEYGEM_LUMP,      // 13\r
55         AMMO_LUMP,        // 14\r
56         LASER_LUMP,       // 15\r
57         WORLDKEEN_LUMP,   // 16\r
58         MASTER_LUMP,      // 17\r
59         SHIKADI_LUMP,     // 18\r
60         SHOCKSHUND_LUMP,  // 19\r
61         SPHEREFUL_LUMP,   // 20\r
62         SPARKY_LUMP,      // 21\r
63         MINE_LUMP,        // 22\r
64         SLICESTAR_LUMP,   // 23\r
65         ROBORED_LUMP,     // 24\r
66         SPIRO_LUMP,       // 25\r
67         AMPTON_LUMP,      // 26\r
68         VOLTE_LUMP,       // 27\r
69         SLOTPLAT_LUMP,    // 28\r
70         SPINDRED_LUMP,    // 29\r
71         SHELLEY_LUMP,     // 30\r
72         PLATFORM_LUMP,    // 31\r
73         SMALLPLAT_LUMP,   // 32\r
74         KEYCARD_LUMP,     // 33\r
75         SCOTTIE_LUMP,     // 34\r
76         FUSE_LUMP,        // 35\r
77         STAREXPLODE_LUMP, // 36\r
78         TELEPORT_LUMP,    // 37\r
79 \r
80         NUMLUMPS=42       // Keen 5 has 4 unused lumps at the end\r
81 };\r
82 \r
83 Uint16 lumpstart[NUMLUMPS] = {\r
84         HELP_LUMP_START,\r
85         CONTROLS_LUMP_START,\r
86         KEENTALK_LUMP_START,\r
87         LOADING_LUMP_START,\r
88         PADDLE_LUMP_START,\r
89         KEEN_LUMP_START,\r
90         SUGAR1_LUMP_START,\r
91         SUGAR2_LUMP_START,\r
92         SUGAR3_LUMP_START,\r
93         SUGAR4_LUMP_START,\r
94         SUGAR5_LUMP_START,\r
95         SUGAR6_LUMP_START,\r
96         ONEUP_LUMP_START,\r
97         KEYGEM_LUMP_START,\r
98         AMMO_LUMP_START,\r
99         LASER_LUMP_START,\r
100         WORLDKEEN_LUMP_START,\r
101         MASTER_LUMP_START,\r
102         SHIKADI_LUMP_START,\r
103         SHOCKSHUND_LUMP_START,\r
104         SPHEREFUL_LUMP_START,\r
105         SPARKY_LUMP_START,\r
106         MINE_LUMP_START,\r
107         SLICESTAR_LUMP_START,\r
108         ROBORED_LUMP_START,\r
109         SPIRO_LUMP_START,\r
110         AMPTON_LUMP_START,\r
111         VOLTE_LUMP_START,\r
112         SLOTPLAT_LUMP_START,\r
113         SPINDRED_LUMP_START,\r
114         SHELLEY_LUMP_START,\r
115         PLATFORM_LUMP_START,\r
116         MINIPLAT_LUMP_START,\r
117         KEYCARD_LUMP_START,\r
118         SCOTTIE_LUMP_START,\r
119         FUSE_LUMP_START,\r
120         STAREXPLODE_LUMP_START,\r
121         TELEPORT_LUMP_START\r
122 };\r
123 \r
124 Uint16 lumpend[NUMLUMPS] = {\r
125         HELP_LUMP_END,\r
126         CONTROLS_LUMP_END,\r
127         KEENTALK_LUMP_END,\r
128         LOADING_LUMP_END,\r
129         PADDLE_LUMP_END,\r
130         KEEN_LUMP_END,\r
131         SUGAR1_LUMP_END,\r
132         SUGAR2_LUMP_END,\r
133         SUGAR3_LUMP_END,\r
134         SUGAR4_LUMP_END,\r
135         SUGAR5_LUMP_END,\r
136         SUGAR6_LUMP_END,\r
137         ONEUP_LUMP_END,\r
138         KEYGEM_LUMP_END,\r
139         AMMO_LUMP_END,\r
140         LASER_LUMP_END,\r
141         WORLDKEEN_LUMP_END,\r
142         MASTER_LUMP_END,\r
143         SHIKADI_LUMP_END,\r
144         SHOCKSHUND_LUMP_END,\r
145         SPHEREFUL_LUMP_END,\r
146         SPARKY_LUMP_END,\r
147         MINE_LUMP_END,\r
148         SLICESTAR_LUMP_END,\r
149         ROBORED_LUMP_END,\r
150         SPIRO_LUMP_END,\r
151         AMPTON_LUMP_END,\r
152         VOLTE_LUMP_END,\r
153         SLOTPLAT_LUMP_END,\r
154         SPINDRED_LUMP_END,\r
155         SHELLEY_LUMP_END,\r
156         PLATFORM_LUMP_END,\r
157         MINIPLAT_LUMP_END,\r
158         KEYCARD_LUMP_END,\r
159         SCOTTIE_LUMP_END,\r
160         FUSE_LUMP_END,\r
161         STAREXPLODE_LUMP_END,\r
162         TELEPORT_LUMP_END\r
163 };\r
164 \r
165 boolean lumpneeded[NUMLUMPS];\r
166 \r
167 #if GRMODE == EGAGR\r
168 \r
169 char far swtext[] =\r
170         "Episode Five\n"\r
171         "\n"\r
172         "The Armageddon Machine\n"\r
173         "\n"\r
174         "After learning the\n"\r
175         "location of the secret\n"\r
176         "Shikadi base, Keen\n"\r
177         "jumped in the trusty\n"\r
178         "Bean-with-Bacon\n"\r
179         "Megarocket and blasted\n"\r
180         "across interstellar\n"\r
181         "space.\n"\r
182         "\n"\r
183         "Seventy-five furious\n"\r
184         "games of Paddle War\n"\r
185         "later, Keen dropped\n"\r
186         "out of lightspeed near\n"\r
187         " the Korath system.\n"\r
188         "\n"\r
189         "He flew toward the\n"\r
190         "planet, keeping it\n"\r
191         "between him and the\n"\r
192         "base.\n"\r
193         "\n"\r
194         "Pulling up underside\n"\r
195         "and docking at the\n"\r
196         "Ion Ventilation System,\n"\r
197         "Keen must destroy the\n"\r
198         "Shikadi Armageddon\n"\r
199         "Machine before it\n"\r
200         "explodes and destroys\n"\r
201         "the Milky Way!  He\n"\r
202         "steps into the dark\n"\r
203         "ventilation duct and\n"\r
204         "begins his most\n"\r
205         "dangerous adventure\n"\r
206         "yet...\n";\r
207 \r
208 #endif\r
209 \r
210 char far l0n[] = "Omegamatic";\r
211 char far l1n[] = "Ion Ventilation System";\r
212 char far l2n[] = "Security Center";\r
213 char far l3n[] = "Defense Tunnel Vlook";\r
214 char far l4n[] = "Energy Flow Systems";\r
215 char far l5n[] = "Defense Tunnel Burrh";\r
216 char far l6n[] = "Regulation\nControl Center";\r
217 char far l7n[] = "Defense Tunnel Sorra";\r
218 char far l8n[] = "Neutrino\nBurst Injector";\r
219 char far l9n[] = "Defense Tunnel Teln";\r
220 char far l10n[] = "Brownian\nMotion Inducer";\r
221 char far l11n[] = "Gravitational\nDamping Hub";\r
222 char far l12n[] = "Quantum\nExplosion Dynamo";\r
223 char far l13n[] = "Korath III Base";\r
224 char far l14n[] = "BWBMegarocket";\r
225 char far l15n[] = "High Scores";\r
226 \r
227 char far l0e[] = "Keen purposefully\nwanders about the\nOmegamatic";\r
228 char far l1e[] = "Keen investigates the\nIon Ventilation System";\r
229 char far l2e[] = "Keen struts through\nthe Security Center";\r
230 char far l3e[] = "Keen invades\nDefense Tunnel Vlook";\r
231 char far l4e[] = "Keen engages\nEnergy Flow Systems";\r
232 char far l5e[] = "Keen barrels into\nDefense Tunnel Burrh";\r
233 char far l6e[] = "Keen goes nuts in\nthe Regulation\nControl Center";\r
234 char far l7e[] = "Keen regrets entering\nDefense Tunnel Sorra";\r
235 char far l8e[] = "Keen blows through\nthe Neutrino\nBurst Injector";\r
236 char far l9e[] = "Keen trots through\nDefense Tunnel Teln";\r
237 char far l10e[] = "Keen breaks into\nthe Brownian\nMotion Inducer";\r
238 char far l11e[] = "Keen hurries through\nthe Gravitational\nDamping Hub";\r
239 char far l12e[] = "Keen explodes into\nthe Quantum\nExplosion Dynamo";\r
240 char far l13e[] = "Keen faces danger\nin the secret\nKorath III Base";\r
241 char far l14e[] = "Keen will not be\nin the BWBMegarocket";\r
242 char far l15e[] = "Keen unexplainedly\nfinds himself by\ntheHigh Scores";       // sic!\r
243 \r
244 char far *levelnames[GAMELEVELS] = {\r
245         l0n,\r
246         l1n,\r
247         l2n,\r
248         l3n,\r
249         l4n,\r
250         l5n,\r
251         l6n,\r
252         l7n,\r
253         l8n,\r
254         l9n,\r
255         l10n,\r
256         l11n,\r
257         l12n,\r
258         l13n,\r
259         l14n,\r
260         l15n\r
261 };\r
262 \r
263 char far *levelenter[GAMELEVELS] = {\r
264         l0e,\r
265         l1e,\r
266         l2e,\r
267         l3e,\r
268         l4e,\r
269         l5e,\r
270         l6e,\r
271         l7e,\r
272         l8e,\r
273         l9e,\r
274         l10e,\r
275         l11e,\r
276         l12e,\r
277         l13e,\r
278         l14e,\r
279         l15e\r
280 };\r
281 \r
282 Uint16 bonuslump[] = {\r
283         KEYGEM_LUMP, KEYGEM_LUMP, KEYGEM_LUMP, KEYGEM_LUMP,\r
284         SUGAR1_LUMP, SUGAR2_LUMP, SUGAR3_LUMP,\r
285         SUGAR4_LUMP, SUGAR5_LUMP, SUGAR6_LUMP,\r
286         ONEUP_LUMP, AMMO_LUMP, KEYCARD_LUMP, 0, 0\r
287 };\r
288 \r
289 //============================================================================\r
290 \r
291 /*\r
292 ===========================\r
293 =\r
294 = OpenMapDoor\r
295 =\r
296 ===========================\r
297 */\r
298 \r
299 void OpenMapDoor(Sint16 tileX, Sint16 tileY)\r
300 {\r
301         Sint16 x, y;\r
302         Uint16 tiles[2][2];\r
303 \r
304         for (y=0; y<2; y++)\r
305         {\r
306                 for (x=0; x<2; x++)\r
307                 {\r
308                         tiles[y][x] = *(mapsegs[1]+mapbwidthtable[y]/2 + x + 10);\r
309                 }\r
310         }\r
311         RF_MemToMap(&tiles[0][0], 1, tileX, tileY, 2, 2);\r
312 }\r
313 \r
314 /*\r
315 ===========================\r
316 =\r
317 = CloseMapDoor\r
318 =\r
319 ===========================\r
320 */\r
321 \r
322 void CloseMapDoor(Sint16 tileX, Sint16 tileY)\r
323 {\r
324         Sint16 x, y;\r
325         Uint16 tiles[2][2];\r
326 \r
327         for (y=0; y<2; y++)\r
328         {\r
329                 for (x=0; x<2; x++)\r
330                 {\r
331                         tiles[y][x] = *(mapsegs[1]+mapbwidthtable[y]/2 + x);\r
332                 }\r
333         }\r
334         RF_MemToMap(&tiles[0][0], 1, tileX, tileY, 2, 2);\r
335 }\r
336 \r
337 //============================================================================\r
338 \r
339 /*\r
340 ==========================\r
341 =\r
342 = ScanInfoPlane\r
343 =\r
344 = Spawn all actors and mark down special places\r
345 =\r
346 ==========================\r
347 */\r
348 \r
349 void ScanInfoPlane(void)\r
350 {\r
351         Uint16 i, x, y, chunk;\r
352         Sint16 info;\r
353         Uint16 far *map;\r
354         objtype *ob;\r
355 \r
356         InitObjArray();                  // start spawning things with a clean slate\r
357 \r
358         memset(lumpneeded, 0, sizeof(lumpneeded));\r
359         gamestate.numfuses = 0;\r
360 \r
361         map = mapsegs[2];\r
362 \r
363         for (y=0; y<mapheight; y++)\r
364         {\r
365                 for (x=0; x<mapwidth; x++)\r
366                 {\r
367                         info = *map++;\r
368 \r
369                         if (info == 0)\r
370                                 continue;\r
371 \r
372                         switch (info)\r
373                         {\r
374                         case 1:\r
375                                 SpawnKeen(x, y, 1);\r
376                                 SpawnScore();\r
377                                 lumpneeded[KEEN_LUMP] = true;\r
378                                 CA_MarkGrChunk(SCOREBOXSPR);\r
379                                 break;\r
380 \r
381                         case 2:\r
382                                 SpawnKeen(x, y, -1);\r
383                                 SpawnScore();\r
384                                 lumpneeded[KEEN_LUMP] = true;\r
385                                 CA_MarkGrChunk(SCOREBOXSPR);\r
386                                 break;\r
387 \r
388                         case 3:\r
389                                 SpawnScore();\r
390                                 lumpneeded[WORLDKEEN_LUMP] = true;\r
391                                 CA_MarkGrChunk(SCOREBOXSPR);\r
392                                 if (playstate == ex_portout)\r
393                                         break;\r
394                                 SpawnWorldKeen(x, y);\r
395                                 break;\r
396 \r
397                         case 26:\r
398                                 if (playstate != ex_portout)\r
399                                         break;\r
400                                 SpawnWorldKeenPort(x, y);\r
401                                 break;\r
402 \r
403                         case 6:\r
404                                 if (gamestate.difficulty < gd_Hard)\r
405                                         break;\r
406                         case 5:\r
407                                 if (gamestate.difficulty < gd_Normal)\r
408                                         break;\r
409                         case 4:\r
410                                 SpawnSparky(x, y);\r
411                                 lumpneeded[SPARKY_LUMP] = true;\r
412                                 break;\r
413 \r
414                         case 9:\r
415                                 if (gamestate.difficulty < gd_Hard)\r
416                                         break;\r
417                         case 8:\r
418                                 if (gamestate.difficulty < gd_Normal)\r
419                                         break;\r
420                         case 7:\r
421                                 SpawnMine(x, y);\r
422                                 lumpneeded[MINE_LUMP] = true;\r
423                                 break;\r
424 \r
425                         case 12:\r
426                                 if (gamestate.difficulty < gd_Hard)\r
427                                         break;\r
428                         case 11:\r
429                                 if (gamestate.difficulty < gd_Normal)\r
430                                         break;\r
431                         case 10:\r
432                                 SpawnSlicestarSlide(x, y, 0);\r
433                                 lumpneeded[SLICESTAR_LUMP] = true;\r
434                                 break;\r
435 \r
436                         case 15:\r
437                                 if (gamestate.difficulty < gd_Hard)\r
438                                         break;\r
439                         case 14:\r
440                                 if (gamestate.difficulty < gd_Normal)\r
441                                         break;\r
442                         case 13:\r
443                                 SpawnRoboRed(x, y);\r
444                                 lumpneeded[ROBORED_LUMP] = true;\r
445                                 break;\r
446 \r
447                         case 18:\r
448                                 if (gamestate.difficulty < gd_Hard)\r
449                                         break;\r
450                         case 17:\r
451                                 if (gamestate.difficulty < gd_Normal)\r
452                                         break;\r
453                         case 16:\r
454                                 SpawnSpirogrip(x, y);\r
455                                 lumpneeded[SPIRO_LUMP] = true;\r
456                                 break;\r
457 \r
458                         case 21:\r
459                                 if (gamestate.difficulty < gd_Hard)\r
460                                         break;\r
461                         case 20:\r
462                                 if (gamestate.difficulty < gd_Normal)\r
463                                         break;\r
464                         case 19:\r
465                                 SpawnSlicestarBounce(x, y);\r
466                                 lumpneeded[SLICESTAR_LUMP] = true;\r
467                                 break;\r
468 \r
469                         case 24:\r
470                                 if (gamestate.difficulty < gd_Hard)\r
471                                         break;\r
472                         case 23:\r
473                                 if (gamestate.difficulty < gd_Normal)\r
474                                         break;\r
475                         case 22:\r
476                                 SpawnSlicestarSlide(x, y, 1);\r
477                                 lumpneeded[SLICESTAR_LUMP] = true;\r
478                                 break;\r
479 \r
480                         case 25:\r
481                                 RF_SetScrollBlock(x, y, true);\r
482                                 break;\r
483 \r
484                         // case 26 (teleported map keen) is handled above\r
485 \r
486                         case 27:\r
487                         case 28:\r
488                         case 29:\r
489                         case 30:\r
490                                 SpawnPlatform(x, y, info-27, 0);\r
491                                 lumpneeded[PLATFORM_LUMP] = true;\r
492                                 break;\r
493 \r
494                         // case 31 is the block icon\r
495 \r
496                         case 32:\r
497                                 SpawnDropPlat(x, y);\r
498                                 lumpneeded[PLATFORM_LUMP] = true;\r
499                                 break;\r
500 \r
501                         case 35:\r
502                                 SpawnStaticPlat(x, y);\r
503                                 lumpneeded[PLATFORM_LUMP] = true;\r
504                                 break;\r
505                         case 34:\r
506                                 if (gamestate.difficulty > gd_Normal)\r
507                                         break;\r
508                                 SpawnStaticPlat(x, y);\r
509                                 lumpneeded[PLATFORM_LUMP] = true;\r
510                                 break;\r
511                         case 33:\r
512                                 if (gamestate.difficulty > gd_Easy)\r
513                                         break;\r
514                                 SpawnStaticPlat(x, y);\r
515                                 lumpneeded[PLATFORM_LUMP] = true;\r
516                                 break;\r
517 \r
518                         case 36:\r
519                         case 37:\r
520                         case 38:\r
521                         case 39:\r
522                                 SpawnGoPlat(x, y, info-36, 0);\r
523                                 lumpneeded[PLATFORM_LUMP] = true;\r
524                                 break;\r
525 \r
526                         case 40:\r
527                                 SpawnSneakPlat(x, y);\r
528                                 lumpneeded[PLATFORM_LUMP] = true;\r
529                                 break;\r
530 \r
531                         case 41:\r
532                                 if (gamestate.mapon == 12)\r
533                                 {\r
534                                         gamestate.numfuses = 4;\r
535                                         SpawnQed(x, y);\r
536                                 }\r
537                                 else\r
538                                 {\r
539                                         gamestate.numfuses++;\r
540                                 }\r
541                                 lumpneeded[FUSE_LUMP] = true;\r
542                                 break;\r
543 \r
544                         case 44:\r
545                                 if (gamestate.difficulty < gd_Hard)\r
546                                         break;\r
547                         case 43:\r
548                                 if (gamestate.difficulty < gd_Normal)\r
549                                         break;\r
550                         case 42:\r
551                                 SpawnAmpton(x, y);\r
552                                 lumpneeded[AMPTON_LUMP] = true;\r
553                                 break;\r
554 \r
555                         case 53:\r
556                                 if (gamestate.difficulty < gd_Hard)\r
557                                         break;\r
558                         case 49:\r
559                                 if (gamestate.difficulty < gd_Normal)\r
560                                         break;\r
561                         case 45:\r
562                                 SpawnCannon(x, y, 0);\r
563                                 lumpneeded[LASER_LUMP] = true;\r
564                                 break;\r
565 \r
566                         case 54:\r
567                                 if (gamestate.difficulty < gd_Hard)\r
568                                         break;\r
569                         case 50:\r
570                                 if (gamestate.difficulty < gd_Normal)\r
571                                         break;\r
572                         case 46:\r
573                                 SpawnCannon(x, y, 1);\r
574                                 lumpneeded[LASER_LUMP] = true;\r
575                                 break;\r
576 \r
577                         case 55:\r
578                                 if (gamestate.difficulty < gd_Hard)\r
579                                         break;\r
580                         case 51:\r
581                                 if (gamestate.difficulty < gd_Normal)\r
582                                         break;\r
583                         case 47:\r
584                                 SpawnCannon(x, y, 2);\r
585                                 lumpneeded[LASER_LUMP] = true;\r
586                                 break;\r
587 \r
588                         case 56:\r
589                                 if (gamestate.difficulty < gd_Hard)\r
590                                         break;\r
591                         case 52:\r
592                                 if (gamestate.difficulty < gd_Normal)\r
593                                         break;\r
594                         case 48:\r
595                                 SpawnCannon(x, y, 3);\r
596                                 lumpneeded[LASER_LUMP] = true;\r
597                                 break;\r
598 \r
599                         case 69:\r
600                                 if (gamestate.ammo >= 5)\r
601                                         break;\r
602                                 info = 68;      // spawn ammo\r
603                                 //no break here!\r
604                         case 57:\r
605                         case 58:\r
606                         case 59:\r
607                         case 60:\r
608                         case 61:\r
609                         case 62:\r
610                         case 63:\r
611                         case 64:\r
612                         case 65:\r
613                         case 66:\r
614                         case 67:\r
615                         case 68:\r
616                                 SpawnBonus(x, y, info-57);\r
617                                 lumpneeded[bonuslump[info-57]] = true;\r
618                                 break;\r
619                         case 70:\r
620                                 SpawnBonus(x, y, info-58);\r
621                                 lumpneeded[bonuslump[info-58]] = true;\r
622                                 break;\r
623 \r
624                         case 73:\r
625                                 if (gamestate.difficulty < gd_Hard)\r
626                                         break;\r
627                         case 72:\r
628                                 if (gamestate.difficulty < gd_Normal)\r
629                                         break;\r
630                         case 71:\r
631                                 SpawnVolte(x, y);\r
632                                 lumpneeded[VOLTE_LUMP] = true;\r
633                                 break;\r
634 \r
635                         case 76:\r
636                                 if (gamestate.difficulty < gd_Hard)\r
637                                         break;\r
638                         case 75:\r
639                                 if (gamestate.difficulty < gd_Normal)\r
640                                         break;\r
641                         case 74:\r
642                                 SpawnShelly(x, y);\r
643                                 lumpneeded[SHELLEY_LUMP] = true;\r
644                                 break;\r
645 \r
646                         case 79:\r
647                                 if (gamestate.difficulty < gd_Hard)\r
648                                         break;\r
649                         case 78:\r
650                                 if (gamestate.difficulty < gd_Normal)\r
651                                         break;\r
652                         case 77:\r
653                                 SpawnSpindread(x, y);\r
654                                 lumpneeded[SPINDRED_LUMP] = true;\r
655                                 break;\r
656 \r
657                         case 80:\r
658                         case 81:\r
659                         case 82:\r
660                         case 83:\r
661                                 SpawnGoPlat(x, y, info-80, 1);\r
662                                 lumpneeded[SLOTPLAT_LUMP] = true;\r
663                                 break;\r
664 \r
665                         case 84:\r
666                         case 85:\r
667                         case 86:\r
668                         case 87:\r
669                                 SpawnPlatform(x, y, info-84, 1);\r
670                                 lumpneeded[SLOTPLAT_LUMP] = true;\r
671                                 break;\r
672 \r
673                         case 90:\r
674                                 if (gamestate.difficulty < gd_Hard)\r
675                                         break;\r
676                         case 89:\r
677                                 if (gamestate.difficulty < gd_Normal)\r
678                                         break;\r
679                         case 88:\r
680                                 SpawnMaster(x, y);\r
681                                 lumpneeded[MASTER_LUMP] = true;\r
682                                 break;\r
683 \r
684                         // cases 91 to 98 are direction arrows\r
685 \r
686                         case 101:\r
687                                 if (gamestate.difficulty < gd_Hard)\r
688                                         break;\r
689                         case 100:\r
690                                 if (gamestate.difficulty < gd_Normal)\r
691                                         break;\r
692                         case 99:\r
693                                 SpawnShikadi(x, y);\r
694                                 lumpneeded[SHIKADI_LUMP] = true;\r
695                                 break;\r
696 \r
697                         case 104:\r
698                                 if (gamestate.difficulty < gd_Hard)\r
699                                         break;\r
700                         case 103:\r
701                                 if (gamestate.difficulty < gd_Normal)\r
702                                         break;\r
703                         case 102:\r
704                                 SpawnPet(x, y);\r
705                                 lumpneeded[SHOCKSHUND_LUMP] = true;\r
706                                 break;\r
707 \r
708                         case 107:\r
709                                 if (gamestate.difficulty < gd_Hard)\r
710                                         break;\r
711                         case 106:\r
712                                 if (gamestate.difficulty < gd_Normal)\r
713                                         break;\r
714                         case 105:\r
715                                 SpawnSphereful(x, y);\r
716                                 lumpneeded[SPHEREFUL_LUMP] = true;\r
717                                 break;\r
718 \r
719                         // cases 108 to 123 are wall collision icons for the WallDebug cheat\r
720 \r
721                         case 124:\r
722                                 SpawnScottie(x, y);\r
723                                 lumpneeded[SCOTTIE_LUMP] = true;\r
724                                 break;\r
725 \r
726                         case 125:\r
727                                 lumpneeded[TELEPORT_LUMP] = true;\r
728 \r
729                         }\r
730                 }\r
731         }\r
732 \r
733         for (ob = player; ob; ob = ob->next)\r
734         {\r
735                 if (ob->active != ac_allways)\r
736                         ob->active = ac_no;\r
737         }\r
738 \r
739         for (i = 0; i < NUMLUMPS; i++)\r
740         {\r
741                 if (lumpneeded[i])\r
742                 {\r
743                         for (chunk = lumpstart[i]; chunk <= lumpend[i]; chunk++)\r
744                         {\r
745                                 CA_MarkGrChunk(chunk);\r
746                         }\r
747                 }\r
748         }\r
749 \r
750         // Keen 5 addition to PatchWorldMap (PatchWorldMap is shared across Keen 4-6)\r
751         if (gamestate.mapon == 0)\r
752         {\r
753                 info = CONVERT_GLOBAL_TO_TILE(player->y);\r
754                 if (info < 75 || info > 100)\r
755                 {\r
756                         CloseMapDoor(24, 76);\r
757                         OpenMapDoor(22, 55);\r
758                 }\r
759                 if (gamestate.leveldone[4] && gamestate.leveldone[6] && gamestate.leveldone[8] && gamestate.leveldone[10]\r
760                         && (info > 39 || info > 100) )\r
761                 {\r
762                         OpenMapDoor(26, 55);\r
763                 }\r
764                 if (info <= 39 || info > 100)\r
765                 {\r
766                         OpenMapDoor(24, 30);\r
767                 }\r
768         }\r
769 }\r
770 \r
771 /*\r
772 =============================================================================\r
773 \r
774                                                   GAME OVER SEQUENCE\r
775 \r
776 =============================================================================\r
777 */\r
778 \r
779 /*\r
780 ------------------------------------------------------------------------------\r
781 The galaxy explosion chunk contains data in the following format:\r
782 \r
783 struct {\r
784         Uint16 posx[4000];\r
785         Uint16 velx[4000];\r
786         Uint16 posy[4000];\r
787         Uint16 vely[4000];\r
788 };\r
789 \r
790 The values are stored as "fixed point" numbers (divide each number by 128 to\r
791 get the amount in pixel units). The code in MoveStars basically does the\r
792 following:\r
793 \r
794 1.      set all pixels on the screen to black\r
795 \r
796 2.      for each of the 4000 entries do:\r
797 \r
798 2.1     x := posx[i] + velx[i]\r
799 \r
800 2.2     if x (in pixels) is < 0 or > 320 then go to 2.8\r
801 \r
802 2.3     posx[i] := x\r
803 \r
804 2.4     y := posy[i] + vely[i]\r
805 \r
806 2.5     if y (in pixels) is < 0 or > 200 then go to 2.8\r
807 \r
808 2.6     posy[i] := y\r
809 \r
810 2.7     draw a white pixel at position (x, y) on the screen\r
811 \r
812 2.8     continue with the next entry\r
813 \r
814 ------------------------------------------------------------------------------\r
815 */\r
816 \r
817 #if GRMODE == CGAGR\r
818 \r
819 Uint8 plotpixels[8] = {0xC0, 0x30, 0x0C, 0x03};\r
820 \r
821 /*\r
822 ===========================\r
823 =\r
824 = MoveStars   CGA\r
825 =\r
826 ===========================\r
827 */\r
828 \r
829 void MoveStars(void)\r
830 {\r
831         asm {\r
832                 mov     ax, screenseg;\r
833                 mov     es, ax;\r
834                 mov     ds, word ptr grsegs + 2*GALAXY;\r
835                 mov     cx, 2000h;\r
836                 xor     ax, ax;\r
837                 xor     di, di;\r
838                 rep stosw;\r
839                 mov     si, 7998;\r
840         }\r
841 l1:\r
842         asm {\r
843                 mov     ax, [si];               // get posx\r
844                 add     ax, [si+8000];          // add velx\r
845                 cmp     ax, 40960;              // check if new posx is on screen\r
846                 ja      l2;\r
847                 mov     [si], ax;               // set new posx\r
848                 mov     bx, [si+16000];         // get posy\r
849                 add     bx, [si+24000];         // add vely\r
850                 cmp     bx, 25600;              // check if new posy is on screen\r
851                 ja      l2;\r
852                 mov     [si+16000], bx;         // set new posy\r
853                 mov     cl, 7;\r
854                 shr     bx, cl;\r
855                 shl     bx, 1;\r
856                 mov     di, word ptr ss:ylookup[bx];\r
857                 mov     bx, ax;\r
858                 mov     cl, 9;\r
859                 shr     ax, cl;\r
860                 add     di, ax;\r
861                 mov     cl, 7;\r
862                 shr     bx, cl;\r
863                 and     bx, 3;\r
864                 mov     al, BYTE PTR ss:plotpixels[bx];\r
865                 or              es:[di], al;            // draw the pixel\r
866         }\r
867 l2:\r
868         asm {\r
869                 sub     si, 2;\r
870                 jns     l1;\r
871                 mov     ax, ss;\r
872                 mov     ds, ax;\r
873         }\r
874 }\r
875 \r
876 /*\r
877 ===========================\r
878 =\r
879 = GameOver   CGA\r
880 =\r
881 ===========================\r
882 */\r
883 \r
884 void GameOver(void)\r
885 {\r
886         Sint16 i;\r
887 \r
888         FreeGraphics();\r
889         CA_CacheGrChunk(MILKYWAYPIC);\r
890         CA_CacheGrChunk(GALAXY);\r
891         CA_CacheGrChunk(GAMEOVERPIC);\r
892         RF_FixOfs();\r
893         VW_ClearVideo(BLACK);\r
894         VWB_DrawPic(0, 0, MILKYWAYPIC);\r
895         VW_UpdateScreen();\r
896 \r
897         SD_WaitSoundDone();\r
898         SD_PlaySound(SND_GAMEOVER2);\r
899         SD_WaitSoundDone();\r
900         SD_PlaySound(SND_GAMEOVER1);\r
901 \r
902         IN_ClearKeysDown();\r
903         VW_SetLineWidth(80);\r
904 \r
905         for (i=0; i<60; i++)\r
906         {\r
907                 lasttimecount = TimeCount;\r
908                 MoveStars();\r
909                 VW_UpdateScreen();\r
910 \r
911                 do {} while (TimeCount-lasttimecount < 4);\r
912 \r
913                 if (LastScan)\r
914                         break;\r
915         }\r
916 \r
917         VW_SetLineWidth(SCREENWIDTH);\r
918         VW_ClearVideo(BLACK);\r
919         StartMusic(18);\r
920         VWB_DrawPic(32, 80, GAMEOVERPIC);\r
921         VW_UpdateScreen();\r
922         IN_UserInput(24*TickBase, false);\r
923         StopMusic();\r
924 }\r
925 \r
926 //============================================================================\r
927 \r
928 #else\r
929 \r
930 Uint16 dim[18] = {8, 8, 7, 15, 7, 8, 0, 8, 7, 15, 7, 8, 0, 0, 0, 0, 0, 0};\r
931 Uint16 bright[18] = {7, 7, 7, 7, 7, 15, 7, 8, 0, 7, 15, 7, 8, 0, 0, 0, 0, 0};\r
932 Uint8 galaxycolors[17] = {0, 1, 2, 3, 4, 5, 6, 7, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 3};\r
933 Uint8 plotpixels[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};\r
934 \r
935 /*\r
936 ===========================\r
937 =\r
938 = MoveStars   EGA\r
939 =\r
940 ===========================\r
941 */\r
942 \r
943 void MoveStars(Uint16 dest)\r
944 {\r
945         asm {\r
946                 mov     dx, GC_INDEX;\r
947                 mov     al, GC_BITMASK;\r
948                 out     dx, al;\r
949                 inc     dx;\r
950                 mov     ds, word ptr grsegs + 2*GALAXY;\r
951                 mov     ax, 0A000h;\r
952                 mov     es, ax;\r
953                 mov     cx, 1000h;\r
954                 xor     ax, ax;\r
955                 mov     di, dest;\r
956                 rep stosw;\r
957                 mov     si, 7998;\r
958         }\r
959 l1:\r
960         asm {\r
961                 mov     ax, [si];               // get posx\r
962                 add     ax, [si+8000];          // add velx\r
963                 cmp     ax, 40960;              // check if new posx is on screen\r
964                 ja      l2;\r
965                 mov     [si], ax;               // set new posx\r
966                 mov     bx, [si+16000];         // get posy\r
967                 add     bx, [si+24000];         // add vely\r
968                 cmp     bx, 25600;              // check if new posy is on screen\r
969                 ja      l2;\r
970                 mov     [si+16000], bx;         // set new posy\r
971                 mov     cl, 7;\r
972                 shr     bx, cl;\r
973                 shl     bx, 1;\r
974                 mov     di, word ptr ss:ylookup[bx];\r
975                 add     di, dest;\r
976                 mov     bx, ax;\r
977                 mov     cl, 10;\r
978                 shr     ax, cl;\r
979                 add     di, ax;\r
980                 mov     cl, 7;\r
981                 shr     bx, cl;\r
982                 and     bx, 7;\r
983                 mov     al, BYTE PTR ss:plotpixels[bx];\r
984                 out     dx, al;\r
985                 mov     al, 0Fh;\r
986                 xchg    al, es:[di];            // draw the pixel\r
987         }\r
988 l2:\r
989         asm {\r
990                 sub     si, 2;\r
991                 jns     l1;\r
992                 mov     ax, ss;\r
993                 mov     ds, ax;\r
994                 mov     al, 0FFh;\r
995                 out     dx, al;\r
996         }\r
997 }\r
998 \r
999 /*\r
1000 ===========================\r
1001 =\r
1002 = SetCrtc   EGA\r
1003 =\r
1004 ===========================\r
1005 */\r
1006 \r
1007 void SetCrtc(Uint16 addr)\r
1008 {\r
1009         asm {\r
1010                 cli;\r
1011                 mov     cx, addr;\r
1012                 mov     dx, CRTC_INDEX;\r
1013                 mov     al, CRTC_STARTHIGH;\r
1014                 out     dx, al;\r
1015                 inc     dx;\r
1016                 mov     al, ch;\r
1017                 out     dx, al;\r
1018                 dec     dx;\r
1019                 mov     al, CRTC_STARTLOW;\r
1020                 out     dx, al;\r
1021                 inc     dx;\r
1022                 mov     al, cl;\r
1023                 out     dx, al;\r
1024                 sti;\r
1025         }\r
1026 }\r
1027 \r
1028 /*\r
1029 ===========================\r
1030 =\r
1031 = GameOver   EGA\r
1032 =\r
1033 ===========================\r
1034 */\r
1035 \r
1036 void GameOver(void)\r
1037 {\r
1038         Sint16 i;\r
1039 \r
1040         FreeGraphics();\r
1041         VW_FadeOut();\r
1042         CA_CacheGrChunk(MILKYWAYPIC);\r
1043         CA_CacheGrChunk(GALAXY);\r
1044         CA_CacheGrChunk(GAMEOVERPIC);\r
1045         VW_SetLineWidth(40);\r
1046         VW_SetScreen(0, 0);\r
1047         bufferofs = 0;\r
1048         VW_ClearVideo(0);\r
1049         VW_DrawPic(0, 0, MILKYWAYPIC);\r
1050         VW_ScreenToScreen(0, 0x2000, 40, 200);\r
1051         VW_FadeIn();\r
1052         IN_ClearKeysDown();\r
1053         SD_PlaySound(SND_GAMEOVER2);\r
1054 \r
1055         for (i=0; i<18; i++)\r
1056         {\r
1057                 galaxycolors[8] = dim[i];\r
1058                 galaxycolors[7] = bright[i];\r
1059 \r
1060                 SetPalette(galaxycolors);\r
1061 \r
1062                 VW_WaitVBL(10);\r
1063                 if (LastScan)\r
1064                         goto gameover;\r
1065         }\r
1066 \r
1067         EGAWRITEMODE(2);\r
1068         EGAMAPMASK(15);\r
1069         SD_PlaySound(SND_GAMEOVER1);\r
1070 \r
1071         for (i=0; i<30; i++)\r
1072         {\r
1073                 lasttimecount = TimeCount;\r
1074                 MoveStars(0x2000);\r
1075                 SetCrtc(0x2000);\r
1076                 do {} while (TimeCount-lasttimecount < 4);\r
1077 \r
1078                 lasttimecount = TimeCount;\r
1079                 MoveStars(0);\r
1080                 SetCrtc(0);\r
1081                 do {} while (TimeCount-lasttimecount < 4);\r
1082 \r
1083                 if (LastScan)\r
1084                         goto gameover;\r
1085         }\r
1086 \r
1087 gameover:\r
1088         EGAWRITEMODE(0);\r
1089         VW_ClearVideo(BLACK);\r
1090         VW_SetLineWidth(SCREENWIDTH);\r
1091         VW_SetDefaultColors();\r
1092         RF_FixOfs();\r
1093         StartMusic(18);\r
1094         VWB_DrawPic(32, 80, GAMEOVERPIC);\r
1095         VW_UpdateScreen();\r
1096         IN_UserInput(24*TickBase, false);\r
1097         StopMusic();\r
1098 }\r
1099 \r
1100 #endif\r
1101 \r
1102 //============================================================================\r
1103 \r
1104 /*\r
1105 ===========================\r
1106 =\r
1107 = FinishedFuse\r
1108 =\r
1109 ===========================\r
1110 */\r
1111 \r
1112 void FinishedFuse(void)\r
1113 {\r
1114         SD_WaitSoundDone();\r
1115         CA_UpLevel();\r
1116 #if 0\r
1117         // bugfix:\r
1118         CA_ClearMarks();        // don't cache more than we actually need here\r
1119 #endif\r
1120         CA_MarkGrChunk(KEENTALK1PIC);\r
1121         CA_MarkGrChunk(KEENTALK2PIC);\r
1122         CA_CacheMarks(NULL);\r
1123 \r
1124         VW_FixRefreshBuffer();\r
1125         US_CenterWindow(26, 8);\r
1126         WindowW -= 48;\r
1127         VWB_DrawPic(WindowX+WindowW, WindowY, KEENTALK1PIC);\r
1128         PrintY += 12;\r
1129         if (gamestate.mapon == 13)\r
1130         {\r
1131                 US_CPrint(\r
1132                         "I wonder what that\n"\r
1133                         "fuse was for....\n"\r
1134                         );\r
1135         }\r
1136         else\r
1137         {\r
1138                 US_CPrint(\r
1139                         "One of the four\n"\r
1140                         "machines protecting the\n"\r
1141                         "main elevator shaft--\n"\r
1142                         "toast!\n"\r
1143                         );\r
1144         }\r
1145         VW_UpdateScreen();\r
1146         VW_WaitVBL(30);\r
1147         IN_ClearKeysDown();\r
1148         IN_Ack();\r
1149 \r
1150         VWB_DrawPic(WindowX+WindowW, WindowY, KEENTALK2PIC);\r
1151         VW_UpdateScreen();\r
1152         VW_WaitVBL(30);\r
1153         IN_ClearKeysDown();\r
1154         IN_Ack();\r
1155 \r
1156         CA_DownLevel();\r
1157         StopMusic();\r
1158 }