--- /dev/null
+/* Catacomb Apocalypse Source Code\r
+ * Copyright (C) 1993-2014 Flat Rock Software\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
+// C3_GAME.C\r
+\r
+#include <stdlib.h>\r
+\r
+#include "DEF.H"\r
+#include "gelib.h"\r
+#pragma hdrstop\r
+\r
+#ifdef PROFILE\r
+#include "TIME.H"\r
+#endif\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+ LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+#define NUMLUMPS 45\r
+\r
+#define EYESTALKLUMP 0\r
+#define BLOBLUMP 1\r
+#define BOLTLUMP 2\r
+#define NUKELUMP 3\r
+#define POTIONLUMP 4\r
+#define RKEYLUMP 5\r
+#define YKEYLUMP 6\r
+#define GKEYLUMP 7\r
+#define BKEYLUMP 8\r
+#define RGEMLUMP 9\r
+#define GGEMLUMP 10\r
+#define BGEMLUMP 11\r
+#define YGEMLUMP 12\r
+#define PGEMLUMP 13\r
+#define CHESTLUMP 14\r
+#define PLAYERLUMP 15\r
+#define FTIMELUMP 16\r
+#define PORTALLUMP 17\r
+#define COLUMN1LUMP 18\r
+#define FIREPOTLUMP 19\r
+#define COLUMN2LUMP 20\r
+#define EYELUMP 21\r
+#define FUTUREMAGELUMP 22\r
+#define FORCEFIELDLUMP 23\r
+#define ROBOTANKLUMP 24\r
+#define RAMBONELUMP 25\r
+#define STOMPYLUMP 26\r
+#define TROLLLUMP 27\r
+#define WIZARDLUMP 28\r
+#define HEADLUMP 29\r
+#define INVISDUDELUMP 30\r
+#define BUGLUMP 31\r
+#define CYBORGLUMP 32\r
+#define WATERCHESTLUMP 33\r
+#define GRELLUMP 34\r
+#define RAYLUMP 35\r
+#define COLUMN3LUMP 36\r
+#define OLDCHESTLUMP 37\r
+#define OLDFIREPOTLUMP 38\r
+#define COLUMN4LUMP 39\r
+#define TOMB1LUMP 40\r
+#define TOMB2LUMP 41\r
+#define DEMONLUMP 42\r
+#define COLUMN5LUMP 43\r
+\r
+int lumpstart[NUMLUMPS] = {\r
+EYESTALK_LUMP_START,\r
+BLOB_LUMP_START,\r
+BOLT_LUMP_START,\r
+NUKE_LUMP_START,\r
+POTION_LUMP_START,\r
+RKEY_LUMP_START,\r
+YKEY_LUMP_START,\r
+GKEY_LUMP_START,\r
+BKEY_LUMP_START,\r
+RGEM_LUMP_START,\r
+GGEM_LUMP_START,\r
+BGEM_LUMP_START,\r
+YGEM_LUMP_START,\r
+PGEM_LUMP_START,\r
+CHEST_LUMP_START,\r
+PLAYER_LUMP_START,\r
+TIME_LUMP_START,\r
+PORTAL_LUMP_START,\r
+COLUMN1_LUMP_START,\r
+FFIREPOT_LUMP_START,\r
+COLUMN2_LUMP_START,\r
+EYE_LUMP_START,\r
+FUTUREMAGE_LUMP_START,\r
+FORCEFIELD_LUMP_START,\r
+ROBOTANK_LUMP_START,\r
+RAMBONE_LUMP_START,\r
+STOMPY_LUMP_START,\r
+TROLL_LUMP_START,\r
+WIZARD_LUMP_START,\r
+HEAD_LUMP_START,\r
+INVISDUDE_LUMP_START,\r
+BUG_LUMP_START,\r
+CYBORG_LUMP_START,\r
+O_WATER_CHEST_LUMP_START,\r
+GREL_LUMP_START,\r
+RAY_LUMP_START,\r
+COLUMN3_LUMP_START,\r
+OLD_CHEST_LUMP_START,\r
+OFIREPOT_LUMP_START,\r
+COLUMN4_LUMP_START,\r
+TOMB1_LUMP_START,\r
+TOMB2_LUMP_START,\r
+DEMON_LUMP_START,\r
+COLUMN5_LUMP_START,\r
+};\r
+\r
+\r
+int lumpend[NUMLUMPS] = {\r
+EYESTALK_LUMP_END,\r
+BLOB_LUMP_END,\r
+BOLT_LUMP_END,\r
+NUKE_LUMP_END,\r
+POTION_LUMP_END,\r
+RKEY_LUMP_END,\r
+YKEY_LUMP_END,\r
+GKEY_LUMP_END,\r
+BKEY_LUMP_END,\r
+RGEM_LUMP_END,\r
+GGEM_LUMP_END,\r
+BGEM_LUMP_END,\r
+YGEM_LUMP_END,\r
+PGEM_LUMP_END,\r
+CHEST_LUMP_END,\r
+PLAYER_LUMP_END,\r
+TIME_LUMP_END,\r
+PORTAL_LUMP_END,\r
+COLUMN1_LUMP_END,\r
+FFIREPOT_LUMP_END,\r
+COLUMN2_LUMP_END,\r
+EYE_LUMP_END,\r
+FUTUREMAGE_LUMP_END,\r
+FORCEFIELD_LUMP_END,\r
+ROBOTANK_LUMP_END,\r
+RAMBONE_LUMP_END,\r
+STOMPY_LUMP_END,\r
+TROLL_LUMP_END,\r
+WIZARD_LUMP_END,\r
+HEAD_LUMP_END,\r
+INVISDUDE_LUMP_END,\r
+BUG_LUMP_END,\r
+CYBORG_LUMP_END,\r
+O_WATER_CHEST_LUMP_END,\r
+GREL_LUMP_END,\r
+RAY_LUMP_END,\r
+COLUMN3_LUMP_END,\r
+OLD_CHEST_LUMP_END,\r
+OFIREPOT_LUMP_END,\r
+COLUMN4_LUMP_END,\r
+TOMB1_LUMP_END,\r
+TOMB2_LUMP_END,\r
+DEMON_LUMP_END,\r
+COLUMN5_LUMP_END,\r
+};\r
+\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+ GLOBAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+unsigned latchpics[NUMLATCHPICS];\r
+unsigned tileoffsets[NUMTILE16];\r
+unsigned textstarts[27];\r
+\r
+boolean splitscreen=false;\r
+/*\r
+=============================================================================\r
+\r
+ LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+boolean lumpneeded[NUMLUMPS];\r
+\r
+\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
+ unsigned char hibyte;\r
+ unsigned x,y,i,j;\r
+ unsigned int tile;\r
+ unsigned far *start;\r
+\r
+ InitObjList(); // start spawning things with a clean slate\r
+\r
+ scolor = gcolor = 0;\r
+ skycolor = &scolor;\r
+ groundcolor = &gcolor;\r
+\r
+\r
+ memset (lumpneeded,0,sizeof(lumpneeded));\r
+\r
+ start = mapsegs[2];\r
+ for (y=0;y<mapheight;y++)\r
+ for (x=0;x<mapwidth;x++)\r
+ {\r
+ tile = *start++;\r
+ hibyte = tile >> 8;\r
+ tile &= 0xff;\r
+\r
+ switch (hibyte)\r
+ {\r
+ char hi;\r
+\r
+ case 0xFB:\r
+ wall_anim_time = tile;\r
+ tile = 0;\r
+ break;\r
+\r
+ case 0xfa: // sky/ground color\r
+ x++;\r
+ tile = *start++;\r
+ hi = tile >> 8;\r
+ tile &= 0xff;\r
+ switch (hibyte)\r
+ {\r
+ case 0xfa: // sky / ground color\r
+ scolor = ((hi)|(hi<<8));\r
+ gcolor = ((tile)|(tile<<8));\r
+ skycolor = &scolor;\r
+ groundcolor = &gcolor;\r
+ break;\r
+\r
+ }\r
+ break;\r
+ }\r
+\r
+ if ((!tile) || (hibyte))\r
+ continue;\r
+\r
+ switch (tile)\r
+ {\r
+ case 1:\r
+ case 2:\r
+ case 3:\r
+ case 4:\r
+ lumpneeded[PLAYERLUMP] = true;\r
+ SpawnPlayer(x,y,NORTH+tile-1);\r
+ break;\r
+\r
+ case 5:\r
+ case 6:\r
+ case 7:\r
+ case 8:\r
+ case 9:\r
+ case 10:\r
+ case 11:\r
+ lumpneeded[tile-5+BOLTLUMP] = true;\r
+ SpawnBonus(x,y,tile-5);\r
+ break;\r
+\r
+ case 12:\r
+ lumpneeded[EYESTALKLUMP] = true;\r
+ SpawnAquaMan(x, y);\r
+ break;\r
+\r
+\r
+ case 13:\r
+ lumpneeded[BLOBLUMP] = true;\r
+ SpawnBlob(x, y);\r
+ break;\r
+\r
+\r
+ case 14:\r
+ lumpneeded[BUGLUMP] = true;\r
+ SpawnBug(x, y);\r
+ break;\r
+\r
+ case 15:\r
+ lumpneeded[CYBORGLUMP] = true;\r
+ SpawnCyborgDemon(x, y);\r
+ break;\r
+\r
+ case 16:\r
+ lumpneeded[EYELUMP] = true;\r
+ SpawnShooterEye(x, y);\r
+ break;\r
+\r
+ case 17:\r
+ lumpneeded[FUTUREMAGELUMP] = true;\r
+ SpawnFutureMage(x, y);\r
+ break;\r
+\r
+ case 18:\r
+ lumpneeded[INVISDUDELUMP] = true;\r
+ SpawnInvisDude(x, y);\r
+ break;\r
+\r
+ case 19:\r
+ lumpneeded[ROBOTANKLUMP] = true;\r
+ SpawnRoboTank(x, y);\r
+ break;\r
+\r
+ case 20:\r
+ lumpneeded[RAMBONELUMP] = true;\r
+ SpawnRamBone(x, y);\r
+ break;\r
+\r
+ case 21:\r
+ lumpneeded[STOMPYLUMP] = true;\r
+ SpawnStompy(x, y);\r
+ break;\r
+\r
+ case 22:\r
+ lumpneeded[TROLLLUMP] = true;\r
+ SpawnTroll(x, y);\r
+ break;\r
+\r
+ case 23:\r
+ lumpneeded[WIZARDLUMP] = true;\r
+ SpawnWizard(x, y);\r
+ break;\r
+\r
+ case 24:\r
+ SpawnBounce(x, y, 0);\r
+ break;\r
+\r
+ case 25:\r
+ SpawnBounce(x, y, 1);\r
+ break;\r
+\r
+ case 26:\r
+ lumpneeded[RKEYLUMP] = lumpneeded[GRELLUMP] = true;\r
+ SpawnGrelminar (x,y);\r
+ break;\r
+\r
+ case 27:\r
+ lumpneeded[EYELUMP] = true;\r
+ SpawnRunningEye(x,y);\r
+ break;\r
+\r
+ case 28:\r
+ lumpneeded[RAYLUMP] = true;\r
+ SpawnRay(x, y);\r
+ break;\r
+\r
+ case 29:\r
+ lumpneeded[HEADLUMP] = true;\r
+ SpawnEgyptianHead(x, y);\r
+ break;\r
+\r
+ case 30:\r
+ lumpneeded[DEMONLUMP] = true;\r
+ SpawnDemon(x, y);\r
+ break;\r
+\r
+ case 31:\r
+ lumpneeded[COLUMN5LUMP] = true;\r
+ SpawnMiscObjects(x, y, 9);\r
+ break;\r
+\r
+ case 32:\r
+ SpawnInvisWallCntroller(x, y);\r
+ break;\r
+\r
+ case 33:\r
+ break;\r
+\r
+ case 34:\r
+ break;\r
+\r
+ case 35:\r
+ break;\r
+\r
+ case 36:\r
+ lumpneeded[COLUMN1LUMP] = true;\r
+ SpawnMiscObjects(x, y, 1);\r
+ break;\r
+\r
+ case 37:\r
+ lumpneeded[FIREPOTLUMP] = true;\r
+ SpawnMiscObjects(x, y, 4);\r
+ break;\r
+\r
+ case 38:\r
+ lumpneeded[PORTALLUMP] = true;\r
+ SpawnWarp(x, y);\r
+ break;\r
+\r
+ case 39:\r
+ lumpneeded[FTIMELUMP] = true;\r
+ SpawnFTime(x,y);\r
+ break;\r
+\r
+\r
+ case 40:\r
+ case 41:\r
+ case 42:\r
+ case 43:\r
+ case 44:\r
+ lumpneeded[tile-40+RGEMLUMP] = true;\r
+ SpawnBonus(x,y,tile-40+B_RGEM);\r
+ break;\r
+\r
+ case 45:\r
+ lumpneeded[COLUMN2LUMP] = true;\r
+ SpawnMiscObjects(x, y, 2);\r
+ break;\r
+\r
+ case 46:\r
+ lumpneeded[COLUMN3LUMP] = true;\r
+ SpawnMiscObjects(x, y, 3);\r
+ break;\r
+\r
+ case 47:\r
+ lumpneeded[FORCEFIELDLUMP] = true;\r
+ SpawnForceField(x, y);\r
+ break;\r
+\r
+ case 48:\r
+ lumpneeded[OLDCHESTLUMP] = true;\r
+ SpawnBonus(x, y, B_OLDCHEST);\r
+ break;\r
+\r
+ case 49: // chest\r
+ if (gcolor == 0x0101)\r
+ lumpneeded[WATERCHESTLUMP] = true;\r
+ else\r
+ lumpneeded[CHESTLUMP] = true;\r
+ SpawnBonus(x,y,B_CHEST);\r
+ break;\r
+\r
+ case 50:\r
+ lumpneeded[COLUMN4LUMP] = true;\r
+ SpawnMiscObjects(x, y, 5);\r
+ break;\r
+\r
+ case 51:\r
+ lumpneeded[OLDFIREPOTLUMP] = true;\r
+ SpawnMiscObjects(x, y, 6);\r
+ break;\r
+\r
+ case 52:\r
+ lumpneeded[TOMB1LUMP] = true;\r
+ SpawnMiscObjects(x, y, 7);\r
+ break;\r
+\r
+ case 53:\r
+ lumpneeded[TOMB2LUMP] = true;\r
+ SpawnMiscObjects(x, y, 8);\r
+ break;\r
+\r
+ case 54:\r
+ break;\r
+\r
+ case 55:\r
+ break;\r
+\r
+ case 56:\r
+ break;\r
+\r
+ case 57:\r
+ break;\r
+\r
+ case 58:\r
+ break;\r
+\r
+ case 59:\r
+ break;\r
+\r
+ case 60:\r
+ break;\r
+\r
+ case 61:\r
+ break;\r
+\r
+ case 62:\r
+ break;\r
+\r
+ case 63:\r
+ break;\r
+\r
+ case 64:\r
+ break;\r
+\r
+ case 65:\r
+ break;\r
+\r
+ case 66:\r
+ break;\r
+\r
+ case 67:\r
+ break;\r
+\r
+ case 68:\r
+ break;\r
+\r
+ case 69:\r
+ break;\r
+\r
+ case 70:\r
+ break;\r
+\r
+ case 71:\r
+ break;\r
+\r
+ }\r
+ }\r
+\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+==================\r
+=\r
+= ScanText\r
+=\r
+==================\r
+*/\r
+\r
+void ScanText (void)\r
+{\r
+ int i;\r
+ char far *text;\r
+\r
+ text = (char _seg *)grsegs[LEVEL1TEXT+mapon];\r
+\r
+ textstarts[0] = 0;\r
+\r
+ for (i=1;i<=26;i++)\r
+ {\r
+ while (*text != '\n')\r
+ {\r
+ if (*text == '\r')\r
+ *text = 0;\r
+ text++;\r
+ }\r
+ text++;\r
+ textstarts[i] = FP_OFF(text);\r
+ }\r
+\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+==================\r
+=\r
+= DrawEnterScreen\r
+=\r
+==================\r
+*/\r
+#if 0\r
+static char *levelnames[] =\r
+ {\r
+ "Programmers Test Map",\r
+ "The Garden of Tears",\r
+ "The Den of Zombies",\r
+ "The Mausoleum Grounds",\r
+ "The Main Floor of the Mausoleum",\r
+ "Mike's Blastable Passage",\r
+ "The Crypt of Nemesis the Undead",\r
+ "The Subterranean Vault",\r
+ "The Ancient Aqueduct",\r
+ "The Orc Mines",\r
+ "The Lair of the Troll",\r
+ "The Demon's Inferno",\r
+ "The Battleground of the Titans",\r
+ "The Coven of Mages",\r
+ "The Inner Sanctum",\r
+ "The Haunt of Nemesis",\r
+ "The Passage to the Surface",\r
+ "Big Jim's Domain",\r
+ "Nolan",\r
+ "19",\r
+ "20",\r
+ "21",\r
+ "22",\r
+ "23",\r
+ "24",\r
+ "25",\r
+ "26",\r
+ "27",\r
+ "28",\r
+ "29",\r
+ "30",\r
+ "31",\r
+ "32",\r
+ "33",\r
+ "34",\r
+ "35",\r
+ "36",\r
+ "37",\r
+ "38",\r
+ "39",\r
+ };\r
+#endif\r
+\r
+void DrawEnterScreen ()\r
+{\r
+ int width;\r
+\r
+ bufferofs = displayofs = screenloc[screenpage];\r
+ VW_Bar(0,0,VIEWWIDTH,VIEWHEIGHT,0);\r
+\r
+// width = strlen(levelnames[gamestate.mapon]);\r
+ width = strlen("A new challenge awaits you.");\r
+ if (width < 20)\r
+ width = 20;\r
+ CenterWindow(width,3);\r
+ US_CPrint("\nA new challenge awaits you.\n");\r
+// US_CPrint(levelnames[gamestate.mapon]);\r
+}\r
+\r
+//==========================================================================\r
+\r
+boolean tileneeded[NUMFLOORS];\r
+\r
+\r
+/*\r
+==================\r
+=\r
+= CacheScaleds\r
+=\r
+==================\r
+*/\r
+\r
+void CacheScaleds (void)\r
+{\r
+ int i,j;\r
+ unsigned source,dest;\r
+\r
+ FreeUpMemory ();\r
+ CA_CacheGrChunk(LEVEL1TEXT+mapon);\r
+ ScanText ();\r
+\r
+//\r
+// make sure we are displaying screenpage 0\r
+//\r
+ if (screenpage)\r
+ {\r
+ source = screenloc[screenpage];\r
+ dest = screenloc[0];\r
+ VW_ScreenToScreen (source,dest,40,VIEWHEIGHT);\r
+ screenpage = 0;\r
+ VW_SetScreen (dest,0);\r
+ displayofs = dest;\r
+ }\r
+\r
+//\r
+// cache wall pictures\r
+//\r
+ for (i=1;i<NUMFLOORS;i++)\r
+ if (tileneeded[i])\r
+ {\r
+ SetupScaleWall (walllight1[i]);\r
+ SetupScaleWall (walldark1[i]);\r
+ }\r
+\r
+//\r
+// cache the actor pictures\r
+//\r
+ for (i=0;i<NUMLUMPS;i++)\r
+ if (lumpneeded[i])\r
+ for (j=lumpstart[i];j<=lumpend[i];j++)\r
+ SetupScalePic(j);\r
+\r
+ source = screenloc[0];\r
+ for (i=1;i<=2;i++)\r
+ {\r
+ dest = screenloc[i];\r
+ VW_ScreenToScreen (source,dest,40,VIEWHEIGHT);\r
+ }\r
+\r
+ screenpage = 1;\r
+}\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+==================\r
+=\r
+= SetupGameLevel\r
+=\r
+==================\r
+*/\r
+\r
+void SetupGameLevel ()\r
+{\r
+ int x,y,i,loop;\r
+ unsigned far *map,tile,far *spotptr,spot;\r
+ unsigned search_tile;\r
+ boolean exploding_walls_present = false;\r
+\r
+ memset (tileneeded,0,sizeof(tileneeded));\r
+//\r
+// randomize if not a demo\r
+//\r
+#if 0\r
+ if (DemoMode)\r
+ {\r
+ US_InitRndT(false);\r
+ gamestate.difficulty = gd_Normal;\r
+ }\r
+ else\r
+#endif\r
+ US_InitRndT(true);\r
+\r
+//\r
+// load the level\r
+//\r
+ CA_CacheMap (gamestate.mapon);\r
+\r
+ mapwidth = mapheaderseg[mapon]->width;\r
+ mapheight = mapheaderseg[mapon]->height;\r
+\r
+//\r
+// make a lookup table for the maps left edge\r
+//\r
+ spot = 0;\r
+ for (y=0;y<mapheight;y++)\r
+ {\r
+ farmapylookup[y] = spot;\r
+ spot += mapwidth;\r
+ }\r
+\r
+\r
+//\r
+// copy the wall data to a data segment array\r
+//\r
+ memset (tilemap,0,sizeof(tilemap));\r
+ memset (actorat,0,sizeof(actorat));\r
+ map = mapsegs[0];\r
+ spotptr = mapsegs[2];\r
+ for (y=0;y<mapheight;y++)\r
+ for (x=0;x<mapwidth;x++)\r
+ {\r
+ tile = *map++;\r
+\r
+ if (((*spotptr)>>8) == EXP_WALL_CODE)\r
+ {\r
+ exploding_walls_present = true;\r
+ }\r
+\r
+ if (tile<NUMFLOORS)\r
+ {\r
+#if 0\r
+ if (tile == WALL_SKELETON_CODE)\r
+ {\r
+ tileneeded[tile+1] = tileneeded[tile+2] = true;\r
+ tilemap[x][y] = tile;\r
+ }\r
+#endif\r
+ if ((tile == 66) || (tile == 67) || (tile == 68) || (tile == 69))\r
+ {\r
+ if ((tile == 66) || (tile == 67))\r
+ tileneeded[tile+2] = true;\r
+ tileneeded[21] = tileneeded[tile] = true;\r
+ tilemap[x][y] = tile;\r
+ }\r
+ else\r
+ if (tile != INVISIBLEWALL)\r
+ {\r
+ tileneeded[tile] = true;\r
+ tilemap[x][y] = tile;\r
+ if (ANIM_FLAGS(tile))\r
+ {\r
+ search_tile = tile+(char signed)ANIM_FLAGS(tile);\r
+\r
+ if (!tileneeded[search_tile])\r
+ while (search_tile != tile)\r
+ {\r
+ tileneeded[search_tile] = true;\r
+ if (ANIM_FLAGS(search_tile))\r
+ search_tile += (char signed)ANIM_FLAGS(search_tile);\r
+ else\r
+ TrashProg("Unending Tile Animation!");\r
+ }\r
+ }\r
+\r
+ }\r
+ if (tile>0)\r
+ (unsigned)actorat[x][y] = tile;\r
+ }\r
+ spotptr++;\r
+ }\r
+\r
+\r
+ //\r
+ // Mark any gfx chunks needed\r
+ //\r
+\r
+// CA_MarkGrChunk(NORTHICONSPR);\r
+// CA_CacheMarks(NULL);\r
+\r
+\r
+//\r
+// decide which graphics are needed and spawn actors\r
+//\r
+ head_base_delay = 0; // (1*60) + random(1*60);\r
+ ScanInfoPlane ();\r
+ _fmemset(wall_anim_pos,0,sizeof(wall_anim_pos));\r
+\r
+\r
+//\r
+// mark which exploding walls are needed ---- the check for floor color\r
+// is preformed in ScanInfoPlane.\r
+//\r
+\r
+ if (exploding_walls_present)\r
+ {\r
+ extern unsigned gnd_colors[];\r
+\r
+ if (gcolor == 0x0101)\r
+ tileneeded[WATEREXP] = tileneeded[WATEREXP+1] = tileneeded[WATEREXP+2] = true;\r
+ else\r
+ tileneeded[WALLEXP] = tileneeded[WALLEXP+1] = tileneeded[WALLEXP+2] = true;\r
+\r
+ }\r
+\r
+\r
+//\r
+// have the caching manager load and purge stuff to make sure all marks\r
+// are in memory\r
+//\r
+ CA_LoadAllSounds ();\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+=====================\r
+=\r
+= LatchDrawPic\r
+=\r
+=====================\r
+*/\r
+\r
+void LatchDrawPic (unsigned x, unsigned y, unsigned picnum)\r
+{\r
+ unsigned height, source, dest;\r
+ unsigned wide;\r
+\r
+ wide = pictable[picnum-STARTPICS].width;\r
+ height = pictable[picnum-STARTPICS].height;\r
+ dest = bufferofs + ylookup[y]+x;\r
+ source = latchpics[picnum-FIRSTLATCHPIC];\r
+\r
+ EGAWRITEMODE(1);\r
+ EGAMAPMASK(15);\r
+\r
+asm mov bx,[linewidth]\r
+asm sub bx,[wide]\r
+\r
+asm mov ax,[screenseg]\r
+asm mov es,ax\r
+asm mov ds,ax\r
+\r
+asm mov si,[source]\r
+asm mov di,[dest]\r
+asm mov dx,[height] // scan lines to draw\r
+asm mov ax,[wide]\r
+\r
+lineloop:\r
+asm mov cx,ax\r
+asm rep movsb\r
+asm add di,bx\r
+\r
+asm dec dx\r
+asm jnz lineloop\r
+\r
+asm mov ax,ss\r
+asm mov ds,ax // restore turbo's data segment\r
+\r
+ EGAWRITEMODE(0);\r
+}\r
+\r
+#if USE_STRIPS\r
+\r
+//--------------------------------------------------------------------------\r
+// LatchDrawPicStrip() - srcoff is distance into source file (in PIXELS!)\r
+//--------------------------------------------------------------------------\r
+void LatchDrawPicStrip (unsigned x, unsigned y, unsigned picnum, unsigned srcoff)\r
+{\r
+ unsigned wide, height, source, dest, shift, srcmod;\r
+\r
+ shift = (srcoff & 7) >> 1;\r
+ srcoff >>= 3;\r
+ wide = pictable[picnum-STARTPICS].width;\r
+ srcmod = wide - linewidth + (shift != 3);\r
+ if (wide > linewidth)\r
+ wide = linewidth;\r
+ height = pictable[picnum-STARTPICS].height;\r
+ dest = bufferofs + ylookup[y]+x;\r
+\r
+ picnum = ((picnum - (FIRSTSTRIPPIC+1)) >> 2) + (shift);\r
+ source = latchpics[(FIRSTSTRIPPIC-FIRSTLATCHPIC+1)+picnum];\r
+\r
+ EGAWRITEMODE(1);\r
+ EGAMAPMASK(15);\r
+\r
+asm mov bx,[linewidth]\r
+asm sub bx,[wide]\r
+\r
+asm mov ax,[screenseg]\r
+asm mov es,ax\r
+asm mov ds,ax\r
+\r
+asm mov si,[source]\r
+asm add si,[srcoff]\r
+asm mov di,[dest]\r
+asm mov dx,[height] // scan lines to draw\r
+asm mov ax,[wide]\r
+\r
+lineloop:\r
+asm mov cx,ax\r
+asm rep movsb\r
+asm add di,bx\r
+asm add si,[srcmod]\r
+\r
+asm dec dx\r
+asm jnz lineloop\r
+\r
+asm mov ax,ss\r
+asm mov ds,ax // restore turbo's data segment\r
+\r
+ EGAWRITEMODE(0);\r
+}\r
+\r
+#endif\r
+\r
+\r
+//==========================================================================\r
+\r
+/*\r
+=====================\r
+=\r
+= Victory\r
+=\r
+=====================\r
+*/\r
+\r
+void Victory (boolean playsounds)\r
+{\r
+ struct Shape shape;\r
+\r
+ if (playsounds)\r
+ {\r
+ SD_PlaySound (GETBOLTSND);\r
+ SD_WaitSoundDone ();\r
+ SD_PlaySound (GETNUKESND);\r
+ SD_WaitSoundDone ();\r
+ SD_PlaySound (GETPOTIONSND);\r
+ SD_WaitSoundDone ();\r
+ SD_PlaySound (GETKEYSND);\r
+ SD_WaitSoundDone ();\r
+// SD_PlaySound (GETSCROLLSND);\r
+// SD_WaitSoundDone ();\r
+ SD_PlaySound (GETPOINTSSND);\r
+ }\r
+\r
+ FreeUpMemory();\r
+\r
+ if (!screenfaded)\r
+ VW_FadeOut();\r
+\r
+ NormalScreen ();\r
+\r
+ screenpage = bufferofs = 0;\r
+\r
+ CA_CacheGrChunk (FINALEPIC);\r
+ UNMARKGRCHUNK(FINALEPIC);\r
+ VW_DrawPic(0, 0, FINALEPIC);\r
+\r
+ VW_FadeIn();\r
+\r
+}\r
+\r
+//==========================================================================\r
+\r
+#if 0\r
+/*\r
+===================\r
+=\r
+= Died\r
+=\r
+===================\r
+*/\r
+\r
+void Died (void)\r
+{\r
+ unsigned page1,page2;\r
+//\r
+// fizzle fade screen to grey\r
+//\r
+ FreeUpMemory ();\r
+ SD_PlaySound (GAMEOVERSND);\r
+ bufferofs = screenloc[(screenpage+1)%3];\r
+ DisplayMsg("Though fallen, your Spirit ...",NULL);\r
+// LatchDrawPic(0,0,DEADPIC);\r
+// FizzleFade(bufferofs,displayofs,VIEWWIDTH,VIEWHEIGHT,false);\r
+ IN_ClearKeysDown();\r
+ while (!Keyboard[sc_Enter]);\r
+// IN_Ack();\r
+ VW_SetScreen (bufferofs,0);\r
+ VW_ColorBorder(0);\r
+}\r
+#endif\r
+\r
+//==========================================================================\r
+\r
+/*\r
+===================\r
+=\r
+= NormalScreen\r
+=\r
+===================\r
+*/\r
+\r
+void NormalScreen (void)\r
+{\r
+ VW_SetSplitScreen (200);\r
+ bufferofs = displayofs = SCREEN1START;\r
+ VW_Bar(0,0,320,200,0);\r
+ bufferofs = SCREEN2START;\r
+ VW_Bar(0,0,320,200,0);\r
+ VW_SetScreen (displayofs,0);\r
+ splitscreen = false;\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+===================\r
+=\r
+= DrawPlayScreen\r
+=\r
+===================\r
+*/\r
+\r
+void DrawPlayScreen (void)\r
+{\r
+ int i,j,p,m;\r
+\r
+ screenpage = 0;\r
+\r
+ bufferofs = 0;\r
+ VW_Bar (0,0,320,STATUSLINES,0);\r
+ for (i=0;i<3;i++)\r
+ {\r
+ bufferofs = screenloc[i];\r
+ VW_Bar (0,0,320,VIEWHEIGHT,0);\r
+ }\r
+\r
+ splitscreen = true;\r
+ VW_SetSplitScreen(120);\r
+ VW_SetScreen(screenloc[0],0);\r
+\r
+ CA_CacheGrChunk (STATUSPIC);\r
+\r
+ bufferofs = 0;\r
+ VW_DrawPic (0,0,STATUSPIC);\r
+\r
+ grneeded[STATUSPIC] &= ~ca_levelbit;\r
+ MM_SetPurge(&grsegs[STATUSPIC],3);\r
+\r
+// RedrawStatusWindow ();\r
+ bufferofs = displayofs = screenloc[0];\r
+}\r
+\r
+\r
+//==========================================================================\r
+\r
+/*\r
+===================\r
+=\r
+= LoadLatchMem\r
+=\r
+===================\r
+*/\r
+\r
+unsigned latchmemavail;\r
+\r
+void LoadLatchMem (void)\r
+{\r
+ static unsigned base_destoff=0;\r
+ static int base_numpics=0;\r
+ int i,j,p,m,numpics;\r
+ byte far *src, far *dest;\r
+ unsigned destoff;\r
+\r
+ EGAWRITEMODE(0);\r
+\r
+//\r
+// draw some pics into latch memory\r
+//\r
+\r
+ if (!base_numpics)\r
+ {\r
+\r
+//\r
+// tile 8s\r
+//\r
+ latchpics[0] = freelatch;\r
+ src = (byte _seg *)grsegs[STARTTILE8];\r
+ dest = MK_FP(0xa000,freelatch);\r
+\r
+ for (i=0;i<NUMTILE8;i++)\r
+ {\r
+ for (p=0;p<4;p++)\r
+ {\r
+ m = 1<<p;\r
+ asm mov dx,SC_INDEX\r
+ asm mov al,SC_MAPMASK\r
+ asm mov ah,[BYTE PTR m]\r
+ asm out dx,ax\r
+ for (j=0;j<8;j++)\r
+ *(dest+j)=*src++;\r
+ }\r
+ dest+=8;\r
+ }\r
+\r
+//\r
+// tile 16s\r
+//\r
+ src = (byte _seg *)grsegs[STARTTILE16];\r
+\r
+ for (i=0;i<NUMTILE16;i++)\r
+ {\r
+ CA_CacheGrChunk (STARTTILE16+i);\r
+ src = (byte _seg *)grsegs[STARTTILE16+i];\r
+ if (src)\r
+ {\r
+ tileoffsets[i] = FP_OFF(dest);\r
+ for (p=0;p<4;p++)\r
+ {\r
+ m = 1<<p;\r
+ asm mov dx,SC_INDEX\r
+ asm mov al,SC_MAPMASK\r
+ asm mov ah,[BYTE PTR m]\r
+ asm out dx,ax\r
+ for (j=0;j<32;j++)\r
+ *(dest+j)=*src++;\r
+ }\r
+ dest+=32;\r
+ MM_FreePtr (&grsegs[STARTTILE16+i]);\r
+ UNMARKGRCHUNK(STARTTILE16+i);\r
+ }\r
+ else\r
+ tileoffsets[i] = 0;\r
+ }\r
+\r
+\r
+//\r
+// pics\r
+//\r
+ numpics=1;\r
+ destoff = FP_OFF(dest);\r
+ for (i=FIRSTLATCHPIC+1;i<FIRSTGROUNDPIC;i++)\r
+ {\r
+ latchpics[numpics++] = destoff;\r
+ CA_CacheGrChunk (i);\r
+ j = pictable[i-STARTPICS].width * pictable[i-STARTPICS].height;\r
+ VW_MemToScreen (grsegs[i],destoff,j,1);\r
+ destoff+=j;\r
+ MM_FreePtr (&grsegs[i]);\r
+ UNMARKGRCHUNK(i);\r
+ }\r
+\r
+ base_numpics = numpics;\r
+ base_destoff = destoff;\r
+\r
+ }\r
+\r
+ numpics = base_numpics;\r
+ destoff = base_destoff;\r
+\r
+#if USE_STRIPS\r
+//\r
+// ground pics\r
+//\r
+ numpics++;\r
+ for (i=FIRSTGROUNDPIC+1;i<FIRSTSTRIPPIC;i++)\r
+ {\r
+ int shape = (*groundcolor & 0xf0) - 16;\r
+\r
+ // Is current shape needed?\r
+ //\r
+ if (shape != (i-(FIRSTGROUNDPIC+1)))\r
+ {\r
+ numpics++;\r
+ continue;\r
+ }\r
+\r
+ latchpics[numpics++] = destoff;\r
+ CA_CacheGrChunk (i);\r
+ j = pictable[i-STARTPICS].width * pictable[i-STARTPICS].height;\r
+ VW_MemToScreen (grsegs[i],destoff,j,1);\r
+ destoff+=j;\r
+ MM_FreePtr (&grsegs[i]);\r
+ UNMARKGRCHUNK(i);\r
+ }\r
+\r
+\r
+//\r
+// 'parallax' strips - used in place of a sky color\r
+//\r
+// Under current setup, each strip takes about 7k in latch memory.\r
+// To create 2 pixel scrolling, 4 strips are needed, that's 28k of\r
+// latch memory needed to produce this effect.\r
+//\r
+ numpics++;\r
+ for (i=FIRSTSTRIPPIC+1;i<FIRSTSCALEPIC;i++)\r
+ {\r
+ memptr work;\r
+ unsigned workdest,stripsize,planesize;\r
+ short loop,pic=i-STARTPICS;\r
+ int shape = (*skycolor & 0xf0) - 16;\r
+\r
+ // Is current shape needed?\r
+ //\r
+ if (shape != (i-(FIRSTSTRIPPIC+1)))\r
+ {\r
+ numpics++;\r
+ continue;\r
+ }\r
+\r
+ // CAL_ShiftSprite() works with the SRC and DST in the same\r
+ // segment. So we must allocate memory for two strips, and\r
+ // move the base strip into that segment. Then we can use the\r
+ // 2nd half of that memory for each shifted strip.\r
+ //\r
+ CA_CacheGrChunk (i);\r
+ planesize = (pictable[pic].width+1) * pictable[pic].height;\r
+ stripsize = planesize * 4;\r
+// MM_GetPtr(&work,(stripsize*2)+0000);\r
+ MM_GetPtr(&work,65536);\r
+ movedata((unsigned)grsegs[i],0,(unsigned)work,0,stripsize);\r
+ workdest = 32768; //(stripsize+15) & 0xFFF0;\r
+\r
+ // Free base strip\r
+ //\r
+ MM_FreePtr (&grsegs[i]);\r
+ UNMARKGRCHUNK(i);\r
+\r
+ // Create three shifted strips and move 'em to latch!\r
+ //\r
+ for (loop=3; loop; loop--)\r
+ {\r
+ // Produce current shift for this strip\r
+ //\r
+ latchpics[numpics++] = destoff;\r
+ CAL_ShiftSprite ((unsigned)work,0,workdest,pictable[pic].width,\r
+ pictable[pic].height,loop*2,false);\r
+\r
+ // Copy this shift to latch memory\r
+ //\r
+ VW_MemToScreen ((memptr)((unsigned)work+(workdest>>4)),destoff,planesize,1);\r
+ destoff+=planesize;\r
+ }\r
+\r
+ // Copy unshifted strip to latch\r
+ //\r
+ latchpics[numpics++] = destoff;\r
+ planesize = pictable[pic].width * pictable[pic].height;\r
+ VW_MemToScreen (work,destoff,planesize,1);\r
+ destoff+=planesize;\r
+\r
+ // Free work buffer\r
+ //\r
+ MM_FreePtr(&work);\r
+ }\r
+#endif\r
+\r
+// Keep track of how much latch memory we have...\r
+//\r
+ latchmemavail = 65535-destoff;\r
+\r
+ EGAMAPMASK(15);\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+===================\r
+=\r
+= FizzleOut\r
+=\r
+===================\r
+*/\r
+\r
+void FizzleOut (int showlevel)\r
+{\r
+ unsigned page1,page2;\r
+//\r
+// fizzle fade screen to grey\r
+//\r
+ bufferofs = screenloc[(screenpage+1)%3];\r
+ if (showlevel)\r
+ DrawEnterScreen ();\r
+ FizzleFade(bufferofs,displayofs,VIEWWIDTH,VIEWHEIGHT,false);\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+====================\r
+=\r
+= FreeUpMemory\r
+=\r
+====================\r
+*/\r
+\r
+void FreeUpMemory (void)\r
+{\r
+ int i;\r
+\r
+ for (i=0;i<NUMSCALEPICS;i++)\r
+ if (shapedirectory[i])\r
+ MM_SetPurge (&(memptr)shapedirectory[i],3);\r
+\r
+ for (i=0;i<NUMSCALEWALLS;i++)\r
+ if (walldirectory[i])\r
+ MM_SetPurge (&(memptr)walldirectory[i],3);\r
+}\r
+\r
+//==========================================================================\r
+\r
+#if 0\r
+\r
+/*\r
+==================\r
+=\r
+= DrawHighScores\r
+=\r
+==================\r
+*/\r
+\r
+void DrawHighScores(void)\r
+{\r
+ char buffer[16],*str;\r
+ word i,j,\r
+ w,h,\r
+ x,y;\r
+ HighScore *s;\r
+\r
+\r
+ CA_CacheGrChunk (HIGHSCORESPIC);\r
+ VWB_DrawPic (0,0,HIGHSCORESPIC);\r
+ MM_SetPurge (&grsegs[HIGHSCORESPIC],3);\r
+ UNMARKGRCHUNK(HIGHSCORESPIC);\r
+\r
+ for (i = 0,s = Scores;i < MaxScores;i++,s++)\r
+ {\r
+ PrintY = 68 + (16 * i);\r
+\r
+ //\r
+ // name\r
+ //\r
+ PrintX = 60;\r
+ US_Print(s->name);\r
+\r
+ //\r
+ // level\r
+ //\r
+ ultoa(s->completed,buffer,10);\r
+ for (str = buffer;*str;str++)\r
+ *str = *str + (129 - '0'); // Used fixed-width numbers (129...)\r
+ USL_MeasureString(buffer,&w,&h);\r
+ PrintX = (25 * 8) - 8 - w;\r
+ US_Print(buffer);\r
+\r
+ //\r
+ // score\r
+ //\r
+ ultoa(s->score,buffer,10);\r
+ for (str = buffer;*str;str++)\r
+ *str = *str + (129 - '0'); // Used fixed-width numbers (129...)\r
+ USL_MeasureString(buffer,&w,&h);\r
+ PrintX = (34 * 8) - 8 - w;\r
+ US_Print(buffer);\r
+ }\r
+\r
+ fontcolor = F_BLACK;\r
+}\r
+\r
+\r
+\r
+/*\r
+=======================\r
+=\r
+= CheckHighScore\r
+=\r
+=======================\r
+*/\r
+\r
+void CheckHighScore (long score,word other)\r
+{\r
+ word i,j;\r
+ int n;\r
+ HighScore myscore;\r
+\r
+ strcpy(myscore.name,"");\r
+ myscore.score = score;\r
+ myscore.completed = other;\r
+\r
+ for (i = 0,n = -1;i < MaxScores;i++)\r
+ {\r
+ if\r
+ (\r
+ (myscore.score > Scores[i].score)\r
+ || (\r
+ (myscore.score == Scores[i].score)\r
+ && (myscore.completed > Scores[i].completed)\r
+ )\r
+ )\r
+ {\r
+ for (j = MaxScores;--j > i;)\r
+ Scores[j] = Scores[j - 1];\r
+ Scores[i] = myscore;\r
+ n = i;\r
+ HighScoresDirty = true;\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (n != -1)\r
+ {\r
+ //\r
+ // got a high score\r
+ //\r
+ DrawHighScores ();\r
+ PrintY = 68 + (16 * n);\r
+ PrintX = 60;\r
+ US_LineInput(PrintX,PrintY,Scores[n].name,nil,true,MaxHighName,100);\r
+ }\r
+}\r
+\r
+#endif\r
+\r
+\r
+//==========================================================================\r
+\r
+/*\r
+===================\r
+=\r
+= GameLoop\r
+=\r
+===================\r
+*/\r
+\r
+void GameLoop (void)\r
+{\r
+ boolean wait = false;\r
+ int i,xl,yl,xh,yh;\r
+ char num[20];\r
+#ifdef PROFILE\r
+ clock_t start,end;\r
+#endif\r
+\r
+ DrawPlayScreen ();\r
+ IN_ClearKeysDown();\r
+\r
+restart:\r
+ if (!loadedgame)\r
+ {\r
+ gamestate.difficulty = restartgame;\r
+ restartgame = gd_Continue;\r
+ DrawEnterScreen ();\r
+ if (gamestate.mapon != 8)\r
+ fizzlein = true;\r
+ wait = true;\r
+ }\r
+\r
+ do\r
+ {\r
+ playstate = gd_Continue;\r
+ if (!loadedgame)\r
+ SetupGameLevel ();\r
+ else\r
+ loadedgame = false;\r
+\r
+ FreeUpMemory();\r
+ LoadLatchMem();\r
+ CacheScaleds ();\r
+\r
+ if (EASYMODEON)\r
+ DisplaySMsg("*** NOVICE ***", NULL);\r
+ else\r
+ DisplaySMsg("*** WARRIOR ***", NULL);\r
+\r
+ status_delay = 250;\r
+\r
+ RedrawStatusWindow();\r
+ if (wait)\r
+ {\r
+ VW_WaitVBL(120);\r
+ wait = false;\r
+ }\r
+\r
+#ifdef PROFILE\r
+start = clock();\r
+while (start == clock());\r
+start++;\r
+#endif\r
+\r
+ PlayLoop ();\r
+\r
+#ifdef PROFILE\r
+end = clock();\r
+itoa(end-start,str,10);\r
+ Quit (str);\r
+#endif\r
+\r
+\r
+ switch (playstate)\r
+ {\r
+ case ex_abort:\r
+ FreeUpMemory ();\r
+ return;\r
+ case ex_resetgame:\r
+ NewGame();\r
+ case ex_loadedgame:\r
+ case ex_warped:\r
+ FreeUpMemory();\r
+ if (playstate != ex_resetgame)\r
+ DisplayMsg(" ", NULL);\r
+ DisplaySMsg(" ", NULL);\r
+ goto restart;\r
+ case ex_victorious:\r
+ screenpage = 0;\r
+ bufferofs = 0;\r
+ status_flag = 0;\r
+ return;\r
+ }\r
+\r
+ } while (1);\r
+\r
+}\r
+\r
+\r
+#if 0\r
+//\r
+// make wall pictures purgable\r
+//\r
+ for (i=0;i<NUMSCALEWALLS;i++)\r
+ if (walldirectory[i])\r
+ MM_SetPurge (&(memptr)walldirectory[i],3);\r
+\r
+\r
+//\r
+// cache wall pictures back in\r
+//\r
+ for (i=1;i<NUMFLOORS;i++)\r
+ if (tileneeded[i])\r
+ {\r
+ SetupScaleWall (walllight1[i]);\r
+ SetupScaleWall (walllight2[i]);\r
+ SetupScaleWall (walldark1[i]);\r
+ SetupScaleWall (walldark2[i]);\r
+ }\r
+#endif\r