Catacomb 3D open source release. master
authorRichard Mandel <richard@tech-transfer.com>
Thu, 5 Jun 2014 23:53:35 +0000 (19:53 -0400)
committerRichard Mandel <richard@tech-transfer.com>
Thu, 5 Jun 2014 23:53:35 +0000 (19:53 -0400)
52 files changed:
AUDIOC3D.H [new file with mode: 0644]
C3DADICT.OBJ [new file with mode: 0644]
C3DAHEAD.OBJ [new file with mode: 0644]
C3DEDICT.OBJ [new file with mode: 0644]
C3DEHEAD.OBJ [new file with mode: 0644]
C3DMHEAD.OBJ [new file with mode: 0644]
C3_ACT1.C [new file with mode: 0644]
C3_ASM.ASM [new file with mode: 0644]
C3_DEBUG.C [new file with mode: 0644]
C3_DEF.H [new file with mode: 0644]
C3_DRAW.C [new file with mode: 0644]
C3_GAME.C [new file with mode: 0644]
C3_MAIN.C [new file with mode: 0644]
C3_PLAY.C [new file with mode: 0644]
C3_SCALE.C [new file with mode: 0644]
C3_SCA_A.ASM [new file with mode: 0644]
C3_STATE.C [new file with mode: 0644]
C3_TRACE.C [new file with mode: 0644]
C3_WIZ.C [new file with mode: 0644]
CAT3D.PRJ [new file with mode: 0644]
COPYING [new file with mode: 0644]
GFXE_C3D.EQU [new file with mode: 0644]
GFXE_C3D.H [new file with mode: 0644]
ID_ASM.EQU [new file with mode: 0644]
ID_CA.C [new file with mode: 0644]
ID_CA.H [new file with mode: 0644]
ID_HEADS.H [new file with mode: 0644]
ID_IN.C [new file with mode: 0644]
ID_IN.H [new file with mode: 0644]
ID_MM.C [new file with mode: 0644]
ID_MM.H [new file with mode: 0644]
ID_RF.C [new file with mode: 0644]
ID_RF.H [new file with mode: 0644]
ID_RF_A.ASM [new file with mode: 0644]
ID_SD.C [new file with mode: 0644]
ID_SD.H [new file with mode: 0644]
ID_STRS.H [new file with mode: 0644]
ID_US.C [new file with mode: 0644]
ID_US.H [new file with mode: 0644]
ID_US_1.C [new file with mode: 0644]
ID_US_2.C [new file with mode: 0644]
ID_US_A.ASM [new file with mode: 0644]
ID_VW.C [new file with mode: 0644]
ID_VW.H [new file with mode: 0644]
ID_VW_A.ASM [new file with mode: 0644]
ID_VW_AC.ASM [new file with mode: 0644]
ID_VW_AE.ASM [new file with mode: 0644]
INTROSCN.OBJ [new file with mode: 0644]
JABHACK.ASM [new file with mode: 0644]
MAPSC3D.H [new file with mode: 0644]
NOTES.TXT [new file with mode: 0644]
README.md [new file with mode: 0644]

diff --git a/AUDIOC3D.H b/AUDIOC3D.H
new file mode 100644 (file)
index 0000000..44da68f
--- /dev/null
@@ -0,0 +1,86 @@
+/* Catacomb 3-D 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
+/////////////////////////////////////////////////\r
+//\r
+// MUSE Header for .C3D\r
+// Created Wed Oct 30 22:44:13 1991\r
+//\r
+/////////////////////////////////////////////////\r
+\r
+#define NUMSOUNDS              30\r
+#define NUMSNDCHUNKS           91\r
+\r
+//\r
+// Sound names & indexes\r
+//\r
+typedef enum {\r
+               HITWALLSND,              // 0\r
+               WARPUPSND,               // 1\r
+               WARPDOWNSND,             // 2\r
+               GETBOLTSND,              // 3\r
+               GETNUKESND,              // 4\r
+               GETPOTIONSND,            // 5\r
+               GETKEYSND,               // 6\r
+               GETSCROLLSND,            // 7\r
+               GETPOINTSSND,            // 8\r
+               USEBOLTSND,              // 9\r
+               USENUKESND,              // 10\r
+               USEPOTIONSND,            // 11\r
+               USEKEYSND,               // 12\r
+               NOITEMSND,               // 13\r
+               WALK1SND,                // 14\r
+               WALK2SND,                // 15\r
+               TAKEDAMAGESND,           // 16\r
+               MONSTERMISSSND,          // 17\r
+               GAMEOVERSND,             // 18\r
+               SHOOTSND,                // 19\r
+               BIGSHOOTSND,             // 20\r
+               SHOOTWALLSND,            // 21\r
+               SHOOTMONSTERSND,         // 22\r
+               TAKEDMGHURTSND,          // 23\r
+               BALLBOUNCESND,           // 24\r
+               COMPSCOREDSND,           // 25\r
+               KEENSCOREDSND,           // 26\r
+               COMPPADDLESND,           // 27\r
+               KEENPADDLESND,           // 28\r
+               NOWAYSND,                // 29\r
+               LASTSOUND\r
+            } soundnames;\r
+\r
+//\r
+// Base offsets\r
+//\r
+#define STARTPCSOUNDS          0\r
+#define STARTADLIBSOUNDS       30\r
+#define STARTDIGISOUNDS                60\r
+#define STARTMUSIC             90\r
+\r
+//\r
+// Music names & indexes\r
+//\r
+typedef enum {\r
+               TOOHOT_MUS,              // 0\r
+               LASTMUSIC\r
+            } musicnames;\r
+\r
+/////////////////////////////////////////////////\r
+//\r
+// Thanks for playing with MUSE!\r
+//\r
+/////////////////////////////////////////////////\r
diff --git a/C3DADICT.OBJ b/C3DADICT.OBJ
new file mode 100644 (file)
index 0000000..c2f9fda
Binary files /dev/null and b/C3DADICT.OBJ differ
diff --git a/C3DAHEAD.OBJ b/C3DAHEAD.OBJ
new file mode 100644 (file)
index 0000000..8906d30
Binary files /dev/null and b/C3DAHEAD.OBJ differ
diff --git a/C3DEDICT.OBJ b/C3DEDICT.OBJ
new file mode 100644 (file)
index 0000000..991491a
Binary files /dev/null and b/C3DEDICT.OBJ differ
diff --git a/C3DEHEAD.OBJ b/C3DEHEAD.OBJ
new file mode 100644 (file)
index 0000000..df8c6b2
Binary files /dev/null and b/C3DEHEAD.OBJ differ
diff --git a/C3DMHEAD.OBJ b/C3DMHEAD.OBJ
new file mode 100644 (file)
index 0000000..1607914
Binary files /dev/null and b/C3DMHEAD.OBJ differ
diff --git a/C3_ACT1.C b/C3_ACT1.C
new file mode 100644 (file)
index 0000000..2706b4f
--- /dev/null
+++ b/C3_ACT1.C
@@ -0,0 +1,1259 @@
+/* Catacomb 3-D 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_PLAY.C\r
+\r
+#include "C3_DEF.H"\r
+#pragma hdrstop\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                GLOBAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+dirtype dirtable[9] = {northwest,north,northeast,west,nodir,east,\r
+       southwest,south,southeast};\r
+\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                 BONUS ITEMS\r
+\r
+=============================================================================\r
+*/\r
+\r
+extern statetype       s_boltbonus2;\r
+extern statetype       s_nukebonus2;\r
+\r
+statetype s_boltbonus = {BOLTOBJPIC,8,NULL,&s_boltbonus2};\r
+statetype s_boltbonus2 = {BOLTOBJ2PIC,8,NULL,&s_boltbonus};\r
+\r
+statetype s_nukebonus = {NUKEOBJPIC,8,NULL,&s_nukebonus2};\r
+statetype s_nukebonus2 = {NUKEOBJ2PIC,8,NULL,&s_nukebonus};\r
+\r
+statetype s_potionbonus = {POTIONOBJPIC,0,NULL,&s_potionbonus};\r
+statetype s_rkeybonus = {RKEYOBJPIC,0,NULL,&s_rkeybonus};\r
+statetype s_ykeybonus = {YKEYOBJPIC,0,NULL,&s_ykeybonus};\r
+statetype s_gkeybonus = {GKEYOBJPIC,0,NULL,&s_gkeybonus};\r
+statetype s_bkeybonus = {BKEYOBJPIC,0,NULL,&s_bkeybonus};\r
+statetype s_scrollbonus = {SCROLLOBJPIC,0,NULL,&s_scrollbonus};\r
+statetype s_chestbonus = {CHESTOBJPIC,0,NULL,&s_chestbonus};\r
+statetype s_goalbonus = {NEMESISPIC,0,NULL,&s_goalbonus};\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnBonus\r
+=\r
+===============\r
+*/\r
+\r
+void SpawnBonus (int tilex, int tiley, int number)\r
+{\r
+       statetype *state;\r
+\r
+       if (number == B_BOLT)\r
+               state = &s_boltbonus;\r
+       else if (number == B_NUKE)\r
+               state = &s_nukebonus;\r
+       else if (number == B_POTION)\r
+               state = &s_potionbonus;\r
+       else if (number == B_RKEY)\r
+               state = &s_rkeybonus;\r
+       else if (number == B_YKEY)\r
+               state = &s_ykeybonus;\r
+       else if (number == B_GKEY)\r
+               state = &s_gkeybonus;\r
+       else if (number == B_BKEY)\r
+               state = &s_bkeybonus;\r
+       else if (number >= B_SCROLL1 && number <= B_SCROLL8)\r
+               state = &s_scrollbonus;\r
+       else if (number == B_CHEST)\r
+               state = &s_chestbonus;\r
+       else if (number == B_GOAL)\r
+               state = &s_goalbonus;\r
+\r
+       SpawnNewObj (tilex,tiley,state,TILEGLOBAL/2);\r
+       new->tileobject = true;\r
+       new->temp1 = number;\r
+       new->obclass = bonusobj;\r
+       new->shootable = false;\r
+}\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                         EXPLODING WALL\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+void T_WallDie (objtype *ob);\r
+\r
+extern statetype s_walldie1;\r
+extern statetype s_walldie2;\r
+extern statetype s_walldie3;\r
+extern statetype s_walldie4;\r
+extern statetype s_walldie5;\r
+extern statetype s_walldie6;\r
+\r
+statetype s_walldie1 = {0,20,NULL,&s_walldie2};\r
+statetype s_walldie2 = {0,-1,T_WallDie,&s_walldie3};\r
+statetype s_walldie3 = {0,20,NULL,&s_walldie4};\r
+statetype s_walldie4 = {0,-1,T_WallDie,&s_walldie5};\r
+statetype s_walldie5 = {0,20,NULL,&s_walldie6};\r
+statetype s_walldie6 = {0,-1,T_WallDie,NULL};\r
+\r
+/*\r
+================\r
+=\r
+= ExplodeWall\r
+=\r
+================\r
+*/\r
+\r
+void ExplodeWall (int tilex, int tiley)\r
+{\r
+       SpawnNewObj (tilex,tiley,&s_walldie1,0);\r
+       new->obclass = inertobj;\r
+       new->active = true;\r
+       (unsigned)actorat[new->tilex][new->tiley] = tilemap[new->tilex][new->tiley] =\r
+       *(mapsegs[0]+farmapylookup[new->tiley]+new->tilex) = WALLEXP;\r
+}\r
+\r
+\r
+/*\r
+================\r
+=\r
+= T_WallDie\r
+=\r
+================\r
+*/\r
+\r
+void T_WallDie (objtype *ob)\r
+{\r
+       unsigned tile,other;\r
+\r
+       if (++ob->temp1 == 3)\r
+               tile = 0;\r
+       else\r
+               tile = WALLEXP-1 + ob->temp1;\r
+\r
+       (unsigned)actorat[ob->tilex][ob->tiley] = tilemap[ob->tilex][ob->tiley] =\r
+       *(mapsegs[0]+farmapylookup[ob->tiley]+ob->tilex) = tile;\r
+\r
+       if (ob->temp1 == 1)\r
+       {\r
+       //\r
+       // blow up nearby walls\r
+       //\r
+               other = tilemap[ob->tilex-1][ob->tiley];\r
+               if ((unsigned)(other-EXPWALLSTART)<NUMEXPWALLS)\r
+                       ExplodeWall (ob->tilex-1,ob->tiley);\r
+               other = tilemap[ob->tilex+1][ob->tiley];\r
+               if ((unsigned)(other-EXPWALLSTART)<NUMEXPWALLS)\r
+                       ExplodeWall (ob->tilex+1,ob->tiley);\r
+               other = tilemap[ob->tilex][ob->tiley-1];\r
+               if ((unsigned)(other-EXPWALLSTART)<NUMEXPWALLS)\r
+                       ExplodeWall (ob->tilex,ob->tiley-1);\r
+               other = tilemap[ob->tilex][ob->tiley+1];\r
+               if ((unsigned)(other-EXPWALLSTART)<NUMEXPWALLS)\r
+                       ExplodeWall (ob->tilex,ob->tiley+1);\r
+       }\r
+}\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                WARP GATE\r
+\r
+=============================================================================\r
+*/\r
+\r
+void T_Gate (objtype *ob);\r
+\r
+extern statetype s_gate1;\r
+extern statetype s_gate2;\r
+extern statetype s_gate3;\r
+extern statetype s_gate4;\r
+\r
+extern statetype s_fgate1;\r
+extern statetype s_fgate2;\r
+extern statetype s_fgate3;\r
+extern statetype s_fgate4;\r
+\r
+statetype s_gate1 = {WARP1PIC,12,T_Gate,&s_gate2};\r
+statetype s_gate2 = {WARP2PIC,12,T_Gate,&s_gate3};\r
+statetype s_gate3 = {WARP3PIC,12,T_Gate,&s_gate4};\r
+statetype s_gate4 = {WARP4PIC,12,T_Gate,&s_gate1};\r
+\r
+statetype s_fgate1 = {WARP1PIC,6,T_Gate,&s_fgate2};\r
+statetype s_fgate2 = {WARP2PIC,6,T_Gate,&s_fgate3};\r
+statetype s_fgate3 = {WARP3PIC,6,T_Gate,&s_fgate4};\r
+statetype s_fgate4 = {WARP4PIC,6,T_Gate,&s_fgate1};\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnWarp\r
+=\r
+===============\r
+*/\r
+\r
+void SpawnWarp (int tilex, int tiley, int type)\r
+{\r
+       if (type)\r
+               SpawnNewObj (tilex,tiley,&s_fgate1,TILEGLOBAL/3);\r
+       else\r
+               SpawnNewObj (tilex,tiley,&s_gate1,TILEGLOBAL/3);\r
+       new->obclass = gateobj;\r
+       new->temp1 = type;\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= T_Gate\r
+=\r
+===============\r
+*/\r
+\r
+#define STATUSCOLOR    4\r
+\r
+void T_Gate (objtype *ob)\r
+{\r
+       int     spot;\r
+       objtype *check;\r
+       unsigned        temp;\r
+\r
+       if (CheckHandAttack (ob) && !playstate)\r
+       {\r
+       //\r
+       // warp\r
+       //\r
+               temp = bufferofs;\r
+               bufferofs = 0;\r
+               VW_Bar (26,4,232,9,STATUSCOLOR);                // clear text description\r
+               bufferofs = temp;\r
+               IN_ClearKeysDown ();\r
+               if (ob->temp1)\r
+               {\r
+               //\r
+               // teleport inside level\r
+               //\r
+                       for (check=player->next;check;check=check->next)\r
+                               if (check->obclass==gateobj && check->temp1==ob->temp1 &&\r
+                                       check != ob)\r
+                               {\r
+                                       player->x = check->x;\r
+                                       player->y = check->y;\r
+                                       Thrust (player->angle,TILEGLOBAL/2);            // move forwards\r
+                                       Thrust (player->angle,TILEGLOBAL/2);            // move forwards\r
+                                       Thrust (player->angle,TILEGLOBAL/2);            // move forwards\r
+                                       fizzlein=true;\r
+                               }\r
+               }\r
+               else\r
+               {\r
+               //\r
+               // teleport out of level\r
+               //\r
+                       playstate = ex_warped;\r
+                       spot = *(mapsegs[0]+farmapylookup[ob->tiley]+ob->tilex)-NAMESTART;\r
+                       if (spot<1)\r
+                               gamestate.mapon++;\r
+                       else\r
+                               gamestate.mapon=spot-1;\r
+                       SD_PlaySound(WARPUPSND);\r
+               }\r
+       }\r
+}\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                  TROLLS\r
+\r
+=============================================================================\r
+*/\r
+\r
+void T_Troll (objtype *ob);\r
+\r
+extern statetype s_trollpause;\r
+\r
+extern statetype s_troll1;\r
+extern statetype s_troll2;\r
+extern statetype s_troll3;\r
+extern statetype s_troll4;\r
+\r
+extern statetype s_trollattack1;\r
+extern statetype s_trollattack2;\r
+extern statetype s_trollattack3;\r
+\r
+extern statetype s_trollouch;\r
+\r
+extern statetype s_trolldie1;\r
+extern statetype s_trolldie2;\r
+extern statetype s_trolldie3;\r
+\r
+\r
+statetype s_trollpause = {TROLL1PIC,40,NULL,&s_troll2};\r
+\r
+statetype s_troll1 = {TROLL1PIC,13,T_Troll,&s_troll2};\r
+statetype s_troll2 = {TROLL2PIC,13,T_Troll,&s_troll3};\r
+statetype s_troll3 = {TROLL3PIC,13,T_Troll,&s_troll4};\r
+statetype s_troll4 = {TROLL4PIC,13,T_Troll,&s_troll1};\r
+\r
+statetype s_trollattack1 = {TROLLATTACK1PIC,20,NULL,&s_trollattack2};\r
+statetype s_trollattack2 = {TROLLATTACK2PIC,10,T_DoDamage,&s_trollattack3};\r
+statetype s_trollattack3 = {TROLLATTACK2PIC,40,NULL,&s_trollpause};\r
+\r
+statetype s_trollouch = {TROLLOUCHPIC,8,NULL,&s_troll1};\r
+\r
+statetype s_trolldie1 = {TROLLDIE1PIC,8,NULL,&s_trolldie2};\r
+statetype s_trolldie2 = {TROLLDIE2PIC,8,NULL,&s_trolldie3};\r
+statetype s_trolldie3 = {TROLLDIE3PIC,0,NULL,&s_trolldie3};\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnTroll\r
+=\r
+===============\r
+*/\r
+\r
+void SpawnTroll (int tilex, int tiley)\r
+{\r
+       SpawnNewObj(tilex,tiley,&s_troll1,40*PIXRADIUS);\r
+       new->speed = 2500;\r
+       new->obclass = trollobj;\r
+       new->shootable = true;\r
+       new->hitpoints = 10;\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= T_Troll\r
+=\r
+===============\r
+*/\r
+\r
+void T_Troll (objtype *ob)\r
+{\r
+       if (Chase (ob,true))\r
+       {\r
+               ob->state = &s_trollattack1;\r
+               ob->ticcount = ob->state->tictime;\r
+               return;\r
+       }\r
+}\r
+\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                  ORCS\r
+\r
+=============================================================================\r
+*/\r
+\r
+void T_Orc (objtype *ob);\r
+\r
+extern statetype s_orcpause;\r
+\r
+extern statetype s_orc1;\r
+extern statetype s_orc2;\r
+extern statetype s_orc3;\r
+extern statetype s_orc4;\r
+\r
+extern statetype s_orcattack1;\r
+extern statetype s_orcattack2;\r
+extern statetype s_orcattack3;\r
+\r
+extern statetype s_orcouch;\r
+\r
+extern statetype s_orcdie1;\r
+extern statetype s_orcdie2;\r
+extern statetype s_orcdie3;\r
+\r
+\r
+\r
+statetype s_orcpause = {ORC1PIC,40,NULL,&s_orc2};\r
+\r
+statetype s_orc1 = {ORC1PIC,20,T_Orc,&s_orc2};\r
+statetype s_orc2 = {ORC2PIC,20,T_Orc,&s_orc3};\r
+statetype s_orc3 = {ORC3PIC,20,T_Orc,&s_orc4};\r
+statetype s_orc4 = {ORC4PIC,20,T_Orc,&s_orc1};\r
+\r
+statetype s_orcattack1 = {ORCATTACK1PIC,20,NULL,&s_orcattack2};\r
+statetype s_orcattack2 = {ORCATTACK2PIC,10,T_DoDamage,&s_orcattack3};\r
+statetype s_orcattack3 = {ORCATTACK2PIC,40,NULL,&s_orcpause};\r
+\r
+statetype s_orcouch = {ORCOUCHPIC,10,NULL,&s_orc1};\r
+\r
+statetype s_orcdie1 = {ORCDIE1PIC,8,NULL,&s_orcdie2};\r
+statetype s_orcdie2 = {ORCDIE2PIC,8,NULL,&s_orcdie3};\r
+statetype s_orcdie3 = {ORCDIE3PIC,0,NULL,&s_orcdie3};\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnOrc\r
+=\r
+===============\r
+*/\r
+\r
+void SpawnOrc (int tilex, int tiley)\r
+{\r
+       SpawnNewObj(tilex,tiley,&s_orc1,PIXRADIUS*32);\r
+       new->obclass = orcobj;\r
+       new->speed = 1536;\r
+       new->shootable = true;\r
+       new->hitpoints = 3;\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= T_Orc\r
+=\r
+===============\r
+*/\r
+\r
+void T_Orc (objtype *ob)\r
+{\r
+       if (Chase (ob,true))\r
+       {\r
+               ob->state = &s_orcattack1;\r
+               ob->ticcount = ob->state->tictime;\r
+               return;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                  DEMON\r
+\r
+=============================================================================\r
+*/\r
+\r
+void T_Demon (objtype *ob);\r
+\r
+\r
+extern statetype s_demonpause;\r
+\r
+extern statetype s_demon1;\r
+extern statetype s_demon2;\r
+extern statetype s_demon3;\r
+extern statetype s_demon4;\r
+\r
+extern statetype s_demonattack1;\r
+extern statetype s_demonattack2;\r
+extern statetype s_demonattack3;\r
+\r
+extern statetype s_demonouch;\r
+\r
+extern statetype s_demondie1;\r
+extern statetype s_demondie2;\r
+extern statetype s_demondie3;\r
+\r
+\r
+statetype s_demonpause = {DEMON1PIC,40,NULL,&s_demon2};\r
+\r
+statetype s_demon1 = {DEMON1PIC,20,T_Demon,&s_demon2};\r
+statetype s_demon2 = {DEMON2PIC,20,T_Demon,&s_demon3};\r
+statetype s_demon3 = {DEMON3PIC,20,T_Demon,&s_demon4};\r
+statetype s_demon4 = {DEMON4PIC,20,T_Demon,&s_demon1};\r
+\r
+statetype s_demonattack1 = {DEMONATTACK1PIC,20,NULL,&s_demonattack2};\r
+statetype s_demonattack2 = {DEMONATTACK2PIC,20,T_DoDamage,&s_demonattack3};\r
+statetype s_demonattack3 = {DEMONATTACK3PIC,30,NULL,&s_demonpause};\r
+\r
+statetype s_demonouch = {DEMONOUCHPIC,10,NULL,&s_demon1};\r
+\r
+statetype s_demondie1 = {DEMONDIE1PIC,20,NULL,&s_demondie2};\r
+statetype s_demondie2 = {DEMONDIE2PIC,20,NULL,&s_demondie3};\r
+statetype s_demondie3 = {DEMONDIE3PIC,0,NULL,&s_demondie3};\r
+\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnDemon\r
+=\r
+===============\r
+*/\r
+\r
+void SpawnDemon (int tilex, int tiley)\r
+{\r
+       SpawnNewObj(tilex,tiley,&s_demon1,TILEGLOBAL/2);\r
+       new->obclass = demonobj;\r
+       new->speed = 2048;\r
+       new->shootable = true;\r
+       new->hitpoints = 50;\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= T_Demon\r
+=\r
+===============\r
+*/\r
+\r
+void T_Demon (objtype *ob)\r
+{\r
+       if (Chase (ob,true))\r
+       {\r
+               ob->state = &s_demonattack1;\r
+               ob->ticcount = ob->state->tictime;\r
+               return;\r
+       }\r
+}\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                       MSHOTS\r
+\r
+temp1 = dir\r
+\r
+=============================================================================\r
+*/\r
+\r
+#define MSHOTDAMAGE    2\r
+#define MSHOTSPEED     10000\r
+\r
+void T_Mshot (objtype *ob);\r
+\r
+\r
+extern statetype s_mshot1;\r
+extern statetype s_mshot2;\r
+\r
+statetype s_mshot1 = {PSHOT1PIC,8,&T_Mshot,&s_mshot2};\r
+statetype s_mshot2 = {PSHOT2PIC,8,&T_Mshot,&s_mshot1};\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= T_Mshot\r
+=\r
+===============\r
+*/\r
+\r
+void T_Mshot (objtype *ob)\r
+{\r
+       objtype *check;\r
+       long    xmove,ymove,speed;\r
+\r
+       xmove = ymove = 0;\r
+\r
+       switch (ob->dir)\r
+       {\r
+       case north:\r
+               ymove = -ob->speed*tics;\r
+               break;\r
+       case east:\r
+               xmove = ob->speed*tics;\r
+               break;\r
+       case south:\r
+               ymove = ob->speed*tics;\r
+               break;\r
+       case west:\r
+               xmove = -ob->speed*tics;\r
+               break;\r
+       }\r
+\r
+       ob->x+=xmove;\r
+       ob->y+=ymove;\r
+\r
+       CalcBounds (ob);\r
+\r
+       ob->tilex = ob->x>>TILESHIFT;\r
+       ob->tiley = ob->y>>TILESHIFT;\r
+\r
+       if (tilemap[ob->tilex][ob->tiley])\r
+       {\r
+               SD_PlaySound (SHOOTWALLSND);\r
+               ob->state = NULL;\r
+               return;\r
+       }\r
+\r
+//\r
+// check final position for monsters hit\r
+//\r
+       if ( ob->xl <= player->xh\r
+       && ob->xh >= player->xl\r
+       && ob->yl <= player->yh\r
+       && ob->yh >= player->yl)\r
+       {\r
+               TakeDamage (MSHOTDAMAGE*2);\r
+               ob->state = NULL;\r
+               return;\r
+       }\r
+\r
+       for (check = player->next; check; check=check->next)\r
+               if (ob->shootable && ob->obclass != mageobj\r
+               && ob->xl <= check->xh\r
+               && ob->xh >= check->xl\r
+               && ob->yl <= check->yh\r
+               && ob->yh >= check->yl)\r
+               {\r
+                       ShootActor (check,MSHOTDAMAGE);\r
+                       ob->state = NULL;\r
+                       return;\r
+               }\r
+}\r
+\r
+\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                       MAGE\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+void T_Mage (objtype *ob);\r
+void T_MageShoot (objtype *ob);\r
+\r
+extern statetype s_magepause;\r
+\r
+extern statetype s_mage1;\r
+extern statetype s_mage2;\r
+\r
+extern statetype s_mageattack1;\r
+extern statetype s_mageattack2;\r
+extern statetype s_mageattack3;\r
+\r
+extern statetype s_mageouch;\r
+\r
+extern statetype s_magedie1;\r
+extern statetype s_magedie2;\r
+\r
+\r
+statetype s_magepause = {MAGE1PIC,100,NULL,&s_mage2};\r
+\r
+statetype s_mage1 = {MAGE1PIC,20,T_Mage,&s_mage2};\r
+statetype s_mage2 = {MAGE2PIC,20,T_Mage,&s_mage1};\r
+\r
+statetype s_mageattack1 = {MAGEATTACKPIC,20,NULL,&s_mageattack2};\r
+statetype s_mageattack2 = {MAGEATTACKPIC,-1,T_MageShoot,&s_mageattack3};\r
+statetype s_mageattack3 = {MAGEATTACKPIC,30,NULL,&s_magepause};\r
+\r
+statetype s_mageouch = {MAGEOUCHPIC,10,NULL,&s_mage1};\r
+\r
+statetype s_magedie1 = {MAGEDIE1PIC,20,NULL,&s_magedie2};\r
+statetype s_magedie2 = {MAGEDIE2PIC,0,NULL,&s_magedie2};\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnMage\r
+=\r
+===============\r
+*/\r
+\r
+void SpawnMage (int tilex, int tiley)\r
+{\r
+       SpawnNewObj(tilex,tiley,&s_mage1,TILEGLOBAL/2);\r
+       new->obclass = mageobj;\r
+       new->speed = 2048;\r
+       new->shootable = true;\r
+       new->hitpoints = 5;\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= T_Mage\r
+=\r
+===============\r
+*/\r
+\r
+void T_Mage (objtype *ob)\r
+{\r
+       Chase (ob,false);\r
+//\r
+// check for line up with player\r
+//\r
+\r
+       if (ob->x-PIXRADIUS*14 < player->xh\r
+       && ob->x+PIXRADIUS > player->xl)\r
+       {\r
+               ob->temp1 = 1;\r
+               ob->state = &s_mageattack1;\r
+       }\r
+       else if (ob->y-PIXRADIUS*14 < player->yh\r
+       && ob->y+PIXRADIUS > player->yl)\r
+       {\r
+               ob->temp1 = 0;\r
+               ob->state = &s_mageattack1;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= T_MageShoot\r
+=\r
+===============\r
+*/\r
+\r
+void T_MageShoot (objtype *ob)\r
+{\r
+       SpawnNewObjFrac (ob->x,ob->y,&s_mshot1,PIXRADIUS*14);\r
+       new->obclass = mshotobj;\r
+       new->speed = MSHOTSPEED;\r
+       if (ob->temp1)\r
+       {\r
+               if (ob->tiley < player->tiley)\r
+                       new->dir = south;\r
+               else\r
+                       new->dir = north;\r
+       }\r
+       else\r
+       {\r
+               if (ob->tilex < player->tilex)\r
+                       new->dir = east;\r
+               else\r
+                       new->dir = west;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                       nemesis\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+void T_Nemesis (objtype *ob);\r
+void T_NemesisShoot (objtype *ob);\r
+\r
+extern statetype s_grelpause;\r
+\r
+extern statetype s_grel1;\r
+extern statetype s_grel2;\r
+\r
+extern statetype s_grelattack1;\r
+extern statetype s_grelattack2;\r
+extern statetype s_grelattack3;\r
+\r
+extern statetype s_grelouch;\r
+\r
+extern statetype s_greldie1;\r
+extern statetype s_greldie2;\r
+extern statetype s_greldie3;\r
+extern statetype s_greldie4;\r
+extern statetype s_greldie5;\r
+extern statetype s_greldie6;\r
+\r
+\r
+statetype s_grelpause = {GREL1PIC,50,NULL,&s_grel2};\r
+\r
+statetype s_grel1 = {GREL1PIC,20,T_Nemesis,&s_grel2};\r
+statetype s_grel2 = {GREL2PIC,20,T_Nemesis,&s_grel1};\r
+\r
+statetype s_grelattack1 = {GRELATTACKPIC,20,NULL,&s_grelattack2};\r
+statetype s_grelattack2 = {GRELATTACKPIC,-1,T_NemesisShoot,&s_grelattack3};\r
+statetype s_grelattack3 = {GRELATTACKPIC,30,NULL,&s_grelpause};\r
+\r
+statetype s_grelouch = {GRELHITPIC,6,NULL,&s_grel1};\r
+\r
+statetype s_greldie1 = {GRELDIE1PIC,20,NULL,&s_greldie2};\r
+statetype s_greldie2 = {GRELDIE2PIC,20,NULL,&s_greldie3};\r
+statetype s_greldie3 = {GRELDIE3PIC,20,NULL,&s_greldie4};\r
+statetype s_greldie4 = {GRELDIE4PIC,20,NULL,&s_greldie5};\r
+statetype s_greldie5 = {GRELDIE5PIC,20,NULL,&s_greldie6};\r
+statetype s_greldie6 = {GRELDIE6PIC,0,NULL,&s_greldie6};\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnNemesis\r
+=\r
+===============\r
+*/\r
+\r
+void SpawnNemesis (int tilex, int tiley)\r
+{\r
+       SpawnNewObj(tilex,tiley,&s_grel1,PIXRADIUS*56);\r
+       new->obclass = grelmobj;\r
+       new->speed = 2048;\r
+       new->shootable = true;\r
+       new->hitpoints = 100;\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= T_Nemesis\r
+=\r
+===============\r
+*/\r
+\r
+void T_Nemesis (objtype *ob)\r
+{\r
+       Chase (ob,false);\r
+//\r
+// check for line up with player\r
+//\r
+       if (ob->tilex == player->tilex)\r
+       {\r
+               ob->temp1 = 1;\r
+               ob->state = &s_grelattack1;\r
+       }\r
+       else if (ob->tiley == player->tiley)\r
+       {\r
+               ob->temp1 = 0;\r
+               ob->state = &s_grelattack1;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= T_NemesisShoot\r
+=\r
+===============\r
+*/\r
+\r
+void T_NemesisShoot (objtype *ob)\r
+{\r
+       SpawnNewObjFrac (ob->x,ob->y,&s_mshot1,PIXRADIUS*14);\r
+       new->obclass = mshotobj;\r
+       new->speed = MSHOTSPEED;\r
+       if (ob->temp1)\r
+       {\r
+               if (ob->tiley < player->tiley)\r
+                       new->dir = south;\r
+               else\r
+                       new->dir = north;\r
+       }\r
+       else\r
+       {\r
+               if (ob->tilex < player->tilex)\r
+                       new->dir = east;\r
+               else\r
+                       new->dir = west;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                  BAT\r
+\r
+=============================================================================\r
+*/\r
+\r
+void T_Bat (objtype *ob);\r
+void T_BatPast (objtype *ob);\r
+\r
+extern statetype s_bat1;\r
+extern statetype s_bat2;\r
+extern statetype s_bat3;\r
+extern statetype s_bat4;\r
+\r
+extern statetype s_batdie1;\r
+extern statetype s_batdie2;\r
+\r
+\r
+statetype s_bat1 = {BAT1PIC,6,T_Bat,&s_bat2};\r
+statetype s_bat2 = {BAT2PIC,6,T_Bat,&s_bat3};\r
+statetype s_bat3 = {BAT3PIC,6,T_Bat,&s_bat4};\r
+statetype s_bat4 = {BAT4PIC,6,T_Bat,&s_bat1};\r
+\r
+statetype s_batpast = {BAT4PIC,80,T_BatPast,&s_bat1};\r
+\r
+statetype s_batdie1 = {BATDIE1PIC,8,NULL,&s_batdie2};\r
+statetype s_batdie2 = {BATDIE2PIC,8,NULL,NULL};\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnBat\r
+=\r
+===============\r
+*/\r
+\r
+void SpawnBat (int tilex, int tiley)\r
+{\r
+       SpawnNewObj(tilex,tiley,&s_bat1,PIXRADIUS*24);\r
+       new->obclass =batobj;\r
+       new->shootable = true;\r
+\r
+       new->hitpoints = 1;\r
+       new->speed = 2000;\r
+}\r
+\r
+\r
+/*\r
+==================================\r
+=\r
+= BatChaseThink\r
+=\r
+==================================\r
+*/\r
+\r
+void BatChaseThink (objtype *obj)\r
+{\r
+       int deltax,deltay;\r
+\r
+       deltax=player->tilex - obj->tilex;\r
+       deltay=player->tiley - obj->tiley;\r
+\r
+       if (deltax>0)\r
+               deltax = 2;\r
+       else if (deltax<0)\r
+               deltax = 0;\r
+       else deltax = 1;\r
+\r
+       if (deltay>0)\r
+               deltay = 2;\r
+       else if (deltay<0)\r
+               deltay = 0;\r
+       else deltay = 1;\r
+\r
+       obj->dir = dirtable[deltay*3+deltax];\r
+       if (Walk(obj))\r
+               return;\r
+\r
+       obj->dir = dirtable[3+deltax];\r
+       if (Walk(obj))\r
+               return;\r
+\r
+       obj->dir = dirtable[deltay*3+1];\r
+       if (Walk(obj))\r
+               return;\r
+\r
+       obj->dir = nodir;\r
+}\r
+\r
+\r
+void BatRunThink (objtype *obj)\r
+{\r
+       int deltax,deltay;\r
+\r
+       deltax=player->tilex - obj->tilex;\r
+       deltay=player->tiley - obj->tiley;\r
+\r
+       if (deltax>=0)\r
+               deltax = 0;\r
+       else\r
+               deltax = 2;\r
+\r
+       if (deltay>=0)\r
+               deltay = 0;\r
+       else\r
+               deltay = 2;\r
+\r
+       obj->dir = dirtable[deltay*3+deltax];\r
+       if (Walk(obj))\r
+               return;\r
+\r
+       obj->dir = dirtable[3+deltax];\r
+       if (Walk(obj))\r
+               return;\r
+\r
+       obj->dir = dirtable[deltay*3+1];\r
+       Walk(obj);\r
+}\r
+\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= T_Bat\r
+=\r
+===============\r
+*/\r
+\r
+void T_Bat (objtype *ob)\r
+{\r
+       long move;\r
+       long deltax,deltay,size;\r
+\r
+       move = ob->speed*tics;\r
+       size = (long)ob->size + player->size + move;\r
+\r
+\r
+       do\r
+       {\r
+               deltax = ob->x - player->x;\r
+               deltay = ob->y - player->y;\r
+\r
+               if (deltax <= size && deltax >= -size\r
+               && deltay <= size && deltay >= -size && !ob->temp1)\r
+               {\r
+                       TakeDamage (4);\r
+                       ob->temp1 = 2;\r
+               }\r
+\r
+               if (move < ob->distance)\r
+               {\r
+                       MoveObj (ob,move);\r
+                       break;\r
+               }\r
+\r
+               actorat[ob->tilex][ob->tiley] = 0;      // pick up marker from goal\r
+               if (ob->dir == nodir)\r
+                       ob->dir = north;\r
+\r
+               ob->x = ((long)ob->tilex<<TILESHIFT)+TILEGLOBAL/2;\r
+               ob->y = ((long)ob->tiley<<TILESHIFT)+TILEGLOBAL/2;\r
+               move -= ob->distance;\r
+\r
+               if (ob->temp1)\r
+               {\r
+                       Walk (ob);                              // go straight\r
+                       if (!--ob->temp1)\r
+                       {\r
+                               ob->state = &s_batpast;\r
+                               ob->ticcount = ob->state->tictime;\r
+                       }\r
+               }\r
+               else\r
+                       BatChaseThink (ob);             // head towards player\r
+\r
+               actorat[ob->tilex][ob->tiley] = ob;     // set down a new goal marker\r
+       } while (0);    // just once\r
+       CalcBounds (ob);\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= T_BatPast\r
+=\r
+===============\r
+*/\r
+\r
+void T_BatPast (objtype *ob)\r
+{\r
+       long move;\r
+       long deltax,deltay,size;\r
+\r
+       move = ob->speed*tics;\r
+\r
+       do\r
+       {\r
+               if (move < ob->distance)\r
+               {\r
+                       MoveObj (ob,move);\r
+                       break;\r
+               }\r
+               actorat[ob->tilex][ob->tiley] = 0;      // pick up marker from goal\r
+\r
+               ob->x = ((long)ob->tilex<<TILESHIFT)+TILEGLOBAL/2;\r
+               ob->y = ((long)ob->tiley<<TILESHIFT)+TILEGLOBAL/2;\r
+               move -= ob->distance;\r
+\r
+               BatRunThink (ob);\r
+\r
+               actorat[ob->tilex][ob->tiley] = ob;     // set down a new goal marker\r
+       } while (0);    //(move)\r
+       CalcBounds (ob);\r
+}\r
+\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                  BOUNCE\r
+\r
+temp2 = set when hit player, reset when hit wall\r
+\r
+=============================================================================\r
+*/\r
+\r
+#define SPDBOUNCE      4096\r
+#define DMGBOUNCE      10\r
+\r
+void T_Bounce (objtype *ob);\r
+\r
+extern statetype s_bounce1;\r
+extern statetype s_bounce2;\r
+\r
+\r
+statetype s_bounce1 = {BIGPSHOT1PIC,8,T_Bounce,&s_bounce2};\r
+statetype s_bounce2 = {BIGPSHOT2PIC,8,T_Bounce,&s_bounce1};\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnBounce\r
+=\r
+===============\r
+*/\r
+\r
+void SpawnBounce (int tilex, int tiley, boolean towest)\r
+{\r
+       SpawnNewObj(tilex,tiley,&s_bounce1,24*PIXRADIUS);\r
+       new->obclass = bounceobj;\r
+       if (towest)\r
+               new->dir = west;\r
+       else\r
+               new->dir = north;\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= T_Bounce\r
+=\r
+===============\r
+*/\r
+\r
+void T_Bounce (objtype *ob)\r
+{\r
+       long move;\r
+       long deltax,deltay,size;\r
+\r
+       move = SPDBOUNCE*tics;\r
+       size = (long)ob->size + player->size + move;\r
+\r
+       while (move)\r
+       {\r
+               deltax = ob->x - player->x;\r
+               deltay = ob->y - player->y;\r
+\r
+               if (deltax <= size && deltax >= -size\r
+               && deltay <= size && deltay >= -size && !ob->temp2)\r
+               {\r
+                       ob->temp2 = 1;\r
+                       TakeDamage (DMGBOUNCE);\r
+               }\r
+\r
+               if (move < ob->distance)\r
+               {\r
+                       MoveObj (ob,move);\r
+                       break;\r
+               }\r
+               actorat[ob->tilex][ob->tiley] = 0;      // pick up marker from goal\r
+\r
+               ob->x = ((long)ob->tilex<<TILESHIFT)+TILEGLOBAL/2;\r
+               ob->y = ((long)ob->tiley<<TILESHIFT)+TILEGLOBAL/2;\r
+               move -= ob->distance;\r
+\r
+               //\r
+               // bounce if hit wall\r
+               //\r
+               switch (ob->dir)\r
+               {\r
+               case north:\r
+                       if (tilemap[ob->tilex][--ob->tiley])\r
+                       {\r
+                               ob->dir = south;\r
+                               ob->tiley+=2;\r
+                               ob->temp2 = 0;\r
+                       }\r
+                       break;\r
+               case east:\r
+                       if (tilemap[++ob->tilex][ob->tiley])\r
+                       {\r
+                               ob->dir = west;\r
+                               ob->tilex-=2;\r
+                               ob->temp2 = 0;\r
+                       }\r
+                       break;\r
+               case south:\r
+                       if (tilemap[ob->tilex][++ob->tiley])\r
+                       {\r
+                               ob->dir = north;\r
+                               ob->tiley-=2;\r
+                               ob->temp2 = 0;\r
+                       }\r
+                       break;\r
+               case west:\r
+                       if (tilemap[--ob->tilex][ob->tiley])\r
+                       {\r
+                               ob->dir = east;\r
+                               ob->tilex+=2;\r
+                               ob->temp2 = 0;\r
+                       }\r
+                       break;\r
+               }\r
+\r
+               ob->distance = TILEGLOBAL;\r
+\r
+               actorat[ob->tilex][ob->tiley] = ob;     // set down a new goal marker\r
+       }\r
+       CalcBounds (ob);\r
+}\r
+\r
diff --git a/C3_ASM.ASM b/C3_ASM.ASM
new file mode 100644 (file)
index 0000000..d9da6eb
--- /dev/null
@@ -0,0 +1,197 @@
+; Catacomb 3-D 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
+IDEAL\r
+\r
+MODEL  MEDIUM,C\r
+\r
+VIEWWIDTH      =       (33*8)\r
+GC_INDEX       =       03CEh\r
+\r
+DATASEG\r
+EVEN\r
+\r
+;=================== Tables filled in by DrawVWall ==========================\r
+\r
+;\r
+; wallheight has the height (scale number) of that collumn of scaled wall\r
+; it is pre bounded to 1-MAXSCALE (the actuial height on screen is 2*height)\r
+;\r
+wallheight     dw      VIEWWIDTH dup (?)\r
+\r
+;\r
+; wallwidth has the pixel width (1-7) of that collumn\r
+;\r
+wallwidth      dw      VIEWWIDTH dup (?)\r
+\r
+;\r
+; wallseg has the segment of the wall picture\r
+;\r
+wallseg                dw      VIEWWIDTH dup (?)\r
+\r
+;\r
+; wallofs has the offset of the wall picture\r
+;\r
+wallofs                dw      VIEWWIDTH dup (?)\r
+\r
+;============================================================================\r
+\r
+;\r
+; screenbyte is just position/8\r
+;\r
+LABEL          screenbyte      WORD\r
+pos    =       0\r
+REPT           VIEWWIDTH\r
+                       dw      pos/8\r
+pos    =       pos+1\r
+ENDM\r
+\r
+;\r
+; screenbit is (position&7)*16\r
+;\r
+LABEL          screenbit       WORD\r
+pos    =       0\r
+REPT           VIEWWIDTH\r
+                       dw      (pos AND 7)*16\r
+pos    =       pos+1\r
+ENDM\r
+\r
+;\r
+; Use offset: screenbit[]+pixwidth*2\r
+; acess from bitmasks-2+offset for one biased pixwidth\r
+; the low byte of bitmasks is for the first screen byte, the high byte\r
+; is the bitmask for the second screen byte (if non 0)\r
+;\r
+\r
+bitmasks       dw      0080h,00c0h,00e0h,00f0h,00f8h,00fch,00feh,00ffh\r
+                       dw      0040h,0060h,0070h,0078h,007ch,007eh,007fh,807fh\r
+                       dw      0020h,0030h,0038h,003ch,003eh,003fh,803fh,0c03fh\r
+                       dw      0010h,0018h,001ch,001eh,001fh,801fh,0c01fh,0e01fh\r
+                       dw      0008h,000ch,000eh,000fh,800fh,0c00fh,0e00fh,0f00fh\r
+                       dw      0004h,0006h,0007h,8007h,0c007h,0e007h,0f007h,0f807h\r
+                       dw      0002h,0003h,8003h,0c003h,0e003h,0f003h,0f803h,0fc03h\r
+                       dw      0001h,8001h,0c001h,0e001h,0f001h,0f801h,0fc01h,0fe01h\r
+\r
+\r
+;\r
+; wallscalecall is a far pointer to the start of a compiled scaler\r
+; The low word will never change, while the high word is set to\r
+; compscaledirectory[scale]\r
+;\r
+wallscalecall  dd      (65*6)                  ; offset of t_compscale->code[0]\r
+\r
+\r
+PUBLIC wallheight,wallwidth,wallseg,wallofs,screenbyte,screenbit\r
+PUBLIC bitmasks,wallscalecall\r
+\r
+\r
+EXTRN  scaledirectory:WORD                     ; array of MAXSCALE segment pointers to\r
+                                                                       ; compiled scalers\r
+EXTRN  screenseg:WORD                          ; basically just 0xa000\r
+EXTRN  bufferofs:WORD                          ; offset of the current work screen\r
+\r
+CODESEG\r
+\r
+;============================================================================\r
+;\r
+; ScaleWalls\r
+;\r
+; AX   AL is scratched in bit mask setting and scaling\r
+; BX   table index\r
+; CX   pixwidth*2\r
+; DX   GC_INDEX\r
+; SI   offset into wall data to scale from, allways 0,64,128,...4032\r
+; DI    byte at top of screen that the collumn is contained in\r
+; BP   x pixel * 2, index into VIEWWIDTH wide tables\r
+; DS   segment of the wall data to texture map\r
+; ES   screenseg\r
+; SS   addressing DGROUP variables\r
+;\r
+;============================================================================\r
+\r
+PROC   ScaleWalls\r
+PUBLIC ScaleWalls\r
+USES   SI,DI,BP\r
+\r
+       xor     bp,bp                                           ; start at location 0 in the tables\r
+       mov     dx,GC_INDEX+1\r
+       mov     es,[screenseg]\r
+\r
+;\r
+; scale one collumn of data, possibly across two bytes\r
+;\r
+nextcollumn:\r
+\r
+       mov     bx,[wallheight+bp]                      ; height of walls (1-MAXSCALE)\r
+       shl     bx,1\r
+       mov     ax,[ss:scaledirectory+bx]       ; segment of the compiled scaler\r
+       mov [WORD PTR ss:wallscalecall+2],ax\r
+\r
+       mov     cx,[wallwidth+bp]\r
+       or      cx,cx\r
+       jnz     okwidth\r
+       mov     cx,2\r
+       jmp     next\r
+\r
+okwidth:\r
+       shl     cx,1\r
+       mov     ds,[wallseg+bp]\r
+       mov     si,[wallofs+bp]\r
+\r
+       mov     di,[screenbyte+bp]                      ; byte at the top of the scaled collumn\r
+       add     di,[ss:bufferofs]                       ; offset of current page flip\r
+       mov     bx,[screenbit+bp]                       ; 0-7 << 4\r
+       add     bx,cx\r
+       mov     ax,[ss:bitmasks-2+bx]\r
+       out     dx,al                                           ; set bit mask register\r
+       call [DWORD PTR ss:wallscalecall]               ; scale the line of pixels\r
+       or      ah,ah                                           ; is there anything in the second byte?\r
+       jnz     secondbyte\r
+;\r
+; next\r
+;\r
+next:\r
+       add     bp,cx\r
+       cmp     bp,VIEWWIDTH*2\r
+       jb      nextcollumn\r
+       jmp     done\r
+\r
+;\r
+; draw a second byte for vertical strips that cross two bytes\r
+;\r
+secondbyte:\r
+       mov     al,ah\r
+       inc     di                                                              ; next byte over\r
+       out     dx,al                                                   ; set bit mask register\r
+       call [DWORD PTR ss:wallscalecall]       ; scale the line of pixels\r
+;\r
+; next\r
+;\r
+       add     bp,cx\r
+       cmp     bp,VIEWWIDTH*2\r
+       jb      nextcollumn\r
+\r
+done:\r
+       mov     ax,ss\r
+       mov     ds,ax\r
+       ret\r
+\r
+ENDP\r
+\r
+\r
+END\r
+\r
diff --git a/C3_DEBUG.C b/C3_DEBUG.C
new file mode 100644 (file)
index 0000000..4aa6831
--- /dev/null
@@ -0,0 +1,606 @@
+/* Catacomb 3-D 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_DEBUG.C\r
+\r
+#include "C3_DEF.H"\r
+#pragma hdrstop\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+#define VIEWTILEX      20\r
+#define VIEWTILEY      (VIEWHEIGHT/16)\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                GLOBAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+int    maporgx;\r
+int    maporgy;\r
+enum {mapview,tilemapview,actoratview,visview} viewtype;\r
+\r
+void ViewMap (void);\r
+\r
+//===========================================================================\r
+\r
+\r
+\r
+/*\r
+==================\r
+=\r
+= DebugMemory\r
+=\r
+==================\r
+*/\r
+\r
+void DebugMemory (void)\r
+{\r
+       int     i;\r
+       char    scratch[80],str[10];\r
+       long    mem;\r
+       spritetype _seg *block;\r
+\r
+       VW_FixRefreshBuffer ();\r
+       US_CenterWindow (16,7);\r
+\r
+#if 0\r
+       CA_OpenDebug ();\r
+       for (i=0;i<NUMCHUNKS;i++)\r
+       {\r
+               if (grsegs[i])\r
+               {\r
+                       strcpy (scratch,"Chunk:");\r
+                       itoa (i,str,10);\r
+                       strcat (scratch,str);\r
+                       strcat (scratch,"\n");\r
+                       write (debughandle,scratch,strlen(scratch));\r
+               }\r
+       }\r
+       CA_CloseDebug ();\r
+#endif\r
+\r
+       US_CPrint ("Memory Usage");\r
+       US_CPrint ("------------");\r
+       US_Print ("Total     :");\r
+       US_PrintUnsigned (mminfo.mainmem/1024);\r
+       US_Print ("k\nFree      :");\r
+       US_PrintUnsigned (MM_UnusedMemory()/1024);\r
+       US_Print ("k\nWith purge:");\r
+       US_PrintUnsigned (MM_TotalFree()/1024);\r
+       US_Print ("k\n");\r
+       VW_UpdateScreen();\r
+       IN_Ack ();\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+================\r
+=\r
+= PicturePause\r
+=\r
+================\r
+*/\r
+\r
+void PicturePause (void)\r
+{\r
+       int     y;\r
+       unsigned        source;\r
+\r
+       source = displayofs+panadjust;\r
+\r
+       VW_ColorBorder (15);\r
+       VW_SetLineWidth (40);\r
+       VW_SetScreen (0,0);\r
+\r
+       if (source<0x10000l-200*64)\r
+       {\r
+       //\r
+       // copy top line first\r
+       //\r
+               for (y=0;y<200;y++)\r
+                       VW_ScreenToScreen (source+y*64,y*40,40,1);\r
+       }\r
+       else\r
+       {\r
+       //\r
+       // copy bottom line first\r
+       //\r
+               for (y=199;y>=0;y--)\r
+                       VW_ScreenToScreen (source+y*64,y*40,40,1);\r
+       }\r
+\r
+       IN_Shutdown ();\r
+\r
+       VW_WaitVBL(70);\r
+       bioskey(0);\r
+       VW_WaitVBL(70);\r
+       Quit (NULL);\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+================\r
+=\r
+= ShapeTest\r
+=\r
+================\r
+*/\r
+\r
+void ShapeTest (void)\r
+{\r
+\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+#define        sc_1                    0x02\r
+#define        sc_2                    0x03\r
+#define        sc_3                    0x04\r
+#define        sc_4                    0x05\r
+#define        sc_5                    0x06\r
+#define        sc_6                    0x07\r
+#define        sc_7                    0x08\r
+#define        sc_8                    0x09\r
+#define        sc_9                    0x0a\r
+#define        sc_0                    0x0b\r
+\r
+\r
+\r
+/*\r
+================\r
+=\r
+= DebugKeys\r
+=\r
+================\r
+*/\r
+\r
+int DebugKeys (void)\r
+{\r
+       boolean esc;\r
+       int level,i;\r
+\r
+       if (Keyboard[sc_B])             // B = border color\r
+       {\r
+               CenterWindow(24,3);\r
+               PrintY+=6;\r
+               US_Print(" Border color (0-15):");\r
+               VW_UpdateScreen();\r
+               esc = !US_LineInput (px,py,str,NULL,true,2,0);\r
+               if (!esc)\r
+               {\r
+                       level = atoi (str);\r
+                       if (level>=0 && level<=15)\r
+                               VW_ColorBorder (level);\r
+               }\r
+               return 1;\r
+       }\r
+\r
+#if 0\r
+\r
+       if (Keyboard[sc_C])             // C = count objects\r
+       {\r
+               CountObjects();\r
+               return 1;\r
+       }\r
+\r
+\r
+       if (Keyboard[sc_D])             // D = start / end demo record\r
+       {\r
+               if (DemoMode == demo_Off)\r
+                       StartDemoRecord ();\r
+               else if (DemoMode == demo_Record)\r
+               {\r
+                       EndDemoRecord ();\r
+                       playstate = ex_completed;\r
+               }\r
+               return 1;\r
+       }\r
+\r
+#endif\r
+\r
+       if (Keyboard[sc_E])             // E = quit level\r
+       {\r
+               if (tedlevel)\r
+                       TEDDeath();\r
+               playstate = ex_warped;\r
+               gamestate.mapon++;\r
+       }\r
+\r
+       if (Keyboard[sc_F])             // F = facing spot\r
+       {\r
+               CenterWindow (12,4);\r
+               US_Print ("X:");\r
+               US_PrintUnsigned (player->x);\r
+               US_Print ("Y:");\r
+               US_PrintUnsigned (player->y);\r
+               US_Print ("A:");\r
+               US_PrintUnsigned (player->angle);\r
+               VW_UpdateScreen();\r
+               IN_Ack();\r
+               return 1;\r
+       }\r
+\r
+       if (Keyboard[sc_G])             // G = god mode\r
+       {\r
+               CenterWindow (12,2);\r
+               if (godmode)\r
+                 US_PrintCentered ("God mode OFF");\r
+               else\r
+                 US_PrintCentered ("God mode ON");\r
+               VW_UpdateScreen();\r
+               IN_Ack();\r
+               godmode ^= 1;\r
+               return 1;\r
+       }\r
+       if (Keyboard[sc_H])             // H = hurt self\r
+       {\r
+               TakeDamage (5);\r
+       }\r
+       else if (Keyboard[sc_I])                        // I = item cheat\r
+       {\r
+               CenterWindow (12,3);\r
+               US_PrintCentered ("Free items!");\r
+               VW_UpdateScreen();\r
+               for (i=0;i<4;i++)\r
+               {\r
+                       GiveBolt ();\r
+                       GiveNuke ();\r
+                       GivePotion ();\r
+                       if (!gamestate.keys[i])\r
+                               GiveKey (i);\r
+               }\r
+               for (i=0;i<8;i++)\r
+                       GiveScroll (i,false);\r
+\r
+               IN_Ack ();\r
+               return 1;\r
+       }\r
+       else if (Keyboard[sc_M])                        // M = memory info\r
+       {\r
+               DebugMemory();\r
+               return 1;\r
+       }\r
+       else if (Keyboard[sc_O])                        // O = overhead\r
+       {\r
+               ViewMap();\r
+               return 1;\r
+       }\r
+       else if (Keyboard[sc_P])                        // P = pause with no screen disruptioon\r
+       {\r
+               PicturePause ();\r
+               return 1;\r
+       }\r
+       else if (Keyboard[sc_S])        // S = slow motion\r
+       {\r
+               singlestep^=1;\r
+               CenterWindow (18,3);\r
+               if (singlestep)\r
+                       US_PrintCentered ("Slow motion ON");\r
+               else\r
+                       US_PrintCentered ("Slow motion OFF");\r
+               VW_UpdateScreen();\r
+               IN_Ack ();\r
+               return 1;\r
+       }\r
+       else if (Keyboard[sc_S])        // T = shape test\r
+       {\r
+               ShapeTest ();\r
+               return 1;\r
+       }\r
+       else if (Keyboard[sc_V])                        // V = extra VBLs\r
+       {\r
+               CenterWindow(30,3);\r
+               PrintY+=6;\r
+               US_Print("  Add how many extra VBLs(0-8):");\r
+               VW_UpdateScreen();\r
+               esc = !US_LineInput (px,py,str,NULL,true,2,0);\r
+               if (!esc)\r
+               {\r
+                       level = atoi (str);\r
+                       if (level>=0 && level<=8)\r
+                               extravbls = level;\r
+               }\r
+               return 1;\r
+       }\r
+       else if (Keyboard[sc_W])        // W = warp to level\r
+       {\r
+               CenterWindow(26,3);\r
+               PrintY+=6;\r
+               US_Print("  Warp to which level(1-21):");\r
+               VW_UpdateScreen();\r
+               esc = !US_LineInput (px,py,str,NULL,true,2,0);\r
+               if (!esc)\r
+               {\r
+                       level = atoi (str);\r
+                       if (level>0 && level<21)\r
+                       {\r
+                               gamestate.mapon = level-1;\r
+                               playstate = ex_warped;\r
+                       }\r
+               }\r
+               return 1;\r
+       }\r
+       else if (Keyboard[sc_X])                        // X = item cheat\r
+       {\r
+               CenterWindow (12,3);\r
+               US_PrintCentered ("Extra stuff!");\r
+               VW_UpdateScreen();\r
+               for (i=0;i<4;i++)\r
+               {\r
+                       GiveBolt ();\r
+                       GiveNuke ();\r
+                       GivePotion ();\r
+               }\r
+               IN_Ack ();\r
+               return 1;\r
+       }\r
+       else if (Keyboard[sc_Z])                        // Z = game over\r
+       {\r
+\r
+       }\r
+       else if (LastScan >= sc_1 && LastScan <= sc_8)  // free scrolls\r
+       {\r
+               GiveScroll (LastScan-sc_1,false);\r
+               IN_ClearKeysDown ();\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= LatchDrawChar\r
+=\r
+=====================\r
+*/\r
+\r
+void LatchDrawChar (unsigned x, unsigned y, unsigned picnum)\r
+{\r
+       unsigned        source, dest;\r
+\r
+       dest = bufferofs + ylookup[y]+x;\r
+       source = latchpics[0]+picnum*8;\r
+\r
+       EGAWRITEMODE(1);\r
+       EGAMAPMASK(15);\r
+\r
+asm    mov     bx,[linewidth]\r
+asm    dec     bx\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
+\r
+asm    movsb\r
+asm    add     di,bx\r
+asm    movsb\r
+asm    add     di,bx\r
+asm    movsb\r
+asm    add     di,bx\r
+asm    movsb\r
+asm    add     di,bx\r
+asm    movsb\r
+asm    add     di,bx\r
+asm    movsb\r
+asm    add     di,bx\r
+asm    movsb\r
+asm    add     di,bx\r
+asm    movsb\r
+\r
+asm    mov     ax,ss\r
+asm    mov     ds,ax                                   // restore turbo's data segment\r
+\r
+       EGAWRITEMODE(0);\r
+}\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= LatchDrawTile\r
+=\r
+=====================\r
+*/\r
+\r
+void LatchDrawTile (unsigned x, unsigned y, unsigned picnum)\r
+{\r
+       unsigned        source, dest;\r
+\r
+       dest = bufferofs + ylookup[y]+x;\r
+       source = tileoffsets[picnum];\r
+\r
+       EGAWRITEMODE(1);\r
+       EGAMAPMASK(15);\r
+\r
+asm    mov     bx,[linewidth]\r
+asm    sub     bx,2\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,16\r
+\r
+lineloop:\r
+asm    movsb\r
+asm    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
+\r
+/*\r
+===================\r
+=\r
+= OverheadRefresh\r
+=\r
+===================\r
+*/\r
+\r
+void OverheadRefresh (void)\r
+{\r
+       unsigned        x,y,endx,endy,sx,sy;\r
+       unsigned        tile;\r
+\r
+\r
+       if (++screenpage == 3)\r
+               screenpage = 0;\r
+\r
+       bufferofs = screenloc[screenpage];\r
+\r
+       endx = maporgx+VIEWTILEX;\r
+       endy = maporgy+VIEWTILEY;\r
+\r
+       for (y=maporgy;y<endy;y++)\r
+               for (x=maporgx;x<endx;x++)\r
+               {\r
+                       sx = (x-maporgx)*2;\r
+                       sy = (y-maporgy)*16;\r
+\r
+                       switch (viewtype)\r
+                       {\r
+                       case mapview:\r
+                               tile = *(mapsegs[0]+farmapylookup[y]+x);\r
+                               break;\r
+\r
+                       case tilemapview:\r
+                               tile = tilemap[x][y];\r
+                               break;\r
+\r
+                       case actoratview:\r
+                               tile = (unsigned)actorat[x][y];\r
+                               break;\r
+\r
+                       case visview:\r
+                               tile = spotvis[x][y];\r
+                               break;\r
+\r
+                       }\r
+\r
+                       if (tile<NUMTILE16)\r
+                               LatchDrawTile(sx,sy,tile);\r
+                       else\r
+                       {\r
+                               LatchDrawChar(sx,sy,NUMBERCHARS+((tile&0xf000)>>12));\r
+                               LatchDrawChar(sx+1,sy,NUMBERCHARS+((tile&0x0f00)>>8));\r
+                               LatchDrawChar(sx,sy+8,NUMBERCHARS+((tile&0x00f0)>>4));\r
+                               LatchDrawChar(sx+1,sy+8,NUMBERCHARS+(tile&0x000f));\r
+                       }\r
+               }\r
+\r
+       VW_SetScreen (bufferofs,0);\r
+       displayofs = bufferofs;\r
+}\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= ViewMap\r
+=\r
+===================\r
+*/\r
+\r
+void ViewMap (void)\r
+{\r
+       boolean         button0held;\r
+\r
+       viewtype = actoratview;\r
+       button0held = false;\r
+\r
+\r
+       maporgx = player->tilex - VIEWTILEX/2;\r
+       if (maporgx<0)\r
+               maporgx = 0;\r
+       maporgy = player->tiley - VIEWTILEY/2;\r
+       if (maporgy<0)\r
+               maporgy = 0;\r
+\r
+       do\r
+       {\r
+//\r
+// let user pan around\r
+//\r
+               IN_ReadControl(0,&c);\r
+               if (c.xaxis == -1 && maporgx>0)\r
+                       maporgx--;\r
+               if (c.xaxis == 1 && maporgx<mapwidth-VIEWTILEX)\r
+                       maporgx++;\r
+               if (c.yaxis == -1 && maporgy>0)\r
+                       maporgy--;\r
+               if (c.yaxis == 1 && maporgy<mapheight-VIEWTILEY)\r
+                       maporgy++;\r
+\r
+               if (c.button0 && !button0held)\r
+               {\r
+                       button0held = true;\r
+                       viewtype++;\r
+                       if (viewtype>visview)\r
+                               viewtype = mapview;\r
+               }\r
+               if (!c.button0)\r
+                       button0held = false;\r
+\r
+\r
+               OverheadRefresh ();\r
+\r
+       } while (!Keyboard[sc_Escape]);\r
+\r
+       IN_ClearKeysDown ();\r
+       DrawPlayScreen ();\r
+}\r
+\r
+\r
diff --git a/C3_DEF.H b/C3_DEF.H
new file mode 100644 (file)
index 0000000..c0fe07f
--- /dev/null
+++ b/C3_DEF.H
@@ -0,0 +1,533 @@
+/* Catacomb 3-D 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
+#include "ID_HEADS.H"\r
+#include <MATH.H>\r
+#include <VALUES.H>\r
+\r
+//#define PROFILE\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                GLOBAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+#define NAMESTART      180\r
+\r
+\r
+#define UNMARKGRCHUNK(chunk)   (grneeded[chunk]&=~ca_levelbit)\r
+\r
+#define MOUSEINT       0x33\r
+\r
+#define EXPWALLSTART   8\r
+#define NUMEXPWALLS            7\r
+#define WALLEXP                        15\r
+#define NUMFLOORS              36\r
+\r
+#define NUMFLOORS      36\r
+\r
+#define NUMLATCHPICS   100\r
+#define NUMSCALEPICS   100\r
+#define NUMSCALEWALLS  30\r
+\r
+\r
+#define FLASHCOLOR     5\r
+#define FLASHTICS      4\r
+\r
+\r
+#define NUMLEVELS      20\r
+\r
+#define VIEWX          0               // corner of view window\r
+#define VIEWY          0\r
+#define VIEWWIDTH      (33*8)          // size of view window\r
+#define VIEWHEIGHT     (18*8)\r
+#define VIEWXH         (VIEWX+VIEWWIDTH-1)\r
+#define VIEWYH         (VIEWY+VIEWHEIGHT-1)\r
+\r
+#define CENTERX                (VIEWX+VIEWWIDTH/2-1)   // middle of view window\r
+#define CENTERY                (VIEWY+VIEWHEIGHT/2-1)\r
+\r
+#define GLOBAL1                (1l<<16)\r
+#define TILEGLOBAL  GLOBAL1\r
+#define TILESHIFT      16l\r
+\r
+#define MINDIST                (2*GLOBAL1/5)\r
+#define FOCALLENGTH    (TILEGLOBAL)    // in global coordinates\r
+\r
+#define ANGLES         360             // must be divisable by 4\r
+\r
+#define MAPSIZE                64              // maps are 64*64 max\r
+#define MAXACTORS      150             // max number of tanks, etc / map\r
+\r
+#define NORTH  0\r
+#define EAST   1\r
+#define SOUTH  2\r
+#define WEST   3\r
+\r
+#define SIGN(x) ((x)>0?1:-1)\r
+#define ABS(x) ((int)(x)>0?(x):-(x))\r
+#define LABS(x) ((long)(x)>0?(x):-(x))\r
+\r
+#define        MAXSCALE        (VIEWWIDTH/2)\r
+\r
+\r
+#define MAXBODY                        64\r
+#define MAXSHOTPOWER   56\r
+\r
+#define SCREEN1START   0\r
+#define SCREEN2START   8320\r
+\r
+#define PAGE1START             0x900\r
+#define PAGE2START             0x2000\r
+#define        PAGE3START              0x3700\r
+#define        FREESTART               0x4e00\r
+\r
+#define PIXRADIUS              512\r
+\r
+#define STATUSLINES            (200-VIEWHEIGHT)\r
+\r
+enum bonusnumbers {B_BOLT,B_NUKE,B_POTION,B_RKEY,B_YKEY,B_GKEY,B_BKEY,B_SCROLL1,\r
+ B_SCROLL2,B_SCROLL3,B_SCROLL4,B_SCROLL5,B_SCROLL6,B_SCROLL7,B_SCROLL8,\r
+ B_GOAL,B_CHEST};\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                  GLOBAL TYPES\r
+\r
+=============================================================================\r
+*/\r
+\r
+enum {BLANKCHAR=9,BOLTCHAR,NUKECHAR,POTIONCHAR,KEYCHARS,SCROLLCHARS=17,\r
+       NUMBERCHARS=25};\r
+\r
+typedef long fixed;\r
+\r
+typedef struct {int x,y;} tilept;\r
+typedef struct {fixed x,y;} globpt;\r
+\r
+typedef struct\r
+{\r
+  int  x1,x2,leftclip,rightclip;// first pixel of wall (may not be visable)\r
+  unsigned     height1,height2,color,walllength,side;\r
+       long    planecoord;\r
+} walltype;\r
+\r
+typedef enum\r
+  {nothing,playerobj,bonusobj,orcobj,batobj,skeletonobj,trollobj,demonobj,\r
+  mageobj,pshotobj,bigpshotobj,mshotobj,inertobj,bounceobj,grelmobj\r
+  ,gateobj} classtype;\r
+\r
+typedef enum {north,east,south,west,northeast,southeast,southwest,\r
+                 northwest,nodir} dirtype;             // a catacombs 2 carryover\r
+\r
+\r
+typedef struct statestruct\r
+{\r
+       int             shapenum;\r
+       int             tictime;\r
+       void    (*think) ();\r
+       struct  statestruct     *next;\r
+} statetype;\r
+\r
+\r
+typedef struct objstruct\r
+{\r
+  enum {no,yes}        active;\r
+  int          ticcount;\r
+  classtype    obclass;\r
+  statetype    *state;\r
+\r
+  boolean      shootable;\r
+  boolean      tileobject;             // true if entirely inside one tile\r
+\r
+  long         distance;\r
+  dirtype      dir;\r
+  fixed        x,y;\r
+  unsigned     tilex,tiley;\r
+  int          viewx;\r
+  unsigned     viewheight;\r
+\r
+  int          angle;\r
+  int          hitpoints;\r
+  long         speed;\r
+\r
+  unsigned     size;                   // global radius for hit rect calculation\r
+  fixed                xl,xh,yl,yh;    // hit rectangle\r
+\r
+  int          temp1,temp2;\r
+  struct       objstruct       *next,*prev;\r
+} objtype;\r
+\r
+\r
+typedef        struct\r
+{\r
+       int             difficulty;\r
+       int             mapon;\r
+       int             bolts,nukes,potions,keys[4],scrolls[8];\r
+       long    score;\r
+       int             body,shotpower;\r
+} gametype;\r
+\r
+typedef        enum    {ex_stillplaying,ex_died,ex_warped,ex_resetgame\r
+       ,ex_loadedgame,ex_victorious,ex_abort} exittype;\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                C3_MAIN DEFINITIONS\r
+\r
+=============================================================================\r
+*/\r
+\r
+extern char            str[80],str2[20];\r
+extern unsigned        tedlevelnum;\r
+extern boolean         tedlevel;\r
+extern gametype        gamestate;\r
+extern exittype        playstate;\r
+\r
+\r
+void NewGame (void);\r
+boolean        SaveTheGame(int file);\r
+boolean        LoadTheGame(int file);\r
+void ResetGame(void);\r
+void ShutdownId (void);\r
+void InitGame (void);\r
+void Quit (char *error);\r
+void TEDDeath(void);\r
+void DemoLoop (void);\r
+void SetupScalePic (unsigned picnum);\r
+void SetupScaleWall (unsigned picnum);\r
+void SetupScaling (void);\r
+void main (void);\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                C3_GAME DEFINITIONS\r
+\r
+=============================================================================\r
+*/\r
+\r
+extern unsigned        latchpics[NUMLATCHPICS];\r
+extern unsigned        tileoffsets[NUMTILE16];\r
+extern unsigned        textstarts[27];\r
+\r
+\r
+#define        L_CHARS         0\r
+#define L_NOSHOT       1\r
+#define L_SHOTBAR      2\r
+#define L_NOBODY       3\r
+#define L_BODYBAR      4\r
+\r
+\r
+void ScanInfoPlane (void);\r
+void ScanText (void);\r
+void SetupGameLevel (void);\r
+void Victory (void);\r
+void Died (void);\r
+void NormalScreen (void);\r
+void DrawPlayScreen (void);\r
+void LoadLatchMem (void);\r
+void FizzleFade (unsigned source, unsigned dest,\r
+       unsigned width,unsigned height, boolean abortable);\r
+void FizzleOut (int showlevel);\r
+void FreeUpMemory (void);\r
+void GameLoop (void);\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                C3_PLAY DEFINITIONS\r
+\r
+=============================================================================\r
+*/\r
+\r
+extern ControlInfo     c;\r
+extern boolean         running,slowturn;\r
+\r
+extern int                     bordertime;\r
+\r
+extern byte            tilemap[MAPSIZE][MAPSIZE];\r
+extern objtype         *actorat[MAPSIZE][MAPSIZE];\r
+extern byte            spotvis[MAPSIZE][MAPSIZE];\r
+\r
+extern objtype         objlist[MAXACTORS],*new,*obj,*player;\r
+\r
+extern unsigned        farmapylookup[MAPSIZE];\r
+extern byte            *nearmapylookup[MAPSIZE];\r
+extern byte            update[];\r
+\r
+extern boolean         godmode,singlestep;\r
+extern int                     extravbls;\r
+\r
+extern int                     mousexmove,mouseymove;\r
+extern int                     pointcount,pointsleft;\r
+\r
+\r
+void CenterWindow(word w,word h);\r
+void DebugMemory (void);\r
+void PicturePause (void);\r
+int  DebugKeys (void);\r
+void CheckKeys (void);\r
+void InitObjList (void);\r
+void GetNewObj (boolean usedummy);\r
+void RemoveObj (objtype *gone);\r
+void PollControlls (void);\r
+void PlayLoop (void);\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                C3_STATE DEFINITIONS\r
+\r
+=============================================================================\r
+*/\r
+\r
+void SpawnNewObj (unsigned x, unsigned y, statetype *state, unsigned size);\r
+void SpawnNewObjFrac (long x, long y, statetype *state, unsigned size);\r
+boolean CheckHandAttack (objtype *ob);\r
+void T_DoDamage (objtype *ob);\r
+boolean Walk (objtype *ob);\r
+void ChaseThink (objtype *obj, boolean diagonal);\r
+void MoveObj (objtype *ob, long move);\r
+boolean Chase (objtype *ob, boolean diagonal);\r
+\r
+extern dirtype opposite[9];\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                C3_TRACE DEFINITIONS\r
+\r
+=============================================================================\r
+*/\r
+\r
+int FollowTrace (fixed tracex, fixed tracey, long deltax, long deltay, int max);\r
+int BackTrace (int finish);\r
+void ForwardTrace (void);\r
+int FinishWall (void);\r
+void InsideCorner (void);\r
+void OutsideCorner (void);\r
+void FollowWalls (void);\r
+\r
+extern boolean aborttrace;\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                C3_DRAW DEFINITIONS\r
+\r
+=============================================================================\r
+*/\r
+\r
+#define MAXWALLS       50\r
+#define DANGERHIGH     45\r
+\r
+#define        MIDWALL         (MAXWALLS/2)\r
+\r
+//==========================================================================\r
+\r
+extern tilept  tile,lasttile,focal,left,mid,right;\r
+\r
+extern globpt  edge,view;\r
+\r
+extern unsigned screenloc[3];\r
+extern unsigned freelatch;\r
+\r
+extern int screenpage;\r
+\r
+extern boolean         fizzlein;\r
+\r
+extern long lasttimecount;\r
+\r
+extern int firstangle,lastangle;\r
+\r
+extern fixed prestep;\r
+\r
+extern int traceclip,tracetop;\r
+\r
+extern fixed sintable[ANGLES+ANGLES/4],*costable;\r
+\r
+extern fixed   viewx,viewy,viewsin,viewcos;                    // the focal point\r
+extern int     viewangle;\r
+\r
+extern fixed scale,scaleglobal;\r
+extern unsigned slideofs;\r
+\r
+extern int zbuffer[VIEWXH+1];\r
+\r
+extern walltype        walls[MAXWALLS],*leftwall,*rightwall;\r
+\r
+\r
+extern fixed   tileglobal;\r
+extern fixed   focallength;\r
+extern fixed   mindist;\r
+extern int             viewheight;\r
+extern fixed scale;\r
+\r
+extern int     walllight1[NUMFLOORS];\r
+extern int     walldark1[NUMFLOORS];\r
+extern int     walllight2[NUMFLOORS];\r
+extern int     walldark2[NUMFLOORS];\r
+\r
+//==========================================================================\r
+\r
+void   DrawLine (int xl, int xh, int y,int color);\r
+void   DrawWall (walltype *wallptr);\r
+void   TraceRay (unsigned angle);\r
+fixed  FixedByFrac (fixed a, fixed b);\r
+void   TransformPoint (fixed gx, fixed gy, int *screenx, unsigned *screenheight);\r
+fixed  TransformX (fixed gx, fixed gy);\r
+int    FollowTrace (fixed tracex, fixed tracey, long deltax, long deltay, int max);\r
+void   ForwardTrace (void);\r
+int    FinishWall (void);\r
+int    TurnClockwise (void);\r
+int    TurnCounterClockwise (void);\r
+void   FollowWall (void);\r
+\r
+void   NewScene (void);\r
+void   BuildTables (void);\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                C3_SCALE DEFINITIONS\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+#define COMPSCALECODESTART     (65*6)          // offset to start of code in comp scaler\r
+\r
+typedef struct\r
+{\r
+       unsigned        codeofs[65];\r
+       unsigned        start[65];\r
+       unsigned        width[65];\r
+       byte            code[];\r
+}      t_compscale;\r
+\r
+typedef struct\r
+{\r
+       unsigned        width;\r
+       unsigned        codeofs[64];\r
+}      t_compshape;\r
+\r
+\r
+extern unsigned        scaleblockwidth,\r
+               scaleblockheight,\r
+               scaleblockdest;\r
+\r
+extern byte    plotpix[8];\r
+extern byte    bitmasks1[8][8];\r
+extern byte    bitmasks2[8][8];\r
+\r
+\r
+extern t_compscale _seg *scaledirectory[MAXSCALE+1];\r
+extern t_compshape _seg *shapedirectory[NUMSCALEPICS];\r
+extern memptr                  walldirectory[NUMSCALEWALLS];\r
+extern unsigned        shapesize[MAXSCALE+1];\r
+\r
+void           DeplanePic (int picnum);\r
+void ScaleShape (int xcenter, t_compshape _seg *compshape, unsigned scale);\r
+unsigned       BuildCompShape (t_compshape _seg **finalspot);\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                C3_ASM DEFINITIONS\r
+\r
+=============================================================================\r
+*/\r
+\r
+extern unsigned        wallheight      [VIEWWIDTH];\r
+extern unsigned        wallwidth       [VIEWWIDTH];\r
+extern unsigned        wallseg         [VIEWWIDTH];\r
+extern unsigned        wallofs         [VIEWWIDTH];\r
+extern unsigned        screenbyte      [VIEWWIDTH];\r
+extern unsigned        screenbit       [VIEWWIDTH];\r
+extern unsigned        bitmasks        [64];\r
+\r
+extern long            wallscalecall;\r
+\r
+void   ScaleWalls (void);\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                C3_WIZ DEFINITIONS\r
+\r
+=============================================================================\r
+*/\r
+\r
+#define MAXHANDHEIGHT  72\r
+\r
+extern long    lastnuke;\r
+extern int             handheight;\r
+extern int             boltsleft;\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                C3_ACT1 DEFINITIONS\r
+\r
+=============================================================================\r
+*/\r
+\r
+extern statetype s_trollouch;\r
+extern statetype s_trolldie1;\r
+\r
+\r
+extern statetype s_orcpause;\r
+\r
+extern statetype s_orc1;\r
+extern statetype s_orc2;\r
+extern statetype s_orc3;\r
+extern statetype s_orc4;\r
+\r
+extern statetype s_orcattack1;\r
+extern statetype s_orcattack2;\r
+extern statetype s_orcattack3;\r
+\r
+extern statetype s_orcouch;\r
+\r
+extern statetype s_orcdie1;\r
+extern statetype s_orcdie2;\r
+extern statetype s_orcdie3;\r
+\r
+\r
+extern statetype s_demonouch;\r
+extern statetype s_demondie1;\r
+\r
+extern statetype s_mageouch;\r
+extern statetype s_magedie1;\r
+\r
+extern statetype s_grelouch;\r
+extern statetype s_greldie1;\r
+\r
+extern statetype s_batdie1;\r
diff --git a/C3_DRAW.C b/C3_DRAW.C
new file mode 100644 (file)
index 0000000..dfb055e
--- /dev/null
+++ b/C3_DRAW.C
@@ -0,0 +1,1592 @@
+/* Catacomb 3-D 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_DRAW.C\r
+\r
+#include "C3_DEF.H"\r
+#pragma hdrstop\r
+\r
+//#define DRAWEACH                             // draw walls one at a time for debugging\r
+\r
+unsigned       highest;\r
+unsigned       mostwalls,numwalls;\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+#define PI     3.141592657\r
+#define ANGLEQUAD      (ANGLES/4)\r
+\r
+unsigned       oldend;\r
+\r
+#define FINEANGLES     3600\r
+\r
+#define MINRATIO       16\r
+\r
+\r
+const  unsigned        MAXSCALEHEIGHT  = (VIEWWIDTH/2);\r
+const  unsigned        MAXVISHEIGHT    = (VIEWHEIGHT/2);\r
+const  unsigned        BASESCALE               = 32;\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                GLOBAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+//\r
+// calculate location of screens in video memory so they have the\r
+// maximum possible distance seperating them (for scaling overflow)\r
+//\r
+\r
+unsigned screenloc[3]= {0x900,0x2000,0x3700};\r
+unsigned freelatch = 0x4e00;\r
+\r
+boolean                fizzlein;\r
+\r
+long   scaleshapecalll;\r
+long   scaletablecall;\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+long   bytecount,endcount;             // for profiling\r
+int            animframe;\r
+int            pixelangle[VIEWWIDTH];\r
+int            far finetangent[FINEANGLES+1];\r
+int            fineviewangle;\r
+unsigned       viewxpix,viewypix;\r
+\r
+/*\r
+============================================================================\r
+\r
+                          3 - D  DEFINITIONS\r
+\r
+============================================================================\r
+*/\r
+\r
+fixed  tileglobal      = TILEGLOBAL;\r
+fixed  focallength     = FOCALLENGTH;\r
+fixed  mindist         = MINDIST;\r
+int            viewheight      = VIEWHEIGHT;\r
+fixed scale;\r
+\r
+\r
+tilept tile,lasttile,          // tile of wall being followed\r
+       focal,                  // focal point in tiles\r
+       left,mid,right;         // rightmost tile in view\r
+\r
+globpt edge,view;\r
+\r
+int    segstart[VIEWHEIGHT],   // addline tracks line segment and draws\r
+       segend[VIEWHEIGHT],\r
+       segcolor[VIEWHEIGHT];   // only when the color changes\r
+\r
+\r
+walltype       walls[MAXWALLS],*leftwall,*rightwall;\r
+\r
+\r
+//==========================================================================\r
+\r
+//\r
+// refresh stuff\r
+//\r
+\r
+int screenpage;\r
+\r
+long lasttimecount;\r
+\r
+//\r
+// rendering stuff\r
+//\r
+\r
+int firstangle,lastangle;\r
+\r
+fixed prestep;\r
+\r
+fixed sintable[ANGLES+ANGLES/4],*costable = sintable+(ANGLES/4);\r
+\r
+fixed  viewx,viewy;                    // the focal point\r
+int    viewangle;\r
+fixed  viewsin,viewcos;\r
+\r
+int    zbuffer[VIEWXH+1];      // holds the height of the wall at that point\r
+\r
+//==========================================================================\r
+\r
+void   DrawLine (int xl, int xh, int y,int color);\r
+void   DrawWall (walltype *wallptr);\r
+void   TraceRay (unsigned angle);\r
+fixed  FixedByFrac (fixed a, fixed b);\r
+fixed  FixedAdd (void);\r
+fixed  TransformX (fixed gx, fixed gy);\r
+int            FollowTrace (fixed tracex, fixed tracey, long deltax, long deltay, int max);\r
+int            BackTrace (int finish);\r
+void   ForwardTrace (void);\r
+int            TurnClockwise (void);\r
+int            TurnCounterClockwise (void);\r
+void   FollowWall (void);\r
+\r
+void   NewScene (void);\r
+void   BuildTables (void);\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+==================\r
+=\r
+= DrawLine\r
+=\r
+= Must be in write mode 2 with all planes enabled\r
+= The bit mask is left set to the end value, so clear it after all lines are\r
+= drawn\r
+=\r
+= draws a black dot at the left edge of the line\r
+=\r
+==================\r
+*/\r
+\r
+unsigned static        char dotmask[8] = {0x80,0x40,0x20,0x10,8,4,2,1};\r
+unsigned static        char leftmask[8] = {0xff,0x7f,0x3f,0x1f,0xf,7,3,1};\r
+unsigned static        char rightmask[8] = {0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff};\r
+\r
+void DrawLine (int xl, int xh, int y,int color)\r
+{\r
+  unsigned dest,xlp,xlb,xhb,maskleft,maskright,maskdot,mid;\r
+\r
+  xlb=xl/8;\r
+  xhb=xh/8;\r
+\r
+  if (xh<xl)\r
+       Quit("DrawLine: xh<xl");\r
+  if (y<VIEWY)\r
+       Quit("DrawLine: y<VIEWY");\r
+  if (y>VIEWYH)\r
+       Quit("DrawLine: y>VIEWYH");\r
+\r
+       xlp = xl&7;\r
+       maskleft = leftmask[xlp];\r
+       maskright = rightmask[xh&7];\r
+\r
+  mid = xhb-xlb-1;\r
+  dest = bufferofs+ylookup[y]+xlb;\r
+\r
+       //\r
+       // set the GC index register to point to the bit mask register\r
+       //\r
+       asm     mov     al,GC_BITMASK\r
+       asm     mov     dx,GC_INDEX\r
+       asm     out     dx,al\r
+\r
+  if (xlb==xhb)\r
+  {\r
+  //\r
+  // entire line is in one byte\r
+  //\r
+\r
+       maskleft&=maskright;\r
+\r
+       asm     mov     es,[screenseg]\r
+       asm     mov     di,[dest]\r
+       asm     mov     dx,GC_INDEX+1\r
+\r
+       asm     mov     al,[BYTE PTR maskleft]\r
+       asm     out     dx,al           // mask off pixels\r
+\r
+       asm     mov     al,[BYTE PTR color]\r
+       asm     xchg    al,[es:di]      // load latches and write pixels\r
+\r
+       return;\r
+  }\r
+\r
+asm    mov     es,[screenseg]\r
+asm    mov     di,[dest]\r
+asm    mov     dx,GC_INDEX+1\r
+asm    mov     bh,[BYTE PTR color]\r
+\r
+//\r
+// draw left side\r
+//\r
+asm    mov     al,[BYTE PTR maskleft]\r
+asm    out     dx,al           // mask off pixels\r
+\r
+asm    mov     al,bh\r
+asm    xchg    al,[es:di]      // load latches and write pixels\r
+asm    inc     di\r
+\r
+//\r
+// draw middle\r
+//\r
+asm    mov     al,255\r
+asm    out     dx,al           // no masking\r
+\r
+asm    mov     al,bh\r
+asm    mov     cx,[mid]\r
+asm    rep     stosb\r
+\r
+//\r
+// draw right side\r
+//\r
+asm    mov     al,[BYTE PTR maskright]\r
+asm    out     dx,al           // mask off pixels\r
+asm    xchg    bh,[es:di]      // load latches and write pixels\r
+\r
+}\r
+\r
+//==========================================================================\r
+\r
+void DrawLineDot (int xl, int xh, int y,int color)\r
+{\r
+  unsigned dest,xlp,xlb,xhb,maskleft,maskright,maskdot,mid;\r
+\r
+  xlb=xl/8;\r
+  xhb=xh/8;\r
+\r
+  if (xh<xl)\r
+       Quit("DrawLine: xh<xl");\r
+  if (y<VIEWY)\r
+       Quit("DrawLine: y<VIEWY");\r
+  if (y>VIEWYH)\r
+       Quit("DrawLine: y>VIEWYH");\r
+\r
+       xlp = xl&7;\r
+       maskdot = dotmask[xlp];\r
+       maskleft = leftmask[xlp];\r
+       maskright = rightmask[xh&7];\r
+\r
+  mid = xhb-xlb-1;\r
+  dest = bufferofs+ylookup[y]+xlb;\r
+\r
+       //\r
+       // set the GC index register to point to the bit mask register\r
+       //\r
+       asm     mov     al,GC_BITMASK\r
+       asm     mov     dx,GC_INDEX\r
+       asm     out     dx,al\r
+\r
+  if (xlb==xhb)\r
+  {\r
+  //\r
+  // entire line is in one byte\r
+  //\r
+\r
+       maskleft&=maskright;\r
+\r
+       asm     mov     es,[screenseg]\r
+       asm     mov     di,[dest]\r
+       asm     mov     dx,GC_INDEX+1\r
+\r
+       asm     mov     al,[BYTE PTR maskleft]\r
+       asm     out     dx,al           // mask off pixels\r
+\r
+       asm     mov     al,[BYTE PTR color]\r
+       asm     xchg    al,[es:di]      // load latches and write pixels\r
+\r
+\r
+       //\r
+       // write the black dot at the start\r
+       //\r
+       asm     mov     al,[BYTE PTR maskdot]\r
+       asm     out     dx,al           // mask off pixels\r
+\r
+       asm     xor     al,al\r
+       asm     xchg    al,[es:di]      // load latches and write pixels\r
+\r
+\r
+       return;\r
+  }\r
+\r
+asm    mov     es,[screenseg]\r
+asm    mov     di,[dest]\r
+asm    mov     dx,GC_INDEX+1\r
+asm    mov     bh,[BYTE PTR color]\r
+\r
+//\r
+// draw left side\r
+//\r
+asm    mov     al,[BYTE PTR maskleft]\r
+asm    out     dx,al           // mask off pixels\r
+\r
+asm    mov     al,bh\r
+asm    xchg    al,[es:di]      // load latches and write pixels\r
+\r
+//\r
+// write the black dot at the start\r
+//\r
+asm    mov     al,[BYTE PTR maskdot]\r
+asm    out     dx,al           // mask off pixels\r
+asm    xor     al,al\r
+asm    xchg    al,[es:di]      // load latches and write pixels\r
+asm    inc     di\r
+\r
+//\r
+// draw middle\r
+//\r
+asm    mov     al,255\r
+asm    out     dx,al           // no masking\r
+\r
+asm    mov     al,bh\r
+asm    mov     cx,[mid]\r
+asm    rep     stosb\r
+\r
+//\r
+// draw right side\r
+//\r
+asm    mov     al,[BYTE PTR maskright]\r
+asm    out     dx,al           // mask off pixels\r
+asm    xchg    bh,[es:di]      // load latches and write pixels\r
+\r
+}\r
+\r
+//==========================================================================\r
+\r
+\r
+long           wallscalesource;\r
+\r
+#ifdef DRAWEACH\r
+/*\r
+====================\r
+=\r
+= ScaleOneWall\r
+=\r
+====================\r
+*/\r
+\r
+void near ScaleOneWall (int xl, int xh)\r
+{\r
+       int     x,pixwidth,height;\r
+\r
+       *(((unsigned *)&wallscalesource)+1) = wallseg[xl];\r
+\r
+       for (x=xl;x<=xh;x+=pixwidth)\r
+       {\r
+               height = wallheight[x];\r
+               pixwidth = wallwidth[x];\r
+               (unsigned)wallscalesource = wallofs[x];\r
+\r
+               *(((unsigned *)&scaletablecall)+1) = (unsigned)scaledirectory[height];\r
+               (unsigned)scaletablecall = scaledirectory[height]->codeofs[0];\r
+\r
+               //\r
+               // scale a byte wide strip of wall\r
+               //\r
+               asm     mov     bx,[x]\r
+               asm     mov     di,bx\r
+               asm     shr     di,1\r
+               asm     shr     di,1\r
+               asm     shr     di,1                                            // X in bytes\r
+               asm     add     di,[bufferofs]\r
+               asm     and     bx,7\r
+               asm     shl     bx,1\r
+               asm     shl     bx,1\r
+               asm     shl     bx,1\r
+               asm     add     bx,[pixwidth]                           // bx = pixel*8+pixwidth-1\r
+               asm     dec     bx\r
+               asm     mov     al,BYTE PTR [bitmasks1+bx]\r
+               asm     mov     dx,GC_INDEX+1\r
+               asm     out     dx,al                                           // set bit mask register\r
+               asm     mov     es,[screenseg]\r
+               asm     lds     si,[wallscalesource]\r
+               asm     call [DWORD PTR ss:scaletablecall]              // scale the line of pixels\r
+\r
+               asm     mov     al,BYTE PTR [ss:bitmasks2+bx]\r
+               asm     or      al,al\r
+               asm     jz      nosecond\r
+\r
+               //\r
+               // draw a second byte for vertical strips that cross two bytes\r
+               //\r
+               asm     inc     di\r
+               asm     out     dx,al                                           // set bit mask register\r
+               asm     call [DWORD PTR ss:scaletablecall]      // scale the line of pixels\r
+       nosecond:\r
+               asm     mov     ax,ss\r
+               asm     mov     ds,ax\r
+       }\r
+}\r
+\r
+#endif\r
+\r
+int    walllight1[NUMFLOORS] = {0,\r
+       WALL1LPIC,WALL2LPIC,WALL3LPIC,WALL4LPIC,WALL5LPIC,WALL6LPIC,WALL7LPIC,\r
+       WALL1LPIC,WALL2LPIC,WALL3LPIC,WALL4LPIC,WALL5LPIC,WALL6LPIC,WALL7LPIC,\r
+       EXPWALL1PIC,EXPWALL2PIC,EXPWALL3PIC,\r
+       RDOOR1PIC,RDOOR2PIC,RDOOR1PIC,RDOOR2PIC,\r
+       YDOOR1PIC,YDOOR2PIC,YDOOR1PIC,YDOOR2PIC,\r
+       GDOOR1PIC,GDOOR2PIC,GDOOR1PIC,GDOOR2PIC,\r
+       BDOOR1PIC,BDOOR2PIC,BDOOR1PIC,BDOOR2PIC};\r
+\r
+int    walldark1[NUMFLOORS] = {0,\r
+       WALL1DPIC,WALL2DPIC,WALL3DPIC,WALL4DPIC,WALL5DPIC,WALL6DPIC,WALL7DPIC,\r
+       WALL1DPIC,WALL2DPIC,WALL3DPIC,WALL4DPIC,WALL5DPIC,WALL6DPIC,WALL7DPIC,\r
+       EXPWALL1PIC,EXPWALL2PIC,EXPWALL3PIC,\r
+       RDOOR1PIC,RDOOR2PIC,RDOOR1PIC,RDOOR2PIC,\r
+       YDOOR1PIC,YDOOR2PIC,YDOOR1PIC,YDOOR2PIC,\r
+       GDOOR1PIC,GDOOR2PIC,GDOOR1PIC,GDOOR2PIC,\r
+       BDOOR1PIC,BDOOR2PIC,BDOOR1PIC,BDOOR2PIC};\r
+\r
+int    walllight2[NUMFLOORS] = {0,\r
+       WALL1LPIC,WALL2LPIC,WALL3LPIC,WALL4LPIC,WALL5LPIC,WALL6LPIC,WALL7LPIC,\r
+       WALL1LPIC,WALL2LPIC,WALL3LPIC,WALL4LPIC,WALL5LPIC,WALL6LPIC,WALL7LPIC,\r
+       EXPWALL1PIC,EXPWALL2PIC,EXPWALL3PIC,\r
+       RDOOR2PIC,RDOOR1PIC,RDOOR2PIC,RDOOR1PIC,\r
+       YDOOR2PIC,YDOOR1PIC,YDOOR2PIC,YDOOR1PIC,\r
+       GDOOR2PIC,GDOOR1PIC,GDOOR2PIC,GDOOR1PIC,\r
+       BDOOR2PIC,BDOOR1PIC,BDOOR2PIC,BDOOR1PIC};\r
+\r
+int    walldark2[NUMFLOORS] = {0,\r
+       WALL1DPIC,WALL2DPIC,WALL3DPIC,WALL4DPIC,WALL5DPIC,WALL6DPIC,WALL7DPIC,\r
+       WALL1DPIC,WALL2DPIC,WALL3DPIC,WALL4DPIC,WALL5DPIC,WALL6DPIC,WALL7DPIC,\r
+       EXPWALL1PIC,EXPWALL2PIC,EXPWALL3PIC,\r
+       RDOOR2PIC,RDOOR1PIC,RDOOR2PIC,RDOOR1PIC,\r
+       YDOOR2PIC,YDOOR1PIC,YDOOR2PIC,YDOOR1PIC,\r
+       GDOOR2PIC,GDOOR1PIC,GDOOR2PIC,GDOOR1PIC,\r
+       BDOOR2PIC,BDOOR1PIC,BDOOR2PIC,BDOOR1PIC};\r
+\r
+/*\r
+=====================\r
+=\r
+= DrawVWall\r
+=\r
+= Draws a wall by vertical segments, for texture mapping!\r
+=\r
+= wallptr->side is true for east/west walls (constant x)\r
+=\r
+= fracheight and fracstep are 16.16 bit fractions\r
+=\r
+=====================\r
+*/\r
+\r
+void DrawVWall (walltype *wallptr)\r
+{\r
+       int                     x,i;\r
+       unsigned        source;\r
+       unsigned        width,sourceint;\r
+       unsigned        wallpic,wallpicseg;\r
+       unsigned        skip;\r
+       long            fracheight,fracstep,longheightchange;\r
+       unsigned        height;\r
+       int                     heightchange;\r
+       unsigned        slope,distance;\r
+       int                     traceangle,angle;\r
+       int                     mapadd;\r
+       unsigned        lastpix,lastsource,lastwidth;\r
+\r
+\r
+       if (wallptr->rightclip < wallptr->leftclip)\r
+               Quit ("DrawVWall: Right < Left");\r
+\r
+//\r
+// setup for height calculation\r
+//\r
+       wallptr->height1 >>= 1;\r
+       wallptr->height2 >>= 1;\r
+       wallptr->planecoord>>=10;                       // remove non significant bits\r
+\r
+       width = wallptr->x2 - wallptr->x1;\r
+       if (width)\r
+       {\r
+               heightchange = wallptr->height2 - wallptr->height1;\r
+               asm     mov     ax,[heightchange]\r
+               asm     mov     WORD PTR [longheightchange+2],ax\r
+               asm     mov     WORD PTR [longheightchange],0   // avoid long shift by 16\r
+               fracstep = longheightchange/width;\r
+       }\r
+\r
+       fracheight = ((long)wallptr->height1<<16)+0x8000;\r
+       skip = wallptr->leftclip - wallptr->x1;\r
+       if (skip)\r
+               fracheight += fracstep*skip;\r
+\r
+//\r
+// setup for texture mapping\r
+//\r
+// mapadd is 64*64 (to keep source positive) + the origin wall intercept\r
+// distance has 6 unit bits, and 6 frac bits\r
+// traceangle is the center view angle in FINEANGLES, moved to be in\r
+// the +-90 degree range (to thew right of origin)\r
+//\r
+       traceangle = fineviewangle;\r
+       //\r
+       // find wall picture to map from\r
+       //\r
+       if (wallptr->side)\r
+       {       // east or west wall\r
+               if (animframe)\r
+                       wallpic = walllight2[wallptr->color];\r
+               else\r
+                       wallpic = walllight1[wallptr->color];\r
+\r
+               if (wallptr->planecoord < viewxpix)\r
+               {\r
+                       distance = viewxpix-wallptr->planecoord;\r
+                       traceangle -= FINEANGLES/2;\r
+                       mapadd = (64-viewypix&63);              // the pixel spot of the origin\r
+               }\r
+               else\r
+               {\r
+                       distance = wallptr->planecoord-viewxpix;\r
+                       // traceangle is correct\r
+                       mapadd = viewypix&63;           // the pixel spot of the origin\r
+               }\r
+       }\r
+       else\r
+       {       // north or south wall\r
+               if (animframe)\r
+                       wallpic = walldark2[wallptr->color];\r
+               else\r
+                       wallpic = walldark1[wallptr->color];\r
+\r
+               if (wallptr->planecoord < viewypix)\r
+               {\r
+                       distance = viewypix-wallptr->planecoord;\r
+                       traceangle -= FINEANGLES/4;\r
+                       mapadd = viewxpix&63;           // the pixel spot of the origin\r
+               }\r
+               else\r
+               {\r
+                       distance = wallptr->planecoord-viewypix;\r
+                       traceangle -= FINEANGLES*3/4;\r
+                       mapadd = (64-viewxpix&63);              // the pixel spot of the origin\r
+               }\r
+       }\r
+\r
+       mapadd = 64*64-mapadd;                          // make sure it stays positive\r
+\r
+       wallpicseg = (unsigned)walldirectory[wallpic-FIRSTWALLPIC];\r
+       if (traceangle > FINEANGLES/2)\r
+               traceangle -= FINEANGLES;\r
+\r
+//\r
+// calculate everything\r
+//\r
+// IMPORTANT!  This loop is executed around 5000 times / second!\r
+//\r
+       lastpix = lastsource = (unsigned)-1;\r
+\r
+       for (x = wallptr->leftclip ; x <= wallptr->rightclip ; x++)\r
+       {\r
+               //\r
+               // height\r
+               //\r
+               asm     mov     ax,WORD PTR [fracheight]\r
+               asm     mov     dx,WORD PTR [fracheight+2]\r
+               asm     mov     cx,dx\r
+               asm     add     ax,WORD PTR [fracstep]\r
+               asm     adc     dx,WORD PTR [fracstep+2]\r
+               asm     mov     WORD PTR [fracheight],ax\r
+               asm     mov     WORD PTR [fracheight+2],dx\r
+               asm     mov     bx,[x]\r
+               asm     shl     bx,1\r
+               asm     cmp     cx,MAXSCALEHEIGHT\r
+               asm     jbe     storeheight\r
+               asm     mov     cx,MAXSCALEHEIGHT\r
+storeheight:\r
+               asm     mov WORD PTR [wallheight+bx],cx\r
+               asm     mov WORD PTR [zbuffer+bx],cx\r
+\r
+//             height = fracheight>>16;\r
+//             fracheight += fracstep;\r
+//             if (height > MAXSCALEHEIGHT)\r
+//                     height = MAXSCALEHEIGHT;\r
+//             wallheight[x] = zbuffer[x] = height;\r
+\r
+               //\r
+               // texture map\r
+               //\r
+               angle = pixelangle[x]+traceangle;\r
+               if (angle<0)\r
+                       angle+=FINEANGLES;\r
+\r
+               slope = finetangent[angle];\r
+\r
+//\r
+// distance is an unsigned 6.6 bit number (12 pixel bits)\r
+// slope is a signed 5.10 bit number\r
+// result is a signed 11.16 bit number\r
+//\r
+\r
+#if 0\r
+               source = distance*slope;\r
+               source >>=20;\r
+\r
+               source += mapadd;\r
+               source &= 63;                           // mask off the unused units\r
+               source = 63-source;\r
+               source <<= 6;                           // multiply by 64 for offset into pic\r
+#endif\r
+               asm     mov     ax,[distance]\r
+               asm     imul    [slope]                 // ax is the source pixel\r
+               asm     mov     al,ah\r
+               asm     shr     al,1\r
+               asm     shr     al,1                            // low 6 bits is now pixel number\r
+               asm     add     ax,[mapadd]\r
+               asm     and ax,63\r
+               asm     mov     dx,63\r
+               asm     sub     dx,ax                           // otherwise it is backwards\r
+               asm     shl     dx,1\r
+               asm     shl     dx,1\r
+               asm     shl     dx,1\r
+               asm     shl     dx,1\r
+               asm     shl     dx,1\r
+               asm     shl     dx,1                            // *64 to index into shape\r
+               asm     mov     [source],dx\r
+\r
+               if (source != lastsource)\r
+               {\r
+                       if (lastpix != (unsigned)-1)\r
+                       {\r
+                               wallofs[lastpix] = lastsource;\r
+                               wallseg[lastpix] = wallpicseg;\r
+                               wallwidth[lastpix] = lastwidth;\r
+                       }\r
+                       lastpix = x;\r
+                       lastsource = source;\r
+                       lastwidth = 1;\r
+               }\r
+               else\r
+                       lastwidth++;                    // optimized draw, same map as last one\r
+       }\r
+       wallofs[lastpix] = lastsource;\r
+       wallseg[lastpix] = wallpicseg;\r
+       wallwidth[lastpix] = lastwidth;\r
+}\r
+\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= TraceRay\r
+=\r
+= Used to find the left and rightmost tile in the view area to be traced from\r
+= Follows a ray of the given angle from viewx,viewy in the global map until\r
+= it hits a solid tile\r
+= sets:\r
+=   tile.x,tile.y      : tile coordinates of contacted tile\r
+=   tilecolor  : solid tile's color\r
+=\r
+==================\r
+*/\r
+\r
+int tilecolor;\r
+\r
+void TraceRay (unsigned angle)\r
+{\r
+  long tracex,tracey,tracexstep,traceystep,searchx,searchy;\r
+  fixed fixtemp;\r
+  int otx,oty,searchsteps;\r
+\r
+  tracexstep = costable[angle];\r
+  traceystep = sintable[angle];\r
+\r
+//\r
+// advance point so it is even with the view plane before we start checking\r
+//\r
+  fixtemp = FixedByFrac(prestep,tracexstep);\r
+  tracex = viewx+fixtemp;\r
+  fixtemp = FixedByFrac(prestep,traceystep);\r
+  tracey = viewy-fixtemp;\r
+\r
+  tile.x = tracex>>TILESHIFT;  // starting point in tiles\r
+  tile.y = tracey>>TILESHIFT;\r
+\r
+\r
+  if (tracexstep<0)                    // use 2's complement, not signed magnitude\r
+       tracexstep = -(tracexstep&0x7fffffff);\r
+\r
+  if (traceystep<0)                    // use 2's complement, not signed magnitude\r
+       traceystep = -(traceystep&0x7fffffff);\r
+\r
+//\r
+// we assume viewx,viewy is not inside a solid tile, so go ahead one step\r
+//\r
+\r
+  do   // until a solid tile is hit\r
+  {\r
+    otx = tile.x;\r
+       oty = tile.y;\r
+       spotvis[otx][oty] = true;\r
+       tracex += tracexstep;\r
+    tracey -= traceystep;\r
+    tile.x = tracex>>TILESHIFT;\r
+       tile.y = tracey>>TILESHIFT;\r
+\r
+       if (tile.x!=otx && tile.y!=oty && (tilemap[otx][tile.y] || tilemap[tile.x][oty]) )\r
+    {\r
+      //\r
+         // trace crossed two solid tiles, so do a binary search along the line\r
+         // to find a spot where only one tile edge is crossed\r
+      //\r
+      searchsteps = 0;\r
+      searchx = tracexstep;\r
+      searchy = traceystep;\r
+      do\r
+      {\r
+       searchx/=2;\r
+       searchy/=2;\r
+       if (tile.x!=otx && tile.y!=oty)\r
+       {\r
+        // still too far\r
+         tracex -= searchx;\r
+         tracey += searchy;\r
+       }\r
+       else\r
+       {\r
+        // not far enough, no tiles crossed\r
+         tracex += searchx;\r
+         tracey -= searchy;\r
+       }\r
+\r
+       //\r
+       // if it is REAL close, go for the most clockwise intersection\r
+       //\r
+       if (++searchsteps == 16)\r
+       {\r
+         tracex = (long)otx<<TILESHIFT;\r
+         tracey = (long)oty<<TILESHIFT;\r
+         if (tracexstep>0)\r
+         {\r
+               if (traceystep<0)\r
+               {\r
+                 tracex += TILEGLOBAL-1;\r
+                 tracey += TILEGLOBAL;\r
+               }\r
+               else\r
+               {\r
+                 tracex += TILEGLOBAL;\r
+               }\r
+         }\r
+         else\r
+         {\r
+               if (traceystep<0)\r
+               {\r
+                 tracex --;\r
+                 tracey += TILEGLOBAL-1;\r
+               }\r
+               else\r
+               {\r
+                 tracey --;\r
+               }\r
+         }\r
+       }\r
+\r
+       tile.x = tracex>>TILESHIFT;\r
+       tile.y = tracey>>TILESHIFT;\r
+\r
+         } while (( tile.x!=otx && tile.y!=oty) || (tile.x==otx && tile.y==oty) );\r
+       }\r
+  } while (!(tilecolor = tilemap[tile.x][tile.y]) );\r
+\r
+}\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+========================\r
+=\r
+= FixedByFrac\r
+=\r
+= multiply a 16/16 bit, 2's complement fixed point number by a 16 bit\r
+= fraction, passed as a signed magnitude 32 bit number\r
+=\r
+========================\r
+*/\r
+\r
+#pragma warn -rvl                      // I stick the return value in with ASMs\r
+\r
+fixed FixedByFrac (fixed a, fixed b)\r
+{\r
+  fixed value;\r
+\r
+//\r
+// setup\r
+//\r
+asm    mov     si,[WORD PTR b+2]       // sign of result = sign of fraction\r
+\r
+asm    mov     ax,[WORD PTR a]\r
+asm    mov     cx,[WORD PTR a+2]\r
+\r
+asm    or      cx,cx\r
+asm    jns     aok:                            // negative?\r
+asm    not     ax\r
+asm    not     cx\r
+asm    add     ax,1\r
+asm    adc     cx,0\r
+asm    xor     si,0x8000                       // toggle sign of result\r
+aok:\r
+\r
+//\r
+// multiply  cx:ax by bx\r
+//\r
+asm    mov     bx,[WORD PTR b]\r
+asm    mul     bx                                      // fraction*fraction\r
+asm    mov     di,dx                           // di is low word of result\r
+asm    mov     ax,cx                           //\r
+asm    mul     bx                                      // units*fraction\r
+asm add        ax,di\r
+asm    adc     dx,0\r
+\r
+//\r
+// put result dx:ax in 2's complement\r
+//\r
+asm    test    si,0x8000               // is the result negative?\r
+asm    jz      ansok:\r
+asm    not     ax\r
+asm    not     dx\r
+asm    add     ax,1\r
+asm    adc     dx,0\r
+\r
+ansok:;\r
+\r
+}\r
+\r
+#pragma warn +rvl\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+========================\r
+=\r
+= TransformPoint\r
+=\r
+= Takes paramaters:\r
+=   gx,gy              : globalx/globaly of point\r
+=\r
+= globals:\r
+=   viewx,viewy                : point of view\r
+=   viewcos,viewsin    : sin/cos of viewangle\r
+=\r
+=\r
+= defines:\r
+=   CENTERX            : pixel location of center of view window\r
+=   TILEGLOBAL         : size of one\r
+=   FOCALLENGTH                : distance behind viewx/y for center of projection\r
+=   scale              : conversion from global value to screen value\r
+=\r
+= returns:\r
+=   screenx,screenheight: projected edge location and size\r
+=\r
+========================\r
+*/\r
+\r
+void TransformPoint (fixed gx, fixed gy, int *screenx, unsigned *screenheight)\r
+{\r
+  int ratio;\r
+  fixed gxt,gyt,nx,ny;\r
+\r
+//\r
+// translate point to view centered coordinates\r
+//\r
+  gx = gx-viewx;\r
+  gy = gy-viewy;\r
+\r
+//\r
+// calculate newx\r
+//\r
+  gxt = FixedByFrac(gx,viewcos);\r
+  gyt = FixedByFrac(gy,viewsin);\r
+  nx = gxt-gyt;\r
+\r
+//\r
+// calculate newy\r
+//\r
+  gxt = FixedByFrac(gx,viewsin);\r
+  gyt = FixedByFrac(gy,viewcos);\r
+  ny = gyt+gxt;\r
+\r
+//\r
+// calculate perspective ratio\r
+//\r
+  if (nx<0)\r
+       nx = 0;\r
+\r
+  ratio = nx*scale/FOCALLENGTH;\r
+\r
+  if (ratio<=MINRATIO)\r
+       ratio = MINRATIO;\r
+\r
+  *screenx = CENTERX + ny/ratio;\r
+\r
+  *screenheight = TILEGLOBAL/ratio;\r
+\r
+}\r
+\r
+\r
+//\r
+// transform actor\r
+//\r
+void TransformActor (objtype *ob)\r
+{\r
+  int ratio;\r
+  fixed gx,gy,gxt,gyt,nx,ny;\r
+\r
+//\r
+// translate point to view centered coordinates\r
+//\r
+  gx = ob->x-viewx;\r
+  gy = ob->y-viewy;\r
+\r
+//\r
+// calculate newx\r
+//\r
+  gxt = FixedByFrac(gx,viewcos);\r
+  gyt = FixedByFrac(gy,viewsin);\r
+  nx = gxt-gyt-ob->size;\r
+\r
+//\r
+// calculate newy\r
+//\r
+  gxt = FixedByFrac(gx,viewsin);\r
+  gyt = FixedByFrac(gy,viewcos);\r
+  ny = gyt+gxt;\r
+\r
+//\r
+// calculate perspective ratio\r
+//\r
+  if (nx<0)\r
+       nx = 0;\r
+\r
+  ratio = nx*scale/FOCALLENGTH;\r
+\r
+  if (ratio<=MINRATIO)\r
+       ratio = MINRATIO;\r
+\r
+  ob->viewx = CENTERX + ny/ratio;\r
+\r
+  ob->viewheight = TILEGLOBAL/ratio;\r
+}\r
+\r
+//==========================================================================\r
+\r
+fixed TransformX (fixed gx, fixed gy)\r
+{\r
+  int ratio;\r
+  fixed gxt,gyt,nx,ny;\r
+\r
+//\r
+// translate point to view centered coordinates\r
+//\r
+  gx = gx-viewx;\r
+  gy = gy-viewy;\r
+\r
+//\r
+// calculate newx\r
+//\r
+  gxt = FixedByFrac(gx,viewcos);\r
+  gyt = FixedByFrac(gy,viewsin);\r
+\r
+  return gxt-gyt;\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+==================\r
+=\r
+= BuildTables\r
+=\r
+= Calculates:\r
+=\r
+= scale                        projection constant\r
+= sintable/costable    overlapping fractional tables\r
+= firstangle/lastangle angles from focalpoint to left/right view edges\r
+= prestep              distance from focal point before checking for tiles\r
+=\r
+==================\r
+*/\r
+\r
+void BuildTables (void)\r
+{\r
+  int          i;\r
+  long         intang;\r
+  long         x;\r
+  float        angle,anglestep,radtoint;\r
+  double       tang;\r
+  fixed        value;\r
+\r
+//\r
+// calculate the angle offset from view angle of each pixel's ray\r
+//\r
+       radtoint = (float)FINEANGLES/2/PI;\r
+       for (i=0;i<VIEWWIDTH/2;i++)\r
+       {\r
+       // start 1/2 pixel over, so viewangle bisects two middle pixels\r
+               x = (TILEGLOBAL*i+TILEGLOBAL/2)/VIEWWIDTH;\r
+               tang = (float)x/(FOCALLENGTH+MINDIST);\r
+               angle = atan(tang);\r
+               intang = angle*radtoint;\r
+               pixelangle[VIEWWIDTH/2-1-i] = intang;\r
+               pixelangle[VIEWWIDTH/2+i] = -intang;\r
+       }\r
+\r
+//\r
+// calculate fine tangents\r
+// 1 sign bit, 5 units (clipped to), 10 fracs\r
+//\r
+#define MININT (-MAXINT)\r
+\r
+       for (i=0;i<FINEANGLES/4;i++)\r
+       {\r
+               intang = tan(i/radtoint)*(1l<<10);\r
+\r
+               //\r
+               // if the tangent is not reprentable in this many bits, bound the\r
+               // units part ONLY\r
+               //\r
+               if (intang>MAXINT)\r
+                       intang = 0x8f00 | (intang & 0xff);\r
+               else if (intang<MININT)\r
+                       intang = 0xff00 | (intang & 0xff);\r
+\r
+               finetangent[i] = intang;\r
+//             finetangent[FINEANGLES/2+i] = intang;\r
+//             finetangent[FINEANGLES/2-i-1] = -intang;\r
+               finetangent[FINEANGLES-i-1] = -intang;\r
+       }\r
+\r
+//\r
+// calculate scale value so one tile at mindist allmost fills the view horizontally\r
+//\r
+  scale = GLOBAL1/VIEWWIDTH;\r
+  scale *= focallength;\r
+  scale /= (focallength+mindist);\r
+\r
+//\r
+// costable overlays sintable with a quarter phase shift\r
+// ANGLES is assumed to be divisable by four\r
+//\r
+// The low word of the value is the fraction, the high bit is the sign bit,\r
+// bits 16-30 should be 0\r
+//\r
+\r
+  angle = 0;\r
+  anglestep = PI/2/ANGLEQUAD;\r
+  for (i=0;i<=ANGLEQUAD;i++)\r
+  {\r
+       value=GLOBAL1*sin(angle);\r
+       sintable[i]=\r
+         sintable[i+ANGLES]=\r
+         sintable[ANGLES/2-i] = value;\r
+       sintable[ANGLES-i]=\r
+         sintable[ANGLES/2+i] = value | 0x80000000l;\r
+       angle += anglestep;\r
+  }\r
+\r
+//\r
+// figure trace angles for first and last pixel on screen\r
+//\r
+  angle = atan((float)VIEWWIDTH/2*scale/FOCALLENGTH);\r
+  angle *= ANGLES/(PI*2);\r
+\r
+  intang = (int)angle+1;\r
+  firstangle = intang;\r
+  lastangle = -intang;\r
+\r
+  prestep = GLOBAL1*((float)FOCALLENGTH/costable[firstangle]);\r
+\r
+//\r
+// misc stuff\r
+//\r
+  walls[0].x2 = VIEWX-1;\r
+  walls[0].height2 = 32000;\r
+}\r
+\r
+\r
+//==========================================================================\r
+\r
+/*\r
+=====================\r
+=\r
+= ClearScreen\r
+=\r
+=====================\r
+*/\r
+\r
+void ClearScreen (void)\r
+{\r
+  //\r
+  // clear the screen\r
+  //\r
+asm    mov     dx,GC_INDEX\r
+asm    mov     ax,GC_MODE + 256*2              // read mode 0, write mode 2\r
+asm    out     dx,ax\r
+asm    mov     ax,GC_BITMASK + 255*256\r
+asm    out     dx,ax\r
+\r
+asm    mov     dx,40-VIEWWIDTH/8\r
+asm    mov     bl,VIEWWIDTH/16\r
+asm    mov     bh,CENTERY+1\r
+\r
+asm    xor     ax,ax\r
+asm    mov     es,[screenseg]\r
+asm    mov     di,[bufferofs]\r
+\r
+toploop:\r
+asm    mov     cl,bl\r
+asm    rep     stosw\r
+asm    stosb\r
+asm    add     di,dx\r
+asm    dec     bh\r
+asm    jnz     toploop\r
+\r
+asm    mov     bh,CENTERY+1\r
+asm    mov     ax,0x0808\r
+\r
+bottomloop:\r
+asm    mov     cl,bl\r
+asm    rep     stosw\r
+asm    stosb\r
+asm    add     di,dx\r
+asm    dec     bh\r
+asm    jnz     bottomloop\r
+\r
+\r
+asm    mov     dx,GC_INDEX\r
+asm    mov     ax,GC_MODE + 256*10             // read mode 1, write mode 2\r
+asm    out     dx,ax\r
+asm    mov     al,GC_BITMASK\r
+asm    out     dx,al\r
+\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+=====================\r
+=\r
+= DrawWallList\r
+=\r
+= Clips and draws all the walls traced this refresh\r
+=\r
+=====================\r
+*/\r
+\r
+void DrawWallList (void)\r
+{\r
+       int i,leftx,newleft,rightclip;\r
+       walltype *wall, *check;\r
+\r
+asm    mov     ax,ds\r
+asm    mov     es,ax\r
+asm    mov     di,OFFSET wallwidth\r
+asm    xor     ax,ax\r
+asm    mov     cx,VIEWWIDTH/2\r
+asm    rep     stosw\r
+\r
+       ClearScreen ();\r
+\r
+       rightwall->x1 = VIEWXH+1;\r
+       rightwall->height1 = 32000;\r
+       (rightwall+1)->x1 = 32000;\r
+\r
+       leftx = -1;\r
+\r
+       for (wall=&walls[1];wall<rightwall && leftx<=VIEWXH ;wall++)\r
+       {\r
+         if (leftx >= wall->x2)\r
+               continue;\r
+\r
+         rightclip = wall->x2;\r
+\r
+         check = wall+1;\r
+         while (check->x1 <= rightclip && check->height1 >= wall->height2)\r
+         {\r
+               rightclip = check->x1-1;\r
+               check++;\r
+         }\r
+\r
+         if (rightclip>VIEWXH)\r
+               rightclip=VIEWXH;\r
+\r
+         if (leftx < wall->x1 - 1)\r
+               newleft = wall->x1-1;           // there was black space between walls\r
+         else\r
+               newleft = leftx;\r
+\r
+         if (rightclip > newleft)\r
+         {\r
+               wall->leftclip = newleft+1;\r
+               wall->rightclip = rightclip;\r
+               DrawVWall (wall);\r
+               leftx = rightclip;\r
+         }\r
+       }\r
+\r
+#ifndef DRAWEACH\r
+       ScaleWalls ();                                  // draw all the walls\r
+#endif\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+=====================\r
+=\r
+= DrawScaleds\r
+=\r
+= Draws all objects that are visable\r
+=\r
+=====================\r
+*/\r
+\r
+objtype *depthsort[MAXACTORS];\r
+\r
+void DrawScaleds (void)\r
+{\r
+       int             i,j,least,numvisable,height;\r
+       objtype         *obj,**vislist,*farthest;\r
+       memptr          shape;\r
+       byte            *tilespot,*visspot;\r
+\r
+       numvisable = 0;\r
+\r
+//\r
+// calculate base positions of all objects\r
+//\r
+       vislist = &depthsort[0];\r
+\r
+       for (obj = player->next;obj;obj=obj->next)\r
+       {\r
+               if (!obj->state->shapenum)\r
+                       continue;\r
+\r
+               tilespot = &tilemap[0][0]+(obj->tilex<<6)+obj->tiley;\r
+               visspot = &spotvis[0][0]+(obj->tilex<<6)+obj->tiley;\r
+               //\r
+               // could be in any of the nine surrounding tiles\r
+               //\r
+               if (*visspot\r
+               || ( *(visspot-1) && !*(tilespot-1) )\r
+               || ( *(visspot+1) && !*(tilespot+1) )\r
+               || ( *(visspot-65) && !*(tilespot-65) )\r
+               || ( *(visspot-64) && !*(tilespot-64) )\r
+               || ( *(visspot-63) && !*(tilespot-63) )\r
+               || ( *(visspot+65) && !*(tilespot+65) )\r
+               || ( *(visspot+64) && !*(tilespot+64) )\r
+               || ( *(visspot+63) && !*(tilespot+63) ) )\r
+               {\r
+                       obj->active = true;\r
+                       TransformActor (obj);\r
+                       if (!obj->viewheight || obj->viewheight > VIEWWIDTH)\r
+                               continue;                       // too close or far away\r
+\r
+                       *vislist++ = obj;\r
+                       numvisable++;\r
+               }\r
+       }\r
+\r
+       if (vislist == &depthsort[0])\r
+               return;                                         // no visable objects\r
+\r
+//\r
+// draw from back to front\r
+//\r
+       for (i = 0; i<numvisable; i++)\r
+       {\r
+               least = 32000;\r
+               for (j=0;j<numvisable;j++)\r
+               {\r
+                       height = depthsort[j]->viewheight;\r
+                       if (height < least)\r
+                       {\r
+                               least = height;\r
+                               farthest = depthsort[j];\r
+                       }\r
+               }\r
+               //\r
+               // draw farthest\r
+               //\r
+               shape = shapedirectory[farthest->state->shapenum-FIRSTSCALEPIC];\r
+               ScaleShape(farthest->viewx,shape,farthest->viewheight);\r
+               farthest->viewheight = 32000;\r
+       }\r
+}\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= CalcTics\r
+=\r
+=====================\r
+*/\r
+\r
+void CalcTics (void)\r
+{\r
+       long    newtime,oldtimecount;\r
+\r
+\r
+#ifdef PROFILE\r
+       tics = 1;\r
+       return;\r
+#endif\r
+\r
+//\r
+// calculate tics since last refresh for adaptive timing\r
+//\r
+       if (lasttimecount > TimeCount)\r
+               TimeCount = lasttimecount;              // if the game was paused a LONG time\r
+\r
+       if (DemoMode)                                   // demo recording and playback needs\r
+       {                                                               // to be constant\r
+//\r
+// take DEMOTICS or more tics, and modify Timecount to reflect time taken\r
+//\r
+               oldtimecount = lasttimecount;\r
+               while (TimeCount<oldtimecount+DEMOTICS*2)\r
+               ;\r
+               lasttimecount = oldtimecount + DEMOTICS;\r
+               TimeCount = lasttimecount + DEMOTICS;\r
+               tics = DEMOTICS;\r
+       }\r
+       else\r
+       {\r
+//\r
+// non demo, so report actual time\r
+//\r
+               newtime = TimeCount;\r
+               tics = newtime-lasttimecount;\r
+               lasttimecount = newtime;\r
+\r
+#ifdef FILEPROFILE\r
+                       strcpy (scratch,"\tTics:");\r
+                       itoa (tics,str,10);\r
+                       strcat (scratch,str);\r
+                       strcat (scratch,"\n");\r
+                       write (profilehandle,scratch,strlen(scratch));\r
+#endif\r
+\r
+               if (tics>MAXTICS)\r
+               {\r
+                       TimeCount -= (tics-MAXTICS);\r
+                       tics = MAXTICS;\r
+               }\r
+       }\r
+}\r
+\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+========================\r
+=\r
+= DrawHand\r
+=\r
+========================\r
+*/\r
+\r
+void   DrawHand (void)\r
+{\r
+       int     picnum;\r
+       memptr source;\r
+       unsigned dest,width,height;\r
+\r
+       picnum = HAND1PICM;\r
+       if (gamestate.shotpower || boltsleft)\r
+               picnum += (((unsigned)TimeCount>>3)&1);\r
+\r
+       source = grsegs[picnum];\r
+       dest = ylookup[VIEWHEIGHT-handheight]+12+bufferofs;\r
+       width = picmtable[picnum-STARTPICM].width;\r
+       height = picmtable[picnum-STARTPICM].height;\r
+\r
+       VW_MaskBlock(source,0,dest,width,handheight,width*height);\r
+       EGAMAPMASK(15);\r
+}\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+========================\r
+=\r
+= ThreeDRefresh\r
+=\r
+========================\r
+*/\r
+\r
+void   ThreeDRefresh (void)\r
+{\r
+       int tracedir;\r
+\r
+restart:\r
+       aborttrace = false;\r
+\r
+//\r
+// clear out the traced array\r
+//\r
+asm    mov     ax,ds\r
+asm    mov     es,ax\r
+asm    mov     di,OFFSET spotvis\r
+asm    xor     ax,ax\r
+asm    mov     cx,[mapwidth]           // mapheight*32 words\r
+asm    shl     cx,1\r
+asm    shl     cx,1\r
+asm    shl     cx,1\r
+asm    shl     cx,1\r
+asm    shl     cx,1\r
+asm    rep stosw\r
+\r
+\r
+//\r
+// set up variables for this view\r
+//\r
+\r
+       viewangle = player->angle;\r
+       fineviewangle = viewangle*(FINEANGLES/ANGLES);\r
+       viewsin = sintable[viewangle];\r
+       viewcos = costable[viewangle];\r
+       viewx = player->x - FixedByFrac(FOCALLENGTH,viewcos);\r
+       viewy = player->y + FixedByFrac(FOCALLENGTH,viewsin);\r
+       viewx &= 0xfffffc00;            // stop on a pixel boundary\r
+       viewy &= 0xfffffc00;\r
+       viewx += 0x180;\r
+       viewy += 0x180;\r
+       viewxpix = viewx>>10;\r
+       viewypix = viewy>>10;\r
+\r
+       focal.x = viewx>>TILESHIFT;\r
+       focal.y = viewy>>TILESHIFT;\r
+\r
+//\r
+// find the rightmost visable tile in view\r
+//\r
+       tracedir = viewangle + lastangle;\r
+       if (tracedir<0)\r
+         tracedir+=ANGLES;\r
+       else if (tracedir>=ANGLES)\r
+         tracedir-=ANGLES;\r
+       TraceRay( tracedir );\r
+       right.x = tile.x;\r
+       right.y = tile.y;\r
+\r
+//\r
+// find the leftmost visable tile in view\r
+//\r
+       tracedir = viewangle + firstangle;\r
+       if (tracedir<0)\r
+         tracedir+=ANGLES;\r
+       else if (tracedir>=ANGLES)\r
+         tracedir-=ANGLES;\r
+       TraceRay( tracedir );\r
+\r
+//\r
+// follow the walls from there to the right\r
+//\r
+       rightwall = &walls[1];\r
+       FollowWalls ();\r
+\r
+       if (aborttrace)\r
+               goto restart;\r
+\r
+//\r
+// actually draw stuff\r
+//\r
+       if (++screenpage == 3)\r
+               screenpage = 0;\r
+\r
+       bufferofs = screenloc[screenpage];\r
+\r
+       EGAWRITEMODE(2);\r
+       EGAMAPMASK(15);\r
+\r
+//\r
+// draw the wall list saved be FollowWalls ()\r
+//\r
+       animframe = (TimeCount&8)>>3;\r
+\r
+//\r
+// draw all the scaled images\r
+//\r
+       asm     mov     dx,GC_INDEX\r
+\r
+       asm     mov     ax,GC_COLORDONTCARE\r
+       asm     out     dx,ax                                           // don't look at any of the planes\r
+\r
+       asm     mov     ax,GC_MODE + 256*(10)           // read mode 1, write mode 2\r
+       asm     out     dx,ax\r
+\r
+       asm     mov     al,GC_BITMASK\r
+       asm     out     dx,al\r
+\r
+       DrawWallList();\r
+       DrawScaleds();\r
+\r
+       EGAWRITEMODE(0);\r
+       EGABITMASK(0xff);\r
+\r
+//\r
+// draw hand\r
+//\r
+       if (handheight)\r
+               DrawHand ();\r
+\r
+//\r
+// show screen and time last cycle\r
+//\r
+       if (fizzlein)\r
+       {\r
+               fizzlein = false;\r
+               FizzleFade(bufferofs,displayofs,VIEWWIDTH,VIEWHEIGHT,true);\r
+               lasttimecount = TimeCount;\r
+               if (MousePresent) Mouse(MDelta);        // Clear accumulated mouse movement\r
+       }\r
+\r
+asm    cli\r
+asm    mov     cx,[bufferofs]\r
+asm    mov     dx,3d4h         // CRTC address register\r
+asm    mov     al,0ch          // start address high register\r
+asm    out     dx,al\r
+asm    inc     dx\r
+asm    mov     al,ch\r
+asm    out     dx,al           // set the high byte\r
+asm    dec     dx\r
+asm    mov     al,0dh          // start address low register\r
+asm    out     dx,al\r
+asm    inc     dx\r
+asm    mov     al,cl\r
+asm    out     dx,al           // set the low byte\r
+asm    sti\r
+\r
+       displayofs = bufferofs;\r
+\r
+       CalcTics ();\r
+\r
+}\r
+\r
diff --git a/C3_GAME.C b/C3_GAME.C
new file mode 100644 (file)
index 0000000..a71d254
--- /dev/null
+++ b/C3_GAME.C
@@ -0,0 +1,1199 @@
+/* Catacomb 3-D 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 "C3_DEF.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        25\r
+\r
+#define CONTROLSLUMP    0\r
+#define ORCLUMP         1\r
+#define TROLLLUMP        2\r
+#define WARPLUMP        3\r
+#define BOLTLUMP        4\r
+#define NUKELUMP        5\r
+#define POTIONLUMP      6\r
+#define RKEYLUMP        7\r
+#define YKEYLUMP        8\r
+#define GKEYLUMP        9\r
+#define BKEYLUMP        10\r
+#define SCROLLLUMP      11\r
+#define CHESTLUMP       12\r
+#define PLAYERLUMP      13\r
+#define WALL1LUMP       14\r
+#define WALL2LUMP       15\r
+#define BDOORLUMP       16\r
+#define DEMONLUMP               17\r
+#define MAGELUMP                18\r
+#define BATLUMP                 19\r
+#define GRELLUMP                20\r
+#define GOALLUMP                21\r
+\r
+\r
+int     lumpstart[NUMLUMPS] = {\r
+CONTROLS_LUMP_START,\r
+ORC_LUMP_START,\r
+TROLL_LUMP_START,\r
+WARP_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
+SCROLL_LUMP_START,\r
+CHEST_LUMP_START,\r
+PLAYER_LUMP_START,\r
+WALL1_LUMP_START,\r
+WALL2_LUMP_START,\r
+BDOOR_LUMP_START,\r
+DEMON_LUMP_START,\r
+MAGE_LUMP_START,\r
+BAT_LUMP_START,\r
+GREL_LUMP_START,\r
+NEMESISPIC\r
+};\r
+\r
+\r
+int     lumpend[NUMLUMPS] = {\r
+CONTROLS_LUMP_END,\r
+ORC_LUMP_END,\r
+TROLL_LUMP_END,\r
+WARP_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
+SCROLL_LUMP_END,\r
+CHEST_LUMP_END,\r
+PLAYER_LUMP_END,\r
+WALL1_LUMP_END,\r
+WALL2_LUMP_END,\r
+BDOOR_LUMP_END,\r
+DEMON_LUMP_END,\r
+MAGE_LUMP_END,\r
+BAT_LUMP_END,\r
+GREL_LUMP_END,\r
+NEMESISPIC\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
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+boolean lumpneeded[NUMLUMPS];\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        x,y,i,j;\r
+       int                     tile;\r
+       unsigned        far     *start;\r
+\r
+       InitObjList();                  // start spawning things with a clean slate\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
+                       if (!tile)\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
+                       case 13:\r
+                       case 14:\r
+                       case 15:\r
+                       case 16:\r
+                       case 17:\r
+                       case 18:\r
+                       case 19:\r
+                               lumpneeded[SCROLLLUMP] = true;\r
+                               SpawnBonus(x,y,B_SCROLL1+tile-12);\r
+                               break;\r
+\r
+                       case 20:        // goal\r
+                               lumpneeded[GOALLUMP] = true;\r
+                               SpawnBonus(x,y,B_GOAL);\r
+                               break;\r
+\r
+                       case 21:        // chest\r
+                               lumpneeded[CHESTLUMP] = true;\r
+                               SpawnBonus(x,y,B_CHEST);\r
+                               break;\r
+\r
+                       case 24:\r
+                               lumpneeded[WARPLUMP] = true;\r
+                               SpawnWarp (x,y,0);\r
+                               break;\r
+//------\r
+                       case 41:\r
+                               if (gamestate.difficulty <gd_Hard)\r
+                                       break;\r
+                       case 36:\r
+                               if (gamestate.difficulty <gd_Normal)\r
+                                       break;\r
+                       case 22:\r
+                               lumpneeded[TROLLLUMP] = true;\r
+                               SpawnTroll (x,y);\r
+                               break;\r
+\r
+                       case 42:\r
+                               if (gamestate.difficulty <gd_Hard)\r
+                                       break;\r
+                       case 37:\r
+                               if (gamestate.difficulty <gd_Normal)\r
+                                       break;\r
+                       case 23:\r
+                               lumpneeded[ORCLUMP] = true;\r
+                               SpawnOrc (x,y);\r
+                               break;\r
+\r
+                       case 43:\r
+                               if (gamestate.difficulty <gd_Hard)\r
+                                       break;\r
+                       case 38:\r
+                               if (gamestate.difficulty <gd_Normal)\r
+                                       break;\r
+                       case 25:\r
+                               lumpneeded[BATLUMP] = true;\r
+                               SpawnBat (x,y);\r
+                               break;\r
+\r
+                       case 44:\r
+                               if (gamestate.difficulty <gd_Hard)\r
+                                       break;\r
+                       case 39:\r
+                               if (gamestate.difficulty <gd_Normal)\r
+                                       break;\r
+                       case 26:\r
+                               lumpneeded[DEMONLUMP] = true;\r
+                               SpawnDemon (x,y);\r
+                               break;\r
+\r
+                       case 45:\r
+                               if (gamestate.difficulty <gd_Hard)\r
+                                       break;\r
+                       case 40:\r
+                               if (gamestate.difficulty <gd_Normal)\r
+                                       break;\r
+                       case 27:\r
+                               lumpneeded[MAGELUMP] = true;\r
+                               SpawnMage (x,y);\r
+                               break;\r
+\r
+                       case 28:\r
+                               lumpneeded[GRELLUMP] = true;\r
+                               SpawnNemesis (x,y);\r
+                               break;\r
+\r
+                       case 29:\r
+                               SpawnBounce (x,y,0);\r
+                               break;\r
+\r
+                       case 30:\r
+                               SpawnBounce (x,y,1);\r
+                               break;\r
+\r
+                       case 31:\r
+                       case 32:\r
+                       case 33:\r
+                       case 34:\r
+                               lumpneeded[WARPLUMP] = true;\r
+                               SpawnWarp (x,y,tile-30);\r
+                               break;\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
+\r
+static  char    *levelnames[] =\r
+                               {\r
+                                       "The Approach",\r
+                                       "Nemesis's Keep",\r
+                                       "Ground Floor",\r
+                                       "Second Floor",\r
+                                       "Third Floor",\r
+                                       "Tower One",\r
+                                       "Tower Two",\r
+                                       "Secret Halls",\r
+                                       "Access Floor",\r
+                                       "The Dungeon",\r
+                                       "Lower Dungeon",\r
+                                       "Catacomb",\r
+                                       "Lower Reaches",\r
+                                       "The Warrens",\r
+                                       "Hidden Caverns",\r
+                                       "The Fens of Insanity",\r
+                                       "Chaos Corridors",\r
+                                       "The Labyrinth",\r
+                                       "Halls of Blood",\r
+                                       "Nemesis's Lair"\r
+                               };\r
+void DrawEnterScreen (void)\r
+{\r
+       int     x,y;\r
+\r
+       VW_Bar(0,0,VIEWWIDTH,VIEWHEIGHT,9);     // Medium blue\r
+\r
+       x = (VIEWWIDTH - (18 * 8)) / 2 -3;\r
+       y = (VIEWHEIGHT - (5 * 8)) / 2;\r
+       VW_DrawPic(x / 8,y,ENTERPLAQUEPIC);\r
+\r
+       WindowX = x;\r
+       WindowW = 18 * 8;\r
+       PrintY = (VIEWHEIGHT/2) + 3;\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 (walllight2[i]);\r
+                       SetupScaleWall (walldark1[i]);\r
+                       SetupScaleWall (walldark2[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
+= SetupGameLevel\r
+=\r
+==================\r
+*/\r
+\r
+void SetupGameLevel (void)\r
+{\r
+       int     x,y,i;\r
+       unsigned        far *map,tile,spot;\r
+\r
+       memset (tileneeded,0,sizeof(tileneeded));\r
+//\r
+// randomize if not a demo\r
+//\r
+       if (DemoMode)\r
+       {\r
+               US_InitRndT(false);\r
+               gamestate.difficulty = gd_Normal;\r
+       }\r
+       else\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
+// 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
+       for (y=0;y<mapheight;y++)\r
+               for (x=0;x<mapwidth;x++)\r
+               {\r
+                       tile = *map++;\r
+                       if (tile<NUMFLOORS)\r
+                       {\r
+                               tileneeded[tile] = true;\r
+                               tilemap[x][y] = tile;\r
+                               if (tile>=EXPWALLSTART && tile<EXPWALLSTART+NUMEXPWALLS)\r
+                               {\r
+                                       tileneeded[WALLEXP] = tileneeded[WALLEXP+1]\r
+                                       = tileneeded[WALLEXP+2] = true;\r
+                               }\r
+\r
+                               if (tile>0)\r
+                                       (unsigned)actorat[x][y] = tile;\r
+                       }\r
+               }\r
+\r
+\r
+//\r
+// decide which graphics are needed and spawn actors\r
+//\r
+       ScanInfoPlane ();\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
+=====================\r
+=\r
+= LatchDrawPic\r
+=\r
+=====================\r
+*/\r
+\r
+void LatchDrawPic (unsigned x, unsigned y, unsigned picnum)\r
+{\r
+       unsigned wide, height, source, dest;\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
+\r
+//==========================================================================\r
+\r
+/*\r
+=====================\r
+=\r
+= Victory\r
+=\r
+=====================\r
+*/\r
+\r
+void Victory (void)\r
+{\r
+       FreeUpMemory ();\r
+       NormalScreen ();\r
+       CA_CacheGrChunk (FINALEPIC);\r
+       VWB_DrawPic (0,0,FINALEPIC);\r
+       UNMARKGRCHUNK(FINALEPIC);\r
+       VW_UpdateScreen ();\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
+       SD_WaitSoundDone ();\r
+       IN_ClearKeysDown ();\r
+       IN_Ack();\r
+}\r
+\r
+//==========================================================================\r
+\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
+       LatchDrawPic(0,0,DEADPIC);\r
+       FizzleFade(bufferofs,displayofs,VIEWWIDTH,VIEWHEIGHT,false);\r
+       IN_ClearKeysDown();\r
+       IN_Ack();\r
+       VW_SetScreen (bufferofs,0);\r
+}\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
+}\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,7);\r
+       for (i=0;i<3;i++)\r
+       {\r
+               bufferofs = screenloc[i];\r
+               VW_Bar (0,0,320,VIEWHEIGHT,7);\r
+       }\r
+\r
+\r
+       VW_SetSplitScreen(144);\r
+       VW_SetScreen(screenloc[0],0);\r
+       bufferofs = 0;\r
+\r
+       CA_CacheGrChunk (STATUSPIC);\r
+       CA_CacheGrChunk (SIDEBARSPIC);\r
+\r
+       VW_DrawPic (0,0,STATUSPIC);\r
+\r
+       for (i=0;i<3;i++)\r
+       {\r
+               bufferofs = screenloc[i];\r
+               VW_DrawPic (33,0,SIDEBARSPIC);\r
+       }\r
+\r
+       grneeded[STATUSPIC]&= ~ca_levelbit;\r
+       grneeded[SIDEBARSPIC]&= ~ca_levelbit;\r
+       MM_SetPurge(&grsegs[STATUSPIC],3);\r
+       MM_SetPurge(&grsegs[SIDEBARSPIC],3);\r
+\r
+       RedrawStatusWindow ();\r
+       bufferofs = displayofs = screenloc[0];\r
+}\r
+\r
+\r
+//==========================================================================\r
+\r
+/*\r
+===================\r
+=\r
+= LoadLatchMem\r
+=\r
+===================\r
+*/\r
+\r
+void LoadLatchMem (void)\r
+{\r
+       int     i,j,p,m;\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
+//\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
+       destoff = FP_OFF(dest);\r
+       for (i=FIRSTLATCHPIC+1;i<FIRSTSCALEPIC;i++)\r
+       {\r
+               latchpics[i-FIRSTLATCHPIC] = 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
+       EGAMAPMASK(15);\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+===================\r
+=\r
+= FizzleFade\r
+=\r
+===================\r
+*/\r
+\r
+#define PIXPERFRAME     1600\r
+\r
+void FizzleFade (unsigned source, unsigned dest,\r
+       unsigned width,unsigned height, boolean abortable)\r
+{\r
+       unsigned        drawofs,pagedelta;\r
+       unsigned        char maskb[8] = {1,2,4,8,16,32,64,128};\r
+       unsigned        x,y,p,frame;\r
+       long            rndval;\r
+\r
+       pagedelta = dest-source;\r
+       VW_SetScreen (dest,0);\r
+       rndval = 1;\r
+       y = 0;\r
+\r
+asm     mov     es,[screenseg]\r
+asm     mov     dx,SC_INDEX\r
+asm     mov     al,SC_MAPMASK\r
+asm     out     dx,al\r
+\r
+       TimeCount=frame=0;\r
+       do      // while (1)\r
+       {\r
+               if (abortable)\r
+               {\r
+                       IN_ReadControl(0,&c);\r
+                       if (c.button0 || c.button1 || Keyboard[sc_Space]\r
+                       || Keyboard[sc_Enter])\r
+                       {\r
+                               VW_ScreenToScreen (source,dest,width/8,height);\r
+                               return;\r
+                       }\r
+               }\r
+\r
+               for (p=0;p<PIXPERFRAME;p++)\r
+               {\r
+                       //\r
+                       // seperate random value into x/y pair\r
+                       //\r
+                       asm     mov     ax,[WORD PTR rndval]\r
+                       asm     mov     dx,[WORD PTR rndval+2]\r
+                       asm     mov     bx,ax\r
+                       asm     dec     bl\r
+                       asm     mov     [BYTE PTR y],bl                 // low 8 bits - 1 = y xoordinate\r
+                       asm     mov     bx,ax\r
+                       asm     mov     cx,dx\r
+                       asm     shr     cx,1\r
+                       asm     rcr     bx,1\r
+                       asm     shr     bx,1\r
+                       asm     shr     bx,1\r
+                       asm     shr     bx,1\r
+                       asm     shr     bx,1\r
+                       asm     shr     bx,1\r
+                       asm     shr     bx,1\r
+                       asm     shr     bx,1\r
+                       asm     mov     [x],bx                                  // next 9 bits = x xoordinate\r
+                       //\r
+                       // advance to next random element\r
+                       //\r
+                       asm     shr     dx,1\r
+                       asm     rcr     ax,1\r
+                       asm     jnc     noxor\r
+                       asm     xor     dx,0x0001\r
+                       asm     xor     ax,0x2000\r
+noxor:\r
+                       asm     mov     [WORD PTR rndval],ax\r
+                       asm     mov     [WORD PTR rndval+2],dx\r
+\r
+                       if (x>width || y>height)\r
+                               continue;\r
+                       drawofs = source+ylookup[y];\r
+\r
+                       asm     mov     cx,[x]\r
+                       asm     mov     si,cx\r
+                       asm     and     si,7\r
+                       asm     mov dx,GC_INDEX\r
+                       asm     mov al,GC_BITMASK\r
+                       asm     mov     ah,BYTE PTR [maskb+si]\r
+                       asm     out dx,ax\r
+\r
+                       asm     mov     si,[drawofs]\r
+                       asm     shr     cx,1\r
+                       asm     shr     cx,1\r
+                       asm     shr     cx,1\r
+                       asm     add     si,cx\r
+                       asm     mov     di,si\r
+                       asm     add     di,[pagedelta]\r
+\r
+                       asm     mov     dx,GC_INDEX\r
+                       asm     mov     al,GC_READMAP                   // leave GC_INDEX set to READMAP\r
+                       asm     out     dx,al\r
+\r
+                       asm     mov     dx,SC_INDEX+1\r
+                       asm     mov     al,1\r
+                       asm     out     dx,al\r
+                       asm     mov     dx,GC_INDEX+1\r
+                       asm     mov     al,0\r
+                       asm     out     dx,al\r
+\r
+                       asm     mov     bl,[es:si]\r
+                       asm     xchg [es:di],bl\r
+\r
+                       asm     mov     dx,SC_INDEX+1\r
+                       asm     mov     al,2\r
+                       asm     out     dx,al\r
+                       asm     mov     dx,GC_INDEX+1\r
+                       asm     mov     al,1\r
+                       asm     out     dx,al\r
+\r
+                       asm     mov     bl,[es:si]\r
+                       asm     xchg [es:di],bl\r
+\r
+                       asm     mov     dx,SC_INDEX+1\r
+                       asm     mov     al,4\r
+                       asm     out     dx,al\r
+                       asm     mov     dx,GC_INDEX+1\r
+                       asm     mov     al,2\r
+                       asm     out     dx,al\r
+\r
+                       asm     mov     bl,[es:si]\r
+                       asm     xchg [es:di],bl\r
+\r
+                       asm     mov     dx,SC_INDEX+1\r
+                       asm     mov     al,8\r
+                       asm     out     dx,al\r
+                       asm     mov     dx,GC_INDEX+1\r
+                       asm     mov     al,3\r
+                       asm     out     dx,al\r
+\r
+                       asm     mov     bl,[es:si]\r
+                       asm     xchg [es:di],bl\r
+\r
+                       if (rndval == 1)                // entire sequence has been completed\r
+                       {\r
+                               EGABITMASK(255);\r
+                               EGAMAPMASK(15);\r
+                               return;\r
+                       };\r
+               }\r
+               frame++;\r
+               while (TimeCount<frame)         // don't go too fast\r
+               ;\r
+       } while (1);\r
+\r
+\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
+/*\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
+\r
+//==========================================================================\r
+\r
+/*\r
+===================\r
+=\r
+= GameLoop\r
+=\r
+===================\r
+*/\r
+\r
+void GameLoop (void)\r
+{\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
+\r
+restart:\r
+       if (!loadedgame)\r
+       {\r
+               gamestate.difficulty = restartgame;\r
+               restartgame = gd_Continue;\r
+               DrawEnterScreen ();\r
+       }\r
+\r
+       do\r
+       {\r
+               playstate = gd_Continue;\r
+               if (!loadedgame)\r
+                       SetupGameLevel ();\r
+               else\r
+                       loadedgame = false;\r
+\r
+               CacheScaleds ();\r
+\r
+#ifdef PROFILE\r
+start = clock();\r
+while (start == clock());\r
+start++;\r
+#endif\r
+               PlayLoop ();\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_died:\r
+                       Died ();\r
+                       NormalScreen ();\r
+                       FreeUpMemory ();\r
+                       CheckHighScore (gamestate.score,gamestate.mapon+1);\r
+                       return;\r
+               case ex_warped:\r
+                       FizzleOut (true);\r
+                       if (gamestate.mapon >= NUMLEVELS)\r
+                       {\r
+                               Victory ();\r
+                               FreeUpMemory ();\r
+                               CheckHighScore(gamestate.score,gamestate.mapon+1);\r
+                               return;\r
+                       }\r
+                       break;\r
+               case ex_abort:\r
+                       FreeUpMemory ();\r
+                       return;\r
+               case ex_resetgame:\r
+               case ex_loadedgame:\r
+                       goto restart;\r
+               case ex_victorious:\r
+                       Victory ();\r
+                       FreeUpMemory();\r
+                       CheckHighScore(gamestate.score,gamestate.mapon+1);\r
+                       return;\r
+               }\r
+\r
+       } while (1);\r
+\r
+}\r
diff --git a/C3_MAIN.C b/C3_MAIN.C
new file mode 100644 (file)
index 0000000..684cb32
--- /dev/null
+++ b/C3_MAIN.C
@@ -0,0 +1,756 @@
+/* Catacomb 3-D 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_MAIN.C\r
+\r
+#include "C3_DEF.H"\r
+#pragma hdrstop\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                  CATACOMB 3-D\r
+\r
+                                         An Id Software production\r
+\r
+                                                  by John Carmack\r
+\r
+=============================================================================\r
+*/\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                GLOBAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+memptr         scalesegs[NUMPICS];\r
+char           str[80],str2[20];\r
+unsigned       tedlevelnum;\r
+boolean                tedlevel;\r
+gametype       gamestate;\r
+exittype       playstate;\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+\r
+//===========================================================================\r
+\r
+// JAB Hack begin\r
+#define        MyInterrupt     0x60\r
+void interrupt (*intaddr)();\r
+void interrupt (*oldintaddr)();\r
+       char    *JHParmStrings[] = {"no386",nil};\r
+\r
+void\r
+jabhack(void)\r
+{\r
+extern void far jabhack2(void);\r
+extern int far CheckIs386(void);\r
+\r
+       int     i;\r
+\r
+       oldintaddr = getvect(MyInterrupt);\r
+\r
+       for (i = 1;i < _argc;i++)\r
+               if (US_CheckParm(_argv[i],JHParmStrings) == 0)\r
+                       return;\r
+\r
+       if (CheckIs386())\r
+       {\r
+               jabhack2();\r
+               setvect(MyInterrupt,intaddr);\r
+       }\r
+}\r
+\r
+void\r
+jabunhack(void)\r
+{\r
+       setvect(MyInterrupt,oldintaddr);\r
+}\r
+//     JAB Hack end\r
+\r
+//===========================================================================\r
+\r
+/*\r
+=====================\r
+=\r
+= NewGame\r
+=\r
+= Set up new game to start from the beginning\r
+=\r
+=====================\r
+*/\r
+\r
+void NewGame (void)\r
+{\r
+       memset (&gamestate,0,sizeof(gamestate));\r
+       gamestate.mapon = 0;\r
+       gamestate.body = MAXBODY;\r
+}\r
+\r
+//===========================================================================\r
+\r
+#define RLETAG 0xABCD\r
+\r
+/*\r
+==================\r
+=\r
+= SaveTheGame\r
+=\r
+==================\r
+*/\r
+\r
+boolean        SaveTheGame(int file)\r
+{\r
+       word    i,compressed,expanded;\r
+       objtype *o;\r
+       memptr  bigbuffer;\r
+\r
+       if (!CA_FarWrite(file,(void far *)&gamestate,sizeof(gamestate)))\r
+               return(false);\r
+\r
+       expanded = mapwidth * mapheight * 2;\r
+       MM_GetPtr (&bigbuffer,expanded);\r
+\r
+       for (i = 0;i < 3;i+=2)  // Write planes 0 and 2\r
+       {\r
+//\r
+// leave a word at start of compressed data for compressed length\r
+//\r
+               compressed = (unsigned)CA_RLEWCompress ((unsigned huge *)mapsegs[i]\r
+                       ,expanded,((unsigned huge *)bigbuffer)+1,RLETAG);\r
+\r
+               *(unsigned huge *)bigbuffer = compressed;\r
+\r
+               if (!CA_FarWrite(file,(void far *)bigbuffer,compressed+2) )\r
+               {\r
+                       MM_FreePtr (&bigbuffer);\r
+                       return(false);\r
+               }\r
+       }\r
+\r
+       for (o = player;o;o = o->next)\r
+               if (!CA_FarWrite(file,(void far *)o,sizeof(objtype)))\r
+               {\r
+                       MM_FreePtr (&bigbuffer);\r
+                       return(false);\r
+               }\r
+\r
+       MM_FreePtr (&bigbuffer);\r
+\r
+       return(true);\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+==================\r
+=\r
+= LoadTheGame\r
+=\r
+==================\r
+*/\r
+\r
+boolean        LoadTheGame(int file)\r
+{\r
+       unsigned        i,x,y;\r
+       objtype         *obj,*prev,*next,*followed;\r
+       unsigned        compressed,expanded;\r
+       unsigned        far *map,tile;\r
+       memptr          bigbuffer;\r
+\r
+       if (!CA_FarRead(file,(void far *)&gamestate,sizeof(gamestate)))\r
+               return(false);\r
+\r
+       SetupGameLevel ();              // load in and cache the base old level\r
+\r
+       expanded = mapwidth * mapheight * 2;\r
+       MM_GetPtr (&bigbuffer,expanded);\r
+\r
+       for (i = 0;i < 3;i+=2)  // Read planes 0 and 2\r
+       {\r
+               if (!CA_FarRead(file,(void far *)&compressed,sizeof(compressed)) )\r
+               {\r
+                       MM_FreePtr (&bigbuffer);\r
+                       return(false);\r
+               }\r
+\r
+               if (!CA_FarRead(file,(void far *)bigbuffer,compressed) )\r
+               {\r
+                       MM_FreePtr (&bigbuffer);\r
+                       return(false);\r
+               }\r
+\r
+               CA_RLEWexpand ((unsigned huge *)bigbuffer,\r
+                       (unsigned huge *)mapsegs[i],expanded,RLETAG);\r
+       }\r
+\r
+       MM_FreePtr (&bigbuffer);\r
+//\r
+// copy the wall data to a data segment array again, to handle doors and\r
+// bomb walls that are allready opened\r
+//\r
+       memset (tilemap,0,sizeof(tilemap));\r
+       memset (actorat,0,sizeof(actorat));\r
+       map = mapsegs[0];\r
+       for (y=0;y<mapheight;y++)\r
+               for (x=0;x<mapwidth;x++)\r
+               {\r
+                       tile = *map++;\r
+                       if (tile<NUMFLOORS)\r
+                       {\r
+                               tilemap[x][y] = tile;\r
+                               if (tile>0)\r
+                                       (unsigned)actorat[x][y] = tile;\r
+                       }\r
+               }\r
+\r
+\r
+       // Read the object list back in - assumes at least one object in list\r
+\r
+       InitObjList ();\r
+       new = player;\r
+       while (true)\r
+       {\r
+               prev = new->prev;\r
+               next = new->next;\r
+               if (!CA_FarRead(file,(void far *)new,sizeof(objtype)))\r
+                       return(false);\r
+               followed = new->next;\r
+               new->prev = prev;\r
+               new->next = next;\r
+               actorat[new->tilex][new->tiley] = new;  // drop a new marker\r
+\r
+               if (followed)\r
+                       GetNewObj (false);\r
+               else\r
+                       break;\r
+       }\r
+\r
+       return(true);\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+==================\r
+=\r
+= ResetGame\r
+=\r
+==================\r
+*/\r
+\r
+void ResetGame(void)\r
+{\r
+       NewGame ();\r
+\r
+       ca_levelnum--;\r
+       ca_levelbit>>=1;\r
+       CA_ClearMarks();\r
+       ca_levelbit<<=1;\r
+       ca_levelnum++;\r
+}\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+==========================\r
+=\r
+= ShutdownId\r
+=\r
+= Shuts down all ID_?? managers\r
+=\r
+==========================\r
+*/\r
+\r
+void ShutdownId (void)\r
+{\r
+  US_Shutdown ();\r
+#ifndef PROFILE\r
+  SD_Shutdown ();\r
+  IN_Shutdown ();\r
+#endif\r
+  VW_Shutdown ();\r
+  CA_Shutdown ();\r
+  MM_Shutdown ();\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+==========================\r
+=\r
+= InitGame\r
+=\r
+= Load a few things right away\r
+=\r
+==========================\r
+*/\r
+\r
+void InitGame (void)\r
+{\r
+       unsigned        segstart,seglength;\r
+       int                     i,x,y;\r
+       unsigned        *blockstart;\r
+\r
+//     US_TextScreen();\r
+\r
+       MM_Startup ();\r
+       VW_Startup ();\r
+#ifndef PROFILE\r
+       IN_Startup ();\r
+       SD_Startup ();\r
+#endif\r
+       US_Startup ();\r
+\r
+//     US_UpdateTextScreen();\r
+\r
+       CA_Startup ();\r
+       US_Setup ();\r
+\r
+       US_SetLoadSaveHooks(LoadTheGame,SaveTheGame,ResetGame);\r
+\r
+//\r
+// load in and lock down some basic chunks\r
+//\r
+\r
+       CA_ClearMarks ();\r
+\r
+       CA_MarkGrChunk(STARTFONT);\r
+       CA_MarkGrChunk(STARTTILE8);\r
+       CA_MarkGrChunk(STARTTILE8M);\r
+       CA_MarkGrChunk(HAND1PICM);\r
+       CA_MarkGrChunk(HAND2PICM);\r
+       CA_MarkGrChunk(ENTERPLAQUEPIC);\r
+\r
+       CA_CacheMarks (NULL);\r
+\r
+       MM_SetLock (&grsegs[STARTFONT],true);\r
+       MM_SetLock (&grsegs[STARTTILE8],true);\r
+       MM_SetLock (&grsegs[STARTTILE8M],true);\r
+       MM_SetLock (&grsegs[HAND1PICM],true);\r
+       MM_SetLock (&grsegs[HAND2PICM],true);\r
+       MM_SetLock (&grsegs[ENTERPLAQUEPIC],true);\r
+\r
+       fontcolor = WHITE;\r
+\r
+\r
+//\r
+// build some tables\r
+//\r
+       for (i=0;i<MAPSIZE;i++)\r
+               nearmapylookup[i] = &tilemap[0][0]+MAPSIZE*i;\r
+\r
+       for (i=0;i<PORTTILESHIGH;i++)\r
+               uwidthtable[i] = UPDATEWIDE*i;\r
+\r
+       blockstart = &blockstarts[0];\r
+       for (y=0;y<UPDATEHIGH;y++)\r
+               for (x=0;x<UPDATEWIDE;x++)\r
+                       *blockstart++ = SCREENWIDTH*16*y+x*TILEWIDTH;\r
+\r
+       BuildTables ();                 // 3-d tables\r
+\r
+       SetupScaling ();\r
+\r
+#ifndef PROFILE\r
+//     US_FinishTextScreen();\r
+#endif\r
+\r
+//\r
+// reclaim the memory from the linked in text screen\r
+//\r
+       segstart = FP_SEG(&introscn);\r
+       seglength = 4000/16;\r
+       if (FP_OFF(&introscn))\r
+       {\r
+               segstart++;\r
+               seglength--;\r
+       }\r
+\r
+       MML_UseSpace (segstart,seglength);\r
+\r
+       VW_SetScreenMode (GRMODE);\r
+       VW_ColorBorder (3);\r
+       VW_ClearVideo (BLACK);\r
+\r
+//\r
+// initialize variables\r
+//\r
+       updateptr = &update[0];\r
+       *(unsigned *)(updateptr + UPDATEWIDE*PORTTILESHIGH) = UPDATETERMINATE;\r
+       bufferofs = 0;\r
+       displayofs = 0;\r
+       VW_SetLineWidth(SCREENWIDTH);\r
+}\r
+\r
+//===========================================================================\r
+\r
+void clrscr (void);            // can't include CONIO.H because of name conflicts...\r
+\r
+/*\r
+==========================\r
+=\r
+= Quit\r
+=\r
+==========================\r
+*/\r
+\r
+void Quit (char *error)\r
+{\r
+       unsigned        finscreen;\r
+\r
+#if 0\r
+       if (!error)\r
+       {\r
+               CA_SetAllPurge ();\r
+               CA_CacheGrChunk (PIRACY);\r
+               finscreen = (unsigned)grsegs[PIRACY];\r
+       }\r
+#endif\r
+\r
+       ShutdownId ();\r
+       if (error && *error)\r
+       {\r
+         puts(error);\r
+         exit(1);\r
+       }\r
+\r
+#if 0\r
+       if (!NoWait)\r
+       {\r
+               movedata (finscreen,0,0xb800,0,4000);\r
+               bioskey (0);\r
+               clrscr();\r
+       }\r
+#endif\r
+\r
+       exit(0);\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+==================\r
+=\r
+= TEDDeath\r
+=\r
+==================\r
+*/\r
+\r
+void   TEDDeath(void)\r
+{\r
+       ShutdownId();\r
+       execlp("TED5.EXE","TED5.EXE","/LAUNCH",NULL);\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+=====================\r
+=\r
+= DemoLoop\r
+=\r
+=====================\r
+*/\r
+\r
+static char *ParmStrings[] = {"easy","normal","hard",""};\r
+\r
+void   DemoLoop (void)\r
+{\r
+       int     i,level;\r
+\r
+//\r
+// check for launch from ted\r
+//\r
+       if (tedlevel)\r
+       {\r
+               NewGame();\r
+               gamestate.mapon = tedlevelnum;\r
+               restartgame = gd_Normal;\r
+               for (i = 1;i < _argc;i++)\r
+               {\r
+                       if ( (level = US_CheckParm(_argv[i],ParmStrings)) == -1)\r
+                               continue;\r
+\r
+                       restartgame = gd_Easy+level;\r
+                       break;\r
+               }\r
+               GameLoop();\r
+               TEDDeath();\r
+       }\r
+\r
+\r
+//\r
+// main game cycle\r
+//\r
+       displayofs = bufferofs = 0;\r
+       VW_Bar (0,0,320,200,0);\r
+\r
+       while (1)\r
+       {\r
+               CA_CacheGrChunk (TITLEPIC);\r
+               bufferofs = SCREEN2START;\r
+               displayofs = SCREEN1START;\r
+               VWB_DrawPic (0,0,TITLEPIC);\r
+               MM_SetPurge (&grsegs[TITLEPIC],3);\r
+               UNMARKGRCHUNK(TITLEPIC);\r
+               FizzleFade (bufferofs,displayofs,320,200,true);\r
+\r
+               if (!IN_UserInput(TickBase*3,false))\r
+               {\r
+                       CA_CacheGrChunk (CREDITSPIC);\r
+                       VWB_DrawPic (0,0,CREDITSPIC);\r
+                       MM_SetPurge (&grsegs[CREDITSPIC],3);\r
+                       UNMARKGRCHUNK(CREDITSPIC);\r
+                       FizzleFade (bufferofs,displayofs,320,200,true);\r
+\r
+               }\r
+\r
+               if (!IN_UserInput(TickBase*3,false))\r
+               {\r
+highscores:\r
+                       DrawHighScores ();\r
+                       FizzleFade (bufferofs,displayofs,320,200,true);\r
+                       IN_UserInput(TickBase*3,false);\r
+               }\r
+\r
+               if (IN_IsUserInput())\r
+               {\r
+                       US_ControlPanel ();\r
+\r
+                       if (restartgame || loadedgame)\r
+                       {\r
+                               GameLoop ();\r
+                               goto highscores;\r
+                       }\r
+               }\r
+\r
+       }\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+==========================\r
+=\r
+= SetupScalePic\r
+=\r
+==========================\r
+*/\r
+\r
+void SetupScalePic (unsigned picnum)\r
+{\r
+       unsigned        scnum;\r
+\r
+       scnum = picnum-FIRSTSCALEPIC;\r
+\r
+       if (shapedirectory[scnum])\r
+       {\r
+               MM_SetPurge (&(memptr)shapedirectory[scnum],0);\r
+               return;                                 // allready in memory\r
+       }\r
+\r
+       CA_CacheGrChunk (picnum);\r
+       DeplanePic (picnum);\r
+       shapesize[scnum] = BuildCompShape (&shapedirectory[scnum]);\r
+       grneeded[picnum]&= ~ca_levelbit;\r
+       MM_FreePtr (&grsegs[picnum]);\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+==========================\r
+=\r
+= SetupScaleWall\r
+=\r
+==========================\r
+*/\r
+\r
+void SetupScaleWall (unsigned picnum)\r
+{\r
+       int             x,y;\r
+       unsigned        scnum;\r
+       byte    far *dest;\r
+\r
+       scnum = picnum-FIRSTWALLPIC;\r
+\r
+       if (walldirectory[scnum])\r
+       {\r
+               MM_SetPurge (&walldirectory[scnum],0);\r
+               return;                                 // allready in memory\r
+       }\r
+\r
+       CA_CacheGrChunk (picnum);\r
+       DeplanePic (picnum);\r
+       MM_GetPtr(&walldirectory[scnum],64*64);\r
+       dest = (byte far *)walldirectory[scnum];\r
+       for (x=0;x<64;x++)\r
+               for (y=0;y<64;y++)\r
+                       *dest++ = spotvis[y][x];\r
+       grneeded[picnum]&= ~ca_levelbit;\r
+       MM_FreePtr (&grsegs[picnum]);\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+==========================\r
+=\r
+= SetupScaling\r
+=\r
+==========================\r
+*/\r
+\r
+void SetupScaling (void)\r
+{\r
+       int             i,x,y;\r
+       byte    far *dest;\r
+\r
+//\r
+// build the compiled scalers\r
+//\r
+       for (i=1;i<=VIEWWIDTH/2;i++)\r
+               BuildCompScale (i*2,&scaledirectory[i]);\r
+}\r
+\r
+//===========================================================================\r
+\r
+int    showscorebox;\r
+\r
+void RF_FixOfs (void)\r
+{\r
+}\r
+\r
+void HelpScreens (void)\r
+{\r
+}\r
+\r
+\r
+/*\r
+==================\r
+=\r
+= CheckMemory\r
+=\r
+==================\r
+*/\r
+\r
+#define MINMEMORY      335000l\r
+\r
+void   CheckMemory(void)\r
+{\r
+       unsigned        finscreen;\r
+\r
+       if (mminfo.nearheap+mminfo.farheap+mminfo.EMSmem+mminfo.XMSmem\r
+               >= MINMEMORY)\r
+               return;\r
+\r
+       CA_CacheGrChunk (OUTOFMEM);\r
+       finscreen = (unsigned)grsegs[OUTOFMEM];\r
+       ShutdownId ();\r
+       movedata (finscreen,7,0xb800,0,4000);\r
+       gotoxy (1,24);\r
+       exit(1);\r
+}\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+==========================\r
+=\r
+= main\r
+=\r
+==========================\r
+*/\r
+\r
+void main (void)\r
+{\r
+       short i;\r
+\r
+       if (stricmp(_argv[1], "/VER") == 0)\r
+       {\r
+               printf("Catacomb 3-D version 1.22  (Rev 1)\n");\r
+               printf("Copyright 1991-93 Softdisk Publishing\n");\r
+               printf("Developed for use with 100%% IBM compatibles\n");\r
+               printf("that have 640K memory and DOS version 3.3 or later\n");\r
+               printf("and EGA graphics or better.\n");\r
+               exit(0);\r
+       }\r
+\r
+       if (stricmp(_argv[1], "/?") == 0)\r
+       {\r
+               printf("Catacomb 3-D version 1.22\n");\r
+               printf("Copyright 1991-93 Softdisk Publishing\n\n");\r
+               printf("Syntax:\n");\r
+               printf("CAT3D [/<switch>]\n\n");\r
+               printf("Switch       What it does\n");\r
+               printf("/?           This Information\n");\r
+               printf("/VER         Display Program Version Information\n");\r
+               printf("/COMP        Fix problems with SVGA screens\n");\r
+               printf("/NOAL        No AdLib or SoundBlaster detection\n");\r
+               printf("/NOJOYS      Tell program to ignore joystick\n");\r
+               printf("/NOMOUSE     Tell program to ignore mouse\n");\r
+               printf("/HIDDENCARD  Overrides video detection\n\n");\r
+               printf("Each switch must include a '/' and multiple switches\n");\r
+               printf("must be seperated by at least one space.\n\n");\r
+\r
+               exit(0);\r
+       }\r
+\r
+       jabhack();\r
+\r
+       InitGame ();\r
+\r
+       CheckMemory ();\r
+\r
+       LoadLatchMem ();\r
+\r
+#ifdef PROFILE\r
+       NewGame ();\r
+       GameLoop ();\r
+#endif\r
+\r
+//NewGame ();\r
+//GameLoop ();\r
+\r
+       DemoLoop();\r
+       Quit("Demo loop exited???");\r
+}\r
diff --git a/C3_PLAY.C b/C3_PLAY.C
new file mode 100644 (file)
index 0000000..112041f
--- /dev/null
+++ b/C3_PLAY.C
@@ -0,0 +1,584 @@
+/* Catacomb 3-D 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_PLAY.C\r
+\r
+#include "C3_DEF.H"\r
+#pragma hdrstop\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+#define POINTTICS      6\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                GLOBAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+ControlInfo    c;\r
+boolean                running,slowturn;\r
+\r
+int                    bordertime;\r
+objtype objlist[MAXACTORS],*new,*obj,*player,*lastobj,*objfreelist;\r
+\r
+unsigned       farmapylookup[MAPSIZE];\r
+byte           *nearmapylookup[MAPSIZE];\r
+\r
+boolean                singlestep,godmode;\r
+int                    extravbls;\r
+\r
+//\r
+// replacing refresh manager\r
+//\r
+unsigned       mapwidth,mapheight,tics;\r
+boolean                compatability;\r
+byte           *updateptr;\r
+unsigned       mapwidthtable[64];\r
+unsigned       uwidthtable[UPDATEHIGH];\r
+unsigned       blockstarts[UPDATEWIDE*UPDATEHIGH];\r
+#define        UPDATESCREENSIZE        (UPDATEWIDE*PORTTILESHIGH+2)\r
+#define        UPDATESPARESIZE         (UPDATEWIDE*2+4)\r
+#define UPDATESIZE                     (UPDATESCREENSIZE+2*UPDATESPARESIZE)\r
+byte           update[UPDATESIZE];\r
+\r
+int            mousexmove,mouseymove;\r
+int            pointcount,pointsleft;\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+void CalcBounds (objtype *ob);\r
+void DrawPlayScreen (void);\r
+\r
+\r
+//\r
+// near data map array (wall values only, get text number from far data)\r
+//\r
+byte           tilemap[MAPSIZE][MAPSIZE];\r
+byte           spotvis[MAPSIZE][MAPSIZE];\r
+objtype                *actorat[MAPSIZE][MAPSIZE];\r
+\r
+objtype dummyobj;\r
+\r
+int bordertime;\r
+int    objectcount;\r
+\r
+void StopMusic(void);\r
+void StartMusic(void);\r
+\r
+\r
+//==========================================================================\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     CenterWindow() - Generates a window of a given width & height in the\r
+//             middle of the screen\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+\r
+#define MAXX   264\r
+#define MAXY   146\r
+\r
+void   CenterWindow(word w,word h)\r
+{\r
+       US_DrawWindow(((MAXX / 8) - w) / 2,((MAXY / 8) - h) / 2,w,h);\r
+}\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= CheckKeys\r
+=\r
+=====================\r
+*/\r
+\r
+void CheckKeys (void)\r
+{\r
+       if (screenfaded)                        // don't do anything with a faded screen\r
+               return;\r
+\r
+//\r
+// pause key wierdness can't be checked as a scan code\r
+//\r
+       if (Paused)\r
+       {\r
+               CenterWindow (8,3);\r
+               US_PrintCentered ("PAUSED");\r
+               VW_UpdateScreen ();\r
+               SD_MusicOff();\r
+               IN_Ack();\r
+               SD_MusicOn();\r
+               Paused = false;\r
+               if (MousePresent) Mouse(MDelta);        // Clear accumulated mouse movement\r
+       }\r
+\r
+//\r
+// F1-F7/ESC to enter control panel\r
+//\r
+       if ( (LastScan >= sc_F1 && LastScan <= sc_F7) || LastScan == sc_Escape)\r
+       {\r
+               StopMusic ();\r
+               NormalScreen ();\r
+               FreeUpMemory ();\r
+               US_CenterWindow (20,8);\r
+               US_CPrint ("Loading");\r
+               VW_UpdateScreen ();\r
+               US_ControlPanel();\r
+               if (abortgame)\r
+               {\r
+                       playstate = ex_abort;\r
+                       return;\r
+               }\r
+               StartMusic ();\r
+               IN_ClearKeysDown();\r
+               if (restartgame)\r
+                       playstate = ex_resetgame;\r
+               if (loadedgame)\r
+                       playstate = ex_loadedgame;\r
+               DrawPlayScreen ();\r
+               CacheScaleds ();\r
+               lasttimecount = TimeCount;\r
+               if (MousePresent) Mouse(MDelta);        // Clear accumulated mouse movement\r
+       }\r
+\r
+//\r
+// F10-? debug keys\r
+//\r
+       if (Keyboard[sc_F10])\r
+       {\r
+               DebugKeys();\r
+               if (MousePresent) Mouse(MDelta);        // Clear accumulated mouse movement\r
+               lasttimecount = TimeCount;\r
+       }\r
+\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+#############################################################################\r
+\r
+                                 The objlist data structure\r
+\r
+#############################################################################\r
+\r
+objlist containt structures for every actor currently playing.  The structure\r
+is accessed as a linked list starting at *player, ending when ob->next ==\r
+NULL.  GetNewObj inserts a new object at the end of the list, meaning that\r
+if an actor spawn another actor, the new one WILL get to think and react the\r
+same frame.  RemoveObj unlinks the given object and returns it to the free\r
+list, but does not damage the objects ->next pointer, so if the current object\r
+removes itself, a linked list following loop can still safely get to the\r
+next element.\r
+\r
+<backwardly linked free list>\r
+\r
+#############################################################################\r
+*/\r
+\r
+\r
+/*\r
+=========================\r
+=\r
+= InitObjList\r
+=\r
+= Call to clear out the entire object list, returning them all to the free\r
+= list.  Allocates a special spot for the player.\r
+=\r
+=========================\r
+*/\r
+\r
+void InitObjList (void)\r
+{\r
+       int     i;\r
+\r
+       for (i=0;i<MAXACTORS;i++)\r
+       {\r
+               objlist[i].prev = &objlist[i+1];\r
+               objlist[i].next = NULL;\r
+       }\r
+\r
+       objlist[MAXACTORS-1].prev = NULL;\r
+\r
+       objfreelist = &objlist[0];\r
+       lastobj = NULL;\r
+\r
+       objectcount = 0;\r
+\r
+//\r
+// give the player and score the first free spots\r
+//\r
+       GetNewObj (false);\r
+       player = new;\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+=========================\r
+=\r
+= GetNewObj\r
+=\r
+= Sets the global variable new to point to a free spot in objlist.\r
+= The free spot is inserted at the end of the liked list\r
+=\r
+= When the object list is full, the caller can either have it bomb out ot\r
+= return a dummy object pointer that will never get used\r
+=\r
+=========================\r
+*/\r
+\r
+void GetNewObj (boolean usedummy)\r
+{\r
+       if (!objfreelist)\r
+       {\r
+               if (usedummy)\r
+               {\r
+                       new = &dummyobj;\r
+                       return;\r
+               }\r
+               Quit ("GetNewObj: No free spots in objlist!");\r
+       }\r
+\r
+       new = objfreelist;\r
+       objfreelist = new->prev;\r
+       memset (new,0,sizeof(*new));\r
+\r
+       if (lastobj)\r
+               lastobj->next = new;\r
+       new->prev = lastobj;    // new->next is allready NULL from memset\r
+\r
+       new->active = false;\r
+       lastobj = new;\r
+\r
+       objectcount++;\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+=========================\r
+=\r
+= RemoveObj\r
+=\r
+= Add the given object back into the free list, and unlink it from it's\r
+= neighbors\r
+=\r
+=========================\r
+*/\r
+\r
+void RemoveObj (objtype *gone)\r
+{\r
+       objtype **spotat;\r
+\r
+       if (gone == player)\r
+               Quit ("RemoveObj: Tried to remove the player!");\r
+\r
+//\r
+// fix the next object's back link\r
+//\r
+       if (gone == lastobj)\r
+               lastobj = (objtype *)gone->prev;\r
+       else\r
+               gone->next->prev = gone->prev;\r
+\r
+//\r
+// fix the previous object's forward link\r
+//\r
+       gone->prev->next = gone->next;\r
+\r
+//\r
+// add it back in to the free list\r
+//\r
+       gone->prev = objfreelist;\r
+       objfreelist = gone;\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+===================\r
+=\r
+= PollControls\r
+=\r
+===================\r
+*/\r
+\r
+void PollControls (void)\r
+{\r
+       unsigned buttons;\r
+\r
+       IN_ReadControl(0,&c);\r
+\r
+       if (MousePresent)\r
+       {\r
+               Mouse(MButtons);\r
+               buttons = _BX;\r
+               Mouse(MDelta);\r
+               mousexmove = _CX;\r
+               mouseymove = _DX;\r
+\r
+               if (buttons&1)\r
+                       c.button0 = 1;\r
+               if (buttons&2)\r
+                       c.button1 = 1;\r
+\r
+       }\r
+\r
+       if (Controls[0]==ctrl_Joystick)\r
+       {\r
+               if (c.x>120 || c.x <-120 || c.y>120 || c.y<-120)\r
+                       running = true;\r
+               else\r
+                       running = false;\r
+               if (c.x>-48 && c.x<48)\r
+                       slowturn = true;\r
+               else\r
+                       slowturn = false;\r
+       }\r
+       else\r
+       {\r
+               if (Keyboard[sc_RShift])\r
+                       running = true;\r
+               else\r
+                       running = false;\r
+               if (c.button0)\r
+                       slowturn = true;\r
+               else\r
+                       slowturn = false;\r
+       }\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+=================\r
+=\r
+= StopMusic\r
+=\r
+=================\r
+*/\r
+\r
+void StopMusic(void)\r
+{\r
+       int     i;\r
+\r
+       SD_MusicOff();\r
+       for (i = 0;i < LASTMUSIC;i++)\r
+               if (audiosegs[STARTMUSIC + i])\r
+               {\r
+                       MM_SetPurge(&((memptr)audiosegs[STARTMUSIC + i]),3);\r
+                       MM_SetLock(&((memptr)audiosegs[STARTMUSIC + i]),false);\r
+               }\r
+}\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= StartMusic\r
+=\r
+=================\r
+*/\r
+\r
+// JAB - Cache & start the appropriate music for this level\r
+void StartMusic(void)\r
+{\r
+       musicnames      chunk;\r
+\r
+       SD_MusicOff();\r
+       chunk = TOOHOT_MUS;\r
+//     if ((chunk == -1) || (MusicMode != smm_AdLib))\r
+//DEBUG control panel          return;\r
+\r
+       MM_BombOnError (false);\r
+       CA_CacheAudioChunk(STARTMUSIC + chunk);\r
+       MM_BombOnError (true);\r
+       if (mmerror)\r
+               mmerror = false;\r
+       else\r
+       {\r
+               MM_SetLock(&((memptr)audiosegs[STARTMUSIC + chunk]),true);\r
+               SD_StartMusic((MusicGroup far *)audiosegs[STARTMUSIC + chunk]);\r
+       }\r
+}\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= PlayLoop\r
+=\r
+===================\r
+*/\r
+\r
+void PlayLoop (void)\r
+{\r
+       int             give;\r
+\r
+       void (*think)();\r
+\r
+       ingame = true;\r
+       playstate = TimeCount = 0;\r
+       gamestate.shotpower = handheight = 0;\r
+       pointcount = pointsleft = 0;\r
+\r
+       DrawLevelNumber (gamestate.mapon);\r
+       DrawBars ();\r
+\r
+#ifndef PROFILE\r
+       fizzlein = true;                                // fizzle fade in the first refresh\r
+#endif\r
+       TimeCount = lasttimecount = lastnuke = 0;\r
+\r
+       PollControls ();                                // center mouse\r
+       StartMusic ();\r
+       do\r
+       {\r
+#ifndef PROFILE\r
+               PollControls();\r
+#else\r
+               c.xaxis = 1;\r
+               if (++TimeCount == 300)\r
+                       return;\r
+#endif\r
+\r
+               for (obj = player;obj;obj = obj->next)\r
+                       if (obj->active)\r
+                       {\r
+                               if (obj->ticcount)\r
+                               {\r
+                                       obj->ticcount-=tics;\r
+                                       while ( obj->ticcount <= 0)\r
+                                       {\r
+                                               think = obj->state->think;\r
+                                               if (think)\r
+                                               {\r
+                                                       think (obj);\r
+                                                       if (!obj->state)\r
+                                                       {\r
+                                                               RemoveObj (obj);\r
+                                                               goto nextactor;\r
+                                                       }\r
+                                               }\r
+\r
+                                               obj->state = obj->state->next;\r
+                                               if (!obj->state)\r
+                                               {\r
+                                                       RemoveObj (obj);\r
+                                                       goto nextactor;\r
+                                               }\r
+                                               if (!obj->state->tictime)\r
+                                               {\r
+                                                       obj->ticcount = 0;\r
+                                                       goto nextactor;\r
+                                               }\r
+                                               if (obj->state->tictime>0)\r
+                                                       obj->ticcount += obj->state->tictime;\r
+                                       }\r
+                               }\r
+                               think = obj->state->think;\r
+                               if (think)\r
+                               {\r
+                                       think (obj);\r
+                                       if (!obj->state)\r
+                                               RemoveObj (obj);\r
+                               }\r
+nextactor:;\r
+                       }\r
+\r
+\r
+               if (bordertime)\r
+               {\r
+                       bordertime -= tics;\r
+                       if (bordertime<=0)\r
+                       {\r
+                               bordertime = 0;\r
+                               VW_ColorBorder (3);\r
+                       }\r
+               }\r
+\r
+               if (pointcount)\r
+               {\r
+                       pointcount -= tics;\r
+                       if (pointcount <= 0)\r
+                       {\r
+                               pointcount += POINTTICS;\r
+                               give = (pointsleft > 1000)? 1000 :\r
+                                               (\r
+                                                       (pointsleft > 100)? 100 :\r
+                                                               ((pointsleft < 20)? pointsleft : 20)\r
+                                               );\r
+                               SD_PlaySound (GETPOINTSSND);\r
+                               AddPoints (give);\r
+                               pointsleft -= give;\r
+                               if (!pointsleft)\r
+                                       pointcount = 0;\r
+                       }\r
+               }\r
+\r
+               ThreeDRefresh ();\r
+\r
+               CheckKeys();\r
+               if (singlestep)\r
+               {\r
+                       VW_WaitVBL(14);\r
+                       lasttimecount = TimeCount;\r
+               }\r
+               if (extravbls)\r
+                       VW_WaitVBL(extravbls);\r
+\r
+       }while (!playstate);\r
+       StopMusic ();\r
+\r
+       ingame = false;\r
+       if (bordertime)\r
+       {\r
+               bordertime = 0;\r
+               VW_ColorBorder (3);\r
+       }\r
+\r
+       if (!abortgame)\r
+               AddPoints (pointsleft);\r
+       else\r
+               abortgame = false;\r
+}\r
+\r
diff --git a/C3_SCALE.C b/C3_SCALE.C
new file mode 100644 (file)
index 0000000..018083d
--- /dev/null
@@ -0,0 +1,690 @@
+/* Catacomb 3-D 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_SCALE.C\r
+\r
+#include "C3_DEF.H"\r
+#pragma hdrstop\r
+\r
+//const        unsigned        viewheight = 144;\r
+const  unsigned        screenbwide = 40;\r
+const  byte            BACKGROUNDPIX   =   5;\r
+\r
+unsigned               shapesize[MAXSCALE+1];\r
+t_compscale _seg *scaledirectory[MAXSCALE+1];\r
+t_compshape _seg *shapedirectory[NUMSCALEPICS];\r
+memptr                 walldirectory[NUMSCALEWALLS];\r
+\r
+/*\r
+===========================\r
+=\r
+= DeplanePic\r
+=\r
+= Takes a raw bit map of width bytes by height and creates a scaleable shape\r
+=\r
+= Returns the length of the shape in bytes\r
+=\r
+= Fills in spotvis (a convenient 64*64 array) with the color values\r
+=\r
+===========================\r
+*/\r
+\r
+void DeplanePic (int picnum)\r
+{\r
+       byte            far *plane0,far *plane1,far *plane2,far *plane3;\r
+       byte            by0,by1,by2,by3;\r
+       unsigned        x,y,b,color,shift,width,height;\r
+       byte            *dest;\r
+\r
+//\r
+// convert ega pixels to byte color values in a temp buffer\r
+//\r
+       width = pictable[picnum-STARTPICS].width;\r
+       height = pictable[picnum-STARTPICS].height;\r
+\r
+       if (width>64 || height!=64)\r
+               Quit ("DePlanePic: Bad size shape");\r
+\r
+       memset (spotvis,BACKGROUNDPIX,sizeof(spotvis));\r
+\r
+       plane0 = (byte _seg *)grsegs[picnum];\r
+       plane1 = plane0 + width*height;\r
+       plane2 = plane1 + width*height;\r
+       plane3 = plane2 + width*height;\r
+\r
+       for (y=0;y<height;y++)\r
+       {\r
+               dest = &spotvis[y][0];\r
+               for (x=0;x<width;x++)\r
+               {\r
+                       by0 = *plane0++;\r
+                       by1 = *plane1++;\r
+                       by2 = *plane2++;\r
+                       by3 = *plane3++;\r
+\r
+                       for (b=0;b<8;b++)\r
+                       {\r
+                               shift=8-b;\r
+\r
+                               color = 0;\r
+                               asm     mov     cl,[BYTE PTR shift]\r
+                               asm     mov     al,[BYTE PTR by3]\r
+                               asm     rcr     al,cl;\r
+                               asm     rcl     [BYTE PTR color],1;\r
+\r
+                               asm     mov     cl,[BYTE PTR shift]\r
+                               asm     mov     al,[BYTE PTR by2]\r
+                               asm     rcr     al,cl;\r
+                               asm     rcl     [BYTE PTR color],1;\r
+\r
+                               asm     mov     cl,[BYTE PTR shift]\r
+                               asm     mov     al,[BYTE PTR by1]\r
+                               asm     rcr     al,cl;\r
+                               asm     rcl     [BYTE PTR color],1;\r
+\r
+                               asm     mov     cl,[BYTE PTR shift]\r
+                               asm     mov     al,[BYTE PTR by0]\r
+                               asm     rcr     al,cl;\r
+                               asm     rcl     [BYTE PTR color],1;\r
+\r
+                               *dest++ = color;\r
+                       }       // B\r
+               }               // X\r
+       }                       // Y\r
+}\r
+\r
+\r
+\r
+\r
+/*\r
+========================\r
+=\r
+= BuildCompScale\r
+=\r
+= Builds a compiled scaler object that will scale a 64 tall object to\r
+= the given height (centered vertically on the screen)\r
+=\r
+= height should be even\r
+=\r
+= Call with\r
+= ---------\r
+= DS:SI                Source for scale\r
+= ES:DI                Dest for scale\r
+=\r
+= Calling the compiled scaler only destroys AL\r
+=\r
+========================\r
+*/\r
+\r
+unsigned BuildCompScale (int height, memptr *finalspot)\r
+{\r
+       t_compscale     _seg *work;\r
+       byte            far *code;\r
+\r
+       int                     i;\r
+       long            fix,step;\r
+       unsigned        src,totalscaled,totalsize;\r
+       int                     startpix,endpix,toppix;\r
+\r
+\r
+       MM_GetPtr (&(memptr)work,20000);\r
+\r
+       step = ((long)height<<16) / 64;\r
+       code = &work->code[0];\r
+       toppix = (viewheight-height)/2;\r
+       fix = 0;\r
+\r
+       for (src=0;src<=64;src++)\r
+       {\r
+               startpix = fix>>16;\r
+               fix += step;\r
+               endpix = fix>>16;\r
+\r
+               work->start[src] = startpix;\r
+               if (endpix>startpix)\r
+                       work->width[src] = endpix-startpix;\r
+               else\r
+                       work->width[src] = 0;\r
+\r
+//\r
+// mark the start of the code\r
+//\r
+               work->codeofs[src] = FP_OFF(code);\r
+\r
+//\r
+// compile some code if the source pixel generates any screen pixels\r
+//\r
+               startpix+=toppix;\r
+               endpix+=toppix;\r
+\r
+               if (startpix == endpix || endpix < 0 || startpix >= VIEWHEIGHT || src == 64)\r
+                       continue;\r
+\r
+       //\r
+       // mov al,[si+src]\r
+       //\r
+               *code++ = 0x8a;\r
+               *code++ = 0x44;\r
+               *code++ = src;\r
+\r
+               for (;startpix<endpix;startpix++)\r
+               {\r
+                       if (startpix >= VIEWHEIGHT)\r
+                               break;                                          // off the bottom of the view area\r
+                       if (startpix < 0)\r
+                               continue;                                       // not into the view area\r
+\r
+               //\r
+               // and [es:di+heightofs],al\r
+               //\r
+                       *code++ = 0x26;\r
+                       *code++ = 0x20;\r
+                       *code++ = 0x85;\r
+                       *((unsigned far *)code)++ = startpix*screenbwide;\r
+               }\r
+\r
+       }\r
+\r
+//\r
+// retf\r
+//\r
+       *code++ = 0xcb;\r
+\r
+       totalsize = FP_OFF(code);\r
+       MM_GetPtr (finalspot,totalsize);\r
+       _fmemcpy ((byte _seg *)(*finalspot),(byte _seg *)work,totalsize);\r
+       MM_FreePtr (&(memptr)work);\r
+\r
+       return totalsize;\r
+}\r
+\r
+\r
+\r
+\r
+/*\r
+========================\r
+=\r
+= BuildCompShape\r
+=\r
+= typedef struct\r
+= {\r
+=      unsigned        width;\r
+=      unsigned        codeofs[64];\r
+= }    t_compshape;\r
+=\r
+= Width is the number of compiled line draws in the shape.  The shape\r
+= drawing code will assume that the midpoint of the shape is in the\r
+= middle of the width.\r
+=\r
+= The non background pixel data will start at codeofs[width], so codeofs\r
+= greater than width will be invalid.\r
+=\r
+= Each code offset will draw one vertical line of the shape, consisting\r
+= of 0 or more segments of scaled pixels.\r
+=\r
+= The scaled shapes use ss:0-4 as a scratch variable for the far call to\r
+= the compiled scaler, so zero it back out after the shape is scaled, or\r
+= a "null pointer assignment" will result upon termination.\r
+=\r
+= Setup for a call to a compiled shape\r
+= -----------------------------------\r
+= ax   toast\r
+= bx   toast\r
+= cx   toast\r
+= dx   segment of compiled shape\r
+= si   toast\r
+= di   byte at top of view area to draw the line in\r
+= bp   0\r
+= ss:2 and ds  the segment of the compiled scaler to use\r
+= es   screenseg\r
+=\r
+= Upon return, ds IS NOT SET to the data segment.  Do:\r
+=      mov     ax,ss\r
+=      mov     ds,ax\r
+=\r
+=\r
+= GC_BITMASK   set to the pixels to be drawn in the row of bytes under DI\r
+= GC_MODE              read mode 1, write mode 2\r
+= GC_COLORDONTCARE  set to 0, so all reads from video memory return 0xff\r
+=\r
+=\r
+= Code generated for each segment\r
+= -------------------------------\r
+=      mov     bx,[(segend+1)*2]\r
+=      mov     cx,[bx]\r
+=      mov     [BYTE PTR bx],0xc8              // far return\r
+=      mov     ax,[segstart*2]\r
+=      mov     [ss:0],ax                               // entry point into the compiled scaler\r
+=      mov     ds,dx                   // (mov ds,cs) the data is after the compiled code\r
+=      mov     si,ofs data\r
+=      call    [bp]                            // scale some pixels\r
+=      mov     ds,[bp+2]\r
+=      mov     [bx],cx                                 // un patch return\r
+=\r
+= Code generated after all segments on a line\r
+= -------------------------------------------\r
+=      retf\r
+=\r
+========================\r
+*/\r
+\r
+unsigned BuildCompShape (t_compshape _seg **finalspot)\r
+{\r
+       t_compshape     _seg *work;\r
+       byte            far *code;\r
+       int                     firstline,lastline,x,y;\r
+       unsigned        firstpix,lastpix,width;\r
+       unsigned        totalsize,pixelofs;\r
+       unsigned        buff;\r
+\r
+\r
+//     MM_GetPtr (&(memptr)work,20000);\r
+       EGAWRITEMODE(0);\r
+       EGAREADMAP(0);          // use ega screen memory for temp buffer\r
+       EGAMAPMASK(1);\r
+       buff = screenloc[1];\r
+       work = (t_compshape _seg *)(0xa000+(buff+15)/16);\r
+\r
+//\r
+// find the width of the shape\r
+//\r
+       firstline = -1;\r
+       x=0;\r
+       do\r
+       {\r
+               for (y=0;y<64;y++)\r
+                       if (spotvis[y][x] != BACKGROUNDPIX)\r
+                       {\r
+                               firstline = x;\r
+                               break;\r
+                       }\r
+               if (++x == 64)\r
+                       Quit ("BuildCompShape: No shape data!");\r
+       } while (firstline == -1);\r
+\r
+       lastline = -1;\r
+       x=63;\r
+       do\r
+       {\r
+               for (y=0;y<64;y++)\r
+                       if (spotvis[y][x] != BACKGROUNDPIX)\r
+                       {\r
+                               lastline = x;\r
+                               break;\r
+                       }\r
+               x--;\r
+       } while (lastline == -1);\r
+\r
+       width = lastline-firstline+1;\r
+\r
+       work->width = width;\r
+       code = (byte far *)&work->codeofs[width];\r
+\r
+//\r
+// copy all non background pixels to the work space\r
+//\r
+       pixelofs = FP_OFF(code);\r
+\r
+       for (x=firstline;x<=lastline;x++)\r
+               for (y=0;y<64;y++)\r
+                       if (spotvis[y][x] != BACKGROUNDPIX)\r
+                               *code++ = spotvis[y][x];\r
+\r
+//\r
+// start compiling the vertical lines\r
+//\r
+       for (x=firstline;x<=lastline;x++)\r
+       {\r
+               work->codeofs[x-firstline] = FP_OFF(code);\r
+\r
+               y=0;\r
+               do\r
+               {\r
+               //\r
+               // scan past black background pixels\r
+               //\r
+                       while (spotvis[y][x] == BACKGROUNDPIX && y<64)\r
+                               y++;\r
+\r
+                       if (y>63)               // no more segments\r
+                               break;\r
+\r
+                       firstpix = y+1;         // +1 because width is before codeofs\r
+\r
+               //\r
+               // scan past scalable pixels\r
+               //\r
+                       while (spotvis[y][x] != BACKGROUNDPIX && y<64)\r
+                               y++;\r
+\r
+                       if (y>63)\r
+                               lastpix = 65;\r
+                       else\r
+                               lastpix = y+1;  // actually one pixel past the last displayed\r
+\r
+               //\r
+               // compile the scale call\r
+               //\r
+                       *code++ = 0x8b;         // mov bx,[lastpix*2]\r
+                       *code++ = 0x1e;\r
+                       *((unsigned far *)code)++ = lastpix*2;\r
+\r
+                       *code++ = 0x8b;         // mov cx,[bx]\r
+                       *code++ = 0x0f;\r
+\r
+                       *code++ = 0xc6;         // move [BYTE bx],0xcb\r
+                       *code++ = 0x07;\r
+                       *code++ = 0xcb;\r
+\r
+                       *code++ = 0xa1;         // mov ax,[firstpix*2]  /*************\r
+                       *((unsigned far *)code)++ = firstpix*2;\r
+\r
+                       *code++ = 0x36;         // mov [ss:0],ax\r
+                       *code++ = 0xa3;\r
+                       *code++ = 0x00;\r
+                       *code++ = 0x00;\r
+\r
+                       *code++ = 0x8e;         // mov ds,dx    (mov ds,cs)\r
+                       *code++ = 0xda;\r
+\r
+                       *code++ = 0xbe;         // mov si,OFFSET pixelofs-firstpixel\r
+                       *((unsigned far *)code)++ = pixelofs-firstpix;\r
+\r
+                       *code++ = 0xff;         // call [DWORD bp]\r
+                       *code++ = 0x5e;\r
+                       *code++ = 0x00;\r
+\r
+                       *code++ = 0x8e;         // mov ds,[bp+2]\r
+                       *code++ = 0x5e;\r
+                       *code++ = 0x02;\r
+\r
+                       *code++ = 0x89;         // mov [bx],cx\r
+                       *code++ = 0x0f;\r
+\r
+                       pixelofs += (lastpix-firstpix);\r
+               } while (y<63);\r
+\r
+       //\r
+       // retf\r
+       //\r
+               *code++ = 0xcb;\r
+       }\r
+\r
+\r
+//\r
+// copy the final shape to a properly sized buffer\r
+//\r
+       totalsize = FP_OFF(code);\r
+       MM_GetPtr ((memptr *)finalspot,totalsize);\r
+       _fmemcpy ((byte _seg *)(*finalspot),(byte _seg *)work,totalsize);\r
+//     MM_FreePtr (&(memptr)work);\r
+\r
+       return totalsize;\r
+}\r
+\r
+\r
+\r
+/*\r
+=======================\r
+=\r
+= ScaleShape\r
+=\r
+= Draws a compiled shape at [scale] pixels high\r
+=\r
+= Setup for call\r
+= --------------\r
+= GC_MODE                      read mode 1, write mode 2\r
+= GC_COLORDONTCARE  set to 0, so all reads from video memory return 0xff\r
+= GC_INDEX                     pointing at GC_BITMASK\r
+=\r
+=======================\r
+*/\r
+\r
+static long            longtemp;\r
+\r
+void ScaleShape (int xcenter, t_compshape _seg *compshape, unsigned scale)\r
+{\r
+       t_compscale _seg *comptable;\r
+       unsigned        width,scalewidth;\r
+       int                     x,pixel,lastpixel,pixwidth,min;\r
+       unsigned        far *codehandle, far *widthptr;\r
+       unsigned        badcodeptr;\r
+       int                     rightclip;\r
+\r
+       if (!compshape)\r
+               Quit ("ScaleShape: NULL compshape ptr!");\r
+\r
+       scale = (scale+1)/2;\r
+       if (!scale)\r
+               return;                                                         // too far away\r
+       if (scale>MAXSCALE)\r
+               scale = MAXSCALE;\r
+       comptable = scaledirectory[scale];\r
+\r
+       width = compshape->width;\r
+       scalewidth = comptable->start[width];\r
+\r
+       pixel = xcenter - scalewidth/2;\r
+       lastpixel = pixel+scalewidth-1;\r
+       if (pixel >= VIEWWIDTH || lastpixel < 0)\r
+               return;                                                         // totally off screen\r
+\r
+//\r
+// scan backwards from the right edge until pixels are visable\r
+// rightclip is the first NON VISABLE pixel\r
+//\r
+       if (lastpixel>=VIEWWIDTH-1)\r
+               rightclip = VIEWWIDTH-1;\r
+       else\r
+               rightclip = lastpixel;\r
+\r
+       if (zbuffer[rightclip]>scale)\r
+       {\r
+               if (pixel>0)\r
+                       min = pixel;\r
+               else\r
+                       min = 0;\r
+               do\r
+               {\r
+                       if (--rightclip < min)\r
+                               return;                                                 // totally covered or before 0\r
+                       if (zbuffer[rightclip]<=scale)\r
+                               break;\r
+               } while (1);\r
+       }\r
+       rightclip++;\r
+\r
+//\r
+// scan from the left until it is on screen, leaving\r
+// [pixel],[pixwidth],[codehandle],and [widthptr] set correctly\r
+//\r
+       *(((unsigned *)&longtemp)+1) = (unsigned)compshape;     // seg of shape\r
+       codehandle = &compshape->codeofs[0];\r
+       badcodeptr = compshape->codeofs[width];\r
+       widthptr = &comptable->width[0];\r
+       asm     mov     ax,[comptable]\r
+       asm     mov     WORD PTR [2],ax                         // ds:0-4 is used as a far call pointer\r
+                                                                               // by the compiled shapes\r
+       pixwidth = *widthptr;                           // scaled width of this pixel\r
+       while (!pixwidth)\r
+       {\r
+               pixwidth = *++widthptr;                 // find the first visable pixel\r
+               codehandle++;\r
+       }\r
+\r
+       if (pixel<0)\r
+       {\r
+               do\r
+               {\r
+                       if (pixel+pixwidth>0)\r
+                       {\r
+                               pixwidth += pixel;\r
+                               pixel = 0;\r
+                               break;\r
+                       }\r
+                       do\r
+                       {\r
+                               pixwidth = *++widthptr;\r
+                               codehandle++;\r
+                       } while (!pixwidth);\r
+                       pixel+=pixwidth;\r
+               } while (1);\r
+       }\r
+\r
+//\r
+// scan until it is visable, leaving\r
+// [pixel],[pixwidth],[codehandle],and [widthptr] set correctly\r
+//\r
+       do\r
+       {\r
+               if (zbuffer[pixel] <= scale)\r
+                       break;                                                  // start drawing here\r
+               pixel++;\r
+               if (!--pixwidth)\r
+               {\r
+                       do\r
+                       {\r
+                               pixwidth = *++widthptr;\r
+                               codehandle++;\r
+                       } while (!pixwidth);\r
+               }\r
+       } while (1);\r
+\r
+       if (pixel+pixwidth>rightclip)\r
+               pixwidth = rightclip-pixel;\r
+//\r
+// draw lines\r
+//\r
+       do              // while (1)\r
+       {\r
+       //\r
+       // scale a vertical segment [pixwidth] pixels wide at [pixel]\r
+       //\r
+               (unsigned)longtemp = *codehandle;       // offset of compiled code\r
+               if ((unsigned)longtemp == badcodeptr)\r
+                       Quit ("ScaleShape: codehandle past end!");\r
+\r
+               asm     mov     bx,[pixel]\r
+               asm     mov     di,bx\r
+               asm     shr     di,1\r
+               asm     shr     di,1\r
+               asm     shr     di,1                                            // X in bytes\r
+               asm     add     di,[bufferofs]\r
+               asm     and     bx,7\r
+               asm     shl     bx,1\r
+               asm     shl     bx,1\r
+               asm     shl     bx,1\r
+               asm     add     bx,[pixwidth]                           // bx = pixel*8+pixwidth-1\r
+               asm     dec     bx\r
+               asm     push    bx\r
+               asm     mov     al,BYTE PTR [bitmasks1+bx]\r
+               asm     mov     dx,GC_INDEX+1\r
+               asm     out     dx,al                                           // set bit mask register\r
+\r
+               asm     mov     es,[screenseg]\r
+               asm     push    si\r
+               asm     push    di\r
+               asm     push    bp\r
+               asm     xor     bp,bp\r
+               asm     mov     dx,[WORD PTR longtemp+2]\r
+               asm     mov     ds,[2]\r
+               asm     call ss:[DWORD PTR longtemp]            // scale the line of pixels\r
+               asm     mov     ax,ss\r
+               asm     mov     ds,ax\r
+               asm     pop             bp\r
+               asm     pop             di\r
+               asm     pop             si\r
+\r
+               asm     pop     bx\r
+               asm     mov     al,BYTE PTR [bitmasks2+bx]\r
+               asm     or      al,al\r
+               asm     jz      nosecond\r
+\r
+       //\r
+       // draw a second byte for vertical strips that cross two bytes\r
+       //\r
+               asm     inc     di\r
+               asm     mov     dx,GC_INDEX+1\r
+               asm     out     dx,al                                           // set bit mask register\r
+               asm     push    si\r
+               asm     push    di\r
+               asm     push    bp\r
+               asm     xor     bp,bp\r
+               asm     mov     dx,[WORD PTR longtemp+2]\r
+               asm     mov     ds,[2]\r
+               asm     call ss:[DWORD PTR longtemp]            // scale the line of pixels\r
+               asm     mov     ax,ss\r
+               asm     mov     ds,ax\r
+               asm     pop             bp\r
+               asm     pop             di\r
+               asm     pop             si\r
+\r
+\r
+       //\r
+       // advance to the next drawn line\r
+       //\r
+nosecond:;\r
+               if ( (pixel+=pixwidth) == rightclip )\r
+               {\r
+                       asm     mov     WORD PTR [0],0\r
+                       asm     mov     WORD PTR [2],0\r
+                       return;                                                 // all done!\r
+               }\r
+\r
+               do\r
+               {\r
+                       pixwidth = *++widthptr;\r
+                       codehandle++;\r
+               } while (!pixwidth);\r
+\r
+               if (pixel+pixwidth > rightclip)\r
+                       pixwidth = rightclip-pixel;\r
+\r
+       } while (1);\r
+\r
+}\r
+\r
+//\r
+// bit mask tables for drawing scaled strips up to eight pixels wide\r
+//\r
+\r
+byte   bitmasks1[8][8] = {\r
+{0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff},\r
+{0x40,0x60,0x70,0x78,0x7c,0x7e,0x7f,0x7f},\r
+{0x20,0x30,0x38,0x3c,0x3e,0x3f,0x3f,0x3f},\r
+{0x10,0x18,0x1c,0x1e,0x1f,0x1f,0x1f,0x1f},\r
+{0x8,0xc,0xe,0xf,0xf,0xf,0xf,0xf},\r
+{0x4,0x6,0x7,0x7,0x7,0x7,0x7,0x7},\r
+{0x2,0x3,0x3,0x3,0x3,0x3,0x3,0x3},\r
+{0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1} };\r
+\r
+byte   bitmasks2[8][8] = {\r
+{0,0,0,0,0,0,0,0},\r
+{0,0,0,0,0,0,0,0x80},\r
+{0,0,0,0,0,0,0x80,0xc0},\r
+{0,0,0,0,0,0x80,0xc0,0xe0},\r
+{0,0,0,0,0x80,0xc0,0xe0,0xf0},\r
+{0,0,0,0x80,0xc0,0xe0,0xf0,0xf8},\r
+{0,0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc},\r
+{0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe} };\r
+\r
+\r
+\r
+\r
+\r
+\r
diff --git a/C3_SCA_A.ASM b/C3_SCA_A.ASM
new file mode 100644 (file)
index 0000000..58a8737
--- /dev/null
@@ -0,0 +1,153 @@
+; Catacomb 3-D 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
+IDEAL\r
+MODEL  MEDIUM,C\r
+\r
+include "ID_ASM.EQU"\r
+\r
+;===========================================================================\r
+;\r
+;                    SCALING GRAPHICS\r
+;\r
+;===========================================================================\r
+\r
+\r
+\r
+MACRO  MAKELAB NUM\r
+\r
+lab&NUM:\r
+\r
+ENDM\r
+\r
+MACRO  MAKEREF NUM\r
+\r
+dw OFFSET lab&NUM\r
+\r
+ENDM\r
+\r
+\r
+;=========================================================================\r
+\r
+MAXSCALES equ 256\r
+\r
+       DATASEG\r
+\r
+EXTRN  screenseg:WORD\r
+EXTRN  linewidth:WORD\r
+\r
+LABEL endtable WORD\r
+labcount = 0\r
+REPT MAXSCALES\r
+MAKEREF %labcount\r
+labcount = labcount + 1\r
+ENDM\r
+\r
+\r
+       CODESEG\r
+\r
+;==================================================\r
+;\r
+; void scaleline (int scale, unsigned picseg, unsigned maskseg,\r
+;                 unsigned screen, unsigned width)\r
+;\r
+;==================================================\r
+\r
+PROC   ScaleLine pixels:word, scaleptr:dword, picptr:dword, screen:word\r
+USES   si,di\r
+PUBLIC ScaleLine\r
+\r
+;\r
+; modify doline procedure for proper width\r
+;\r
+       mov     bx,[pixels]\r
+       cmp     bx,MAXSCALES\r
+       jbe     @@scaleok\r
+       mov     bx,MAXSCALES\r
+@@scaleok:\r
+       shl     bx,1\r
+       mov     bx,[endtable+bx]\r
+       push    [cs:bx]                 ;save the code that will be modified over\r
+       mov     [WORD cs:bx],0d18eh     ;mov ss,cx\r
+       push    [cs:bx+2]               ;save the code that will be modified over\r
+       mov     [WORD cs:bx+2],90c3h    ;ret / nop\r
+       push    bx\r
+\r
+       mov     dx,[linewidth]\r
+\r
+       mov     di,[WORD screen]\r
+       mov     es,[screenseg]\r
+\r
+       mov     si,[WORD scaleptr]\r
+       mov     ds,[WORD scaleptr+2]\r
+\r
+       mov     bx,[WORD picptr]\r
+       mov     ax,[WORD picptr+2]      ;will be moved into ss after call\r
+\r
+       mov     bp,bx\r
+\r
+       cli\r
+       call    doline\r
+       sti\r
+;\r
+; restore doline to regular state\r
+;\r
+       pop     bx              ;address of modified code\r
+       pop     [cs:bx+2]\r
+       pop     [cs:bx]\r
+\r
+       mov     ax,ss\r
+       mov     ds,ax\r
+       ret\r
+\r
+;================\r
+;\r
+; doline\r
+;\r
+; Big unwound scaling routine\r
+;\r
+; ds:si = scale table\r
+; ss:bx = pic data\r
+; es:di = screen location\r
+;\r
+;================\r
+\r
+doline:\r
+\r
+       mov     cx,ss\r
+       mov     ss,ax           ;can't call a routine with ss used...\r
+\r
+labcount = 0\r
+\r
+REPT MAXSCALES\r
+\r
+MAKELAB %labcount\r
+labcount = labcount + 1\r
+\r
+       lodsb                   ; get scaled pixel number\r
+       xlat    [ss:bx]         ; look it up in the picture\r
+       xchg    [es:di],al      ; load latches and write pixel to screen\r
+       add     di,dx           ; down to next line\r
+\r
+ENDM\r
+\r
+       mov     ss,cx\r
+       ret\r
+\r
+ENDP\r
+\r
+END
\ No newline at end of file
diff --git a/C3_STATE.C b/C3_STATE.C
new file mode 100644 (file)
index 0000000..8c31eb0
--- /dev/null
@@ -0,0 +1,546 @@
+/* Catacomb 3-D 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_STATE.C\r
+\r
+#include "C3_DEF.H"\r
+#pragma hdrstop\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                GLOBAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+