--- /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
+K6_SPEC.C\r
+=========\r
+\r
+Contains (in this order):\r
+\r
+- lump definition\r
+- "Star Wars" crawl text\r
+- level names & messages\r
+- ScanInfoPlane() - for spawning the level objects and marking required sprites\r
+- stunned state for Keen\r
+- code to flip the big yellow switches\r
+- messages for sandwich, rope and passcard\r
+*/\r
+\r
+#include "CK_DEF.H"\r
+\r
+enum {\r
+ CONTROLS_LUMP, // 0\r
+ KEEN_LUMP, // 1\r
+ SUGAR1_LUMP, // 2\r
+ SUGAR2_LUMP, // 3\r
+ SUGAR3_LUMP, // 4\r
+ SUGAR4_LUMP, // 5\r
+ SUGAR5_LUMP, // 6\r
+ SUGAR6_LUMP, // 7\r
+ ONEUP_LUMP, // 8\r
+ KEYGEM_LUMP, // 9\r
+ AMMO_LUMP, // 10\r
+ WORLDKEEN_LUMP, // 11\r
+ UNUSED1_LUMP, // 12\r
+ BLOOG_LUMP, // 13\r
+ RBLOOGLET_LUMP, // 14\r
+ YBLOOGLET_LUMP, // 15\r
+ BBLOOGLET_LUMP, // 16\r
+ GBLOOGLET_LUMP, // 17\r
+ PLATFORM_LUMP, // 18\r
+ GIK_LUMP, // 19\r
+ BLORB_LUMP, // 20\r
+ BOBBA_LUMP, // 21\r
+ BABOBBA_LUMP, // 22\r
+ BLOOGUARD_LUMP, // 23\r
+ FLECT_LUMP, // 24\r
+ BIP_LUMP, // 25\r
+ BIPSQUISHED_LUMP, // 26\r
+ BIPSHIP_LUMP, // 27\r
+ NOSPIKE_LUMP, // 28\r
+ ORBATRIX_LUMP, // 29\r
+ CEILICK_LUMP, // 30\r
+ FLEEX_LUMP, // 31\r
+ HOOK_LUMP, // 32\r
+ SANDWICH_LUMP, // 33\r
+ LASER_LUMP, // 34\r
+ PASSCARD_LUMP, // 35\r
+ MOLLY_LUMP, // 36\r
+\r
+ NUMLUMPS=40 // Keen 6 has 3 unused lumps at the end\r
+};\r
+\r
+Uint16 lumpstart[NUMLUMPS] = {\r
+ CONTROLS_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
+ WORLDKEEN_LUMP_START,\r
+ 0,\r
+ BLOOG_LUMP_START,\r
+ RBLOOGLET_LUMP_START,\r
+ YBLOOGLET_LUMP_START,\r
+ BBLOOGLET_LUMP_START,\r
+ GBLOOGLET_LUMP_START,\r
+ PLATFORM_LUMP_START,\r
+ GIK_LUMP_START,\r
+ BLORB_LUMP_START,\r
+ BOBBA_LUMP_START,\r
+ BABOBBA_LUMP_START,\r
+ BLOOGUARD_LUMP_START,\r
+ FLECT_LUMP_START,\r
+ BIP_LUMP_START,\r
+ BIPSQUISHED_LUMP_START,\r
+ BIPSHIP_LUMP_START,\r
+ NOSPIKE_LUMP_START,\r
+ ORBATRIX_LUMP_START,\r
+ CEILICK_LUMP_START,\r
+ FLEEX_LUMP_START,\r
+ HOOK_LUMP_START,\r
+ SANDWICH_LUMP_START,\r
+ LASER_LUMP_START,\r
+ PASSCARD_LUMP_START,\r
+ MOLLY_LUMP_START\r
+};\r
+\r
+Uint16 lumpend[NUMLUMPS] = {\r
+ CONTROLS_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
+ WORLDKEEN_LUMP_END,\r
+ 0,\r
+ BLOOG_LUMP_END,\r
+ RBLOOGLET_LUMP_END,\r
+ YBLOOGLET_LUMP_END,\r
+ BBLOOGLET_LUMP_END,\r
+ GBLOOGLET_LUMP_END,\r
+ PLATFORM_LUMP_END,\r
+ GIK_LUMP_END,\r
+ BLORB_LUMP_END,\r
+ BOBBA_LUMP_END,\r
+ BABOBBA_LUMP_END,\r
+ BLOOGUARD_LUMP_END,\r
+ FLECT_LUMP_END,\r
+ BIP_LUMP_END,\r
+ BIPSQUISHED_LUMP_END,\r
+ BIPSHIP_LUMP_END,\r
+ NOSPIKE_LUMP_END,\r
+ ORBATRIX_LUMP_END,\r
+ CEILICK_LUMP_END,\r
+ FLEEX_LUMP_END,\r
+ HOOK_LUMP_END,\r
+ SANDWICH_LUMP_END,\r
+ LASER_LUMP_END,\r
+ PASSCARD_LUMP_END,\r
+ MOLLY_LUMP_END\r
+};\r
+\r
+boolean lumpneeded[NUMLUMPS];\r
+\r
+#if GRMODE == EGAGR\r
+\r
+char far swtext[] =\r
+ "Episode Six\n"\r
+ "\n"\r
+ "Aliens Ate My\n"\r
+ "Baby Sitter!\n"\r
+ "\n"\r
+ "While out in his\n"\r
+ "backyard clubhouse,\n"\r
+ "Billy's baby sitter\n"\r
+ "Molly calls him for\n"\r
+ "dinner. He continues\n"\r
+ "working on his new\n"\r
+ "wrist computer.\n"\r
+ "\n"\r
+ "Suddenly, there is a\n"\r
+ "loud noise outside.\n"\r
+ "\n"\r
+ "Rushing out, Keen finds\n"\r
+ "his baby sitter gone\n"\r
+ "and a note on a patch\n"\r
+ "of scorched grass. The\n"\r
+ "Bloogs of Fribbulus Xax\n"\r
+ "are going to make a\n"\r
+ "meal out of Molly!\n"\r
+ "\n"\r
+ "You've got to rescue\n"\r
+ "her, because your\n"\r
+ "parents will never\n"\r
+ "believe you when you\n"\r
+ "tell them...\n"\r
+ "\n"\r
+ "\"Aliens Ate My\n"\r
+ "Baby Sitter!\"\n";\r
+\r
+#endif\r
+\r
+char far l0n[] = "Fribbulus Xax";\r
+char far l1n[] = "Bloogwaters\nCrossing";\r
+char far l2n[] = "Guard Post One";\r
+char far l3n[] = "First Dome\nof Darkness";\r
+char far l4n[] = "Second Dome\nof Darkness";\r
+char far l5n[] = "The Bloogdome";\r
+char far l6n[] = "Bloogton Mfg.,\nIncorporated";\r
+char far l7n[] = "Bloogton Tower";\r
+char far l8n[] = "Bloogfoods, Inc.";\r
+char far l9n[] = "Guard Post Two";\r
+char far l10n[] = "Bloogville";\r
+char far l11n[] = "BASA";\r
+char far l12n[] = "Guard Post Three";\r
+char far l13n[] = "Bloogbase Rec\nDistrict";\r
+char far l14n[] = "Bloogbase Mgmt.\nDistrict";\r
+char far l15n[] = "Bloog Control Center";\r
+char far l16n[] = "Blooglab";\r
+char far l17n[] = "Bean-with-Bacon\nMegarocket";\r
+char far l18n[] = "High Scores";\r
+\r
+char far l0e[] = "Keen attacks\nFribbulus Xax";\r
+char far l1e[] = "Keen hops across\nBloogwaters\nCrossing";\r
+char far l2e[] = "Keen fights his way\nthrough Guard Post One";\r
+char far l3e[] = "Keen crosses into the\nFirst Dome of Darkness";\r
+char far l4e[] = "Keen dares to enter the\nSecond Dome of Darkness";\r
+char far l5e[] = "Keen foolishly enters\nthe Bloogdome";\r
+char far l6e[] = "Keen makes his way\ninto Bloogton\nManufacturing";\r
+char far l7e[] = "Keen ascends\nBloogton Tower";\r
+char far l8e[] = "Keen hungrily enters\nBloogfoods, Inc.";\r
+char far l9e[] = "Keen smashes through\nGuard Post Two";\r
+char far l10e[] = "Keen seeks thrills\nin Bloogville";\r
+char far l11e[] = "Keen rockets into the\nBloog Aeronautics and\nSpace Administration";\r
+char far l12e[] = "Keen boldly assaults\nGuard Post Three";\r
+char far l13e[] = "Keen whoops it up in\nthe Bloogbae\nRecreational District"; // sic!\r
+char far l14e[] = "Keen purposefully struts\ninto the Bloogbase\nManagement District";\r
+char far l15e[] = "Keen bravely enters the\nBloog Control Center,\nlooking for Molly";\r
+char far l16e[] = "Keen warily enters\nBlooglab Space\nStation";\r
+char far l17e[] = "Keen returns to the\nBean-with-Bacon\nMegarocket";\r
+char far l18e[] = "Keen is in the High\nScore screen. Call Id!";\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
+ l16n,\r
+ l17n,\r
+ l18n\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
+ l16e,\r
+ l17e,\r
+ l18e\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, AMMO_LUMP, 0, 0\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
+ 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
+ SpawnWorldKeen(x, y);\r
+ SpawnScore();\r
+ lumpneeded[WORLDKEEN_LUMP] = true;\r
+ CA_MarkGrChunk(SCOREBOXSPR);\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
+ SpawnBloog(x, y);\r
+ lumpneeded[BLOOG_LUMP] = true;\r
+ break;\r
+\r
+ case 7:\r
+ case 8:\r
+ case 9:\r
+ case 10:\r
+ case 11:\r
+ case 12:\r
+ case 13:\r
+ case 14:\r
+ SpawnBlooglet(x, y, info-7);\r
+ lumpneeded[(info-7) % 4 + RBLOOGLET_LUMP] = true;\r
+ if (info > 10)\r
+ lumpneeded[KEYGEM_LUMP] = true;\r
+ break;\r
+\r
+ case 15:\r
+ case 16:\r
+ SpawnGrappleSpot(x, y, info-15);\r
+ break;\r
+\r
+ // case 17 is not used\r
+\r
+ case 20:\r
+ if (gamestate.difficulty < gd_Hard)\r
+ break;\r
+ case 19:\r
+ if (gamestate.difficulty < gd_Normal)\r
+ break;\r
+ case 18:\r
+ SpawnFleex(x, y);\r
+ lumpneeded[FLEEX_LUMP] = true;\r
+ break;\r
+\r
+ case 21:\r
+ case 22:\r
+ case 23:\r
+ case 24:\r
+ SpawnMolly(x, y);\r
+ lumpneeded[MOLLY_LUMP] = true;\r
+ break;\r
+\r
+ case 25:\r
+ RF_SetScrollBlock(x, y, true);\r
+ break;\r
+\r
+ case 26:\r
+ RF_SetScrollBlock(x, y, false);\r
+ break;\r
+\r
+ case 27:\r
+ case 28:\r
+ case 29:\r
+ case 30:\r
+ SpawnPlatform(x, y, info-27);\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);\r
+ lumpneeded[PLATFORM_LUMP] = true;\r
+ lumpneeded[BIPSQUISHED_LUMP] = true; // why?\r
+ break;\r
+\r
+ case 40:\r
+ SpawnSneakPlat(x, y);\r
+ lumpneeded[PLATFORM_LUMP] = true;\r
+ break;\r
+\r
+ case 43:\r
+ if (gamestate.difficulty < gd_Hard)\r
+ break;\r
+ case 42:\r
+ if (gamestate.difficulty < gd_Normal)\r
+ break;\r
+ case 41:\r
+ SpawnBobba(x, y);\r
+ lumpneeded[BOBBA_LUMP] = true;\r
+ break;\r
+\r
+ case 44:\r
+ case 45:\r
+ SpawnSatelliteStop(x, y, info-44);\r
+ break;\r
+\r
+ // case 46 is not used\r
+\r
+ case 49:\r
+ if (gamestate.difficulty < gd_Hard)\r
+ break;\r
+ case 48:\r
+ if (gamestate.difficulty < gd_Normal)\r
+ break;\r
+ case 47:\r
+ SpawnNospike(x, y);\r
+ lumpneeded[NOSPIKE_LUMP] = true;\r
+ break;\r
+\r
+ case 52:\r
+ if (gamestate.difficulty < gd_Hard)\r
+ break;\r
+ case 51:\r
+ if (gamestate.difficulty < gd_Normal)\r
+ break;\r
+ case 50:\r
+ SpawnGik(x, y);\r
+ lumpneeded[GIK_LUMP] = true;\r
+ break;\r
+\r
+ case 53:\r
+ case 54:\r
+ case 55:\r
+ case 56:\r
+ SpawnCannon(x, y, info-53);\r
+ lumpneeded[LASER_LUMP] = true;\r
+ break;\r
+\r
+ case 69:\r
+ if (gamestate.ammo >= 5)\r
+ break;\r
+ info = 68;\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
+\r
+ case 72:\r
+ if (gamestate.difficulty < gd_Hard)\r
+ break;\r
+ case 71:\r
+ if (gamestate.difficulty < gd_Normal)\r
+ break;\r
+ case 70:\r
+ SpawnOrbatrix(x, y);\r
+ lumpneeded[ORBATRIX_LUMP] = true;\r
+ break;\r
+\r
+ case 75:\r
+ if (gamestate.difficulty < gd_Hard)\r
+ break;\r
+ case 74:\r
+ if (gamestate.difficulty < gd_Normal)\r
+ break;\r
+ case 73:\r
+ SpawnBipship(x, y);\r
+ lumpneeded[BIP_LUMP]=lumpneeded[BIPSHIP_LUMP]=lumpneeded[BIPSQUISHED_LUMP] = true;\r
+ break;\r
+\r
+ case 78:\r
+ if (gamestate.difficulty < gd_Hard)\r
+ break;\r
+ case 77:\r
+ if (gamestate.difficulty < gd_Normal)\r
+ break;\r
+ case 76:\r
+ SpawnFlect(x, y);\r
+ lumpneeded[FLECT_LUMP] = true;\r
+ break;\r
+\r
+ case 81:\r
+ if (gamestate.difficulty < gd_Hard)\r
+ break;\r
+ case 80:\r
+ if (gamestate.difficulty < gd_Normal)\r
+ break;\r
+ case 79:\r
+ SpawnBlorb(x, y);\r
+ lumpneeded[BLORB_LUMP] = true;\r
+ break;\r
+\r
+ case 84:\r
+ if (gamestate.difficulty < gd_Hard)\r
+ break;\r
+ case 83:\r
+ if (gamestate.difficulty < gd_Normal)\r
+ break;\r
+ case 82:\r
+ SpawnCeilick(x, y);\r
+ lumpneeded[CEILICK_LUMP] = true;\r
+ break;\r
+\r
+ case 87:\r
+ if (gamestate.difficulty < gd_Hard)\r
+ break;\r
+ case 86:\r
+ if (gamestate.difficulty < gd_Normal)\r
+ break;\r
+ case 85:\r
+ SpawnBlooguard(x, y);\r
+ lumpneeded[BLOOGUARD_LUMP] = true;\r
+ break;\r
+\r
+ case 88:\r
+ SpawnGrabbiter(x, y);\r
+ // no additional lump needed - sprites are in WORLDKEEN_LUMP\r
+ break;\r
+\r
+ case 89:\r
+ SpawnSatellite(x, y);\r
+ // no additional lump needed - sprites are in WORLDKEEN_LUMP\r
+ break;\r
+\r
+ // case 90 is not used\r
+ // cases 91 to 98 are direction arrows\r
+\r
+ case 99:\r
+ SpawnHook(x, y);\r
+ lumpneeded[HOOK_LUMP] = true;\r
+ break;\r
+\r
+ case 100:\r
+ SpawnSandwich(x, y);\r
+ lumpneeded[SANDWICH_LUMP] = true;\r
+ break;\r
+\r
+ case 101:\r
+ SpawnPasscard(x, y);\r
+ lumpneeded[PASSCARD_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
+ SpawnBabobba(x, y);\r
+ lumpneeded[BABOBBA_LUMP] = true;\r
+ break;\r
+\r
+ case 105:\r
+ case 106:\r
+ SpawnRocket(x, y, info-105);\r
+ // no additional lump needed - sprites are in WORLDKEEN_LUMP\r
+ break;\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
+\r
+//============================================================================\r
+\r
+statetype s_keenstun = {KEENSTUNSPR, KEENSTUNSPR, step, false, true, 60, 0, 0, T_Projectile, KeenContact, KeenStandReact, &s_keenstand};\r
+\r
+//============================================================================\r
+\r
+/*\r
+===========================\r
+=\r
+= FlipBigSwitch\r
+=\r
+===========================\r
+*/\r
+\r
+void FlipBigSwitch(objtype *ob, boolean isup)\r
+{\r
+ Uint16 x, y;\r
+ Uint16 far *map;\r
+ Uint16 top, mid, bot;\r
+ Uint16 *tileptr;\r
+ Uint16 tile, tx, ty, xi, yi, offset, anim;\r
+ Uint16 tiles[6];\r
+\r
+ //\r
+ // handle flipping the switch itself:\r
+ //\r
+ if (isup)\r
+ {\r
+ ty = ob->tilebottom;\r
+ }\r
+ else\r
+ {\r
+ ty = ob->tiletop - 2;\r
+ }\r
+ tx = ob->tileleft - 1;\r
+ map = mapsegs[2] + mapbwidthtable[ty+1]/2 + tx + 1;\r
+ while (*map == 0)\r
+ {\r
+ map++;\r
+ tx++;\r
+ }\r
+ map = mapsegs[1] + mapbwidthtable[ty]/2 + tx;\r
+ tileptr = tiles;\r
+ for (y = 0; y < 3; y++, map += mapwidth)\r
+ {\r
+ for (x = 0; x < 2; tileptr++, x++)\r
+ {\r
+ tile = map[x];\r
+ *tileptr = tile + (Sint8)tinf[tile+MANIM];\r
+ }\r
+ }\r
+ RF_MemToMap(tiles, 1, tx, ty, 2, 3);\r
+\r
+ tile = *(mapsegs[2]+mapbwidthtable[ty+1]/2 + tx + 1);\r
+ x = tile >> 8;\r
+ y = tile & 0xFF;\r
+ SD_PlaySound(SND_USESWITCH);\r
+\r
+ //\r
+ // toggle whatever was linked to the switch (at tile x, y):\r
+ //\r
+ offset = mapbwidthtable[y]/2 + x;\r
+ map = mapsegs[2] + offset;\r
+ tile = *map;\r
+\r
+ if (tile >= DIRARROWSTART && tile < DIRARROWEND)\r
+ {\r
+ // turn direction arrow:\r
+ *map = arrowflip[tile-DIRARROWSTART] + DIRARROWSTART;\r
+ }\r
+ else\r
+ {\r
+ map = mapsegs[1] + offset;\r
+ tile = *map;\r
+ switch (tinf[tile+INTILE] & INTILE_TYPEMASK)\r
+ {\r
+ case INTILE_NOTHING: // no special tiles\r
+ mapsegs[2][offset] ^= PLATFORMBLOCK;\r
+ break;\r
+\r
+ case INTILE_BRIDGE: // bridge\r
+ for (yi=y; y+2 > yi; yi++)\r
+ {\r
+ map = mapsegs[1] + mapbwidthtable[yi]/2 + x - (yi != y);\r
+ for (xi = x - (yi != y); xi < mapwidth; xi++)\r
+ {\r
+ tile = *map;\r
+ map++;\r
+ anim = tinf[tile + MANIM];\r
+ if (!anim)\r
+ break;\r
+ tile += (Sint8)anim;\r
+ RF_MemToMap(&tile, 1, xi, yi, 1, 1);\r
+ }\r
+ }\r
+ break;\r
+\r
+ case INTILE_FORCEFIELD: // active force field\r
+ map = mapsegs[1];\r
+ top = *map;\r
+ mid = *++map;\r
+ bot = *++map;\r
+ map = mapsegs[1] + mapbwidthtable[y+1]/2 + x;\r
+\r
+ RF_MemToMap(&top, 1, x, y++, 1, 1);\r
+ while (tinf[*map+INTILE] == INTILE_DEADLY)\r
+ {\r
+ RF_MemToMap(&mid, 1, x, y++, 1, 1);\r
+ map += mapwidth;\r
+ }\r
+ RF_MemToMap(&bot, 1, x, y, 1, 1);\r
+ break;\r
+\r
+ case INTILE_FORCEFIELDEND: // inactive force field\r
+ map = mapsegs[1] + 3;\r
+ top = *map;\r
+ mid = *++map;\r
+ bot = *++map;\r
+ map = mapsegs[1] + mapbwidthtable[y+1]/2 + x;\r
+\r
+ RF_MemToMap(&top, 1, x, y++, 1, 1);\r
+ while (tinf[*map+INTILE] != INTILE_FORCEFIELDEND)\r
+ {\r
+ RF_MemToMap(&mid, 1, x, y++, 1, 1);\r
+ map += mapwidth;\r
+ }\r
+ RF_MemToMap(&bot, 1, x, y, 1, 1);\r
+ }\r
+ }\r
+}\r
+\r
+//============================================================================\r
+\r
+/*\r
+===========================\r
+=\r
+= GotSandwich\r
+=\r
+===========================\r
+*/\r
+\r
+void GotSandwich(void)\r
+{\r
+ SD_WaitSoundDone();\r
+ SD_PlaySound(SND_QUESTITEM);\r
+ CA_UpLevel(); // kinda useless without CA_CacheMarks or CA_SetGrPurge\r
+ // BUG: haven't made anything purgable here, caching the pic may cause an "out of memory" crash\r
+ CA_CacheGrChunk(KEENTALK1PIC);\r
+\r
+ US_CenterWindow(26, 8);\r
+ VWB_DrawPic(WindowX+WindowW-48, WindowY, KEENTALK1PIC);\r
+ WindowW -= 48;\r
+ PrintY += 12;\r
+ US_CPrint(\r
+ "This is the second\n"\r
+ "biggest sandwich\n"\r
+ "I ever saw!\n"\r
+ );\r
+ VW_UpdateScreen();\r
+ VW_WaitVBL(30);\r
+ IN_ClearKeysDown();\r
+ IN_Ack();\r
+ CA_DownLevel();\r
+ gamestate.sandwichstate = 1;\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= GotHook\r
+=\r
+===========================\r
+*/\r
+\r
+void GotHook(void)\r
+{\r
+ SD_WaitSoundDone();\r
+ SD_PlaySound(SND_QUESTITEM);\r
+ CA_UpLevel(); // kinda useless without CA_CacheMarks or CA_SetGrPurge\r
+ // BUG: haven't made anything purgable here, caching the pic may cause an "out of memory" crash\r
+ CA_CacheGrChunk(KEENTALK1PIC);\r
+\r
+ US_CenterWindow(26, 8);\r
+ VWB_DrawPic(WindowX+WindowW-48, WindowY, KEENTALK1PIC);\r
+ WindowW -= 48;\r
+ PrintY += 12;\r
+ US_CPrint(\r
+ "Wow! A rope and\n"\r
+ "grappling hook!\n"\r
+ "They look useful!\n"\r
+ );\r
+ VW_UpdateScreen();\r
+ VW_WaitVBL(30);\r
+ IN_ClearKeysDown();\r
+ IN_Ack();\r
+ CA_DownLevel();\r
+ gamestate.hookstate = 1;\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= GotPasscard\r
+=\r
+===========================\r
+*/\r
+\r
+void GotPasscard(void)\r
+{\r
+ SD_WaitSoundDone();\r
+ SD_PlaySound(SND_QUESTITEM);\r
+ CA_UpLevel(); // kinda useless without CA_CacheMarks or CA_SetGrPurge\r
+ // BUG: haven't made anything purgable here, caching the pic may cause an "out of memory" crash\r
+ CA_CacheGrChunk(KEENTALK1PIC);\r
+\r
+ US_CenterWindow(26, 8);\r
+ VWB_DrawPic(WindowX+WindowW-48, WindowY, KEENTALK1PIC);\r
+ WindowW -= 48;\r
+ PrintY += 4;\r
+ US_CPrint(\r
+ "What's this? Cool!\n"\r
+ "A passcard for\n"\r
+ "the Bloogstar Rocket!\n"\r
+ "(It can fly through\n"\r
+ "their force field.)"\r
+ );\r
+ VW_UpdateScreen();\r
+ VW_WaitVBL(30);\r
+ IN_ClearKeysDown();\r
+ IN_Ack();\r
+ CA_DownLevel();\r
+ gamestate.passcardstate = 1;\r
+}\r