--- /dev/null
+/* Reconstructed Commander Keen 4-6 Source Code\r
+ * Copyright (C) 2021 K1n9_Duk3\r
+ *\r
+ * This file is loosely based on:\r
+ * Keen Dreams Source Code\r
+ * Copyright (C) 2014 Javier M. Chavez\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License along\r
+ * with this program; if not, write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+ */\r
+\r
+/*\r
+K5_SPEC.C\r
+=========\r
+\r
+Contains (in this order):\r
+\r
+- lump definition\r
+- "Star Wars" crawl text\r
+- level names & messages\r
+- Airlock opening & closing code\r
+- ScanInfoPlane() - for spawning the level objects and marking required sprites\r
+- game over animation\r
+- messages for breaking fuses\r
+*/\r
+\r
+#include "CK_DEF.H"\r
+\r
+enum {\r
+ HELP_LUMP, // 0\r
+ CONTROLS_LUMP, // 1\r
+ KEENTALK_LUMP, // 2\r
+ LOADING_LUMP, // 3\r
+ PADDLE_LUMP, // 4\r
+ KEEN_LUMP, // 5\r
+ SUGAR1_LUMP, // 6\r
+ SUGAR2_LUMP, // 7\r
+ SUGAR3_LUMP, // 8\r
+ SUGAR4_LUMP, // 9\r
+ SUGAR5_LUMP, // 10\r
+ SUGAR6_LUMP, // 11\r
+ ONEUP_LUMP, // 12\r
+ KEYGEM_LUMP, // 13\r
+ AMMO_LUMP, // 14\r
+ LASER_LUMP, // 15\r
+ WORLDKEEN_LUMP, // 16\r
+ MASTER_LUMP, // 17\r
+ SHIKADI_LUMP, // 18\r
+ SHOCKSHUND_LUMP, // 19\r
+ SPHEREFUL_LUMP, // 20\r
+ SPARKY_LUMP, // 21\r
+ MINE_LUMP, // 22\r
+ SLICESTAR_LUMP, // 23\r
+ ROBORED_LUMP, // 24\r
+ SPIRO_LUMP, // 25\r
+ AMPTON_LUMP, // 26\r
+ VOLTE_LUMP, // 27\r
+ SLOTPLAT_LUMP, // 28\r
+ SPINDRED_LUMP, // 29\r
+ SHELLEY_LUMP, // 30\r
+ PLATFORM_LUMP, // 31\r
+ SMALLPLAT_LUMP, // 32\r
+ KEYCARD_LUMP, // 33\r
+ SCOTTIE_LUMP, // 34\r
+ FUSE_LUMP, // 35\r
+ STAREXPLODE_LUMP, // 36\r
+ TELEPORT_LUMP, // 37\r
+\r
+ NUMLUMPS=42 // Keen 5 has 4 unused lumps at the end\r
+};\r
+\r
+Uint16 lumpstart[NUMLUMPS] = {\r
+ HELP_LUMP_START,\r
+ CONTROLS_LUMP_START,\r
+ KEENTALK_LUMP_START,\r
+ LOADING_LUMP_START,\r
+ PADDLE_LUMP_START,\r
+ KEEN_LUMP_START,\r
+ SUGAR1_LUMP_START,\r
+ SUGAR2_LUMP_START,\r
+ SUGAR3_LUMP_START,\r
+ SUGAR4_LUMP_START,\r
+ SUGAR5_LUMP_START,\r
+ SUGAR6_LUMP_START,\r
+ ONEUP_LUMP_START,\r
+ KEYGEM_LUMP_START,\r
+ AMMO_LUMP_START,\r
+ LASER_LUMP_START,\r
+ WORLDKEEN_LUMP_START,\r
+ MASTER_LUMP_START,\r
+ SHIKADI_LUMP_START,\r
+ SHOCKSHUND_LUMP_START,\r
+ SPHEREFUL_LUMP_START,\r
+ SPARKY_LUMP_START,\r
+ MINE_LUMP_START,\r
+ SLICESTAR_LUMP_START,\r
+ ROBORED_LUMP_START,\r
+ SPIRO_LUMP_START,\r
+ AMPTON_LUMP_START,\r
+ VOLTE_LUMP_START,\r
+ SLOTPLAT_LUMP_START,\r
+ SPINDRED_LUMP_START,\r
+ SHELLEY_LUMP_START,\r
+ PLATFORM_LUMP_START,\r
+ MINIPLAT_LUMP_START,\r
+ KEYCARD_LUMP_START,\r
+ SCOTTIE_LUMP_START,\r
+ FUSE_LUMP_START,\r
+ STAREXPLODE_LUMP_START,\r
+ TELEPORT_LUMP_START\r
+};\r
+\r
+Uint16 lumpend[NUMLUMPS] = {\r
+ HELP_LUMP_END,\r
+ CONTROLS_LUMP_END,\r
+ KEENTALK_LUMP_END,\r
+ LOADING_LUMP_END,\r
+ PADDLE_LUMP_END,\r
+ KEEN_LUMP_END,\r
+ SUGAR1_LUMP_END,\r
+ SUGAR2_LUMP_END,\r
+ SUGAR3_LUMP_END,\r
+ SUGAR4_LUMP_END,\r
+ SUGAR5_LUMP_END,\r
+ SUGAR6_LUMP_END,\r
+ ONEUP_LUMP_END,\r
+ KEYGEM_LUMP_END,\r
+ AMMO_LUMP_END,\r
+ LASER_LUMP_END,\r
+ WORLDKEEN_LUMP_END,\r
+ MASTER_LUMP_END,\r
+ SHIKADI_LUMP_END,\r
+ SHOCKSHUND_LUMP_END,\r
+ SPHEREFUL_LUMP_END,\r
+ SPARKY_LUMP_END,\r
+ MINE_LUMP_END,\r
+ SLICESTAR_LUMP_END,\r
+ ROBORED_LUMP_END,\r
+ SPIRO_LUMP_END,\r
+ AMPTON_LUMP_END,\r
+ VOLTE_LUMP_END,\r
+ SLOTPLAT_LUMP_END,\r
+ SPINDRED_LUMP_END,\r
+ SHELLEY_LUMP_END,\r
+ PLATFORM_LUMP_END,\r
+ MINIPLAT_LUMP_END,\r
+ KEYCARD_LUMP_END,\r
+ SCOTTIE_LUMP_END,\r
+ FUSE_LUMP_END,\r
+ STAREXPLODE_LUMP_END,\r
+ TELEPORT_LUMP_END\r
+};\r
+\r
+boolean lumpneeded[NUMLUMPS];\r
+\r
+#if GRMODE == EGAGR\r
+\r
+char far swtext[] =\r
+ "Episode Five\n"\r
+ "\n"\r
+ "The Armageddon Machine\n"\r
+ "\n"\r
+ "After learning the\n"\r
+ "location of the secret\n"\r
+ "Shikadi base, Keen\n"\r
+ "jumped in the trusty\n"\r
+ "Bean-with-Bacon\n"\r
+ "Megarocket and blasted\n"\r
+ "across interstellar\n"\r
+ "space.\n"\r
+ "\n"\r
+ "Seventy-five furious\n"\r
+ "games of Paddle War\n"\r
+ "later, Keen dropped\n"\r
+ "out of lightspeed near\n"\r
+ " the Korath system.\n"\r
+ "\n"\r
+ "He flew toward the\n"\r
+ "planet, keeping it\n"\r
+ "between him and the\n"\r
+ "base.\n"\r
+ "\n"\r
+ "Pulling up underside\n"\r
+ "and docking at the\n"\r
+ "Ion Ventilation System,\n"\r
+ "Keen must destroy the\n"\r
+ "Shikadi Armageddon\n"\r
+ "Machine before it\n"\r
+ "explodes and destroys\n"\r
+ "the Milky Way! He\n"\r
+ "steps into the dark\n"\r
+ "ventilation duct and\n"\r
+ "begins his most\n"\r
+ "dangerous adventure\n"\r
+ "yet...\n";\r
+\r
+#endif\r
+\r
+char far l0n[] = "Omegamatic";\r
+char far l1n[] = "Ion Ventilation System";\r
+char far l2n[] = "Security Center";\r
+char far l3n[] = "Defense Tunnel Vlook";\r
+char far l4n[] = "Energy Flow Systems";\r
+char far l5n[] = "Defense Tunnel Burrh";\r
+char far l6n[] = "Regulation\nControl Center";\r
+char far l7n[] = "Defense Tunnel Sorra";\r
+char far l8n[] = "Neutrino\nBurst Injector";\r
+char far l9n[] = "Defense Tunnel Teln";\r
+char far l10n[] = "Brownian\nMotion Inducer";\r
+char far l11n[] = "Gravitational\nDamping Hub";\r
+char far l12n[] = "Quantum\nExplosion Dynamo";\r
+char far l13n[] = "Korath III Base";\r
+char far l14n[] = "BWBMegarocket";\r
+char far l15n[] = "High Scores";\r
+\r
+char far l0e[] = "Keen purposefully\nwanders about the\nOmegamatic";\r
+char far l1e[] = "Keen investigates the\nIon Ventilation System";\r
+char far l2e[] = "Keen struts through\nthe Security Center";\r
+char far l3e[] = "Keen invades\nDefense Tunnel Vlook";\r
+char far l4e[] = "Keen engages\nEnergy Flow Systems";\r
+char far l5e[] = "Keen barrels into\nDefense Tunnel Burrh";\r
+char far l6e[] = "Keen goes nuts in\nthe Regulation\nControl Center";\r
+char far l7e[] = "Keen regrets entering\nDefense Tunnel Sorra";\r
+char far l8e[] = "Keen blows through\nthe Neutrino\nBurst Injector";\r
+char far l9e[] = "Keen trots through\nDefense Tunnel Teln";\r
+char far l10e[] = "Keen breaks into\nthe Brownian\nMotion Inducer";\r
+char far l11e[] = "Keen hurries through\nthe Gravitational\nDamping Hub";\r
+char far l12e[] = "Keen explodes into\nthe Quantum\nExplosion Dynamo";\r
+char far l13e[] = "Keen faces danger\nin the secret\nKorath III Base";\r
+char far l14e[] = "Keen will not be\nin the BWBMegarocket";\r
+char far l15e[] = "Keen unexplainedly\nfinds himself by\ntheHigh Scores"; // sic!\r
+\r
+char far *levelnames[GAMELEVELS] = {\r
+ l0n,\r
+ l1n,\r
+ l2n,\r
+ l3n,\r
+ l4n,\r
+ l5n,\r
+ l6n,\r
+ l7n,\r
+ l8n,\r
+ l9n,\r
+ l10n,\r
+ l11n,\r
+ l12n,\r
+ l13n,\r
+ l14n,\r
+ l15n\r
+};\r
+\r
+char far *levelenter[GAMELEVELS] = {\r
+ l0e,\r
+ l1e,\r
+ l2e,\r
+ l3e,\r
+ l4e,\r
+ l5e,\r
+ l6e,\r
+ l7e,\r
+ l8e,\r
+ l9e,\r
+ l10e,\r
+ l11e,\r
+ l12e,\r
+ l13e,\r
+ l14e,\r
+ l15e\r
+};\r
+\r
+Uint16 bonuslump[] = {\r
+ KEYGEM_LUMP, KEYGEM_LUMP, KEYGEM_LUMP, KEYGEM_LUMP,\r
+ SUGAR1_LUMP, SUGAR2_LUMP, SUGAR3_LUMP,\r
+ SUGAR4_LUMP, SUGAR5_LUMP, SUGAR6_LUMP,\r
+ ONEUP_LUMP, AMMO_LUMP, KEYCARD_LUMP, 0, 0\r
+};\r
+\r
+//============================================================================\r
+\r
+/*\r
+===========================\r
+=\r
+= OpenMapDoor\r
+=\r
+===========================\r
+*/\r
+\r
+void OpenMapDoor(Sint16 tileX, Sint16 tileY)\r
+{\r
+ Sint16 x, y;\r
+ Uint16 tiles[2][2];\r
+\r
+ for (y=0; y<2; y++)\r
+ {\r
+ for (x=0; x<2; x++)\r
+ {\r
+ tiles[y][x] = *(mapsegs[1]+mapbwidthtable[y]/2 + x + 10);\r
+ }\r
+ }\r
+ RF_MemToMap(&tiles[0][0], 1, tileX, tileY, 2, 2);\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= CloseMapDoor\r
+=\r
+===========================\r
+*/\r
+\r
+void CloseMapDoor(Sint16 tileX, Sint16 tileY)\r
+{\r
+ Sint16 x, y;\r
+ Uint16 tiles[2][2];\r
+\r
+ for (y=0; y<2; y++)\r
+ {\r
+ for (x=0; x<2; x++)\r
+ {\r
+ tiles[y][x] = *(mapsegs[1]+mapbwidthtable[y]/2 + x);\r
+ }\r
+ }\r
+ RF_MemToMap(&tiles[0][0], 1, tileX, tileY, 2, 2);\r
+}\r
+\r
+//============================================================================\r
+\r
+/*\r
+==========================\r
+=\r
+= ScanInfoPlane\r
+=\r
+= Spawn all actors and mark down special places\r
+=\r
+==========================\r
+*/\r
+\r
+void ScanInfoPlane(void)\r
+{\r
+ Uint16 i, x, y, chunk;\r
+ Sint16 info;\r
+ Uint16 far *map;\r
+ objtype *ob;\r
+\r
+ InitObjArray(); // start spawning things with a clean slate\r
+\r
+ memset(lumpneeded, 0, sizeof(lumpneeded));\r
+ gamestate.numfuses = 0;\r
+\r
+ map = mapsegs[2];\r
+\r
+ for (y=0; y<mapheight; y++)\r
+ {\r
+ for (x=0; x<mapwidth; x++)\r
+ {\r
+ info = *map++;\r
+\r
+ if (info == 0)\r
+ continue;\r
+\r
+ switch (info)\r
+ {\r
+ case 1:\r
+ SpawnKeen(x, y, 1);\r
+ SpawnScore();\r
+ lumpneeded[KEEN_LUMP] = true;\r
+ CA_MarkGrChunk(SCOREBOXSPR);\r
+ break;\r
+\r
+ case 2:\r
+ SpawnKeen(x, y, -1);\r
+ SpawnScore();\r
+ lumpneeded[KEEN_LUMP] = true;\r
+ CA_MarkGrChunk(SCOREBOXSPR);\r
+ break;\r
+\r
+ case 3:\r
+ SpawnScore();\r
+ lumpneeded[WORLDKEEN_LUMP] = true;\r
+ CA_MarkGrChunk(SCOREBOXSPR);\r
+ if (playstate == ex_portout)\r
+ break;\r
+ SpawnWorldKeen(x, y);\r
+ break;\r
+\r
+ case 26:\r
+ if (playstate != ex_portout)\r
+ break;\r
+ SpawnWorldKeenPort(x, y);\r
+ break;\r
+\r
+ case 6:\r
+ if (gamestate.difficulty < gd_Hard)\r
+ break;\r
+ case 5:\r
+ if (gamestate.difficulty < gd_Normal)\r
+ break;\r
+ case 4:\r
+ SpawnSparky(x, y);\r
+ lumpneeded[SPARKY_LUMP] = true;\r
+ break;\r
+\r
+ case 9:\r
+ if (gamestate.difficulty < gd_Hard)\r
+ break;\r
+ case 8:\r
+ if (gamestate.difficulty < gd_Normal)\r
+ break;\r
+ case 7:\r
+ SpawnMine(x, y);\r
+ lumpneeded[MINE_LUMP] = true;\r
+ break;\r
+\r
+ case 12:\r
+ if (gamestate.difficulty < gd_Hard)\r
+ break;\r
+ case 11:\r
+ if (gamestate.difficulty < gd_Normal)\r
+ break;\r
+ case 10:\r
+ SpawnSlicestarSlide(x, y, 0);\r
+ lumpneeded[SLICESTAR_LUMP] = true;\r
+ break;\r
+\r
+ case 15:\r
+ if (gamestate.difficulty < gd_Hard)\r
+ break;\r
+ case 14:\r
+ if (gamestate.difficulty < gd_Normal)\r
+ break;\r
+ case 13:\r
+ SpawnRoboRed(x, y);\r
+ lumpneeded[ROBORED_LUMP] = true;\r
+ break;\r
+\r
+ case 18:\r
+ if (gamestate.difficulty < gd_Hard)\r
+ break;\r
+ case 17:\r
+ if (gamestate.difficulty < gd_Normal)\r
+ break;\r
+ case 16:\r
+ SpawnSpirogrip(x, y);\r
+ lumpneeded[SPIRO_LUMP] = true;\r
+ break;\r
+\r
+ case 21:\r
+ if (gamestate.difficulty < gd_Hard)\r
+ break;\r
+ case 20:\r
+ if (gamestate.difficulty < gd_Normal)\r
+ break;\r
+ case 19:\r
+ SpawnSlicestarBounce(x, y);\r
+ lumpneeded[SLICESTAR_LUMP] = true;\r
+ break;\r
+\r
+ case 24:\r
+ if (gamestate.difficulty < gd_Hard)\r
+ break;\r
+ case 23:\r
+ if (gamestate.difficulty < gd_Normal)\r
+ break;\r
+ case 22:\r
+ SpawnSlicestarSlide(x, y, 1);\r
+ lumpneeded[SLICESTAR_LUMP] = true;\r
+ break;\r
+\r
+ case 25:\r
+ RF_SetScrollBlock(x, y, true);\r
+ break;\r
+\r
+ // case 26 (teleported map keen) is handled above\r
+\r
+ case 27:\r
+ case 28:\r
+ case 29:\r
+ case 30:\r
+ SpawnPlatform(x, y, info-27, 0);\r
+ lumpneeded[PLATFORM_LUMP] = true;\r
+ break;\r
+\r
+ // case 31 is the block icon\r
+\r
+ case 32:\r
+ SpawnDropPlat(x, y);\r
+ lumpneeded[PLATFORM_LUMP] = true;\r
+ break;\r
+\r
+ case 35:\r
+ SpawnStaticPlat(x, y);\r
+ lumpneeded[PLATFORM_LUMP] = true;\r
+ break;\r
+ case 34:\r
+ if (gamestate.difficulty > gd_Normal)\r
+ break;\r
+ SpawnStaticPlat(x, y);\r
+ lumpneeded[PLATFORM_LUMP] = true;\r
+ break;\r
+ case 33:\r
+ if (gamestate.difficulty > gd_Easy)\r
+ break;\r
+ SpawnStaticPlat(x, y);\r
+ lumpneeded[PLATFORM_LUMP] = true;\r
+ break;\r
+\r
+ case 36:\r
+ case 37:\r
+ case 38:\r
+ case 39:\r
+ SpawnGoPlat(x, y, info-36, 0);\r
+ lumpneeded[PLATFORM_LUMP] = true;\r
+ break;\r
+\r
+ case 40:\r
+ SpawnSneakPlat(x, y);\r
+ lumpneeded[PLATFORM_LUMP] = true;\r
+ break;\r
+\r
+ case 41:\r
+ if (gamestate.mapon == 12)\r
+ {\r
+ gamestate.numfuses = 4;\r
+ SpawnQed(x, y);\r
+ }\r
+ else\r
+ {\r
+ gamestate.numfuses++;\r
+ }\r
+ lumpneeded[FUSE_LUMP] = true;\r
+ break;\r
+\r
+ case 44:\r
+ if (gamestate.difficulty < gd_Hard)\r
+ break;\r
+ case 43:\r
+ if (gamestate.difficulty < gd_Normal)\r
+ break;\r
+ case 42:\r
+ SpawnAmpton(x, y);\r
+ lumpneeded[AMPTON_LUMP] = true;\r
+ break;\r
+\r
+ case 53:\r
+ if (gamestate.difficulty < gd_Hard)\r
+ break;\r
+ case 49:\r
+ if (gamestate.difficulty < gd_Normal)\r
+ break;\r
+ case 45:\r
+ SpawnCannon(x, y, 0);\r
+ lumpneeded[LASER_LUMP] = true;\r
+ break;\r
+\r
+ case 54:\r
+ if (gamestate.difficulty < gd_Hard)\r
+ break;\r
+ case 50:\r
+ if (gamestate.difficulty < gd_Normal)\r
+ break;\r
+ case 46:\r
+ SpawnCannon(x, y, 1);\r
+ lumpneeded[LASER_LUMP] = true;\r
+ break;\r
+\r
+ case 55:\r
+ if (gamestate.difficulty < gd_Hard)\r
+ break;\r
+ case 51:\r
+ if (gamestate.difficulty < gd_Normal)\r
+ break;\r
+ case 47:\r
+ SpawnCannon(x, y, 2);\r
+ lumpneeded[LASER_LUMP] = true;\r
+ break;\r
+\r
+ case 56:\r
+ if (gamestate.difficulty < gd_Hard)\r
+ break;\r
+ case 52:\r
+ if (gamestate.difficulty < gd_Normal)\r
+ break;\r
+ case 48:\r
+ SpawnCannon(x, y, 3);\r
+ lumpneeded[LASER_LUMP] = true;\r
+ break;\r
+\r
+ case 69:\r
+ if (gamestate.ammo >= 5)\r
+ break;\r
+ info = 68; // spawn ammo\r
+ //no break here!\r
+ case 57:\r
+ case 58:\r
+ case 59:\r
+ case 60:\r
+ case 61:\r
+ case 62:\r
+ case 63:\r
+ case 64:\r
+ case 65:\r
+ case 66:\r
+ case 67:\r
+ case 68:\r
+ SpawnBonus(x, y, info-57);\r
+ lumpneeded[bonuslump[info-57]] = true;\r
+ break;\r
+ case 70:\r
+ SpawnBonus(x, y, info-58);\r
+ lumpneeded[bonuslump[info-58]] = true;\r
+ break;\r
+\r
+ case 73:\r
+ if (gamestate.difficulty < gd_Hard)\r
+ break;\r
+ case 72:\r
+ if (gamestate.difficulty < gd_Normal)\r
+ break;\r
+ case 71:\r
+ SpawnVolte(x, y);\r
+ lumpneeded[VOLTE_LUMP] = true;\r
+ break;\r
+\r
+ case 76:\r
+ if (gamestate.difficulty < gd_Hard)\r
+ break;\r
+ case 75:\r
+ if (gamestate.difficulty < gd_Normal)\r
+ break;\r
+ case 74:\r
+ SpawnShelly(x, y);\r
+ lumpneeded[SHELLEY_LUMP] = true;\r
+ break;\r
+\r
+ case 79:\r
+ if (gamestate.difficulty < gd_Hard)\r
+ break;\r
+ case 78:\r
+ if (gamestate.difficulty < gd_Normal)\r
+ break;\r
+ case 77:\r
+ SpawnSpindread(x, y);\r
+ lumpneeded[SPINDRED_LUMP] = true;\r
+ break;\r
+\r
+ case 80:\r
+ case 81:\r
+ case 82:\r
+ case 83:\r
+ SpawnGoPlat(x, y, info-80, 1);\r
+ lumpneeded[SLOTPLAT_LUMP] = true;\r
+ break;\r
+\r
+ case 84:\r
+ case 85:\r
+ case 86:\r
+ case 87:\r
+ SpawnPlatform(x, y, info-84, 1);\r
+ lumpneeded[SLOTPLAT_LUMP] = true;\r
+ break;\r
+\r
+ case 90:\r
+ if (gamestate.difficulty < gd_Hard)\r
+ break;\r
+ case 89:\r
+ if (gamestate.difficulty < gd_Normal)\r
+ break;\r
+ case 88:\r
+ SpawnMaster(x, y);\r
+ lumpneeded[MASTER_LUMP] = true;\r
+ break;\r
+\r
+ // cases 91 to 98 are direction arrows\r
+\r
+ case 101:\r
+ if (gamestate.difficulty < gd_Hard)\r
+ break;\r
+ case 100:\r
+ if (gamestate.difficulty < gd_Normal)\r
+ break;\r
+ case 99:\r
+ SpawnShikadi(x, y);\r
+ lumpneeded[SHIKADI_LUMP] = true;\r
+ break;\r
+\r
+ case 104:\r
+ if (gamestate.difficulty < gd_Hard)\r
+ break;\r
+ case 103:\r
+ if (gamestate.difficulty < gd_Normal)\r
+ break;\r
+ case 102:\r
+ SpawnPet(x, y);\r
+ lumpneeded[SHOCKSHUND_LUMP] = true;\r
+ break;\r
+\r
+ case 107:\r
+ if (gamestate.difficulty < gd_Hard)\r
+ break;\r
+ case 106:\r
+ if (gamestate.difficulty < gd_Normal)\r
+ break;\r
+ case 105:\r
+ SpawnSphereful(x, y);\r
+ lumpneeded[SPHEREFUL_LUMP] = true;\r
+ break;\r
+\r
+ // cases 108 to 123 are wall collision icons for the WallDebug cheat\r
+\r
+ case 124:\r
+ SpawnScottie(x, y);\r
+ lumpneeded[SCOTTIE_LUMP] = true;\r
+ break;\r
+\r
+ case 125:\r
+ lumpneeded[TELEPORT_LUMP] = true;\r
+\r
+ }\r
+ }\r
+ }\r
+\r
+ for (ob = player; ob; ob = ob->next)\r
+ {\r
+ if (ob->active != ac_allways)\r
+ ob->active = ac_no;\r
+ }\r
+\r
+ for (i = 0; i < NUMLUMPS; i++)\r
+ {\r
+ if (lumpneeded[i])\r
+ {\r
+ for (chunk = lumpstart[i]; chunk <= lumpend[i]; chunk++)\r
+ {\r
+ CA_MarkGrChunk(chunk);\r
+ }\r
+ }\r
+ }\r
+\r
+ // Keen 5 addition to PatchWorldMap (PatchWorldMap is shared across Keen 4-6)\r
+ if (gamestate.mapon == 0)\r
+ {\r
+ info = CONVERT_GLOBAL_TO_TILE(player->y);\r
+ if (info < 75 || info > 100)\r
+ {\r
+ CloseMapDoor(24, 76);\r
+ OpenMapDoor(22, 55);\r
+ }\r
+ if (gamestate.leveldone[4] && gamestate.leveldone[6] && gamestate.leveldone[8] && gamestate.leveldone[10]\r
+ && (info > 39 || info > 100) )\r
+ {\r
+ OpenMapDoor(26, 55);\r
+ }\r
+ if (info <= 39 || info > 100)\r
+ {\r
+ OpenMapDoor(24, 30);\r
+ }\r
+ }\r
+}\r
+\r
+/*\r
+=============================================================================\r
+\r
+ GAME OVER SEQUENCE\r
+\r
+=============================================================================\r
+*/\r
+\r
+/*\r
+------------------------------------------------------------------------------\r
+The galaxy explosion chunk contains data in the following format:\r
+\r
+struct {\r
+ Uint16 posx[4000];\r
+ Uint16 velx[4000];\r
+ Uint16 posy[4000];\r
+ Uint16 vely[4000];\r
+};\r
+\r
+The values are stored as "fixed point" numbers (divide each number by 128 to\r
+get the amount in pixel units). The code in MoveStars basically does the\r
+following:\r
+\r
+1. set all pixels on the screen to black\r
+\r
+2. for each of the 4000 entries do:\r
+\r
+2.1 x := posx[i] + velx[i]\r
+\r
+2.2 if x (in pixels) is < 0 or > 320 then go to 2.8\r
+\r
+2.3 posx[i] := x\r
+\r
+2.4 y := posy[i] + vely[i]\r
+\r
+2.5 if y (in pixels) is < 0 or > 200 then go to 2.8\r
+\r
+2.6 posy[i] := y\r
+\r
+2.7 draw a white pixel at position (x, y) on the screen\r
+\r
+2.8 continue with the next entry\r
+\r
+------------------------------------------------------------------------------\r
+*/\r
+\r
+#if GRMODE == CGAGR\r
+\r
+Uint8 plotpixels[8] = {0xC0, 0x30, 0x0C, 0x03};\r
+\r
+/*\r
+===========================\r
+=\r
+= MoveStars CGA\r
+=\r
+===========================\r
+*/\r
+\r
+void MoveStars(void)\r
+{\r
+ asm {\r
+ mov ax, screenseg;\r
+ mov es, ax;\r
+ mov ds, word ptr grsegs + 2*GALAXY;\r
+ mov cx, 2000h;\r
+ xor ax, ax;\r
+ xor di, di;\r
+ rep stosw;\r
+ mov si, 7998;\r
+ }\r
+l1:\r
+ asm {\r
+ mov ax, [si]; // get posx\r
+ add ax, [si+8000]; // add velx\r
+ cmp ax, 40960; // check if new posx is on screen\r
+ ja l2;\r
+ mov [si], ax; // set new posx\r
+ mov bx, [si+16000]; // get posy\r
+ add bx, [si+24000]; // add vely\r
+ cmp bx, 25600; // check if new posy is on screen\r
+ ja l2;\r
+ mov [si+16000], bx; // set new posy\r
+ mov cl, 7;\r
+ shr bx, cl;\r
+ shl bx, 1;\r
+ mov di, word ptr ss:ylookup[bx];\r
+ mov bx, ax;\r
+ mov cl, 9;\r
+ shr ax, cl;\r
+ add di, ax;\r
+ mov cl, 7;\r
+ shr bx, cl;\r
+ and bx, 3;\r
+ mov al, BYTE PTR ss:plotpixels[bx];\r
+ or es:[di], al; // draw the pixel\r
+ }\r
+l2:\r
+ asm {\r
+ sub si, 2;\r
+ jns l1;\r
+ mov ax, ss;\r
+ mov ds, ax;\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= GameOver CGA\r
+=\r
+===========================\r
+*/\r
+\r
+void GameOver(void)\r
+{\r
+ Sint16 i;\r
+\r
+ FreeGraphics();\r
+ CA_CacheGrChunk(MILKYWAYPIC);\r
+ CA_CacheGrChunk(GALAXY);\r
+ CA_CacheGrChunk(GAMEOVERPIC);\r
+ RF_FixOfs();\r
+ VW_ClearVideo(BLACK);\r
+ VWB_DrawPic(0, 0, MILKYWAYPIC);\r
+ VW_UpdateScreen();\r
+\r
+ SD_WaitSoundDone();\r
+ SD_PlaySound(SND_GAMEOVER2);\r
+ SD_WaitSoundDone();\r
+ SD_PlaySound(SND_GAMEOVER1);\r
+\r
+ IN_ClearKeysDown();\r
+ VW_SetLineWidth(80);\r
+\r
+ for (i=0; i<60; i++)\r
+ {\r
+ lasttimecount = TimeCount;\r
+ MoveStars();\r
+ VW_UpdateScreen();\r
+\r
+ do {} while (TimeCount-lasttimecount < 4);\r
+\r
+ if (LastScan)\r
+ break;\r
+ }\r
+\r
+ VW_SetLineWidth(SCREENWIDTH);\r
+ VW_ClearVideo(BLACK);\r
+ StartMusic(18);\r
+ VWB_DrawPic(32, 80, GAMEOVERPIC);\r
+ VW_UpdateScreen();\r
+ IN_UserInput(24*TickBase, false);\r
+ StopMusic();\r
+}\r
+\r
+//============================================================================\r
+\r
+#else\r
+\r
+Uint16 dim[18] = {8, 8, 7, 15, 7, 8, 0, 8, 7, 15, 7, 8, 0, 0, 0, 0, 0, 0};\r
+Uint16 bright[18] = {7, 7, 7, 7, 7, 15, 7, 8, 0, 7, 15, 7, 8, 0, 0, 0, 0, 0};\r
+Uint8 galaxycolors[17] = {0, 1, 2, 3, 4, 5, 6, 7, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 3};\r
+Uint8 plotpixels[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};\r
+\r
+/*\r
+===========================\r
+=\r
+= MoveStars EGA\r
+=\r
+===========================\r
+*/\r
+\r
+void MoveStars(Uint16 dest)\r
+{\r
+ asm {\r
+ mov dx, GC_INDEX;\r
+ mov al, GC_BITMASK;\r
+ out dx, al;\r
+ inc dx;\r
+ mov ds, word ptr grsegs + 2*GALAXY;\r
+ mov ax, 0A000h;\r
+ mov es, ax;\r
+ mov cx, 1000h;\r
+ xor ax, ax;\r
+ mov di, dest;\r
+ rep stosw;\r
+ mov si, 7998;\r
+ }\r
+l1:\r
+ asm {\r
+ mov ax, [si]; // get posx\r
+ add ax, [si+8000]; // add velx\r
+ cmp ax, 40960; // check if new posx is on screen\r
+ ja l2;\r
+ mov [si], ax; // set new posx\r
+ mov bx, [si+16000]; // get posy\r
+ add bx, [si+24000]; // add vely\r
+ cmp bx, 25600; // check if new posy is on screen\r
+ ja l2;\r
+ mov [si+16000], bx; // set new posy\r
+ mov cl, 7;\r
+ shr bx, cl;\r
+ shl bx, 1;\r
+ mov di, word ptr ss:ylookup[bx];\r
+ add di, dest;\r
+ mov bx, ax;\r
+ mov cl, 10;\r
+ shr ax, cl;\r
+ add di, ax;\r
+ mov cl, 7;\r
+ shr bx, cl;\r
+ and bx, 7;\r
+ mov al, BYTE PTR ss:plotpixels[bx];\r
+ out dx, al;\r
+ mov al, 0Fh;\r
+ xchg al, es:[di]; // draw the pixel\r
+ }\r
+l2:\r
+ asm {\r
+ sub si, 2;\r
+ jns l1;\r
+ mov ax, ss;\r
+ mov ds, ax;\r
+ mov al, 0FFh;\r
+ out dx, al;\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= SetCrtc EGA\r
+=\r
+===========================\r
+*/\r
+\r
+void SetCrtc(Uint16 addr)\r
+{\r
+ asm {\r
+ cli;\r
+ mov cx, addr;\r
+ mov dx, CRTC_INDEX;\r
+ mov al, CRTC_STARTHIGH;\r
+ out dx, al;\r
+ inc dx;\r
+ mov al, ch;\r
+ out dx, al;\r
+ dec dx;\r
+ mov al, CRTC_STARTLOW;\r
+ out dx, al;\r
+ inc dx;\r
+ mov al, cl;\r
+ out dx, al;\r
+ sti;\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= GameOver EGA\r
+=\r
+===========================\r
+*/\r
+\r
+void GameOver(void)\r
+{\r
+ Sint16 i;\r
+\r
+ FreeGraphics();\r
+ VW_FadeOut();\r
+ CA_CacheGrChunk(MILKYWAYPIC);\r
+ CA_CacheGrChunk(GALAXY);\r
+ CA_CacheGrChunk(GAMEOVERPIC);\r
+ VW_SetLineWidth(40);\r
+ VW_SetScreen(0, 0);\r
+ bufferofs = 0;\r
+ VW_ClearVideo(0);\r
+ VW_DrawPic(0, 0, MILKYWAYPIC);\r
+ VW_ScreenToScreen(0, 0x2000, 40, 200);\r
+ VW_FadeIn();\r
+ IN_ClearKeysDown();\r
+ SD_PlaySound(SND_GAMEOVER2);\r
+\r
+ for (i=0; i<18; i++)\r
+ {\r
+ galaxycolors[8] = dim[i];\r
+ galaxycolors[7] = bright[i];\r
+\r
+ SetPalette(galaxycolors);\r
+\r
+ VW_WaitVBL(10);\r
+ if (LastScan)\r
+ goto gameover;\r
+ }\r
+\r
+ EGAWRITEMODE(2);\r
+ EGAMAPMASK(15);\r
+ SD_PlaySound(SND_GAMEOVER1);\r
+\r
+ for (i=0; i<30; i++)\r
+ {\r
+ lasttimecount = TimeCount;\r
+ MoveStars(0x2000);\r
+ SetCrtc(0x2000);\r
+ do {} while (TimeCount-lasttimecount < 4);\r
+\r
+ lasttimecount = TimeCount;\r
+ MoveStars(0);\r
+ SetCrtc(0);\r
+ do {} while (TimeCount-lasttimecount < 4);\r
+\r
+ if (LastScan)\r
+ goto gameover;\r
+ }\r
+\r
+gameover:\r
+ EGAWRITEMODE(0);\r
+ VW_ClearVideo(BLACK);\r
+ VW_SetLineWidth(SCREENWIDTH);\r
+ VW_SetDefaultColors();\r
+ RF_FixOfs();\r
+ StartMusic(18);\r
+ VWB_DrawPic(32, 80, GAMEOVERPIC);\r
+ VW_UpdateScreen();\r
+ IN_UserInput(24*TickBase, false);\r
+ StopMusic();\r
+}\r
+\r
+#endif\r
+\r
+//============================================================================\r
+\r
+/*\r
+===========================\r
+=\r
+= FinishedFuse\r
+=\r
+===========================\r
+*/\r
+\r
+void FinishedFuse(void)\r
+{\r
+ SD_WaitSoundDone();\r
+ CA_UpLevel();\r
+#if 0\r
+ // bugfix:\r
+ CA_ClearMarks(); // don't cache more than we actually need here\r
+#endif\r
+ CA_MarkGrChunk(KEENTALK1PIC);\r
+ CA_MarkGrChunk(KEENTALK2PIC);\r
+ CA_CacheMarks(NULL);\r
+\r
+ VW_FixRefreshBuffer();\r
+ US_CenterWindow(26, 8);\r
+ WindowW -= 48;\r
+ VWB_DrawPic(WindowX+WindowW, WindowY, KEENTALK1PIC);\r
+ PrintY += 12;\r
+ if (gamestate.mapon == 13)\r
+ {\r
+ US_CPrint(\r
+ "I wonder what that\n"\r
+ "fuse was for....\n"\r
+ );\r
+ }\r
+ else\r
+ {\r
+ US_CPrint(\r
+ "One of the four\n"\r
+ "machines protecting the\n"\r
+ "main elevator shaft--\n"\r
+ "toast!\n"\r
+ );\r
+ }\r
+ VW_UpdateScreen();\r
+ VW_WaitVBL(30);\r
+ IN_ClearKeysDown();\r
+ IN_Ack();\r
+\r
+ VWB_DrawPic(WindowX+WindowW, WindowY, KEENTALK2PIC);\r
+ VW_UpdateScreen();\r
+ VW_WaitVBL(30);\r
+ IN_ClearKeysDown();\r
+ IN_Ack();\r
+\r
+ CA_DownLevel();\r
+ StopMusic();\r
+}
\ No newline at end of file