]> 4ch.mooo.com Git - 16.git/blob - 16/keen456/KEEN4-6/KEEN4/K4_SPEC.C
extrcted keen code remake
[16.git] / 16 / keen456 / KEEN4-6 / KEEN4 / K4_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 K4_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 - ScanInfoPlane() - for spawning the level objects and marking required sprites\r
33 - messages for Lindsey, Janitor, Oracle Members and more\r
34 \r
35 - actor states & implementation for swimming Keen\r
36 \r
37 */\r
38 \r
39 #include "CK_DEF.H"\r
40 \r
41 enum {\r
42         CONTROLS_LUMP,     //  0\r
43         KEEN_LUMP,         //  1\r
44         SUGAR1_LUMP,       //  2\r
45         SUGAR2_LUMP,       //  3\r
46         SUGAR3_LUMP,       //  4\r
47         SUGAR4_LUMP,       //  5\r
48         SUGAR5_LUMP,       //  6\r
49         SUGAR6_LUMP,       //  7\r
50         ONEUP_LUMP,        //  8\r
51         AMMO_LUMP,         //  9\r
52         WOLRDKEEN_LUMP,    // 10\r
53         SLUG_LUMP,         // 11\r
54         MADMUSHROOM_LUMP,  // 12\r
55         UNUSED1_LUMP,      // 13\r
56         LINDSEY_LUMP,      // 14\r
57         INCHWORM_LUMP,     // 15\r
58         EATER_LUMP,        // 16\r
59         COUNCIL_LUMP,      // 17\r
60         EGGBIRD_LUMP,      // 18\r
61         MIMROCK_LUMP,      // 19\r
62         DOPEFISH_LUMP,     // 20\r
63         SCHOOLFISH_LUMP,   // 21\r
64         ARACHNUT_LUMP,     // 22\r
65         SKYPEST_LUMP,      // 23\r
66         WORMOUTH_LUMP,     // 24\r
67         LICK_LUMP,         // 25\r
68         PLATFORM_LUMP,     // 26\r
69         BOUNDER_LUMP,      // 27\r
70         THUNDERCLOUD_LUMP, // 28\r
71         BERKELOID_LUMP,    // 29\r
72         KEYGEM_LUMP,       // 30\r
73         DARTS_LUMP,        // 31\r
74         SCUBAKEEN_LUMP,    // 32\r
75         SPRITE_LUMP,       // 33\r
76         MINE_LUMP,         // 34\r
77         MOON_LUMP,         // 35\r
78         EGG_LUMP,          // 36\r
79         NUMLUMPS           // 37\r
80 };\r
81 \r
82 Uint16 lumpstart[NUMLUMPS] = {\r
83         CONTROLS_LUMP_START,\r
84         KEEN_LUMP_START,\r
85         SUGAR1_LUMP_START,\r
86         SUGAR2_LUMP_START,\r
87         SUGAR3_LUMP_START,\r
88         SUGAR4_LUMP_START,\r
89         SUGAR5_LUMP_START,\r
90         SUGAR6_LUMP_START,\r
91         ONEUP_LUMP_START,\r
92         AMMO_LUMP_START,\r
93         WORLDKEEN_LUMP_START,\r
94         SLUG_LUMP_START,\r
95         MADMUSHROOM_LUMP_START,\r
96         0,\r
97         LINDSEY_LUMP_START,\r
98         INCHWORM_LUMP_START,\r
99         EATER_LUMP_START,\r
100         COUNCIL_LUMP_START,\r
101         EGGBIRD_LUMP_START,\r
102         MIMROCK_LUMP_START,\r
103         DOPEFISH_LUMP_START,\r
104         SCHOOLFISH_LUMP_START,\r
105         ARACHNUT_LUMP_START,\r
106         SKYPEST_LUMP_START,\r
107         WORMOUTH_LUMP_START,\r
108         LICK_LUMP_START,\r
109         PLATFORM_LUMP_START,\r
110         BOUNDER_LUMP_START,\r
111         THUNDERCLOUD_LUMP_START,\r
112         BERKELOID_LUMP_START,\r
113         KEYGEM_LUMP_START,\r
114         DARTS_LUMP_START,\r
115         SCUBAKEEN_LUMP_START,\r
116         SPRITE_LUMP_START,\r
117         MINE_LUMP_START,\r
118         MOON_LUMP_START,\r
119         EGG_LUMP_START\r
120 };\r
121 \r
122 Uint16 lumpend[NUMLUMPS] = {\r
123         CONTROLS_LUMP_END,\r
124         KEEN_LUMP_END,\r
125         SUGAR1_LUMP_END,\r
126         SUGAR2_LUMP_END,\r
127         SUGAR3_LUMP_END,\r
128         SUGAR4_LUMP_END,\r
129         SUGAR5_LUMP_END,\r
130         SUGAR6_LUMP_END,\r
131         ONEUP_LUMP_END,\r
132         AMMO_LUMP_END,\r
133         WORLDKEEN_LUMP_END,\r
134         SLUG_LUMP_END,\r
135         MADMUSHROOM_LUMP_END,\r
136         0,\r
137         LINDSEY_LUMP_END,\r
138         INCHWORM_LUMP_END,\r
139         EATER_LUMP_END,\r
140         COUNCIL_LUMP_END,\r
141         EGGBIRD_LUMP_END,\r
142         MIMROCK_LUMP_END,\r
143         DOPEFISH_LUMP_END,\r
144         SCHOOLFISH_LUMP_END,\r
145         ARACHNUT_LUMP_END,\r
146         SKYPEST_LUMP_END,\r
147         WORMOUTH_LUMP_END,\r
148         LICK_LUMP_END,\r
149         PLATFORM_LUMP_END,\r
150         BOUNDER_LUMP_END,\r
151         THUNDERCLOUD_LUMP_END,\r
152         BERKELOID_LUMP_END,\r
153         KEYGEM_LUMP_END,\r
154         DARTS_LUMP_END,\r
155         SCUBAKEEN_LUMP_END,\r
156         SPRITE_LUMP_END,\r
157         MINE_LUMP_END,\r
158         MOON_LUMP_END,\r
159         EGG_LUMP_END\r
160 };\r
161 \r
162 boolean lumpneeded[NUMLUMPS];\r
163 \r
164 #if GRMODE == EGAGR\r
165 \r
166 char far swtext[] =\r
167         "Episode Four\n"\r
168         "\n"\r
169         "Secret of the Oracle\n"\r
170         "\n"\r
171         "After delivering a\n"\r
172         "crippling blow to the\n"\r
173         "plans of Mortimer\n"\r
174         "McMire and receiving\n"\r
175         "the praise of the\n"\r
176         "Vorticon race,\n"\r
177         "Commander Keen\n"\r
178         "returned to his home in\n"\r
179         "the suburbs.\n"\r
180         "\n"\r
181         "Here he was forced to\n"\r
182         "go to bed at an early\n"\r
183         "hour, and to eat mashed\n"\r
184         "potatoes.\n"\r
185         "\n"\r
186         "Months later, Billy\n"\r
187         "tinkered around with\n"\r
188         "his latest invention,\n"\r
189         "the Photachyon\n"\r
190         "Transceiver, or faster-\n"\r
191         "than-light radio. After\n"\r
192         "picking up a lot of bad\n"\r
193         "alien sitcoms, he\n"\r
194         "stumbled upon a strange\n"\r
195         "message of terrible\n"\r
196         "importance....\n";\r
197 \r
198 #endif\r
199 \r
200 char far l0n[] = "Shadowlands";\r
201 char far l1n[] = "Border Village";\r
202 char far l2n[] = "Slug Village";\r
203 char far l3n[] = "The Perilous Pit";\r
204 char far l4n[] = "Cave of the Descendents";\r
205 char far l5n[] = "Chasm of Chills";\r
206 char far l6n[] = "Crystalus";\r
207 char far l7n[] = "Hillville";\r
208 char far l8n[] = "Sand Yego";\r
209 char far l9n[] = "Miragia";\r
210 char far l10n[] = "Lifewater Oasis";\r
211 char far l11n[] = "Pyramid of the Moons";\r
212 char far l12n[] = "Pyramid of Shadows";\r
213 char far l13n[] = "Pyramid of the\nGnosticene Ancients";\r
214 char far l14n[] = "Pyramid of the Forbidden";\r
215 char far l15n[] = "Isle of Tar";\r
216 char far l16n[] = "Isle of Fire";\r
217 char far l17n[] = "Well of Wishes";\r
218 char far l18n[] = "Bean-with-Bacon\nMegarocket";\r
219 \r
220 char far l0e[] = "Keen enters the\nShadowlands";\r
221 char far l1e[] = "Keen makes a run for\nthe Border Village";\r
222 char far l2e[] = "Keen slips into\nSlug Village";\r
223 char far l3e[] = "Keen plummets into\nthe The Perilous Pit";    // sic!\r
224 char far l4e[] = "Keen plods down into\nthe Cave of the\nDescendents";\r
225 char far l5e[] = "Keen shivers along\nthe Chasm of Chills";\r
226 char far l6e[] = "Keen reflects upon\nentering Crystalus";\r
227 char far l7e[] = "Keen stumbles upon\nHillville";\r
228 char far l8e[] = "Keen grits his teeth\nand enters Sand Yego";\r
229 char far l9e[] = "Keen disappears into\nMiragia";\r
230 char far l10e[] = "Keen crawls into\nLifewater Oasis";\r
231 char far l11e[] = "Keen backs into the\nPyramid of the Moons";\r
232 char far l12e[] = "Keen move silently in\nthe Pyramid of Shadows";      // sic!\r
233 char far l13e[] = "Keen reverently enters\nthe Pyramid of the\nGnosticene Ancients";\r
234 char far l14e[] = "Keen hesitantly crosses\ninto the Pyramid of the\nForbidden";\r
235 char far l15e[] = "Keen mucks along the\nIsle of Tar";\r
236 char far l16e[] = "Keen blazes across the\nIsle of Fire";\r
237 char far l17e[] = "Keen hopefully enters\nthe Well of Wishes";\r
238 char far l18e[] = "Keen launches into the\nBean-with-Bacon\nMegarocket";\r
239 \r
240 char far *levelnames[GAMELEVELS] = {\r
241         l0n,\r
242         l1n,\r
243         l2n,\r
244         l3n,\r
245         l4n,\r
246         l5n,\r
247         l6n,\r
248         l7n,\r
249         l8n,\r
250         l9n,\r
251         l10n,\r
252         l11n,\r
253         l12n,\r
254         l13n,\r
255         l14n,\r
256         l15n,\r
257         l16n,\r
258         l17n,\r
259         l18n\r
260 };\r
261 \r
262 char far *levelenter[GAMELEVELS] = {\r
263         l0e,\r
264         l1e,\r
265         l2e,\r
266         l3e,\r
267         l4e,\r
268         l5e,\r
269         l6e,\r
270         l7e,\r
271         l8e,\r
272         l9e,\r
273         l10e,\r
274         l11e,\r
275         l12e,\r
276         l13e,\r
277         l14e,\r
278         l15e,\r
279         l16e,\r
280         l17e,\r
281         l18e\r
282 };\r
283 \r
284 Uint16 bonuslump[] = {\r
285         KEYGEM_LUMP, KEYGEM_LUMP, KEYGEM_LUMP, KEYGEM_LUMP,\r
286         SUGAR1_LUMP, SUGAR2_LUMP, SUGAR3_LUMP,\r
287         SUGAR4_LUMP, SUGAR5_LUMP, SUGAR6_LUMP,\r
288         ONEUP_LUMP, AMMO_LUMP\r
289 };\r
290 \r
291 //==========================================================================\r
292 \r
293 /*\r
294 ==========================\r
295 =\r
296 = ScanInfoPlane\r
297 =\r
298 = Spawn all actors and mark down special places\r
299 =\r
300 ==========================\r
301 */\r
302 \r
303 void ScanInfoPlane(void)\r
304 {\r
305         objtype *ob;\r
306         Uint16 i, x, y, chunk;\r
307         Sint16 info;\r
308         Uint16 far *map;\r
309 \r
310         InitObjArray();                  // start spawning things with a clean slate\r
311 \r
312         memset(lumpneeded, 0, sizeof(lumpneeded));\r
313         map = mapsegs[2];\r
314 \r
315         for (y=0; y<mapheight; y++)\r
316         {\r
317                 for (x=0; x<mapwidth; x++)\r
318                 {\r
319                         info = *map++;\r
320 \r
321                         if (info == 0)\r
322                                 continue;\r
323 \r
324                         switch (info)\r
325                         {\r
326                         case 1:\r
327                                 SpawnKeen(x, y, 1);\r
328                                 SpawnScore();\r
329                                 lumpneeded[KEEN_LUMP] = true;\r
330                                 CA_MarkGrChunk(SCOREBOXSPR);\r
331                                 break;\r
332 \r
333                         case 2:\r
334                                 SpawnKeen(x, y, -1);\r
335                                 SpawnScore();\r
336                                 lumpneeded[KEEN_LUMP] = true;\r
337                                 CA_MarkGrChunk(SCOREBOXSPR);\r
338                                 break;\r
339 \r
340                         case 3:\r
341                                 SpawnWorldKeen(x, y);\r
342                                 SpawnScore();\r
343                                 lumpneeded[WOLRDKEEN_LUMP] = true;\r
344                                 CA_MarkGrChunk(SCOREBOXSPR);\r
345                                 break;\r
346 \r
347                         case 4:\r
348                                 SpawnCouncil(x, y);\r
349                                 lumpneeded[COUNCIL_LUMP] = true;\r
350                                 break;\r
351 \r
352                         case 50:\r
353                                 if (gamestate.difficulty < gd_Hard)\r
354                                         break;\r
355                         case 49:\r
356                                 if (gamestate.difficulty < gd_Normal)\r
357                                         break;\r
358                         case 5:\r
359                                 SpawnBerkeloid(x, y);\r
360                                 lumpneeded[BERKELOID_LUMP] = true;\r
361                                 break;\r
362 \r
363                         case 6:\r
364                                 SpawnLindsey(x, y);\r
365                                 lumpneeded[LINDSEY_LUMP] = true;\r
366                                 break;\r
367 \r
368                         case 52:\r
369                                 if (gamestate.difficulty < gd_Hard)\r
370                                         break;\r
371                         case 51:\r
372                                 if (gamestate.difficulty < gd_Normal)\r
373                                         break;\r
374                         case 7:\r
375                                 SpawnWormMouth(x, y);\r
376                                 lumpneeded[WORMOUTH_LUMP] = true;\r
377                                 break;\r
378 \r
379                         case 46:\r
380                                 if (gamestate.difficulty < gd_Hard)\r
381                                         break;\r
382                         case 45:\r
383                                 if (gamestate.difficulty < gd_Normal)\r
384                                         break;\r
385                         case 8:\r
386                                 SpawnSkypest(x, y);\r
387                                 lumpneeded[SKYPEST_LUMP] = true;\r
388                                 break;\r
389 \r
390                         case 9:\r
391                                 SpawnCloudster(x, y);\r
392                                 lumpneeded[THUNDERCLOUD_LUMP] = true;\r
393                                 break;\r
394 \r
395                         case 10:\r
396                                 SpawnFoot(x, y);\r
397                                 lumpneeded[INCHWORM_LUMP] = true;       // lump includes the foot sprite\r
398                                 // Note: The smoke sprites aren't actually required for the foot!\r
399                                 for (i=SMOKE1SPR; i<=SMOKE4SPR; i++)\r
400                                 {\r
401                                         CA_MarkGrChunk(i);\r
402                                 }\r
403                                 break;\r
404 \r
405                         case 11:\r
406                                 SpawnInchworm(x, y);\r
407                                 lumpneeded[INCHWORM_LUMP] = true;\r
408                                 for (i=SMOKE1SPR; i<=SMOKE4SPR; i++)\r
409                                 {\r
410                                         CA_MarkGrChunk(i);\r
411                                 }\r
412                                 break;\r
413 \r
414                         case 12:\r
415                                 SpawnBounder(x, y);\r
416                                 lumpneeded[BOUNDER_LUMP] = true;\r
417                                 break;\r
418 \r
419                         case 13:\r
420                                 SpawnEggbird(x, y);\r
421                                 lumpneeded[EGGBIRD_LUMP] = true;\r
422                                 lumpneeded[EGG_LUMP] = true;\r
423                                 break;\r
424 \r
425                         case 48:\r
426                                 if (gamestate.difficulty < gd_Hard)\r
427                                         break;\r
428                         case 47:\r
429                                 if (gamestate.difficulty < gd_Normal)\r
430                                         break;\r
431                         case 14:\r
432                                 SpawnLick(x, y);\r
433                                 lumpneeded[LICK_LUMP] = true;\r
434                                 break;\r
435 \r
436                         case 88:\r
437                                 if (gamestate.difficulty < gd_Hard)\r
438                                         break;\r
439                         case 87:\r
440                                 if (gamestate.difficulty < gd_Normal)\r
441                                         break;\r
442                         case 15:\r
443                                 SpawnDopefish(x, y);\r
444                                 lumpneeded[DOPEFISH_LUMP] = true;\r
445                                 break;\r
446 \r
447                         case 16:\r
448                                 SpawnSchoolfish(x, y);\r
449                                 lumpneeded[SCHOOLFISH_LUMP] = true;\r
450                                 break;\r
451 \r
452                         case 24:\r
453                                 if (gamestate.difficulty < gd_Hard)\r
454                                         break;\r
455                         case 23:\r
456                                 if (gamestate.difficulty < gd_Normal)\r
457                                         break;\r
458                         case 17:\r
459                                 SpawnPixie(x, y);\r
460                                 lumpneeded[SPRITE_LUMP] = true;\r
461                                 break;\r
462 \r
463                         case 18:\r
464                                 SpawnEater(x, y);\r
465                                 lumpneeded[EATER_LUMP] = true;\r
466                                 break;\r
467 \r
468                         case 19:\r
469                                 SpawnMimrock(x, y);\r
470                                 lumpneeded[MIMROCK_LUMP] = true;\r
471                                 break;\r
472 \r
473                         case 74:\r
474                                 if (gamestate.difficulty < gd_Hard)\r
475                                         break;\r
476                         case 73:\r
477                                 if (gamestate.difficulty < gd_Normal)\r
478                                         break;\r
479                         case 20:\r
480                                 SpawnArachnut(x, y);\r
481                                 lumpneeded[ARACHNUT_LUMP] = true;\r
482                                 break;\r
483 \r
484                         case 21:\r
485                                 SpawnMadMushroom(x, y);\r
486                                 lumpneeded[MADMUSHROOM_LUMP] = true;\r
487                                 break;\r
488 \r
489                         case 44:\r
490                                 if (gamestate.difficulty < gd_Hard)\r
491                                         break;\r
492                         case 43:\r
493                                 if (gamestate.difficulty < gd_Normal)\r
494                                         break;\r
495                         case 22:\r
496                                 SpawnSlug(x, y);\r
497                                 lumpneeded[SLUG_LUMP] = true;\r
498                                 break;\r
499 \r
500                         case 25:\r
501                                 RF_SetScrollBlock(x, y, 1);\r
502                                 break;\r
503 \r
504                         case 26:\r
505                                 RF_SetScrollBlock(x, y, 0);\r
506                                 break;\r
507 \r
508                         case 27:\r
509                         case 28:\r
510                         case 29:\r
511                         case 30:\r
512                                 SpawnPlatform(x, y, info-27);\r
513                                 lumpneeded[PLATFORM_LUMP] = true;;\r
514                                 break;\r
515 \r
516                         case 32:\r
517                                 SpawnDropPlat(x, y);\r
518                                 lumpneeded[PLATFORM_LUMP] = true;\r
519                                 break;\r
520 \r
521                         case 33:\r
522                                 SpawnMiragia(x, y);\r
523                                 break;\r
524 \r
525                         case 34:\r
526                                 if (gamestate.ammo < 5)\r
527                                 {\r
528                                         SpawnBonus(x, y, 11);\r
529                                         lumpneeded[bonuslump[11]] = true;\r
530                                 }\r
531                                 break;\r
532 \r
533                         case 35:\r
534                                 SpawnScuba(x, y);\r
535                                 CA_MarkGrChunk(SCUBASPR);\r
536                                 break;\r
537 \r
538                         case 42:\r
539                                 SpawnSwimKeen(x, y);\r
540                                 SpawnScore();\r
541                                 lumpneeded[SCUBAKEEN_LUMP] = true;\r
542                                 //mark pickup shapes:\r
543                                 for (i=BONUS100SPR; i<=BONUSCLIPSPR; i++)\r
544                                 {\r
545                                         CA_MarkGrChunk(i);\r
546                                 }\r
547                                 CA_MarkGrChunk(SCOREBOXSPR);\r
548                                 break;\r
549 \r
550                         case 83:\r
551                         case 84:\r
552                         case 85:\r
553                         case 86:\r
554                                 if (gamestate.difficulty < gd_Hard)\r
555                                         break;\r
556                                 SpawnDartShooter(x, y, info-83);\r
557                                 lumpneeded[DARTS_LUMP] = true;\r
558                                 break;\r
559 \r
560                         case 79:\r
561                         case 80:\r
562                         case 81:\r
563                         case 82:\r
564                                 if (gamestate.difficulty < gd_Normal)\r
565                                         break;\r
566                                 SpawnDartShooter(x, y, info-79);\r
567                                 lumpneeded[DARTS_LUMP] = true;\r
568                                 break;\r
569 \r
570                         case 53:\r
571                         case 54:\r
572                         case 55:\r
573                         case 56:\r
574                                 SpawnDartShooter(x, y, info-53);\r
575                                 lumpneeded[DARTS_LUMP] = true;\r
576                                 break;\r
577 \r
578                         case 57:\r
579                         case 58:\r
580                         case 59:\r
581                         case 60:\r
582                         case 61:\r
583                         case 62:\r
584                         case 63:\r
585                         case 64:\r
586                         case 65:\r
587                         case 66:\r
588                         case 67:\r
589                         case 68:\r
590                                 SpawnBonus(x, y, info-57);\r
591                                 lumpneeded[bonuslump[info-57]] = true;\r
592                                 break;\r
593 \r
594                         case 69:\r
595                         case 70:\r
596                         case 71:\r
597                         case 72:\r
598                                 SpawnMine(x, y, info-69);\r
599                                 lumpneeded[MINE_LUMP] = true;\r
600                                 break;\r
601 \r
602                         case 75:\r
603                                 lumpneeded[MOON_LUMP] = true;\r
604                                 break;\r
605 \r
606                         case 78:\r
607                                 if (gamestate.difficulty < gd_Hard)\r
608                                         break;\r
609                         case 77:\r
610                                 if (gamestate.difficulty < gd_Normal)\r
611                                         break;\r
612                         case 76:\r
613                                 SpawnEggbirdOut(x, y);\r
614                                 lumpneeded[EGGBIRD_LUMP] = true;\r
615                                 break;\r
616                         }\r
617                 }\r
618         }\r
619 \r
620         for (ob = player; ob; ob = ob->next)\r
621         {\r
622                 if (ob->active != ac_allways)\r
623                         ob->active = ac_no;\r
624         }\r
625 \r
626         for (i = 0; i < NUMLUMPS; i++)\r
627         {\r
628                 if (lumpneeded[i])\r
629                 {\r
630                         for (chunk = lumpstart[i]; chunk <= lumpend[i]; chunk++)\r
631                         {\r
632                                 CA_MarkGrChunk(chunk);\r
633                         }\r
634                 }\r
635         }\r
636 }\r
637 \r
638 //============================================================================\r
639 \r
640 /*\r
641 ===========================\r
642 =\r
643 = PrincessLindsey\r
644 =\r
645 ===========================\r
646 */\r
647 \r
648 char *lindseytext[2] =\r
649 {\r
650         "There's gear to help\n"\r
651         "you swim in Three-Tooth\n"\r
652         "Lake. It is hidden in\n"\r
653         "Miragia.\n"\r
654         ,\r
655         "The way to the Pyramid\n"\r
656         "of the Forbidden lies\n"\r
657         "under the Pyramid of\n"\r
658         "Moons.\n"\r
659 };\r
660 \r
661 char *klindseytext[2] =\r
662 {\r
663         "Thanks, your Highness!"\r
664         ,\r
665         "Thanks for the\n"\r
666         "mysterious clue,\n"\r
667         "Princess!\n"\r
668 };\r
669 \r
670 void PrincessLindsey(void)\r
671 {\r
672         SD_WaitSoundDone();\r
673         StopMusic();\r
674         CA_UpLevel();\r
675         CA_MarkGrChunk(LINDSEYPIC);\r
676         CA_MarkGrChunk(KEENTALK1PIC);\r
677         CA_MarkGrChunk(KEENTALK2PIC);\r
678         CA_CacheMarks(NULL);\r
679         VW_FixRefreshBuffer();\r
680 \r
681         US_CenterWindow(26, 8);\r
682         VWB_DrawPic(WindowX, WindowY, LINDSEYPIC);\r
683         PrintY += 6;\r
684         WindowW -= 48;\r
685         WindowX += 48;\r
686         US_CPrint("Princess Lindsey says:\n");\r
687         if (mapon == 7)\r
688         {\r
689                 US_CPrint(lindseytext[0]);\r
690         }\r
691         else\r
692         {\r
693                 US_CPrint(lindseytext[1]);\r
694         }\r
695         VW_UpdateScreen();\r
696         SD_PlaySound(SND_MAKEFOOT);\r
697         VW_WaitVBL(60);\r
698         IN_ClearKeysDown();\r
699         IN_Ack();\r
700 \r
701         US_CenterWindow(26, 8);\r
702         VWB_DrawPic(WindowX+WindowW-48, WindowY, KEENTALK1PIC);\r
703         WindowW -= 48;\r
704         PrintY += 12;\r
705         if (mapon == 7)\r
706         {\r
707                 US_CPrint(klindseytext[0]);\r
708         }\r
709         else\r
710         {\r
711                 US_CPrint(klindseytext[1]);\r
712         }\r
713         VW_UpdateScreen();\r
714         VW_WaitVBL(30);\r
715         IN_ClearKeysDown();\r
716         IN_Ack();\r
717 \r
718         VWB_DrawPic(WindowX+WindowW, WindowY, KEENTALK2PIC);\r
719         VW_UpdateScreen();\r
720         VW_WaitVBL(30);\r
721         IN_ClearKeysDown();\r
722         IN_Ack();\r
723 \r
724         CA_DownLevel();\r
725         StartMusic(gamestate.mapon);\r
726 \r
727         //reset scorebox (sprite may have been re-cached by CA_DownLevel)\r
728         scoreobj->temp2 = -1;\r
729         scoreobj->temp1 = -1;\r
730         scoreobj->temp3 = -1;\r
731         scoreobj->temp4 = -1;\r
732 }\r
733 \r
734 //============================================================================\r
735 \r
736 /*\r
737 ===========================\r
738 =\r
739 = RescueJanitor\r
740 =\r
741 ===========================\r
742 */\r
743 \r
744 char far jantext1[] =\r
745         "Thanks for going to all\n"\r
746         "that trouble, but I'm\n"\r
747         "just the janitor for the\n"\r
748         "High Council.";\r
749 \r
750 char far jantext2[] =\r
751         "I tried to tell the\n"\r
752         "Shikadi that but they\n"\r
753         "just wouldn't listen...";\r
754 \r
755 char far keenjantext[] =\r
756         "This had better\n"\r
757         "be a joke.";\r
758 \r
759 char far jantext3[] =\r
760         "Sorry.  You aren't\n"\r
761         "mad, are you?";\r
762 \r
763 void RescueJanitor(void)\r
764 {\r
765         char str[200];\r
766 \r
767         SD_WaitSoundDone();\r
768         CA_UpLevel();\r
769         CA_MarkGrChunk(ORACLEPIC);\r
770         CA_MarkGrChunk(KEENTALK1PIC);\r
771         CA_MarkGrChunk(KEENMADPIC);\r
772         CA_CacheMarks(NULL);\r
773         VW_FixRefreshBuffer();\r
774         StartMusic(-1);\r
775         \r
776         US_CenterWindow(26, 8);\r
777         VWB_DrawPic(WindowX, WindowY, ORACLEPIC);\r
778         PrintY += 6;\r
779         WindowW -= 48;\r
780         WindowX += 48;\r
781         _fstrcpy(str, jantext1);\r
782         US_CPrint(str);\r
783         VW_UpdateScreen();\r
784         VW_WaitVBL(60);\r
785         IN_ClearKeysDown();\r
786         IN_Ack();\r
787 \r
788         US_CenterWindow(26, 8);\r
789         VWB_DrawPic(WindowX, WindowY, ORACLEPIC);\r
790         PrintY += 6;\r
791         WindowW -= 48;\r
792         WindowX += 48;\r
793         _fstrcpy(str, jantext2);\r
794         US_CPrint(str);\r
795         VW_UpdateScreen();\r
796         VW_WaitVBL(60);\r
797         IN_ClearKeysDown();\r
798         IN_Ack();\r
799 \r
800         US_CenterWindow(26, 8);\r
801         VWB_DrawPic(WindowX+WindowW-48, WindowY, KEENTALK1PIC);\r
802         WindowW -= 48;\r
803         PrintY += 12;\r
804         _fstrcpy(str, keenjantext);\r
805         US_CPrint(str);\r
806         VW_UpdateScreen();\r
807         VW_WaitVBL(60);\r
808         IN_ClearKeysDown();\r
809         IN_Ack();\r
810 \r
811         US_CenterWindow(26, 8);\r
812         VWB_DrawPic(WindowX, WindowY, ORACLEPIC);\r
813         PrintY += 6;\r
814         WindowW -= 48;\r
815         WindowX += 48;\r
816         _fstrcpy(str, jantext3);\r
817         US_CPrint(str);\r
818         VW_UpdateScreen();\r
819         VW_WaitVBL(60);\r
820         IN_ClearKeysDown();\r
821         IN_Ack();\r
822 \r
823         US_CenterWindow(26, 8);\r
824         VWB_DrawPic(WindowX+WindowW-48, WindowY, KEENTALK1PIC);\r
825         VWB_DrawPic(WindowX+WindowW-40, WindowY+24, KEENMADPIC);\r
826         VW_UpdateScreen();\r
827         VW_WaitVBL(30);\r
828         IN_ClearKeysDown();\r
829         IN_Ack();\r
830 \r
831         StopMusic();\r
832         CA_DownLevel();\r
833         StartMusic(gamestate.mapon);\r
834 \r
835         //BUG: scorebox needs to be reset here (sprite may have been re-cached by CA_DownLevel)\r
836 }\r
837 \r
838 //============================================================================\r
839 \r
840 /*\r
841 ===========================\r
842 =\r
843 = CanitSwim\r
844 =\r
845 ===========================\r
846 */\r
847 \r
848 void CantSwim(void)\r
849 {\r
850         SD_WaitSoundDone();\r
851         CA_UpLevel();   // kinda useless without CA_CacheMarks or CA_SetGrPurge\r
852         // BUG: haven't made anything purgable here, caching the pic may cause an "out of memory" crash\r
853         CA_CacheGrChunk(KEENTALK1PIC);\r
854 \r
855         US_CenterWindow(26, 8);\r
856         VWB_DrawPic(WindowX+WindowW-48, WindowY, KEENTALK1PIC);\r
857         WindowW -= 48;\r
858         PrintY += 12;\r
859         US_CPrint("I can't swim!");\r
860         VW_UpdateScreen();\r
861         VW_WaitVBL(30);\r
862         IN_ClearKeysDown();\r
863         IN_Ack();\r
864         CA_DownLevel();\r
865 \r
866         //Note: scorebox sprite has not been re-cached here (didn't use CA_CacheMarks or anything else that would have made the sprite purgable)\r
867 }\r
868 \r
869 //============================================================================\r
870 \r
871 /*\r
872 ===========================\r
873 =\r
874 = GotScuba\r
875 =\r
876 ===========================\r
877 */\r
878 \r
879 void GotScuba(void)\r
880 {\r
881         SD_WaitSoundDone();\r
882         CA_UpLevel();\r
883         CA_MarkGrChunk(KEENTALK1PIC);\r
884         CA_MarkGrChunk(KEENTALK2PIC);\r
885         CA_CacheMarks(NULL);\r
886 \r
887         US_CenterWindow(26, 8);\r
888         VWB_DrawPic(WindowX+WindowW-48, WindowY, KEENTALK1PIC);\r
889         WindowW -= 48;\r
890         PrintY += 12;\r
891         US_CPrint(\r
892                 "Cool!  I can breathe\n"\r
893                 "under water now!"\r
894                 );\r
895         VW_UpdateScreen();\r
896         VW_WaitVBL(30);\r
897         IN_ClearKeysDown();\r
898         IN_Ack();\r
899 \r
900         VWB_DrawPic(WindowX+WindowW, WindowY, KEENTALK2PIC);\r
901         VW_UpdateScreen();\r
902         VW_WaitVBL(30);\r
903         IN_ClearKeysDown();\r
904         IN_Ack();\r
905 \r
906         CA_DownLevel();\r
907 \r
908         //Note: scorebox sprite may have been re-cached by CA_DownLevel, but the level ends after this anyway\r
909 }\r
910 \r
911 //============================================================================\r
912 \r
913 /*\r
914 ===========================\r
915 =\r
916 = RescuedMember\r
917 =\r
918 ===========================\r
919 */\r
920 \r
921 char *keentext[] = {\r
922         "No sweat, oh guardian\n"\r
923         "of wisdom!"\r
924         ,\r
925         "Sounds like a plan,\n"\r
926         "bearded one!"\r
927         ,\r
928         "No problemo."\r
929         ,\r
930         "Great.  You know, you\n"\r
931         "look a lot like the\n"\r
932         "last guy I rescued..."\r
933         ,\r
934         "Good idea, Gramps."\r
935         ,\r
936         "May the road rise\n"\r
937         "to meet your feet,\n"\r
938         "Mr. Member."\r
939         ,\r
940         "Wise plan of action,\n"\r
941         "your ancientness."\r
942         ,\r
943         "You're the last one,\n"\r
944         "fella.  Let's both\n"\r
945         "get back to the\n"\r
946         "Oracle chamber!"\r
947 };\r
948 \r
949 void RescuedMember(void)\r
950 {\r
951         SD_WaitSoundDone();\r
952         CA_UpLevel();\r
953         CA_MarkGrChunk(ORACLEPIC);\r
954         CA_MarkGrChunk(KEENTALK1PIC);\r
955         CA_MarkGrChunk(KEENTALK2PIC);\r
956         CA_CacheMarks(NULL);\r
957         StartMusic(-1);\r
958         VW_FixRefreshBuffer();\r
959 \r
960         US_CenterWindow(26, 8);\r
961         VWB_DrawPic(WindowX, WindowY, ORACLEPIC);\r
962         PrintY += 6;\r
963         WindowW -= 48;\r
964         WindowX += 48;\r
965         if (mapon == 17)\r
966         {\r
967                 US_CPrint(\r
968                         "Ggoh thig you sogh mg\n"\r
969                         "fgor regscuing mgge!\n"\r
970                         "I'gll regur tgo the\n"\r
971                         "Goracle chagber\n"\r
972                         "igmediatggely. Blub."\r
973                         );\r
974         }\r
975         else\r
976         {\r
977                 US_CPrint(\r
978                         "Oh thank you so much\n"\r
979                         "for rescuing me!\n"\r
980                         "I'll return to the\n"\r
981                         "Oracle chamber\n"\r
982                         "immediately."\r
983                         );\r
984         }\r
985         VW_UpdateScreen();\r
986         VW_WaitVBL(60);\r
987         IN_ClearKeysDown();\r
988         IN_Ack();\r
989 \r
990         US_CenterWindow(26, 8);\r
991         VWB_DrawPic(WindowX+WindowW-48, WindowY, KEENTALK1PIC);\r
992         WindowW -= 48;\r
993         PrintY += 12;\r
994         US_CPrint(keentext[gamestate.rescued]);\r
995         VW_UpdateScreen();\r
996         VW_WaitVBL(30);\r
997         IN_ClearKeysDown();\r
998         IN_Ack();\r
999 \r
1000         VWB_DrawPic(WindowX+WindowW, WindowY, KEENTALK2PIC);\r
1001         VW_UpdateScreen();\r
1002         VW_WaitVBL(30);\r
1003         IN_ClearKeysDown();\r
1004         IN_Ack();\r
1005 \r
1006         gamestate.rescued++;\r
1007         CA_DownLevel();\r
1008         StopMusic();\r
1009 \r
1010         //Note: scorebox sprite may have been re-cached by CA_DownLevel, but the level ends after this anyway\r
1011 }\r
1012 \r
1013 /*\r
1014 =============================================================================\r
1015 \r
1016                                                   SWIMMING KEEN\r
1017 \r
1018 temp4 = counter for spawning bubbles\r
1019 \r
1020 =============================================================================\r
1021 */\r
1022 \r
1023 statetype s_keenswimslow1 = {SCUBAKEENL1SPR, SCUBAKEENR1SPR, stepthink, false, false, 50, 0, 0, T_KeenSwimSlow, C_KeenSwim, R_KeenSwim, &s_keenswimslow2};\r
1024 statetype s_keenswimslow2 = {SCUBAKEENL2SPR, SCUBAKEENR2SPR, stepthink, false, false, 50, 0, 0, T_KeenSwimSlow, C_KeenSwim, R_KeenSwim, &s_keenswimslow1};\r
1025 statetype s_keenswim1     = {SCUBAKEENL1SPR, SCUBAKEENR1SPR, stepthink, false, false, 50, 0, 0, T_KeenSwim, C_KeenSwim, R_KeenSwim, &s_keenswimslow2};\r
1026 statetype s_keenswim2     = {SCUBAKEENL2SPR, SCUBAKEENR2SPR, stepthink, false, false, 50, 0, 0, T_KeenSwim, C_KeenSwim, R_KeenSwim, &s_keenswimslow1};\r
1027 //Note: the die states for swimming Keen are in CK_KEEN.C and K4_ACT3.C (dopefish section)\r
1028 \r
1029 statetype s_kbubble1  = {SMALLBUBBLE1SPR, SMALLBUBBLE1SPR, think, false, false, 20, 0, 24, T_Bubble, NULL, R_Draw, &s_kbubble1};\r
1030 statetype s_kbubble2  = {SMALLBUBBLE2SPR, SMALLBUBBLE2SPR, think, false, false, 20, 0, 24, T_Bubble, NULL, R_Draw, &s_kbubble2};\r
1031 statetype s_kbubble3  = {SMALLBUBBLE3SPR, SMALLBUBBLE3SPR, think, false, false, 20, 0, 24, T_Bubble, NULL, R_Draw, &s_kbubble3};\r
1032 statetype s_kbubble4  = {SMALLBUBBLE4SPR, SMALLBUBBLE4SPR, think, false, false, 20, 0, 24, T_Bubble, NULL, R_Draw, &s_kbubble4};\r
1033 \r
1034 /*\r
1035 ===========================\r
1036 =\r
1037 = SpawnSwimKeen\r
1038 =\r
1039 ===========================\r
1040 */\r
1041 \r
1042 void SpawnSwimKeen(Sint16 x, Sint16 y)\r
1043 {\r
1044         player->obclass = keenobj;\r
1045         player->active = ac_allways;\r
1046         player->priority = 1;\r
1047         player->x = CONVERT_TILE_TO_GLOBAL(x);\r
1048         player->y = CONVERT_TILE_TO_GLOBAL(y);\r
1049         player->xdir = 1;\r
1050         player->ydir = 1;\r
1051         player->needtoclip = cl_fullclip;\r
1052         NewState(player, &s_keenswimslow1);\r
1053 }\r
1054 \r
1055 /*\r
1056 ===========================\r
1057 =\r
1058 = SpawnKbubble\r
1059 =\r
1060 ===========================\r
1061 */\r
1062 \r
1063 void SpawnKbubble(objtype *ob)\r
1064 {\r
1065         ob->temp4 = 0;\r
1066         GetNewObj(true);\r
1067         if (ob->xdir == -1)\r
1068         {\r
1069                 new->x = ob->x;\r
1070         }\r
1071         else\r
1072         {\r
1073                 new->x = ob->x + 24*PIXGLOBAL;\r
1074         }\r
1075         new->y = ob->y;\r
1076         new->obclass = inertobj;\r
1077         new->priority = 3;\r
1078         new->active = ac_removable;\r
1079         new->needtoclip = cl_noclip;\r
1080         new->yspeed = -24;\r
1081         new->xspeed = 4;\r
1082         switch (US_RndT() / 64)\r
1083         {\r
1084         case 0:\r
1085                 NewState(new, &s_kbubble1);\r
1086                 break;\r
1087         case 1:\r
1088                 NewState(new, &s_kbubble2);\r
1089                 break;\r
1090         case 2:\r
1091                 NewState(new, &s_kbubble3);\r
1092                 break;\r
1093         case 3:\r
1094                 NewState(new, &s_kbubble4);\r
1095                 break;\r
1096         }\r
1097         SD_PlaySound(SND_BLUB);\r
1098 }\r
1099 \r
1100 /*\r
1101 ===========================\r
1102 =\r
1103 = T_KeenSwimSlow\r
1104 =\r
1105 ===========================\r
1106 */\r
1107 \r
1108 void T_KeenSwimSlow(objtype *ob)\r
1109 {\r
1110         Sint32 i;\r
1111         Sint16 vx, vy, xc, yc;\r
1112 \r
1113         xc = ob->xspeed < 0;\r
1114         yc = ob->yspeed < 4;\r
1115 \r
1116         ob->temp4 = ob->temp4 + tics;\r
1117         if (ob->temp4 > 60)\r
1118                 SpawnKbubble(ob);\r
1119 \r
1120         if (jumpbutton && !jumpheld)\r
1121         {\r
1122                 jumpheld = true;\r
1123                 if (c.xaxis)\r
1124                         ob->xspeed = c.xaxis * 18;\r
1125                 if (c.yaxis)\r
1126                         ob->yspeed = c.yaxis * 18;\r
1127                 ob->state = ob->state->nextstate;\r
1128         }\r
1129         if (c.xaxis)\r
1130                 ob->xdir = c.xaxis;\r
1131 \r
1132         for (i = lasttimecount-tics; i < lasttimecount; i++)\r
1133         {\r
1134                 if ((i & 7) == 0)\r
1135                 {\r
1136                         if (ob->xspeed > 12)\r
1137                         {\r
1138                                 vx = -3;\r
1139                         }\r
1140                         else if (ob->xspeed > 0)\r
1141                         {\r
1142                                 vx = -1;\r
1143                         }\r
1144                         else if (ob->xspeed > -12)\r
1145                         {\r
1146                                 vx = 1;\r
1147                         }\r
1148                         else\r
1149                         {\r
1150                                 vx = 3;\r
1151                         }\r
1152                         vx += c.xaxis;\r
1153                         vx += c.xaxis;\r
1154                         ob->xspeed += vx;\r
1155 \r
1156                         if (c.xaxis == 0 && (ob->xspeed < 0) != xc)\r
1157                                 ob->xspeed = 0;\r
1158 \r
1159                         if (ob->yspeed > 12)\r
1160                         {\r
1161                                 vy = -3;\r
1162                         }\r
1163                         else if (ob->yspeed > 4)\r
1164                         {\r
1165                                 vy = -1;\r
1166                         }\r
1167                         else if (ob->yspeed > -12)\r
1168                         {\r
1169                                 vy = 1;\r
1170                         }\r
1171                         else\r
1172                         {\r
1173                                 vy = 3;\r
1174                         }\r
1175                         vy += c.yaxis;\r
1176                         vy += c.yaxis;\r
1177                         ob->yspeed += vy;\r
1178 \r
1179                         if (c.yaxis == 0 && ob->yspeed > 4 && yc)\r
1180                                 ob->yspeed = 0;\r
1181                 }\r
1182                 xtry += ob->xspeed;\r
1183                 ytry += ob->yspeed;\r
1184         }\r
1185 }\r
1186 \r
1187 /*\r
1188 ===========================\r
1189 =\r
1190 = T_KeenSwim\r
1191 =\r
1192 ===========================\r
1193 */\r
1194 \r
1195 void T_KeenSwim(objtype *ob)    //never actually used\r
1196 {\r
1197         ob->temp4 = ob->temp4 + tics;\r
1198         if (ob->temp4 > 60)\r
1199                 SpawnKbubble(ob);\r
1200 \r
1201         if (jumpbutton && !jumpheld)\r
1202         {\r
1203                 jumpheld = true;\r
1204                 ob->xspeed = c.xaxis * 18;\r
1205                 if (c.yaxis)\r
1206                         ob->yspeed = c.yaxis * 18;\r
1207 \r
1208                 if (ob->state == &s_keenswim1)\r
1209                 {\r
1210                         ob->state = &s_keenswim2;\r
1211                 }\r
1212                 else\r
1213                 {\r
1214                         ob->state = &s_keenswim1;\r
1215                 }\r
1216         }\r
1217 \r
1218         xtry = xtry + ob->xspeed * tics;\r
1219         ytry = ytry + ob->yspeed * tics;\r
1220         if (xtry > 0)\r
1221         {\r
1222                 ob->xdir = 1;\r
1223         }\r
1224         else if (xtry < 0)\r
1225         {\r
1226                 ob->xdir = -1;\r
1227         }\r
1228 \r
1229         ytry = ytry + tics*4;\r
1230 }\r
1231 \r
1232 /*\r
1233 ===========================\r
1234 =\r
1235 = C_KeenSwim\r
1236 =\r
1237 ===========================\r
1238 */\r
1239 \r
1240 void C_KeenSwim(objtype *ob, objtype *hit)\r
1241 {\r
1242         switch (hit->obclass)\r
1243         {\r
1244         case bonusobj:\r
1245                 switch (hit->temp1)\r
1246                 {\r
1247                 case 0:\r
1248                 case 1:\r
1249                 case 2:\r
1250                 case 3:\r
1251                 case 4:\r
1252                 case 5:\r
1253                 case 6:\r
1254                 case 7:\r
1255                 case 8:\r
1256                 case 9:\r
1257                 case 10:\r
1258                 case 11:\r
1259                         SD_PlaySound(bonussound[hit->temp1]);\r
1260                         hit->obclass = inertobj;\r
1261                         hit->priority = 3;\r
1262                         hit->shapenum = bonussprite[hit->temp1];\r
1263                         GivePoints(bonuspoints[hit->temp1]);\r
1264                         if (hit->temp1 < 4)\r
1265                         {\r
1266                                 gamestate.keys[hit->temp1]++;\r
1267                         }\r
1268                         else if (hit->temp1 == 10)\r
1269                         {\r
1270                                 gamestate.lives++;\r
1271                         }\r
1272                         else if (hit->temp1 == 11)\r
1273                         {\r
1274                                 gamestate.ammo += shotsinclip[gamestate.difficulty];\r
1275                         }\r
1276                         ChangeState(hit, &s_bonusrise);\r
1277                         break;\r
1278                 }\r
1279                 break;\r
1280 \r
1281         case oracleobj:\r
1282                 playstate = ex_rescued;\r
1283                 break;\r
1284         }\r
1285         ob++;                   // shut up compiler\r
1286 }\r
1287 \r
1288 /*\r
1289 ===========================\r
1290 =\r
1291 = R_KeenSwim\r
1292 =\r
1293 ===========================\r
1294 */\r
1295 \r
1296 void R_KeenSwim(objtype *ob)\r
1297 {\r
1298         if (ob->hiteast && ob->xspeed < 0 || ob->hitwest && ob->xspeed > 0)\r
1299                 ob->xspeed = 0;\r
1300 \r
1301         if (ob->hitnorth && ob->yspeed > 0 || ob->hitsouth && ob->yspeed < 0)\r
1302                 ob->yspeed = 0;\r
1303 \r
1304         RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);\r
1305 }\r