]> 4ch.mooo.com Git - 16.git/commitdiff
[16_ca needs huge amounts of work and I should remember what needs to be done soon...
authorsparky4 <sparky4@cock.li>
Fri, 24 Mar 2017 17:34:44 +0000 (12:34 -0500)
committersparky4 <sparky4@cock.li>
Fri, 24 Mar 2017 17:34:44 +0000 (12:34 -0500)
65 files changed:
16/src/lib/16_in_o.c [moved from src/lib/16_in_o.c with 100% similarity]
16/src/lib/16_in_o.h [moved from src/lib/16_in_o.h with 100% similarity]
_pm_use.txt
makefile
src/16.c
src/lib/16_dbg.c
src/lib/16_dbg.h
src/lib/16_pm.c
src/lib/16_tail.c
src/lib/16_tdef.h
src/lib/16_vl.h
src/lib/hb/c3_act1.c [new file with mode: 0755]
src/lib/hb/c3_asm.asm [new file with mode: 0755]
src/lib/hb/c3_debug.c [new file with mode: 0755]
src/lib/hb/c3_def.h [new file with mode: 0755]
src/lib/hb/c3_draw.c [new file with mode: 0755]
src/lib/hb/c3_game.c [new file with mode: 0755]
src/lib/hb/c3_main.c [new file with mode: 0755]
src/lib/hb/c3_play.c [new file with mode: 0755]
src/lib/hb/c3_sca_a.asm [new file with mode: 0755]
src/lib/hb/c3_scale.c [new file with mode: 0755]
src/lib/hb/c3_state.c [new file with mode: 0755]
src/lib/hb/c3_trace.c [new file with mode: 0755]
src/lib/hb/c3_wiz.c [new file with mode: 0755]
src/lib/hb/c6_act1.c [new file with mode: 0755]
src/lib/hb/c6_act2.c [new file with mode: 0755]
src/lib/hb/c6_act3.c [new file with mode: 0755]
src/lib/hb/c6_act4.c [new file with mode: 0755]
src/lib/hb/c6_asm.asm [new file with mode: 0755]
src/lib/hb/c6_debug.c [new file with mode: 0755]
src/lib/hb/c6_draw.c [new file with mode: 0755]
src/lib/hb/c6_game.c [new file with mode: 0755]
src/lib/hb/c6_main.c [new file with mode: 0755]
src/lib/hb/c6_play.c [new file with mode: 0755]
src/lib/hb/c6_sca_a.asm [new file with mode: 0755]
src/lib/hb/c6_scale.c [new file with mode: 0755]
src/lib/hb/c6_state.c [new file with mode: 0755]
src/lib/hb/c6_trace.c [new file with mode: 0755]
src/lib/hb/c6_wiz.c [new file with mode: 0755]
src/lib/hb/demokd.c [new file with mode: 0755]
src/lib/hb/demowl.c [new file with mode: 0755]
src/lib/hb/kd_act1.c [new file with mode: 0755]
src/lib/hb/kd_act2.c [new file with mode: 0755]
src/lib/hb/kd_def.h [new file with mode: 0755]
src/lib/hb/kd_demo.c [new file with mode: 0755]
src/lib/hb/kd_keen.c [new file with mode: 0755]
src/lib/hb/kd_main.c [new file with mode: 0755]
src/lib/hb/kd_play.c [new file with mode: 0755]
src/lib/hb/wl_act1.c [new file with mode: 0755]
src/lib/hb/wl_act2.c [new file with mode: 0755]
src/lib/hb/wl_agent.c [new file with mode: 0755]
src/lib/hb/wl_asm.asm [new file with mode: 0755]
src/lib/hb/wl_debug.c [moved from src/lib/wl_debug.c with 100% similarity]
src/lib/hb/wl_def.h [new file with mode: 0755]
src/lib/hb/wl_dr_a.asm [new file with mode: 0755]
src/lib/hb/wl_draw.c [new file with mode: 0755]
src/lib/hb/wl_game.c [new file with mode: 0755]
src/lib/hb/wl_inter.c [new file with mode: 0755]
src/lib/hb/wl_main.c [new file with mode: 0755]
src/lib/hb/wl_menu.c [new file with mode: 0755]
src/lib/hb/wl_menu.h [new file with mode: 0755]
src/lib/hb/wl_play.c [new file with mode: 0755]
src/lib/hb/wl_scale.c [new file with mode: 0755]
src/lib/hb/wl_state.c [new file with mode: 0755]
src/lib/hb/wl_text.c [new file with mode: 0755]

similarity index 100%
rename from src/lib/16_in_o.c
rename to 16/src/lib/16_in_o.c
similarity index 100%
rename from src/lib/16_in_o.h
rename to 16/src/lib/16_in_o.h
index 934d267f0074650fa1168b2521872444272fc269..43ba6c4ad5c5d00b154defac6a61d29e7f0e6dca 100755 (executable)
 16/wf3d8086/wl_game.c:         PM_CheckMainMem ();\r
 16/wf3d8086/wl_game.c:                 PM_CheckMainMem ();\r
 \r
-16/wf3d8086/wl_inter.c:        PM_Preload (PreloadUpdate);\r
+\r
+\r
+       16/wf3d8086/wl_inter.c: PM_Preload (PreloadUpdate);     //related to chunksinfile\r
+\r
+\r
 \r
 16/wf3d8086/wl_main.c: PM_Shutdown ();\r
 16/wf3d8086/wl_main.c: PM_Startup ();\r
index b7a7a580bef5d9d67b4e0b08f70a5bb567d5320e..ea59beda3f4b612007b207bebb8c5acb52d5748b 100755 (executable)
--- a/makefile
+++ b/makefile
@@ -34,7 +34,7 @@
 # comment this out on game release.
 # serial output goes to COM1 at 9600 baud 1 stop bit odd parity.
 # serial output is plain text ASCII.
-DEBUGSERIAL=0
+DEBUGSERIAL=1
 
 DELLOGFILE=1
 
@@ -357,7 +357,7 @@ mapread.$(OBJ):$(SRCLIB)/mapread.c $(SRCLIB)/mapread.h
 16_map.$(OBJ):$(SRCLIB)/16_map.c $(SRCLIB)/16_map.h
 16_timer.$(OBJ):$(SRCLIB)/16_timer.c $(SRCLIB)/16_timer.h
 16_in.$(OBJ):   $(SRCLIB)/16_in.c $(SRCLIB)/16_in.h
-16_in_1.$(OBJ):         $(SRCLIB)/16_in_1.c $(SRCLIB)/16_in_1.h
+#16_in_1.$(OBJ):        $(SRCLIB)/16_in_1.c $(SRCLIB)/16_in_1.h
 16_rf.$(OBJ):   $(SRCLIB)/16_rf.c      $(SRCLIB)/16_rf.h
 16_mm.$(OBJ):   $(SRCLIB)/16_mm.c      $(SRCLIB)/16_mm.h
 16_pm.$(OBJ):   $(SRCLIB)/16_pm.c      $(SRCLIB)/16_pm.h
index af711c37aa1d794319d6f6351b0ab87f0dc9d4d6..e87446c6378f1192920ec09c11ff0c2b05db0f5e 100755 (executable)
--- a/src/16.c
+++ b/src/16.c
@@ -28,8 +28,6 @@ main(int argc, char *argv[])
        static global_game_variables_t gvar;\r
        Startup16(&gvar);\r
 \r
-       gvar.engi_stat = ENGI_RUN;\r
-\r
        /* save the palette */\r
        modexPalSave(gvar.video.dpal);\r
        modexFadeOff(4, gvar.video.dpal);\r
@@ -39,10 +37,10 @@ main(int argc, char *argv[])
 //     modexPalBlack();        //so player will not see loadings~\r
        IN_Default(0,&gvar.player[0],ctrl_Joystick, &gvar);\r
        //modexprint(&screen, 32, 32, 1, 2, 0, "a", 1);\r
-       while(ENGI_QUIT != gvar.engi_stat)\r
+       while(1)\r
        {\r
                IN_ReadControl(&gvar.player[0], &gvar);\r
-               if(IN_KeyDown(sc_Escape)) gvar.engi_stat = ENGI_QUIT;\r
+               if(IN_KeyDown(sc_Escape)) break;\r
                shinku(&gvar);\r
                _DEBUGF("Serial debug output printf test %u %u %u\n",1U,2U,3U);\r
        }\r
index db8f71a10365279798763005f247c2be657b22b2..9878998be3621b9468bb9bbdb4d1bc83bc5a9ebf 100755 (executable)
@@ -257,12 +257,10 @@ static    char    buf[10];
 //             VW_UpdateScreen();\r
 \r
                while (!(scan = gvar->in.inst->LastScan))\r
-               {\r
-               }\r
-//                     scan = *IN_GetScanName(scan);\r
+               {}\r
 //                     SD_Poll();\r
 \r
-if(IN_KeyDown(sc_Escape)) break;\r
+//if(IN_KeyDown(sc_Escape)) break;\r
 \r
                IN_ClearKey(scan);\r
                switch (scan)\r
index 3d7ef4afe9690e4912e3f18cf8d7af65d1a44c59..3be65fa663c79cf67a3096c155a8a27a401df8f3 100755 (executable)
@@ -9,6 +9,7 @@
 #define __DEBUG__\r
 #define __DEBUG_InputMgr__\r
 #define __DEBUG_MAP__\r
+//#define __DEBUG_2__\r
 //#define __DEBUG_CA__\r
 //#define __DEBUG_PM__\r
 //#define __DEBUG_MM__\r
index 4d9ac9d8f7874515369dfa8f2fcbfb75a6ad9533..9fabd9be60af74cd1001c5c27c695c6d0435ebe6 100755 (executable)
@@ -1207,7 +1207,7 @@ PM_GetPage(int pagenum, global_game_variables_t *gvar)
        if (pagenum >= gvar->pm.fi.ChunksInFile)\r
                Quit (gvar, "PM_GetPage: Invalid page request");\r
 \r
-#ifdef __DEBUG_2__     // for debugging\r
+//#ifdef __DEBUG_2__   // for debugging\r
        __asm {\r
                mov     dx,STATUS_REGISTER_1\r
                in      al,dx\r
@@ -1217,7 +1217,7 @@ PM_GetPage(int pagenum, global_game_variables_t *gvar)
                mov     al,10   // bright green\r
                out     dx,al\r
        }\r
-#endif\r
+//#endif\r
 \r
        if (!(result = PM_GetPageAddress(pagenum, gvar)))\r
        {\r
@@ -1235,7 +1235,7 @@ if (!gvar->pm.PMPages[pagenum].offset)    // JDC: sparse page
        }\r
        gvar->pm.PMPages[pagenum].lastHit =  gvar->pm.PMFrameCount;\r
 \r
-#ifdef __DEBUG_2__     // for debugging\r
+//#ifdef __DEBUG_2__   // for debugging\r
        __asm{\r
                mov     dx,STATUS_REGISTER_1\r
                in      al,dx\r
@@ -1246,7 +1246,8 @@ if (!gvar->pm.PMPages[pagenum].offset)    // JDC: sparse page
                out     dx,al\r
                mov     al,0x20 // normal\r
                out     dx,al\r
-#endif\r
+       }\r
+//#endif\r
 \r
        return(result);\r
 }\r
index 7b5fdcb4de0c44ea65d8a5809290383c367d39d7..3b1cb42c3b0c9c76887689bd9dccc4f97aed0d17 100755 (executable)
@@ -394,37 +394,37 @@ char global_temp_status_text2[512];
 void turboXT(byte bakapee)\r
 {\r
        __asm {\r
-       push    ax\r
-       push    bx\r
-       push    cx\r
-       in      al, 61h                         //; Read equipment flags\r
-       xor     al, bakapee                     //;   toggle speed\r
-       out     61h, al                         //; Write new flags back\r
-\r
-       mov     bx, 0F89h                       //; low pitch blip\r
-       and     al, 4                           //; Is turbo mode set?\r
-       jz      @@do_beep\r
-       mov     bx, 52Eh                        //; high pitch blip\r
-\r
-@@do_beep:\r
-       mov     al, 10110110b           //; Timer IC 8253 square waves\r
-       out     43h, al                         //;   channel 2, speaker\r
-       mov     ax, bx\r
-       out     42h, al                         //;   send low order\r
-       mov     al, ah                          //;   load high order\r
-       out     42h, al                         //;   send high order\r
-       in      al, 61h                         //; Read IC 8255 machine status\r
-       push    ax\r
-       or      al, 00000011b\r
-       out     61h, al                         //; Turn speaker on\r
-       mov     cx, 2000h\r
-@@delay:\r
-       loop    @@delay\r
-       pop     ax\r
-       out     61h, al                         //; Turn speaker off\r
-       pop     cx\r
-       pop     bx\r
-       pop     ax\r
+               push    ax\r
+               push    bx\r
+               push    cx\r
+               in      al, 61h                         //; Read equipment flags\r
+               xor     al, bakapee                     //;   toggle speed\r
+               out     61h, al                         //; Write new flags back\r
+\r
+               mov     bx, 0F89h                       //; low pitch blip\r
+               and     al, 4                           //; Is turbo mode set?\r
+               jz      @@do_beep\r
+               mov     bx, 52Eh                        //; high pitch blip\r
+\r
+       @@do_beep:\r
+               mov     al, 10110110b           //; Timer IC 8253 square waves\r
+               out     43h, al                         //;   channel 2, speaker\r
+               mov     ax, bx\r
+               out     42h, al                         //;   send low order\r
+               mov     al, ah                          //;   load high order\r
+               out     42h, al                         //;   send high order\r
+               in      al, 61h                         //; Read IC 8255 machine status\r
+               push    ax\r
+               or      al, 00000011b\r
+               out     61h, al                         //; Turn speaker on\r
+               mov     cx, 2000h\r
+       @@delay:\r
+               loop    @@delay\r
+               pop     ax\r
+               out     61h, al                         //; Turn speaker off\r
+               pop     cx\r
+               pop     bx\r
+               pop     ax\r
        }\r
 }\r
 #endif\r
index 08b9699624d2e35b85c6abcaa82bc49d6794ae71..e9f19bbd9524c4aba2efb3750c5ffd676a0eaddc 100755 (executable)
@@ -642,17 +642,17 @@ typedef struct    //TODO: USE THIS!!!!
 //==========================================================================\r
 \r
 //actual global game varables!\r
-typedef enum {\r
+/*typedef enum {\r
        ENGI_QUIT,\r
        ENGI_RUN,\r
        ENGI_MENU,\r
        ENGI_PAUSE\r
-} engi_stat_t;\r
+} engi_stat_t;*/\r
 //ENGI_INPUT,\r
 \r
 typedef struct\r
 {\r
-       engi_stat_t     engi_stat;\r
+//---- engi_stat_t     engi_stat;\r
        video_t video;  // video settings variable\r
        ca_t            ca;     // ca stuff\r
        pm_t            pm;     // pm stuff\r
index b1b03a21f60874ff59d21792f43222017c894c5b..cec79507ad5189ec035ab3b06fe07a36ea6aabf7 100755 (executable)
@@ -84,6 +84,9 @@ extern byte far*  VGA;  /* The VGA Memory */
 #define LOW_ADDRESS            0x0D\r
 #define VRETRACE               0x08\r
 //#define INPUT_STATUS_1               0x03da  defined in 16_head\r
+#define STATUS_REGISTER_1      INPUT_STATUS_1\r
+#define ATR_INDEX                      AC_INDEX\r
+#define ATR_OVERSCAN           17\r
 #define DISPLAY_ENABLE         0x01\r
 #define MAP_MASK               0x02\r
 #define PAL_READ_REG                   0x03C7   /* Color register, read address */\r
diff --git a/src/lib/hb/c3_act1.c b/src/lib/hb/c3_act1.c
new file mode 100755 (executable)
index 0000000..2706b4f
--- /dev/null
@@ -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/src/lib/hb/c3_asm.asm b/src/lib/hb/c3_asm.asm
new file mode 100755 (executable)
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/src/lib/hb/c3_debug.c b/src/lib/hb/c3_debug.c
new file mode 100755 (executable)
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/src/lib/hb/c3_def.h b/src/lib/hb/c3_def.h
new file mode 100755 (executable)
index 0000000..c0fe07f
--- /dev/null
@@ -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/src/lib/hb/c3_draw.c b/src/lib/hb/c3_draw.c
new file mode 100755 (executable)
index 0000000..dfb055e
--- /dev/null
@@ -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/src/lib/hb/c3_game.c b/src/lib/hb/c3_game.c
new file mode 100755 (executable)
index 0000000..a71d254
--- /dev/null
@@ -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/src/lib/hb/c3_main.c b/src/lib/hb/c3_main.c
new file mode 100755 (executable)
index 0000000..684cb32
--- /dev/null
@@ -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/src/lib/hb/c3_play.c b/src/lib/hb/c3_play.c
new file mode 100755 (executable)
index 0000000..112041f
--- /dev/null
@@ -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/src/lib/hb/c3_sca_a.asm b/src/lib/hb/c3_sca_a.asm
new file mode 100755 (executable)
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/src/lib/hb/c3_scale.c b/src/lib/hb/c3_scale.c
new file mode 100755 (executable)
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/src/lib/hb/c3_state.c b/src/lib/hb/c3_state.c
new file mode 100755 (executable)
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
+                                                LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+dirtype opposite[9] =\r
+       {south,west,north,east,southwest,northwest,northeast,southeast,nodir};\r
+\r
+\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= SpawnNewObj\r
+=\r
+===================\r
+*/\r
+\r
+void SpawnNewObj (unsigned x, unsigned y, statetype *state, unsigned size)\r
+{\r
+       GetNewObj (false);\r
+       new->size = size;\r
+       new->state = state;\r
+       new->ticcount = random (state->tictime)+1;\r
+\r
+       new->tilex = x;\r
+       new->tiley = y;\r
+       new->x = ((long)x<<TILESHIFT)+TILEGLOBAL/2;\r
+       new->y = ((long)y<<TILESHIFT)+TILEGLOBAL/2;\r
+       CalcBounds(new);\r
+       new->dir = nodir;\r
+\r
+       actorat[new->tilex][new->tiley] = new;\r
+}\r
+\r
+void SpawnNewObjFrac (long x, long y, statetype *state, unsigned size)\r
+{\r
+       GetNewObj (false);\r
+       new->size = size;\r
+       new->state = state;\r
+       new->ticcount = random (state->tictime)+1;\r
+       new->active = true;\r
+\r
+       new->x = x;\r
+       new->y = y;\r
+       new->tilex = x>>TILESHIFT;\r
+       new->tiley = y>>TILESHIFT;\r
+       CalcBounds(new);\r
+       new->distance = 100;\r
+       new->dir = nodir;\r
+}\r
+\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= CheckHandAttack\r
+=\r
+= If the object can move next to the player, it will return true\r
+=\r
+===================\r
+*/\r
+\r
+boolean CheckHandAttack (objtype *ob)\r
+{\r
+       long deltax,deltay,size;\r
+\r
+       size = (long)ob->size + player->size + ob->speed*tics;\r
+       deltax = ob->x - player->x;\r
+       deltay = ob->y - player->y;\r
+\r
+       if (deltax > size || deltax < -size || deltay > size || deltay < -size)\r
+               return false;\r
+\r
+       return true;\r
+}\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= T_DoDamage\r
+=\r
+= Attacks the player if still nearby, then immediately changes to next state\r
+=\r
+===================\r
+*/\r
+\r
+void T_DoDamage (objtype *ob)\r
+{\r
+       int     points;\r
+\r
+\r
+       if (!CheckHandAttack (ob))\r
+       {\r
+               SD_PlaySound (MONSTERMISSSND);\r
+       }\r
+       else\r
+       {\r
+               points = 0;\r
+\r
+               switch (ob->obclass)\r
+               {\r
+               case orcobj:\r
+                       points = 4;\r
+                       break;\r
+               case trollobj:\r
+                       points = 8;\r
+                       break;\r
+               case demonobj:\r
+                       points = 15;\r
+                       break;\r
+               }\r
+               TakeDamage (points);\r
+       }\r
+\r
+       ob->state = ob->state->next;\r
+}\r
+\r
+\r
+//==========================================================================\r
+\r
+/*\r
+==================================\r
+=\r
+= Walk\r
+=\r
+==================================\r
+*/\r
+\r
+boolean Walk (objtype *ob)\r
+{\r
+       switch (ob->dir)\r
+       {\r
+       case north:\r
+               if (actorat[ob->tilex][ob->tiley-1])\r
+                       return false;\r
+               ob->tiley--;\r
+               ob->distance = TILEGLOBAL;\r
+               return true;\r
+\r
+       case northeast:\r
+               if (actorat[ob->tilex+1][ob->tiley-1])\r
+                       return false;\r
+               ob->tilex++;\r
+               ob->tiley--;\r
+               ob->distance = TILEGLOBAL;\r
+               return true;\r
+\r
+       case east:\r
+               if (actorat[ob->tilex+1][ob->tiley])\r
+                       return false;\r
+               ob->tilex++;\r
+               ob->distance = TILEGLOBAL;\r
+               return true;\r
+\r
+       case southeast:\r
+               if (actorat[ob->tilex+1][ob->tiley+1])\r
+                       return false;\r
+               ob->tilex++;\r
+               ob->tiley++;\r
+               ob->distance = TILEGLOBAL;\r
+               return true;\r
+\r
+       case south:\r
+               if (actorat[ob->tilex][ob->tiley+1])\r
+                       return false;\r
+               ob->tiley++;\r
+               ob->distance = TILEGLOBAL;\r
+               return true;\r
+\r
+       case southwest:\r
+               if (actorat[ob->tilex-1][ob->tiley+1])\r
+                       return false;\r
+               ob->tilex--;\r
+               ob->tiley++;\r
+               ob->distance = TILEGLOBAL;\r
+               return true;\r
+\r
+       case west:\r
+               if (actorat[ob->tilex-1][ob->tiley])\r
+                       return false;\r
+               ob->tilex--;\r
+               ob->distance = TILEGLOBAL;\r
+               return true;\r
+\r
+       case northwest:\r
+               if (actorat[ob->tilex-1][ob->tiley-1])\r
+                       return false;\r
+               ob->tilex--;\r
+               ob->tiley--;\r
+               ob->distance = TILEGLOBAL;\r
+               return true;\r
+\r
+       case nodir:\r
+               return false;\r
+       }\r
+\r
+       Quit ("Walk: Bad dir");\r
+       return false;\r
+}\r
+\r
+\r
+\r
+/*\r
+==================================\r
+=\r
+= ChaseThink\r
+= have the current monster go after the player,\r
+= either diagonally or straight on\r
+=\r
+==================================\r
+*/\r
+\r
+void ChaseThink (objtype *obj, boolean diagonal)\r
+{\r
+       int deltax,deltay,i;\r
+       dirtype d[3];\r
+       dirtype tdir, olddir, turnaround;\r
+\r
+\r
+       olddir=obj->dir;\r
+       turnaround=opposite[olddir];\r
+\r
+       deltax=player->tilex - obj->tilex;\r
+       deltay=player->tiley - obj->tiley;\r
+\r
+       d[1]=nodir;\r
+       d[2]=nodir;\r
+\r
+       if (deltax>0)\r
+               d[1]= east;\r
+       if (deltax<0)\r
+               d[1]= west;\r
+       if (deltay>0)\r
+               d[2]=south;\r
+       if (deltay<0)\r
+               d[2]=north;\r
+\r
+       if (abs(deltay)>abs(deltax))\r
+       {\r
+               tdir=d[1];\r
+               d[1]=d[2];\r
+               d[2]=tdir;\r
+       }\r
+\r
+       if (d[1]==turnaround)\r
+               d[1]=nodir;\r
+       if (d[2]==turnaround)\r
+               d[2]=nodir;\r
+\r
+\r
+       if (diagonal)\r
+       {                           /*ramdiagonals try the best dir first*/\r
+               if (d[1]!=nodir)\r
+               {\r
+                       obj->dir=d[1];\r
+                       if (Walk(obj))\r
+                               return;     /*either moved forward or attacked*/\r
+               }\r
+\r
+               if (d[2]!=nodir)\r
+               {\r
+                       obj->dir=d[2];\r
+                       if (Walk(obj))\r
+                               return;\r
+               }\r
+       }\r
+       else\r
+       {                  /*ramstraights try the second best dir first*/\r
+\r
+               if (d[2]!=nodir)\r
+               {\r
+                       obj->dir=d[2];\r
+                       if (Walk(obj))\r
+                               return;\r
+               }\r
+\r
+               if (d[1]!=nodir)\r
+               {\r
+                       obj->dir=d[1];\r
+                       if (Walk(obj))\r
+                               return;\r
+               }\r
+       }\r
+\r
+/* there is no direct path to the player, so pick another direction */\r
+\r
+       obj->dir=olddir;\r
+       if (Walk(obj))\r
+               return;\r
+\r
+       if (US_RndT()>128)      /*randomly determine direction of search*/\r
+       {\r
+               for (tdir=north;tdir<=west;tdir++)\r
+               {\r
+                       if (tdir!=turnaround)\r
+                       {\r
+                               obj->dir=tdir;\r
+                               if (Walk(obj))\r
+                                       return;\r
+                       }\r
+               }\r
+       }\r
+       else\r
+       {\r
+               for (tdir=west;tdir>=north;tdir--)\r
+               {\r
+                       if (tdir!=turnaround)\r
+                       {\r
+                         obj->dir=tdir;\r
+                         if (Walk(obj))\r
+                               return;\r
+                       }\r
+               }\r
+       }\r
+\r
+       obj->dir=turnaround;\r
+       Walk(obj);              /*last chance, don't worry about returned value*/\r
+}\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= MoveObj\r
+=\r
+=================\r
+*/\r
+\r
+void MoveObj (objtype *ob, long move)\r
+{\r
+       ob->distance -=move;\r
+\r
+       switch (ob->dir)\r
+       {\r
+       case north:\r
+               ob->y -= move;\r
+               return;\r
+       case northeast:\r
+               ob->x += move;\r
+               ob->y -= move;\r
+               return;\r
+       case east:\r
+               ob->x += move;\r
+               return;\r
+       case southeast:\r
+               ob->x += move;\r
+               ob->y += move;\r
+               return;\r
+       case south:\r
+               ob->y += move;\r
+               return;\r
+       case southwest:\r
+               ob->x -= move;\r
+               ob->y += move;\r
+               return;\r
+       case west:\r
+               ob->x -= move;\r
+               return;\r
+       case northwest:\r
+               ob->x -= move;\r
+               ob->y -= move;\r
+               return;\r
+\r
+       case nodir:\r
+               return;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= Chase\r
+=\r
+= returns true if hand attack range\r
+=\r
+=================\r
+*/\r
+\r
+boolean Chase (objtype *ob, boolean diagonal)\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
+       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)\r
+               {\r
+                       CalcBounds (ob);\r
+                       return true;\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
+               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
+               ChaseThink (ob,diagonal);\r
+               if (!ob->distance)\r
+                       break;                  // no possible move\r
+               actorat[ob->tilex][ob->tiley] = ob;     // set down a new goal marker\r
+       }\r
+       CalcBounds (ob);\r
+       return false;\r
+}\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= ShootActor\r
+=\r
+===================\r
+*/\r
+\r
+void ShootActor (objtype *ob, unsigned damage)\r
+{\r
+       ob->hitpoints -= damage;\r
+       if (ob->hitpoints<=0)\r
+       {\r
+               switch (ob->obclass)\r
+               {\r
+               case orcobj:\r
+                       ob->state = &s_orcdie1;\r
+                       GivePoints (100);\r
+                       break;\r
+               case trollobj:\r
+                       ob->state = &s_trolldie1;\r
+                       GivePoints (400);\r
+                       break;\r
+               case demonobj:\r
+                       ob->state = &s_demondie1;\r
+                       GivePoints (1000);\r
+                       break;\r
+               case mageobj:\r
+                       ob->state = &s_magedie1;\r
+                       GivePoints (600);\r
+                       break;\r
+               case batobj:\r
+                       ob->state = &s_batdie1;\r
+                       GivePoints (100);\r
+                       break;\r
+               case grelmobj:\r
+                       ob->state = &s_greldie1;\r
+                       GivePoints (10000);\r
+                       break;\r
+\r
+               }\r
+               ob->obclass = inertobj;\r
+               ob->shootable = false;\r
+               actorat[ob->tilex][ob->tiley] = NULL;\r
+       }\r
+       else\r
+       {\r
+               switch (ob->obclass)\r
+               {\r
+               case orcobj:\r
+                       ob->state = &s_orcouch;\r
+                       break;\r
+               case trollobj:\r
+                       ob->state = &s_trollouch;\r
+                       break;\r
+               case demonobj:\r
+                       ob->state = &s_demonouch;\r
+                       break;\r
+               case mageobj:\r
+                       ob->state = &s_mageouch;\r
+                       break;\r
+               case grelmobj:\r
+                       ob->state = &s_grelouch;\r
+                       break;\r
+\r
+               }\r
+       }\r
+       ob->ticcount = ob->state->tictime;\r
+}\r
+\r
diff --git a/src/lib/hb/c3_trace.c b/src/lib/hb/c3_trace.c
new file mode 100755 (executable)
index 0000000..45cb1bc
--- /dev/null
@@ -0,0 +1,872 @@
+/* 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_TRACE.C\r
+\r
+#include "C3_DEF.H"\r
+#pragma hdrstop\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+//\r
+// TESTWALLVISABLE will set the global variable wallvisable to 1 or 0\r
+// depending on if tile.x,tile.y,wallon is visable from focal point\r
+//\r
+#define TESTWALLVISABLE {                                              \\r
+       if (tile.y<focal.y)                         \\r
+               voffset = 0;                            \\r
+       else if (tile.y==focal.y)                   \\r
+               voffset = 3;                            \\r
+       else                                        \\r
+               voffset = 6;                            \\r
+       if (tile.x==focal.x)                        \\r
+               voffset ++;                             \\r
+       else if (tile.x>focal.x)                    \\r
+               voffset += 2;                           \\r
+       wallvisable = visable[voffset][wallon]; }\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                GLOBAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+boolean        aborttrace;\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+unsigned       wallvisable,voffset;\r
+\r
+\r
+fixed edgex,edgey;\r
+\r
+int wallon;\r
+int basecolor;\r
+\r
+walltype *oldwall;\r
+\r
+//\r
+// offsets from upper left corner of a tile to the left and right edges of\r
+// a given wall (NORTH-WEST)\r
+//\r
+fixed point1x[4] = {GLOBAL1,GLOBAL1,0      ,0       };\r
+fixed point1y[4] = {0      ,GLOBAL1,GLOBAL1,0       };\r
+\r
+fixed point2x[4] = {0      ,GLOBAL1,GLOBAL1,0       };\r
+fixed point2y[4] = {0     ,0      ,GLOBAL1 ,GLOBAL1};\r
+\r
+\r
+//\r
+// offset from tile.x,tile.y of the tile that shares wallon side\r
+// (side is not visable if it is shared)\r
+//\r
+int sharex[4] = { 0, 1, 0,-1};\r
+int sharey[4] = {-1, 0, 1, 0};\r
+\r
+//\r
+// amount to move tile.x,tile.y to follow wallon to another tile\r
+//\r
+int followx[4] = {-1, 0, 1, 0};\r
+int followy[4] = { 0,-1, 0, 1};\r
+\r
+//\r
+// cornerwall gives the wall on the same tile to start following when the\r
+// wall ends at an empty tile (go around an edge on same tile)\r
+// turnwall gives the wall on tile.x+sharex,tile.y+sharey to start following\r
+// when the wall hits another tile (right angle corner)\r
+//\r
+int cornerwall[4] = {WEST,NORTH,EAST,SOUTH};\r
+int turnwall[4] = {EAST,SOUTH,WEST,NORTH};\r
+\r
+//\r
+// wall visabilities in reletive locations\r
+// -,- 0,- +,-\r
+// -,0 0,0 +,0\r
+// -,+ 0,+ +,+\r
+//\r
+int visable[9][4] =\r
+{\r
+ {0,1,1,0}, {0,0,1,0}, {0,0,1,1},\r
+ {0,1,0,0}, {0,0,0,0}, {0,0,0,1},\r
+ {1,1,0,0}, {1,0,0,0}, {1,0,0,1}\r
+};\r
+\r
+int startwall[9] =  {2,2,3, 1,0,3, 1,0,0};\r
+int backupwall[9] = {3,3,0, 2,0,0, 2,1,1};\r
+\r
+\r
+int    walllength;\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                        FUNCTIONS\r
+\r
+=============================================================================\r
+*/\r
+\r
+/*\r
+========================\r
+=\r
+= FollowTrace\r
+=\r
+========================\r
+*/\r
+\r
+int FollowTrace (fixed tracex, fixed tracey, long deltax, long deltay, int max)\r
+{\r
+       int tx,ty,otx,oty;\r
+       long absdx,absdy,xstep,ystep;\r
+\r
+       tx = tracex>>TILESHIFT;\r
+       ty = tracey>>TILESHIFT;\r
+\r
+       spotvis[tx][ty] = true;\r
+\r
+       absdx=LABS(deltax);\r
+       absdy=LABS(deltay);\r
+\r
+       if (absdx>absdy)\r
+       {\r
+               ystep = (deltay<<8)/(absdx>>8);\r
+\r
+               if (!ystep)\r
+                       ystep = deltay>0 ? 1 : -1;\r
+\r
+               oty = (tracey+ystep)>>TILESHIFT;\r
+               if (deltax>0)\r
+               {\r
+//###############\r
+//\r
+// step x by +1\r
+//\r
+//###############\r
+                       do\r
+                       {\r
+                               tx++;\r
+                               spotvis[tx][ty] = true;\r
+                               tracey+=ystep;\r
+                               ty = tracey>>TILESHIFT;\r
+\r
+                               if (ty!=oty)\r
+                               {\r
+                                       if (tilemap[tx-1][ty])\r
+                                       {\r
+                                               tile.x = tx-1;\r
+                                               tile.y = ty;\r
+                                               return 1;\r
+                                       }\r
+                                       oty = ty;\r
+                               }\r
+                               if (tilemap[tx][ty])\r
+                               {\r
+                                       tile.x = tx;\r
+                                       tile.y = ty;\r
+                                       return 1;\r
+                               }\r
+                       } while (--max);\r
+                       return 0;\r
+               }\r
+               else\r
+               {\r
+//###############\r
+//\r
+// step x by -1\r
+//\r
+//###############\r
+                       do\r
+                       {\r
+                               tx--;\r
+                               spotvis[tx][ty] = true;\r
+                               tracey+=ystep;\r
+                               ty = tracey>>TILESHIFT;\r
+\r
+                               if (ty!=oty)\r
+                               {\r
+                                       if (tilemap[tx][oty])\r
+                                       {\r
+                                               tile.x = tx;\r
+                                               tile.y = oty;\r
+                                               return 1;\r
+                                       }\r
+                                       oty = ty;\r
+                               }\r
+                               if (tilemap[tx][ty])\r
+                               {\r
+                                       tile.x = tx;\r
+                                       tile.y = ty;\r
+                                       return 1;\r
+                               }\r
+                       } while (--max);\r
+                       return 0;\r
+\r
+               }\r
+       }\r
+       else\r
+       {\r
+               xstep = (deltax<<8)/(absdy>>8);\r
+               if (!xstep)\r
+                       xstep = deltax>0 ? 1 : -1;\r
+\r
+\r
+               otx = (tracex+xstep)>>TILESHIFT;\r
+               if (deltay>0)\r
+               {\r
+//###############\r
+//\r
+// step y by +1\r
+//\r
+//###############\r
+                       do\r
+                       {\r
+                               ty++;\r
+                               spotvis[tx][ty] = true;\r
+                               tracex+=xstep;\r
+                               tx = tracex>>TILESHIFT;\r
+\r
+                               if (tx!=otx)\r
+                               {\r
+                                       if (tilemap[tx][ty-1])\r
+                                       {\r
+                                               tile.x = tx;\r
+                                               tile.y = ty-1;\r
+                                               return 1;\r
+                                       }\r
+                                       otx = tx;\r
+                               }\r
+                               if (tilemap[tx][ty])\r
+                               {\r
+                                       tile.x = tx;\r
+                                       tile.y = ty;\r
+                                       return 1;\r
+                               }\r
+                       } while (--max);\r
+                       return 0;\r
+               }\r
+               else\r
+               {\r
+//###############\r
+//\r
+// step y by -1\r
+//\r
+//###############\r
+                       do\r
+                       {\r
+                               ty--;\r
+                               spotvis[tx][ty] = true;\r
+                               tracex+=xstep;\r
+                               tx = tracex>>TILESHIFT;\r
+\r
+                               if (tx!=otx)\r
+                               {\r
+                                       if (tilemap[otx][ty])\r
+                                       {\r
+                                               tile.x = otx;\r
+                                               tile.y = ty;\r
+                                               return 1;\r
+                                       }\r
+                                       otx = tx;\r
+                               }\r
+                               if (tilemap[tx][ty])\r
+                               {\r
+                                       tile.x = tx;\r
+                                       tile.y = ty;\r
+                                       return 1;\r
+                               }\r
+                       } while (--max);\r
+                       return 0;\r
+               }\r
+\r
+       }\r
+\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= BackTrace\r
+=\r
+= Traces backwards from edgex,edgey to viewx,viewy to see if a closer\r
+= tile obscures the given point.  If it does, it finishes the wall and\r
+= starts a new one.\r
+= Returns true if a tile is hit.\r
+= Call with a 1 to have it automatically finish the current wall\r
+=\r
+=================\r
+*/\r
+\r
+int BackTrace (int finish)\r
+{\r
+  fixed tracex,tracey;\r
+  long deltax,deltay,absdx,absdy;\r
+  int steps,otx,oty,testx,testheight,offset,wall;\r
+\r
+  deltax = viewx-edgex;\r
+  deltay = viewy-edgey;\r
+\r
+  absdx = LABS(deltax);\r
+  absdy = LABS(deltay);\r
+\r
+  if (absdx>absdy)\r
+    steps = ABS(focal.x-(edgex>>TILESHIFT))-1;\r
+  else\r
+    steps = ABS(focal.y-(edgey>>TILESHIFT))-1;\r
+\r
+  if (steps<=0)\r
+    return 0;\r
+\r
+  otx = tile.x;\r
+  oty = tile.y;\r
+  if (!FollowTrace(edgex,edgey,deltax,deltay,steps))\r
+    return 0;\r
+\r
+//\r
+// if the start wall is behind the focal point, the trace went too far back\r
+//\r
+  if (ABS(tile.x-focal.x)<2 && ABS(tile.y-focal.y)<2)  // too close\r
+  {\r
+    if (tile.x == focal.x && tile.y == focal.y)\r
+    {\r
+      tile.x = otx;\r
+      tile.y = oty;\r
+      return 0;\r
+    }\r
+\r
+    if (tile.x<focal.x)\r
+    {\r
+      if (tile.y<focal.y)\r
+       wall = SOUTH;\r
+      else\r
+       wall = EAST;\r
+    }\r
+    else if (tile.x==focal.x)\r
+    {\r
+         if (tile.y<focal.y)\r
+       wall = SOUTH;\r
+      else\r
+       wall = NORTH;\r
+    }\r
+    else\r
+       {\r
+      if (tile.y<=focal.y)\r
+       wall = WEST;\r
+      else\r
+       wall = NORTH;\r
+    }\r
+\r
+    //\r
+    // rotate the X value to see if it is behind the view plane\r
+    //\r
+    if (TransformX (((long)tile.x<<16)+point1x[wall],\r
+                   ((long)tile.y<<16)+point1y[wall]) < FOCALLENGTH)\r
+    {\r
+      tile.x = otx;\r
+      tile.y = oty;\r
+      return 0;\r
+    }\r
+  }\r
+\r
+//\r
+// if the old wall is still behind a closer wall, ignore the back trace\r
+// and continue on (dealing with limited precision...)\r
+//\r
+  if (finish && !FinishWall ())        // the wall is still behind a forward wall\r
+  {\r
+    tile.x = otx;\r
+    tile.y = oty;\r
+    rightwall->x1 = oldwall->x2;               // common edge with last wall\r
+    rightwall->height1 = oldwall->height2;\r
+    return 0;\r
+  }\r
+\r
+\r
+//\r
+// back up along the intersecting face to find the rightmost wall\r
+//\r
+\r
+  if (tile.y<focal.y)\r
+    offset = 0;\r
+  else if (tile.y==focal.y)\r
+    offset = 3;\r
+  else\r
+    offset = 6;\r
+  if (tile.x==focal.x)\r
+    offset ++;\r
+  else if (tile.x>focal.x)\r
+    offset += 2;\r
+\r
+  wallon = backupwall[offset];\r
+\r
+  while (tilemap[tile.x][tile.y])\r
+  {\r
+    tile.x += followx[wallon];\r
+    tile.y += followy[wallon];\r
+  };\r
+\r
+  tile.x -= followx[wallon];\r
+  tile.y -= followy[wallon];\r
+\r
+  wallon = cornerwall[wallon]; // turn to first visable face\r
+\r
+  edgex = ((long)tile.x<<16);\r
+  edgey = ((long)tile.y<<16);\r
+\r
+  TransformPoint (edgex+point1x[wallon],edgey+point1y[wallon],\r
+    &rightwall->x1,&rightwall->height1);\r
+\r
+  basecolor = tilemap[tile.x][tile.y];\r
+\r
+  return 1;\r
+}\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= ForwardTrace\r
+=\r
+= Traces forwards from edgex,edgey along the line from viewx,viewy until\r
+= a solid tile is hit.  Sets tile.x,tile.y\r
+=\r
+=================\r
+*/\r
+\r
+void ForwardTrace (void)\r
+{\r
+  int offset;\r
+  fixed tracex,tracey;\r
+  long deltax,deltay;\r
+\r
+  deltax = edgex-viewx;\r
+  deltay = edgey-viewy;\r
+\r
+  FollowTrace(edgex,edgey,deltax,deltay,0);\r
+\r
+  if (tile.y<focal.y)\r
+    offset = 0;\r
+  else if (tile.y==focal.y)\r
+    offset = 3;\r
+  else\r
+    offset = 6;\r
+  if (tile.x==focal.x)\r
+    offset ++;\r
+  else if (tile.x>focal.x)\r
+    offset += 2;\r
+\r
+  wallon = startwall[offset];\r
+\r
+//\r
+// start the new wall\r
+//\r
+  edgex = ((long)tile.x<<16);\r
+  edgey = ((long)tile.y<<16);\r
+\r
+//\r
+// if entire first wall is invisable, corner\r
+//\r
+  TransformPoint (edgex+point2x[wallon],edgey+point2y[wallon],\r
+    &rightwall->x2,&rightwall->height2);\r
+\r
+  if (tilemap [tile.x+sharex[wallon]] [tile.y+sharey[wallon]]\r
+  || rightwall->x2 < (rightwall-1)->x2 )\r
+    wallon = cornerwall [wallon];\r
+\r
+//\r
+// transform first point\r
+//\r
+\r
+  TransformPoint (edgex+point1x[wallon],edgey+point1y[wallon],\r
+    &rightwall->x1,&rightwall->height1);\r
+\r
+  basecolor = tilemap[tile.x][tile.y];\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= FinishWall\r
+=\r
+= Transforms edgex,edgey as the next point of the current wall\r
+= and sticks it in the wall list\r
+=\r
+=================\r
+*/\r
+\r
+int FinishWall (void)\r
+{\r
+  char num[20];\r
+\r
+  oldwall = rightwall;\r
+\r
+       rightwall->color  = basecolor;\r
+\r
+  TransformPoint (edgex,edgey,&rightwall->x2,&rightwall->height2);\r
+\r
+  if (rightwall->x2 <= (rightwall-1)->x2+2\r
+  && rightwall->height2 < (rightwall-1)->height2 )\r
+       return 0;\r
+\r
+  rightwall->walllength = walllength;\r
+\r
+  switch (wallon)\r
+  {\r
+  case north:\r
+  case south:\r
+         rightwall->side = 0;\r
+         rightwall->planecoord = edgey;\r
+         break;\r
+\r
+  case west:\r
+  case east:\r
+         rightwall->side = 1;\r
+         rightwall->planecoord = edgex;\r
+         break;\r
+  }\r
+\r
+  walllength = 1;\r
+\r
+  rightwall++;\r
+\r
+  return 1;\r
+}\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= InsideCorner\r
+=\r
+=================\r
+*/\r
+\r
+void InsideCorner (void)\r
+{\r
+  int offset;\r
+\r
+  //\r
+  // the wall turned -90 degrees, so draw what we have, move to the new tile,\r
+  // change wallon, change color, and continue following.\r
+  //\r
+  FinishWall ();\r
+\r
+  tile.x += sharex[wallon];\r
+  tile.y += sharey[wallon];\r
+\r
+  wallon = turnwall[wallon];\r
+\r
+  //\r
+  // if the new wall is visable, continue following it.  Otherwise\r
+  // follow it backwards until it turns\r
+  //\r
+  TESTWALLVISABLE;\r
+\r
+  if (wallvisable)\r
+  {\r
+  //\r
+  // just turn to the next wall and continue\r
+  //\r
+    rightwall->x1 = oldwall->x2;               // common edge with last wall\r
+    rightwall->height1 = oldwall->height2;\r
+    basecolor = tilemap[tile.x][tile.y];\r
+    return;                    // continue from here\r
+  }\r
+\r
+  //\r
+  // back follow the invisable wall until it turns, then follow that\r
+  //\r
+  do\r
+  {\r
+       tile.x += followx[wallon];\r
+    tile.y += followy[wallon];\r
+  } while (tilemap[tile.x][tile.y]);\r
+\r
+  tile.x -= followx[wallon];\r
+  tile.y -= followy[wallon];\r
+\r
+  wallon = cornerwall[wallon]; // turn to first visable face\r
+\r
+  edgex = ((long)tile.x<<16)+point1x[wallon];\r
+  edgey = ((long)tile.y<<16)+point1y[wallon];\r
+\r
+  if (!BackTrace(0))           // backtrace without finishing a wall\r
+  {\r
+    TransformPoint (edgex,edgey,&rightwall->x1,&rightwall->height1);\r
+    basecolor = tilemap[tile.x][tile.y];\r
+  }\r
+}\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= OutsideCorner\r
+=\r
+=================\r
+*/\r
+\r
+void OutsideCorner (void)\r
+{\r
+  int offset;\r
+\r
+  //\r
+  // edge is the outside edge of a corner, so draw the current wall and\r
+  // turn the corner (+90 degrees)\r
+  //\r
+  FinishWall ();\r
+\r
+  tile.x -= followx[wallon];   // backup to the real tile\r
+  tile.y -= followy[wallon];\r
+  wallon = cornerwall[wallon];\r
+\r
+  //\r
+  // if the new wall is visable, continue following it.  Otherwise\r
+  // trace a ray from the corner to find a wall in the distance to\r
+  // follow\r
+  //\r
+  TESTWALLVISABLE;\r
+\r
+  if (wallvisable)\r
+  {\r
+  //\r
+  // the new wall is visable, so just continue on\r
+  //\r
+    rightwall->x1 = oldwall->x2;               // common edge with last wall\r
+    rightwall->height1 = oldwall->height2;\r
+    return;                    // still on same tile, so color is ok\r
+  }\r
+\r
+//\r
+// start from a new tile further away\r
+//\r
+  ForwardTrace();              // find the next wall further back\r
+\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= FollowWalls\r
+=\r
+= Starts a wall edge at the leftmost edge of tile.x,tile.y and follows it\r
+= until something else is seen or the entire view area is covered\r
+=\r
+=================\r
+*/\r
+\r
+void FollowWalls (void)\r
+{\r
+  int height,newcolor,offset,wall;\r
+\r
+//####################\r
+//\r
+// figure leftmost wall of new tile\r
+//\r
+//####################\r
+\r
+restart:\r
+\r
+  walllength = 1;\r
+\r
+  if (tile.y<focal.y)\r
+       offset = 0;\r
+  else if (tile.y==focal.y)\r
+       offset = 3;\r
+  else\r
+       offset = 6;\r
+  if (tile.x==focal.x)\r
+       offset ++;\r
+  else if (tile.x>focal.x)\r
+       offset += 2;\r
+\r
+  wallon = startwall[offset];\r
+\r
+//\r
+// if the start wall is inside a block, skip it by cornering to the second wall\r
+//\r
+  if ( tilemap [tile.x+sharex[wallon]] [tile.y+sharey[wallon]])\r
+       wallon = cornerwall [wallon];\r
+\r
+//\r
+// transform first edge to screen coordinates\r
+//\r
+  edgex = ((long)tile.x<<16);\r
+  edgey = ((long)tile.y<<16);\r
+\r
+  TransformPoint (edgex+point1x[wallon],edgey+point1y[wallon],\r
+       &rightwall->x1,&rightwall->height1);\r
+\r
+  basecolor = tilemap[tile.x][tile.y];\r
+\r
+//##################\r
+//\r
+// follow the wall as long as possible\r
+//\r
+//##################\r
+\r
+advance:\r
+\r
+  do   // while ( tile.x != right.x || tile.y != right.y)\r
+  {\r
+//\r
+// check for conditions that shouldn't happed...\r
+//\r
+       if (rightwall->x1 > VIEWXH)     // somehow missed right tile...\r
+         return;\r
+\r
+       if (rightwall == &walls[DANGERHIGH])\r
+       {\r
+  //\r
+  // somethiing got messed up!  Correct by thrusting ahead...\r
+  //\r
+               VW_ColorBorder(6);\r
+               bordertime = 60;\r
+               Thrust(player->angle,TILEGLOBAL/4);\r
+               player->angle+=5;\r
+               if (player->angle>ANGLES)\r
+                       player->angle-=ANGLES;\r
+               aborttrace = true;\r
+               return;\r
+\r
+#if 0\r
+         strcpy (str,"Wall list overflow at LE:");\r
+         itoa(mapon+1,str2,10);\r
+         strcat (str,str2);\r
+         strcat (str," X:");\r
+         ltoa(objlist[0].x,str2,10);\r
+         strcat (str,str2);\r
+         strcat (str," Y:");\r
+         ltoa(objlist[0].y,str2,10);\r
+         strcat (str,str2);\r
+         strcat (str," AN:");\r
+         itoa(objlist[0].angle,str2,10);\r
+         strcat (str,str2);\r
+\r
+         Quit (str);\r
+#endif\r
+       }\r
+\r
+//\r
+// proceed along wall\r
+//\r
+\r
+       edgex = ((long)tile.x<<16)+point2x[wallon];\r
+       edgey = ((long)tile.y<<16)+point2y[wallon];\r
+\r
+       if (BackTrace(1))               // went behind a closer wall\r
+         continue;\r
+\r
+       //\r
+       // advance to next tile along wall\r
+       //\r
+       tile.x += followx[wallon];\r
+       tile.y += followy[wallon];\r
+\r
+       if (tilemap [tile.x+sharex[wallon]] [tile.y+sharey[wallon]])\r
+       {\r
+         InsideCorner ();              // turn at a corner\r
+         continue;\r
+       }\r
+\r
+       newcolor = tilemap[tile.x][tile.y];\r
+\r
+       if (!newcolor)          // turn around an edge\r
+       {\r
+         OutsideCorner ();\r
+         continue;\r
+       }\r
+\r
+       if (newcolor != basecolor)\r
+       {\r
+         //\r
+         // wall changed color, so draw what we have and continue following\r
+         //\r
+         FinishWall ();\r
+         rightwall->x1 = oldwall->x2;  // new wall shares this edge\r
+         rightwall->height1 = oldwall->height2;\r
+         basecolor = newcolor;\r
+\r
+         continue;\r
+       }\r
+       walllength++;\r
+  } while (tile.x != right.x || tile.y != right.y);\r
+\r
+\r
+\r
+//######################\r
+//\r
+// draw the last tile\r
+//\r
+//######################\r
+\r
+  edgex = ((long)tile.x<<16)+point2x[wallon];\r
+  edgey = ((long)tile.y<<16)+point2y[wallon];\r
+  FinishWall();\r
+\r
+  wallon = cornerwall[wallon];\r
+\r
+  //\r
+  // if the corner wall is visable, draw it\r
+  //\r
+  TESTWALLVISABLE;\r
+\r
+  if (wallvisable)\r
+  {\r
+    rightwall->x1 = oldwall->x2;               // common edge with last wall\r
+    rightwall->height1 = oldwall->height2;\r
+    edgex = ((long)tile.x<<16)+point2x[wallon];\r
+    edgey = ((long)tile.y<<16)+point2y[wallon];\r
+    FinishWall();\r
+  }\r
+\r
+}\r
+\r
+//===========================================================================\r
diff --git a/src/lib/hb/c3_wiz.c b/src/lib/hb/c3_wiz.c
new file mode 100755 (executable)
index 0000000..1d68bc7
--- /dev/null
@@ -0,0 +1,2046 @@
+/* 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_WIZ.C\r
+\r
+#include "C3_DEF.H"\r
+#pragma hdrstop\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+#define NUMSCROLLS     8\r
+\r
+#define        SHOWITEMS       9\r
+\r
+#define        NUKETIME        40\r
+#define NUMBOLTS       10\r
+#define BOLTTICS       6\r
+\r
+#define STATUSCOLOR    4\r
+#define TEXTCOLOR      14\r
+\r
+#define SIDEBARWIDTH   5\r
+\r
+#define BODYLINE    8\r
+#define POWERLINE      80\r
+\r
+#define SPECTILESTART  18\r
+\r
+\r
+#define SHOTDAMAGE             1\r
+#define BIGSHOTDAMAGE  3\r
+\r
+\r
+#define PLAYERSPEED    5120\r
+#define RUNSPEED       8192\r
+\r
+#define SHOTSPEED      10000\r
+\r
+#define LASTWALLTILE   17\r
+#define LASTSPECIALTILE        37\r
+\r
+#define FIRETIME       4       // DEBUG 60\r
+\r
+#define HANDPAUSE      60\r
+\r
+#define COMPASSX       33\r
+#define COMPASSY       0\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                GLOBAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+long           lastnuke,lasthand;\r
+int                    handheight;\r
+int                    boltsleft;\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+int                    lasttext,lastcompass;\r
+int                    bolttimer;\r
+unsigned       lastfiretime;\r
+\r
+int    strafeangle[9] = {0,90,180,270,45,135,225,315,0};\r
+\r
+\r
+//===========================================================================\r
+\r
+void DrawChar (unsigned x, unsigned y, unsigned tile);\r
+void RedrawStatusWindow (void);\r
+void GiveBolt (void);\r
+void TakeBolt (void);\r
+void GiveNuke (void);\r
+void TakeNuke (void);\r
+void GivePotion (void);\r
+void TakePotion (void);\r
+void GiveKey (int keytype);\r
+void TakeKey (int keytype);\r
+void GiveScroll (int scrolltype,boolean show);\r
+void ReadScroll (int scroll);\r
+void GivePoints (int points);\r
+void DrawLevelNumber (int number);\r
+void DrawText (void);\r
+void DrawBars (void);\r
+\r
+//----------\r
+\r
+void Shoot (void);\r
+void BigShoot (void);\r
+void CastBolt (void);\r
+void CastNuke (void);\r
+void DrinkPotion (void);\r
+\r
+//----------\r
+\r
+void SpawnPlayer (int tilex, int tiley, int dir);\r
+void Thrust (int angle, unsigned speed);\r
+void T_Player (objtype *ob);\r
+\r
+void AddPoints (int points);\r
+\r
+void ClipMove (objtype *ob, long xmove, long ymove);\r
+boolean ShotClipMove (objtype *ob, long xmove, long ymove);\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= DrawChar\r
+=\r
+===============\r
+*/\r
+\r
+void DrawChar (unsigned x, unsigned y, unsigned tile)\r
+{\r
+       unsigned junk = latchpics[0];\r
+\r
+       EGAWRITEMODE(1);\r
+asm    mov     bx,[y]\r
+asm    shl     bx,1\r
+asm    mov     di,[WORD PTR ylookup+bx]\r
+asm    add     di,[x]\r
+asm    mov     si,[tile]\r
+asm    shl     si,1\r
+asm    shl     si,1\r
+asm    shl     si,1\r
+asm    add     si,[junk]               // the damn inline assembler won't reference latchpics\r
+asm    mov     ax,[screenseg]\r
+asm    mov     es,ax\r
+asm    mov     ds,ax\r
+asm    mov     dx,SCREENWIDTH-1\r
+asm    movsb\r
+asm    add     di,dx\r
+asm    movsb\r
+asm    add     di,dx\r
+asm    movsb\r
+asm    add     di,dx\r
+asm    movsb\r
+asm    add     di,dx\r
+asm    movsb\r
+asm    add     di,dx\r
+asm    movsb\r
+asm    add     di,dx\r
+asm    movsb\r
+asm    add     di,dx\r
+asm    movsb\r
+\r
+asm    mov     ax,ss\r
+asm    mov     ds,ax\r
+       EGAWRITEMODE(0);\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= RedrawStatusWindow\r
+=\r
+===============\r
+*/\r
+\r
+void RedrawStatusWindow (void)\r
+{\r
+       int     i,j,x;\r
+\r
+       DrawLevelNumber (gamestate.mapon);\r
+       lasttext = -1;\r
+       lastcompass = -1;\r
+\r
+       j = gamestate.bolts < SHOWITEMS ? gamestate.bolts : SHOWITEMS;\r
+       for (i=0;i<j;i++)\r
+               DrawChar(7+i,20,BOLTCHAR);\r
+       j = gamestate.nukes < SHOWITEMS ? gamestate.nukes : SHOWITEMS;\r
+       for (i=0;i<j;i++)\r
+               DrawChar(7+i,30,NUKECHAR);\r
+       j = gamestate.potions < SHOWITEMS ? gamestate.potions : SHOWITEMS;\r
+       for (i=0;i<j;i++)\r
+               DrawChar(7+i,40,POTIONCHAR);\r
+\r
+       x=24;\r
+       for (i=0;i<4;i++)\r
+               for (j=0;j<gamestate.keys[i];j++)\r
+                       DrawChar(x++,20,KEYCHARS+i);\r
+\r
+       x=24;\r
+       for (i=0;i<8;i++)\r
+               if (gamestate.scrolls[i])\r
+                       DrawChar(x++,30,SCROLLCHARS+i);\r
+\r
+       AddPoints(0);\r
+\r
+       DrawBars ();\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= GiveBolt\r
+=\r
+===============\r
+*/\r
+\r
+void GiveBolt (void)\r
+{\r
+       SD_PlaySound (GETBOLTSND);\r
+       if (++gamestate.bolts<=9)\r
+               DrawChar(6+gamestate.bolts,20,BOLTCHAR);\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= TakeBolt\r
+=\r
+===============\r
+*/\r
+\r
+void TakeBolt (void)\r
+{\r
+       SD_PlaySound (USEBOLTSND);\r
+       if (--gamestate.bolts<=9)\r
+               DrawChar(7+gamestate.bolts,20,BLANKCHAR);\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= GiveNuke\r
+=\r
+===============\r
+*/\r
+\r
+void GiveNuke (void)\r
+{\r
+       SD_PlaySound (GETNUKESND);\r
+       if (++gamestate.nukes<=9)\r
+               DrawChar(6+gamestate.nukes,30,NUKECHAR);\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= TakeNuke\r
+=\r
+===============\r
+*/\r
+\r
+void TakeNuke (void)\r
+{\r
+       SD_PlaySound (USENUKESND);\r
+       if (--gamestate.nukes<=9)\r
+               DrawChar(7+gamestate.nukes,30,BLANKCHAR);\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= GivePotion\r
+=\r
+===============\r
+*/\r
+\r
+void GivePotion (void)\r
+{\r
+       SD_PlaySound (GETPOTIONSND);\r
+       if (++gamestate.potions<=9)\r
+               DrawChar(6+gamestate.potions,40,POTIONCHAR);\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= TakePotion\r
+=\r
+===============\r
+*/\r
+\r
+void TakePotion (void)\r
+{\r
+       SD_PlaySound (USEPOTIONSND);\r
+       if (--gamestate.potions<=9)\r
+               DrawChar(7+gamestate.potions,40,BLANKCHAR);\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= GiveKey\r
+=\r
+===============\r
+*/\r
+\r
+void GiveKey (int keytype)\r
+{\r
+       int     i,j,x;\r
+\r
+       SD_PlaySound (GETKEYSND);\r
+       gamestate.keys[keytype]++;\r
+\r
+       x=24;\r
+       for (i=0;i<4;i++)\r
+               for (j=0;j<gamestate.keys[i];j++)\r
+                       DrawChar(x++,20,KEYCHARS+i);\r
+\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= TakeKey\r
+=\r
+===============\r
+*/\r
+\r
+void TakeKey (int keytype)\r
+{\r
+       int     i,j,x;\r
+\r
+       SD_PlaySound (USEKEYSND);\r
+       gamestate.keys[keytype]--;\r
+\r
+       x=24;\r
+       for (i=0;i<4;i++)\r
+               for (j=0;j<gamestate.keys[i];j++)\r
+                       DrawChar(x++,20,KEYCHARS+i);\r
+\r
+       DrawChar(x,20,BLANKCHAR);\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= GiveScroll\r
+=\r
+===============\r
+*/\r
+\r
+void GiveScroll (int scrolltype,boolean show)\r
+{\r
+       int     i,x;\r
+\r
+       SD_PlaySound (GETSCROLLSND);\r
+       gamestate.scrolls[scrolltype] = true;\r
+\r
+       x=24;\r
+       for (i=0;i<8;i++)\r
+               if (gamestate.scrolls[i])\r
+                       DrawChar(x++,30,SCROLLCHARS+i);\r
+       if (show)\r
+               ReadScroll(scrolltype);\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= GivePoints\r
+=\r
+===============\r
+*/\r
+\r
+void GivePoints (int points)\r
+{\r
+       pointcount = 1;\r
+       pointsleft += points;\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= AddPoints\r
+=\r
+===============\r
+*/\r
+\r
+void AddPoints (int points)\r
+{\r
+       char    str[10];\r
+       int             len,x,i;\r
+\r
+       gamestate.score += points;\r
+\r
+       ltoa (gamestate.score,str,10);\r
+       len = strlen (str);\r
+\r
+       x=24+(8-len);\r
+       for (i=0;i<len;i++)\r
+               DrawChar(x++,40,NUMBERCHARS+str[i]-'0');\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= GiveChest\r
+=\r
+===============\r
+*/\r
+\r
+void GiveChest (void)\r
+{\r
+       SD_PlaySound (GETPOINTSSND);\r
+       GivePoints ((gamestate.mapon+1)*100);\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= GiveGoal\r
+=\r
+===============\r
+*/\r
+\r
+void GiveGoal (void)\r
+{\r
+       SD_PlaySound (GETPOINTSSND);\r
+       GivePoints (100000);\r
+       playstate = ex_victorious;\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= DrawLevelNumber\r
+=\r
+===============\r
+*/\r
+\r
+void DrawLevelNumber (int number)\r
+{\r
+       char    str[10];\r
+       int             len;\r
+       unsigned        temp;\r
+\r
+       bufferofs = 0;\r
+       if (number<9)\r
+               PrintX=13;\r
+       else\r
+               PrintX = 5;\r
+       PrintY = 4;\r
+       VW_Bar (5,4,16,9,STATUSCOLOR);\r
+       temp = fontcolor;\r
+       fontcolor = TEXTCOLOR^STATUSCOLOR;\r
+       US_PrintUnsigned (number+1);\r
+       fontcolor = temp;\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= DrawText\r
+=\r
+===============\r
+*/\r
+\r
+void DrawText (void)\r
+{\r
+       unsigned        number;\r
+       char            str[80];\r
+       char            far *text;\r
+       unsigned        temp;\r
+\r
+       //\r
+       // draw a new text description if needed\r
+       //\r
+       number = *(mapsegs[0]+farmapylookup[player->tiley]+player->tilex)-NAMESTART;\r
+\r
+       if ( number>26 )\r
+               number = 0;\r
+\r
+       if (number == lasttext)\r
+               return;\r
+\r
+       bufferofs = 0;\r
+       lasttext = number;\r
+\r
+       PrintY = 4;\r
+       WindowX = 26;\r
+       WindowW = 232;\r
+\r
+       text = (char _seg *)grsegs[LEVEL1TEXT+mapon]+textstarts[number];\r
+\r
+       _fmemcpy (str,text,80);\r
+\r
+       VW_Bar (26,4,232,9,STATUSCOLOR);\r
+       temp = fontcolor;\r
+       fontcolor = TEXTCOLOR^STATUSCOLOR;\r
+       US_CPrintLine (str);\r
+       fontcolor = temp;\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= DrawCompass\r
+=\r
+===============\r
+*/\r
+\r
+void DrawCompass (void)\r
+{\r
+       int             angle,number;\r
+\r
+       //\r
+       // draw the compass if needed\r
+       //\r
+       angle = player->angle-ANGLES/4;\r
+       angle -= ANGLES/32;\r
+       if (angle<0)\r
+               angle+=ANGLES;\r
+       number = angle/(ANGLES/16);\r
+       if (number>15)                                  // because 360 angles doesn't divide by 16\r
+               number = 15;\r
+\r
+       if (number == lastcompass)\r
+               return;\r
+\r
+       lastcompass = number;\r
+\r
+       bufferofs = 0;\r
+       LatchDrawPic (COMPASSX,COMPASSY,COMPAS1PIC+15-number);\r
+}\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= DrawBars\r
+=\r
+===============\r
+*/\r
+\r
+void DrawBars (void)\r
+{\r
+       int                     i;\r
+       unsigned        source,dest,topline;\r
+\r
+       for (i=0;i<3;i++)\r
+       {\r
+               bufferofs = screenloc[i];\r
+               VW_Bar (34*8,POWERLINE,40,MAXSHOTPOWER,1);\r
+       }\r
+       EGAWRITEMODE(1);\r
+       asm     mov     es,[screenseg]\r
+\r
+//\r
+// shot power\r
+//\r
+       if (gamestate.shotpower)\r
+       {\r
+               topline = MAXSHOTPOWER - gamestate.shotpower;\r
+\r
+               source = latchpics[SHOTPOWERPIC-FIRSTLATCHPIC]+topline*SIDEBARWIDTH;\r
+               dest = (POWERLINE+topline)*SCREENWIDTH+34;\r
+\r
+               asm     mov     si,[source]\r
+               asm     mov     di,[dest]\r
+\r
+               asm     mov     cx,[WORD PTR gamestate.shotpower]\r
+newline:\r
+       asm     mov     al,[es:si]\r
+       asm     mov     [es:di+PAGE1START],al\r
+       asm     mov     [es:di+PAGE2START],al\r
+       asm     mov     [es:di+PAGE3START],al\r
+       asm     mov     al,[es:si+1]\r
+       asm     mov     [es:di+1+PAGE1START],al\r
+       asm     mov     [es:di+1+PAGE2START],al\r
+       asm     mov     [es:di+1+PAGE3START],al\r
+       asm     mov     al,[es:si+2]\r
+       asm     mov     [es:di+2+PAGE1START],al\r
+       asm     mov     [es:di+2+PAGE2START],al\r
+       asm     mov     [es:di+2+PAGE3START],al\r
+       asm     mov     al,[es:si+3]\r
+       asm     mov     [es:di+3+PAGE1START],al\r
+       asm     mov     [es:di+3+PAGE2START],al\r
+       asm     mov     [es:di+3+PAGE3START],al\r
+       asm     mov     al,[es:si+4]\r
+       asm     mov     [es:di+4+PAGE1START],al\r
+       asm     mov     [es:di+4+PAGE2START],al\r
+       asm     mov     [es:di+4+PAGE3START],al\r
+\r
+       asm     add     di,SCREENWIDTH\r
+       asm     add     si,5\r
+\r
+               asm     loop    newline\r
+       }\r
+\r
+//\r
+// body\r
+//\r
+       if (gamestate.body)\r
+       {\r
+               source = latchpics[BODYPIC-FIRSTLATCHPIC];\r
+               dest = BODYLINE*SCREENWIDTH+34;\r
+\r
+               asm     mov     si,[source]\r
+               asm     mov     di,[dest]\r
+\r
+               asm     mov     cx,[WORD PTR gamestate.body]\r
+newline2:\r
+       asm     mov     al,[es:si]\r
+       asm     mov     [es:di+PAGE1START],al\r
+       asm     mov     [es:di+PAGE2START],al\r
+       asm     mov     [es:di+PAGE3START],al\r
+       asm     mov     al,[es:si+1]\r
+       asm     mov     [es:di+1+PAGE1START],al\r
+       asm     mov     [es:di+1+PAGE2START],al\r
+       asm     mov     [es:di+1+PAGE3START],al\r
+       asm     mov     al,[es:si+2]\r
+       asm     mov     [es:di+2+PAGE1START],al\r
+       asm     mov     [es:di+2+PAGE2START],al\r
+       asm     mov     [es:di+2+PAGE3START],al\r
+       asm     mov     al,[es:si+3]\r
+       asm     mov     [es:di+3+PAGE1START],al\r
+       asm     mov     [es:di+3+PAGE2START],al\r
+       asm     mov     [es:di+3+PAGE3START],al\r
+       asm     mov     al,[es:si+4]\r
+       asm     mov     [es:di+4+PAGE1START],al\r
+       asm     mov     [es:di+4+PAGE2START],al\r
+       asm     mov     [es:di+4+PAGE3START],al\r
+\r
+       asm     add     di,SCREENWIDTH\r
+       asm     add     si,5\r
+\r
+               asm     loop    newline2\r
+       }\r
+\r
+       if (gamestate.body != MAXBODY)\r
+       {\r
+               source = latchpics[NOBODYPIC-FIRSTLATCHPIC]+gamestate.body*SIDEBARWIDTH;\r
+               dest = (BODYLINE+gamestate.body)*SCREENWIDTH+34;\r
+               topline = MAXBODY-gamestate.body;\r
+\r
+               asm     mov     si,[source]\r
+               asm     mov     di,[dest]\r
+\r
+               asm     mov     cx,[WORD PTR topline]\r
+newline3:\r
+       asm     mov     al,[es:si]\r
+       asm     mov     [es:di+PAGE1START],al\r
+       asm     mov     [es:di+PAGE2START],al\r
+       asm     mov     [es:di+PAGE3START],al\r
+       asm     mov     al,[es:si+1]\r
+       asm     mov     [es:di+1+PAGE1START],al\r
+       asm     mov     [es:di+1+PAGE2START],al\r
+       asm     mov     [es:di+1+PAGE3START],al\r
+       asm     mov     al,[es:si+2]\r
+       asm     mov     [es:di+2+PAGE1START],al\r
+       asm     mov     [es:di+2+PAGE2START],al\r
+       asm     mov     [es:di+2+PAGE3START],al\r
+       asm     mov     al,[es:si+3]\r
+       asm     mov     [es:di+3+PAGE1START],al\r
+       asm     mov     [es:di+3+PAGE2START],al\r
+       asm     mov     [es:di+3+PAGE3START],al\r
+       asm     mov     al,[es:si+4]\r
+       asm     mov     [es:di+4+PAGE1START],al\r
+       asm     mov     [es:di+4+PAGE2START],al\r
+       asm     mov     [es:di+4+PAGE3START],al\r
+\r
+       asm     add     di,SCREENWIDTH\r
+       asm     add     si,5\r
+\r
+               asm     loop    newline3\r
+       }\r
+\r
+       EGAWRITEMODE(0);\r
+}\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                       SHOTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+void T_Pshot (objtype *ob);\r
+\r
+\r
+extern statetype s_pshot1;\r
+extern statetype s_pshot2;\r
+\r
+extern statetype s_bigpshot1;\r
+extern statetype s_bigpshot2;\r
+\r
+\r
+statetype s_pshot1 = {PSHOT1PIC,8,&T_Pshot,&s_pshot2};\r
+statetype s_pshot2 = {PSHOT2PIC,8,&T_Pshot,&s_pshot1};\r
+\r
+statetype s_shotexplode = {PSHOT2PIC,8,NULL,NULL};\r
+\r
+statetype s_bigpshot1 = {BIGPSHOT1PIC,8,&T_Pshot,&s_bigpshot2};\r
+statetype s_bigpshot2 = {BIGPSHOT2PIC,8,&T_Pshot,&s_bigpshot1};\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= SpawnPShot\r
+=\r
+===================\r
+*/\r
+\r
+void SpawnPShot (void)\r
+{\r
+       SpawnNewObjFrac (player->x,player->y,&s_pshot1,PIXRADIUS*14);\r
+       new->obclass = pshotobj;\r
+       new->speed = SHOTSPEED;\r
+       new->angle = player->angle;\r
+}\r
+\r
+void SpawnBigPShot (void)\r
+{\r
+       SpawnNewObjFrac (player->x,player->y,&s_bigpshot1,24*PIXRADIUS);\r
+       new->obclass = bigpshotobj;\r
+       new->speed = SHOTSPEED;\r
+       new->angle = player->angle;\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= T_Pshot\r
+=\r
+===============\r
+*/\r
+\r
+void T_Pshot (objtype *ob)\r
+{\r
+       objtype *check;\r
+       long    xmove,ymove,speed;\r
+\r
+//\r
+// check current position for monsters having moved into it\r
+//\r
+       for (check = player->next; check; check=check->next)\r
+               if (check->shootable\r
+               && ob->xl <= check->xh\r
+               && ob->xh >= check->xl\r
+               && ob->yl <= check->yh\r
+               && ob->yh >= check->yl)\r
+               {\r
+                       SD_PlaySound (SHOOTMONSTERSND);\r
+                       if (ob->obclass == bigpshotobj)\r
+                               ShootActor (check,BIGSHOTDAMAGE);\r
+                       else\r
+                               ShootActor (check,SHOTDAMAGE);\r
+                       ob->state = &s_shotexplode;\r
+                       ob->ticcount = ob->state->tictime;\r
+                       return;\r
+               }\r
+\r
+\r
+//\r
+// move ahead, possibly hitting a wall\r
+//\r
+       speed = ob->speed*tics;\r
+\r
+       xmove = FixedByFrac(speed,costable[ob->angle]);\r
+       ymove = -FixedByFrac(speed,sintable[ob->angle]);\r
+\r
+       if (ShotClipMove(ob,xmove,ymove))\r
+       {\r
+               ob->state = &s_shotexplode;\r
+               ob->ticcount = ob->state->tictime;\r
+               return;\r
+       }\r
+\r
+       ob->tilex = ob->x >> TILESHIFT;\r
+       ob->tiley = ob->y >> TILESHIFT;\r
+\r
+//\r
+// check final position for monsters hit\r
+//\r
+       for (check = player->next; check; check=check->next)\r
+               if (ob->shootable\r
+               && ob->xl <= check->xh\r
+               && ob->xh >= check->xl\r
+               && ob->yl <= check->yh\r
+               && ob->yh >= check->yl)\r
+               {\r
+                       ShootActor (check,SHOTDAMAGE);\r
+                       ob->state = &s_shotexplode;\r
+                       ob->ticcount = ob->state->tictime;\r
+                       return;\r
+               }\r
+\r
+}\r
+\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                  PLAYER ACTIONS\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= BuildShotPower\r
+=\r
+===============\r
+*/\r
+\r
+void BuildShotPower (void)\r
+{\r
+       int             newlines,topline;\r
+       long    i;\r
+       unsigned        source,dest;\r
+\r
+       if (gamestate.shotpower == MAXSHOTPOWER)\r
+               return;\r
+\r
+       newlines = 0;\r
+       for (i=lasttimecount-tics;i<lasttimecount;i++)\r
+               newlines += (i&1);\r
+\r
+       gamestate.shotpower += newlines;\r
+\r
+       if (gamestate.shotpower > MAXSHOTPOWER)\r
+       {\r
+               newlines -= (gamestate.shotpower - MAXSHOTPOWER);\r
+               gamestate.shotpower = MAXSHOTPOWER;\r
+       }\r
+\r
+       topline = MAXSHOTPOWER - gamestate.shotpower;\r
+\r
+       source = latchpics[L_SHOTBAR]+topline*SIDEBARWIDTH;\r
+       dest = (POWERLINE+topline)*SCREENWIDTH+34;\r
+\r
+       asm     mov     es,[screenseg]\r
+       asm     mov     si,[source]\r
+       asm     mov     di,[dest]\r
+\r
+       EGAWRITEMODE(1);\r
+\r
+       if (newlines)\r
+       {\r
+               asm     mov     cx,[newlines]\r
+newline:\r
+               asm     mov     al,[es:si]\r
+               asm     mov     [es:di+PAGE1START],al\r
+               asm     mov     [es:di+PAGE2START],al\r
+               asm     mov     [es:di+PAGE3START],al\r
+               asm     mov     al,[es:si+1]\r
+               asm     mov     [es:di+1+PAGE1START],al\r
+               asm     mov     [es:di+1+PAGE2START],al\r
+               asm     mov     [es:di+1+PAGE3START],al\r
+               asm     mov     al,[es:si+2]\r
+               asm     mov     [es:di+2+PAGE1START],al\r
+               asm     mov     [es:di+2+PAGE2START],al\r
+               asm     mov     [es:di+2+PAGE3START],al\r
+               asm     mov     al,[es:si+3]\r
+               asm     mov     [es:di+3+PAGE1START],al\r
+               asm     mov     [es:di+3+PAGE2START],al\r
+               asm     mov     [es:di+3+PAGE3START],al\r
+               asm     mov     al,[es:si+4]\r
+               asm     mov     [es:di+4+PAGE1START],al\r
+               asm     mov     [es:di+4+PAGE2START],al\r
+               asm     mov     [es:di+4+PAGE3START],al\r
+\r
+               asm     add     di,SCREENWIDTH\r
+               asm     add     si,5\r
+\r
+               asm     loop    newline\r
+       }\r
+\r
+       EGAWRITEMODE(0);\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= ClearShotPower\r
+=\r
+===============\r
+*/\r
+\r
+void ClearShotPower (void)\r
+{\r
+       unsigned        source,dest,topline;\r
+\r
+       topline = MAXSHOTPOWER - gamestate.shotpower;\r
+\r
+       source = latchpics[L_NOSHOT]+topline*SIDEBARWIDTH;\r
+       dest = (POWERLINE+topline)*SCREENWIDTH+34;\r
+\r
+       asm     mov     es,[screenseg]\r
+       asm     mov     si,[source]\r
+       asm     mov     di,[dest]\r
+\r
+       if (!gamestate.shotpower)\r
+               return;\r
+\r
+       EGAWRITEMODE(1);\r
+\r
+       asm     mov     cx,[WORD PTR gamestate.shotpower]\r
+newline:\r
+       asm     mov     al,[es:si]\r
+       asm     mov     [es:di+PAGE1START],al\r
+       asm     mov     [es:di+PAGE2START],al\r
+       asm     mov     [es:di+PAGE3START],al\r
+       asm     mov     al,[es:si+1]\r
+       asm     mov     [es:di+1+PAGE1START],al\r
+       asm     mov     [es:di+1+PAGE2START],al\r
+       asm     mov     [es:di+1+PAGE3START],al\r
+       asm     mov     al,[es:si+2]\r
+       asm     mov     [es:di+2+PAGE1START],al\r
+       asm     mov     [es:di+2+PAGE2START],al\r
+       asm     mov     [es:di+2+PAGE3START],al\r
+       asm     mov     al,[es:si+3]\r
+       asm     mov     [es:di+3+PAGE1START],al\r
+       asm     mov     [es:di+3+PAGE2START],al\r
+       asm     mov     [es:di+3+PAGE3START],al\r
+       asm     mov     al,[es:si+4]\r
+       asm     mov     [es:di+4+PAGE1START],al\r
+       asm     mov     [es:di+4+PAGE2START],al\r
+       asm     mov     [es:di+4+PAGE3START],al\r
+\r
+       asm     add     di,SCREENWIDTH\r
+       asm     add     si,5\r
+\r
+       asm     loop    newline\r
+\r
+       EGAWRITEMODE(0);\r
+\r
+       gamestate.shotpower = 0;\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= Shoot\r
+=\r
+===============\r
+*/\r
+\r
+void Shoot (void)\r
+{\r
+       ClearShotPower ();\r
+       SD_PlaySound (SHOOTSND);\r
+       SpawnPShot ();\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= BigShoot\r
+=\r
+===============\r
+*/\r
+\r
+void BigShoot (void)\r
+{\r
+       ClearShotPower ();\r
+       SD_PlaySound (BIGSHOOTSND);\r
+       SpawnBigPShot ();\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= CastBolt\r
+=\r
+===============\r
+*/\r
+\r
+void CastBolt (void)\r
+{\r
+       if (!gamestate.bolts)\r
+       {\r
+               SD_PlaySound (NOITEMSND);\r
+               return;\r
+       }\r
+\r
+       TakeBolt ();\r
+       boltsleft = NUMBOLTS;\r
+       bolttimer = BOLTTICS;\r
+       BigShoot ();\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= ContinueBolt\r
+=\r
+===============\r
+*/\r
+\r
+void ContinueBolt (void)\r
+{\r
+       bolttimer-=tics;\r
+       if (bolttimer<0)\r
+       {\r
+               boltsleft--;\r
+               bolttimer = BOLTTICS;\r
+               BigShoot ();\r
+       }\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= CastNuke\r
+=\r
+===============\r
+*/\r
+\r
+void CastNuke (void)\r
+{\r
+       int     angle;\r
+\r
+       if (!gamestate.nukes)\r
+       {\r
+               SD_PlaySound (NOITEMSND);\r
+               return;\r
+       }\r
+\r
+       TakeNuke ();\r
+       lastnuke = TimeCount;\r
+\r
+       for (angle = 0; angle < ANGLES; angle+= ANGLES/16)\r
+       {\r
+               SpawnNewObjFrac (player->x,player->y,&s_bigpshot1,24*PIXRADIUS);\r
+               new->obclass = bigpshotobj;\r
+               new->speed = SHOTSPEED;\r
+               new->angle = angle;\r
+       }\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= DrinkPotion\r
+=\r
+===============\r
+*/\r
+\r
+void DrinkPotion (void)\r
+{\r
+       unsigned        source,dest,topline;\r
+\r
+       if (!gamestate.potions)\r
+       {\r
+               SD_PlaySound (NOITEMSND);\r
+               return;\r
+       }\r
+\r
+       TakePotion ();\r
+       gamestate.body = MAXBODY;\r
+\r
+//\r
+// draw a full up bar\r
+//\r
+       source = latchpics[L_BODYBAR];\r
+       dest = BODYLINE*SCREENWIDTH+34;\r
+\r
+       asm     mov     es,[screenseg]\r
+       asm     mov     si,[source]\r
+       asm     mov     di,[dest]\r
+\r
+       EGAWRITEMODE(1);\r
+\r
+       asm     mov     cx,MAXBODY\r
+newline:\r
+       asm     mov     al,[es:si]\r
+       asm     mov     [es:di+PAGE1START],al\r
+       asm     mov     [es:di+PAGE2START],al\r
+       asm     mov     [es:di+PAGE3START],al\r
+       asm     mov     al,[es:si+1]\r
+       asm     mov     [es:di+1+PAGE1START],al\r
+       asm     mov     [es:di+1+PAGE2START],al\r
+       asm     mov     [es:di+1+PAGE3START],al\r
+       asm     mov     al,[es:si+2]\r
+       asm     mov     [es:di+2+PAGE1START],al\r
+       asm     mov     [es:di+2+PAGE2START],al\r
+       asm     mov     [es:di+2+PAGE3START],al\r
+       asm     mov     al,[es:si+3]\r
+       asm     mov     [es:di+3+PAGE1START],al\r
+       asm     mov     [es:di+3+PAGE2START],al\r
+       asm     mov     [es:di+3+PAGE3START],al\r
+       asm     mov     al,[es:si+4]\r
+       asm     mov     [es:di+4+PAGE1START],al\r
+       asm     mov     [es:di+4+PAGE2START],al\r
+       asm     mov     [es:di+4+PAGE3START],al\r
+       asm     add     di,SCREENWIDTH\r
+       asm     add     si,5\r
+\r
+       asm     loop    newline\r
+\r
+       EGAWRITEMODE(0);\r
+}\r
+\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= ReadScroll\r
+=\r
+===============\r
+*/\r
+\r
+extern boolean tileneeded[NUMFLOORS];\r
+\r
+void ReadScroll (int scroll)\r
+{\r
+       int     i;\r
+\r
+//\r
+// make wall pictures purgable\r
+//\r
+       for (i=0;i<NUMSCALEWALLS;i++)\r
+               if (walldirectory[i])\r
+                       MM_SetPurge (&(memptr)walldirectory[i],3);\r
+\r
+       CA_CacheGrChunk (SCROLLTOPPIC);\r
+       CA_CacheGrChunk (SCROLL1PIC + scroll);\r
+       VW_DrawPic (0,0,SCROLLTOPPIC);\r
+       VW_DrawPic (0,32,SCROLL1PIC + scroll);\r
+       UNMARKGRCHUNK(SCROLL1PIC + scroll);\r
+       UNMARKGRCHUNK(SCROLLTOPPIC);\r
+       MM_FreePtr (&grsegs[SCROLL1PIC + scroll]);\r
+       MM_FreePtr (&grsegs[SCROLLTOPPIC]);\r
+\r
+//\r
+// cache wall pictures back in\r
+//\r
+       for (i=1;i<NUMFLOORS;i++)\r
+               if (tileneeded[i])\r
+               {\r
+                       SetupScaleWall (walllight1[i]);\r
+                       SetupScaleWall (walllight2[i]);\r
+                       SetupScaleWall (walldark1[i]);\r
+                       SetupScaleWall (walldark2[i]);\r
+               }\r
+\r
+       VW_WaitVBL(80);\r
+waitkey:\r
+       IN_ClearKeysDown ();\r
+       IN_Ack();\r
+\r
+}\r
+\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= TakeDamage\r
+=\r
+===============\r
+*/\r
+\r
+void TakeDamage (int points)\r
+{\r
+       unsigned        source,dest,topline;\r
+\r
+       if (!gamestate.body || bordertime || godmode)\r
+               return;\r
+\r
+       if (points >= gamestate.body)\r
+       {\r
+               points = gamestate.body;\r
+               playstate = ex_died;\r
+       }\r
+\r
+       bordertime = points*FLASHTICS;\r
+       VW_ColorBorder (FLASHCOLOR);\r
+\r
+       if (gamestate.body<MAXBODY/3)\r
+               SD_PlaySound (TAKEDMGHURTSND);\r
+       else\r
+               SD_PlaySound (TAKEDAMAGESND);\r
+\r
+       gamestate.body -= points;\r
+//\r
+// shrink the body bar\r
+//\r
+       source = latchpics[L_NOBODY]+gamestate.body*SIDEBARWIDTH;\r
+       dest = (BODYLINE+gamestate.body)*SCREENWIDTH+34;\r
+\r
+\r
+       asm     mov     es,[screenseg]\r
+       asm     mov     si,[source]\r
+       asm     mov     di,[dest]\r
+\r
+       EGAWRITEMODE(1);\r
+\r
+       asm     mov     cx,[points]\r
+newline:\r
+       asm     mov     al,[es:si]\r
+       asm     mov     [es:di+PAGE1START],al\r
+       asm     mov     [es:di+PAGE2START],al\r
+       asm     mov     [es:di+PAGE3START],al\r
+       asm     mov     al,[es:si+1]\r
+       asm     mov     [es:di+1+PAGE1START],al\r
+       asm     mov     [es:di+1+PAGE2START],al\r
+       asm     mov     [es:di+1+PAGE3START],al\r
+       asm     mov     al,[es:si+2]\r
+       asm     mov     [es:di+2+PAGE1START],al\r
+       asm     mov     [es:di+2+PAGE2START],al\r
+       asm     mov     [es:di+2+PAGE3START],al\r
+       asm     mov     al,[es:si+3]\r
+       asm     mov     [es:di+3+PAGE1START],al\r
+       asm     mov     [es:di+3+PAGE2START],al\r
+       asm     mov     [es:di+3+PAGE3START],al\r
+       asm     mov     al,[es:si+4]\r
+       asm     mov     [es:di+4+PAGE1START],al\r
+       asm     mov     [es:di+4+PAGE2START],al\r
+       asm     mov     [es:di+4+PAGE3START],al\r
+\r
+       asm     add     di,SCREENWIDTH\r
+       asm     add     si,5\r
+\r
+       asm     loop    newline\r
+\r
+       EGAWRITEMODE(0);\r
+\r
+}\r
+\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                       INTERACTION\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+/*\r
+==================\r
+=\r
+= OpenDoor\r
+=\r
+==================\r
+*/\r
+\r
+void OpenDoor (unsigned bx, unsigned by, unsigned doorbase)\r
+{\r
+       int x,y;\r
+       unsigned        far *map;\r
+\r
+       x=bx;\r
+       y=by;\r
+       map = mapsegs[0]+farmapylookup[y]+x;\r
+       while (tilemap[x][y]-doorbase<4)\r
+       {\r
+               tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;\r
+               map--;\r
+               x--;\r
+       }\r
+       x=bx+1;\r
+       map = mapsegs[0]+farmapylookup[y]+x;\r
+       while (tilemap[x][y]-doorbase<4)\r
+       {\r
+               tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;\r
+               map++;\r
+               x++;\r
+       }\r
+       x=bx;\r
+       y=by-1;\r
+       map = mapsegs[0]+farmapylookup[y]+x;\r
+       while (tilemap[x][y]-doorbase<4)\r
+       {\r
+               tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;\r
+               map-=mapwidth;\r
+               y--;\r
+       }\r
+       y=by+1;\r
+       map = mapsegs[0]+farmapylookup[y]+x;\r
+       while (tilemap[x][y]-doorbase<4)\r
+       {\r
+               tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;\r
+               map+=mapwidth;\r
+               y++;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+==================\r
+=\r
+= HitSpecialTile\r
+=\r
+= Returns true if the move is blocked\r
+=\r
+==================\r
+*/\r
+\r
+boolean HitSpecialTile (unsigned x, unsigned y, unsigned tile)\r
+{\r
+       switch (tile)\r
+       {\r
+       case 0:\r
+       case 1:\r
+       case 2:\r
+       case 3:\r
+               if (!gamestate.keys[0])\r
+                       return true;\r
+               TakeKey(0);\r
+               OpenDoor (x,y,SPECTILESTART+0);\r
+               return false;\r
+\r
+       case 4:\r
+       case 5:\r
+       case 6:\r
+       case 7:\r
+               if (!gamestate.keys[1])\r
+                       return true;\r
+               TakeKey(1);\r
+               OpenDoor (x,y,SPECTILESTART+4);\r
+               return false;\r
+\r
+       case 8:\r
+       case 9:\r
+       case 10:\r
+       case 11:\r
+               if (!gamestate.keys[2])\r
+                       return true;\r
+               TakeKey(2);\r
+               OpenDoor (x,y,SPECTILESTART+8);\r
+               return false;\r
+\r
+       case 12:\r
+       case 13:\r
+       case 14:\r
+       case 15:\r
+               if (!gamestate.keys[3])\r
+                       return true;\r
+               TakeKey(3);\r
+               OpenDoor (x,y,SPECTILESTART+12);\r
+               return false;\r
+\r
+       }\r
+\r
+       return true;\r
+}\r
+\r
+\r
+\r
+/*\r
+==================\r
+=\r
+= TouchActor\r
+=\r
+= Returns true if the move is blocked\r
+=\r
+==================\r
+*/\r
+\r
+boolean TouchActor (objtype *ob, objtype *check)\r
+{\r
+       if (ob->xh < check->xl || ob->xl > check->xh ||\r
+               ob->yh < check->yl || ob->yl > check->yh)\r
+               return false;                           // not quite touching\r
+\r
+       switch (check->obclass)\r
+       {\r
+       case bonusobj:\r
+               if (check->temp1 == B_BOLT)\r
+                       GiveBolt ();\r
+               else if (check->temp1 == B_NUKE)\r
+                       GiveNuke ();\r
+               else if (check->temp1 == B_POTION)\r
+                       GivePotion ();\r
+               else if (check->temp1 >= B_RKEY && check->temp1 <= B_BKEY)\r
+                       GiveKey (check->temp1-B_RKEY);\r
+               else if (check->temp1 >= B_SCROLL1 && check->temp1 <= B_SCROLL8)\r
+                       GiveScroll (check->temp1-B_SCROLL1,true);\r
+               else if (check->temp1 == B_CHEST)\r
+                       GiveChest ();\r
+               else if (check->temp1 == B_GOAL)\r
+                       GiveGoal ();\r
+               (unsigned)actorat[check->tilex][check->tiley] = 0;\r
+               RemoveObj (check);\r
+\r
+               return false;\r
+\r
+       }\r
+       return  true;\r
+}\r
+\r
+\r
+/*\r
+==================\r
+=\r
+= CalcBounds\r
+=\r
+==================\r
+*/\r
+\r
+void CalcBounds (objtype *ob)\r
+{\r
+//\r
+// calculate hit rect\r
+//\r
+  ob->xl = ob->x - ob->size;\r
+  ob->xh = ob->x + ob->size;\r
+  ob->yl = ob->y - ob->size;\r
+  ob->yh = ob->y + ob->size;\r
+}\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= LocationInActor\r
+=\r
+===================\r
+*/\r
+\r
+boolean LocationInActor (objtype *ob)\r
+{\r
+       int     x,y,xmin,ymin,xmax,ymax;\r
+       objtype *check;\r
+\r
+       CalcBounds (ob);\r
+\r
+       xmin = (ob->x >> TILESHIFT)-2;\r
+       ymin = (ob->y >> TILESHIFT)-2;\r
+       xmax = xmin+5;\r
+       ymax = ymin+5;\r
+\r
+       for (x=xmin;x<xmax;x++)\r
+               for (y=ymin;y<ymax;y++)\r
+               {\r
+                       check = actorat[x][y];\r
+                       if (check>(objtype *)LASTSPECIALTILE\r
+                       && check->shootable\r
+                       && ob->xl <= check->xh\r
+                       && ob->xh >= check->xl\r
+                       && ob->yl <= check->yh\r
+                       && ob->yh >= check->yl)\r
+                               return true;\r
+               }\r
+\r
+       return false;\r
+}\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= ClipMove\r
+=\r
+= Only checks corners, so the object better be less than one tile wide!\r
+=\r
+===================\r
+*/\r
+\r
+void ClipMove (objtype *ob, long xmove, long ymove)\r
+{\r
+       int                     xl,yl,xh,yh,tx,ty,nt1,nt2,x,y;\r
+       long            intersect,basex,basey,pointx,pointy;\r
+       unsigned        inside,total,tile;\r
+       objtype         *check;\r
+       boolean         moveok;\r
+\r
+//\r
+// move player and check to see if any corners are in solid tiles\r
+//\r
+       basex = ob->x;\r
+       basey = ob->y;\r
+\r
+       ob->x += xmove;\r
+       ob->y += ymove;\r
+\r
+       CalcBounds (ob);\r
+\r
+       xl = ob->xl>>TILESHIFT;\r
+       yl = ob->yl>>TILESHIFT;\r
+\r
+       xh = ob->xh>>TILESHIFT;\r
+       yh = ob->yh>>TILESHIFT;\r
+\r
+       for (y=yl;y<=yh;y++)\r
+               for (x=xl;x<=xh;x++)\r
+               {\r
+                       check = actorat[x][y];\r
+                       if (!check)\r
+                               continue;               // blank floor, walk ok\r
+\r
+                       if ((unsigned)check<=LASTWALLTILE)\r
+                               goto blockmove; // solid wall\r
+\r
+                       if ((unsigned)check<=LASTSPECIALTILE)\r
+                       {\r
+                               if ( HitSpecialTile (x,y,(unsigned)check-SPECTILESTART) )\r
+                                       goto blockmove;         // whatever it was, it blocked the move\r
+                               else\r
+                                       continue;\r
+                       }\r
+                       TouchActor(ob,check);           // pick up items\r
+               }\r
+\r
+//\r
+// check nearby actors\r
+//\r
+       if (LocationInActor(ob))\r
+       {\r
+               ob->x -= xmove;\r
+               if (LocationInActor(ob))\r
+               {\r
+                       ob->x += xmove;\r
+                       ob->y -= ymove;\r
+                       if (LocationInActor(ob))\r
+                               ob->x -= xmove;\r
+               }\r
+       }\r
+       return;         // move is OK!\r
+\r
+\r
+blockmove:\r
+\r
+       if (!SD_SoundPlaying())\r
+               SD_PlaySound (HITWALLSND);\r
+\r
+       moveok = false;\r
+\r
+       do\r
+       {\r
+               xmove /= 2;\r
+               ymove /= 2;\r
+               if (moveok)\r
+               {\r
+                       ob->x += xmove;\r
+                       ob->y += ymove;\r
+               }\r
+               else\r
+               {\r
+                       ob->x -= xmove;\r
+                       ob->y -= ymove;\r
+               }\r
+               CalcBounds (ob);\r
+               xl = ob->xl>>TILESHIFT;\r
+               yl = ob->yl>>TILESHIFT;\r
+               xh = ob->xh>>TILESHIFT;\r
+               yh = ob->yh>>TILESHIFT;\r
+               if (tilemap[xl][yl] || tilemap[xh][yl]\r
+               || tilemap[xh][yh] || tilemap[xl][yh] )\r
+               {\r
+                       moveok = false;\r
+                       if (xmove>=-2048 && xmove <=2048 && ymove>=-2048 && ymove <=2048)\r
+                       {\r
+                               ob->x = basex;\r
+                               ob->y = basey;\r
+                               return;\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       if (xmove>=-2048 && xmove <=2048 && ymove>=-2048 && ymove <=2048)\r
+                               return;\r
+                       moveok = true;\r
+               }\r
+       } while (1);\r
+}\r
+\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= ShotClipMove\r
+=\r
+= Only checks corners, so the object better be less than one tile wide!\r
+=\r
+===================\r
+*/\r
+\r
+boolean ShotClipMove (objtype *ob, long xmove, long ymove)\r
+{\r
+       int                     xl,yl,xh,yh,tx,ty,nt1,nt2,x,y;\r
+       long            intersect,basex,basey,pointx,pointy;\r
+       unsigned        inside,total,tile;\r
+       objtype         *check;\r
+       boolean         moveok;\r
+\r
+//\r
+// move shot and check to see if any corners are in solid tiles\r
+//\r
+       basex = ob->x;\r
+       basey = ob->y;\r
+\r
+       ob->x += xmove;\r
+       ob->y += ymove;\r
+\r
+       CalcBounds (ob);\r
+\r
+       xl = ob->xl>>TILESHIFT;\r
+       yl = ob->yl>>TILESHIFT;\r
+\r
+       xh = ob->xh>>TILESHIFT;\r
+       yh = ob->yh>>TILESHIFT;\r
+\r
+       for (y=yl;y<=yh;y++)\r
+               for (x=xl;x<=xh;x++)\r
+               {\r
+                       tile = tilemap[x][y];\r
+                       if (tile)\r
+                       {\r
+                               if ((unsigned)(tile-EXPWALLSTART)<NUMEXPWALLS)\r
+                                       ExplodeWall (x,y);\r
+                               goto blockmove;\r
+                       }\r
+               }\r
+       return false;           // move is OK!\r
+\r
+\r
+blockmove:\r
+\r
+       SD_PlaySound (SHOOTWALLSND);\r
+\r
+       moveok = false;\r
+\r
+       do\r
+       {\r
+               xmove /= 2;\r
+               ymove /= 2;\r
+               if (moveok)\r
+               {\r
+                       ob->x += xmove;\r
+                       ob->y += ymove;\r
+               }\r
+               else\r
+               {\r
+                       ob->x -= xmove;\r
+                       ob->y -= ymove;\r
+               }\r
+               CalcBounds (ob);\r
+               xl = ob->xl>>TILESHIFT;\r
+               yl = ob->yl>>TILESHIFT;\r
+               xh = ob->xh>>TILESHIFT;\r
+               yh = ob->yh>>TILESHIFT;\r
+               if (tilemap[xl][yl] || tilemap[xh][yl]\r
+               || tilemap[xh][yh] || tilemap[xl][yh] )\r
+               {\r
+                       moveok = false;\r
+                       if (xmove>=-2048 && xmove <=2048 && ymove>=-2048 && ymove <=2048)\r
+                       {\r
+                               ob->x = basex;\r
+                               ob->y = basey;\r
+                               return true;\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       if (xmove>=-2048 && xmove <=2048 && ymove>=-2048 && ymove <=2048)\r
+                               return true;\r
+                       moveok = true;\r
+               }\r
+       } while (1);\r
+}\r
+\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                  PLAYER CONTROL\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+\r
+void   T_Player (objtype *ob);\r
+\r
+statetype s_player = {0,0,&T_Player,&s_player};\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnPlayer\r
+=\r
+===============\r
+*/\r
+\r
+void SpawnPlayer (int tilex, int tiley, int dir)\r
+{\r
+       player->obclass = playerobj;\r
+       player->active = true;\r
+       player->tilex = tilex;\r
+       player->tiley = tiley;\r
+       player->x = ((long)tilex<<TILESHIFT)+TILEGLOBAL/2;\r
+       player->y = ((long)tiley<<TILESHIFT)+TILEGLOBAL/2;\r
+       player->state = &s_player;\r
+       player->angle = (1-dir)*90;\r
+       player->size = MINDIST;\r
+       CalcBounds (player);\r
+       if (player->angle<0)\r
+               player->angle += ANGLES;\r
+}\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= Thrust\r
+=\r
+===================\r
+*/\r
+\r
+void Thrust (int angle, unsigned speed)\r
+{\r
+       long xmove,ymove;\r
+\r
+       if (lasttimecount>>5 != ((lasttimecount-tics)>>5) )\r
+       {\r
+       //\r
+       // walk sound\r
+       //\r
+               if (lasttimecount&32)\r
+                       SD_PlaySound (WALK1SND);\r
+               else\r
+                       SD_PlaySound (WALK2SND);\r
+       }\r
+\r
+       xmove = FixedByFrac(speed,costable[angle]);\r
+       ymove = -FixedByFrac(speed,sintable[angle]);\r
+\r
+       ClipMove(player,xmove,ymove);\r
+       player->tilex = player->x >> TILESHIFT;\r
+       player->tiley = player->y >> TILESHIFT;\r
+}\r
+\r
+\r
+\r
+/*\r
+=======================\r
+=\r
+= ControlMovement\r
+=\r
+=======================\r
+*/\r
+\r
+void ControlMovement (objtype *ob)\r
+{\r
+       int     angle;\r
+       long    speed;\r
+\r
+\r
+       if (c.button1)\r
+       {\r
+       //\r
+       // strafing\r
+       //\r
+               //\r
+               // side to side move\r
+               //\r
+               if (!mousexmove)\r
+                       speed = 0;\r
+               else if (mousexmove<0)\r
+                       speed = -(long)mousexmove*300;\r
+               else\r
+                       speed = -(long)mousexmove*300;\r
+\r
+               if (c.xaxis == -1)\r
+               {\r
+                       if (running)\r
+                               speed += RUNSPEED*tics;\r
+                       else\r
+                               speed += PLAYERSPEED*tics;\r
+               }\r
+               else if (c.xaxis == 1)\r
+               {\r
+                       if (running)\r
+                               speed -= RUNSPEED*tics;\r
+                       else\r
+                               speed -= PLAYERSPEED*tics;\r
+               }\r
+\r
+               if (speed > 0)\r
+               {\r
+                       if (speed >= TILEGLOBAL)\r
+                               speed = TILEGLOBAL-1;\r
+                       angle = ob->angle + ANGLES/4;\r
+                       if (angle >= ANGLES)\r
+                               angle -= ANGLES;\r
+                       Thrust (angle,speed);                           // move to left\r
+               }\r
+               else if (speed < 0)\r
+               {\r
+                       if (speed <= -TILEGLOBAL)\r
+                               speed = -TILEGLOBAL+1;\r
+                       angle = ob->angle - ANGLES/4;\r
+                       if (angle < 0)\r
+                               angle += ANGLES;\r
+                       Thrust (angle,-speed);                          // move to right\r
+               }\r
+       }\r
+       else\r
+       {\r
+       //\r
+       // not strafing\r
+       //\r
+\r
+               //\r
+               // turning\r
+               //\r
+               if (c.xaxis == 1)\r
+               {\r
+                       ob->angle -= tics;\r
+                       if (running)                            // fast turn\r
+                               ob->angle -= tics;\r
+               }\r
+               else if (c.xaxis == -1)\r
+               {\r
+                       ob->angle+= tics;\r
+                       if (running)                            // fast turn\r
+                               ob->angle += tics;\r
+               }\r
+\r
+               ob->angle -= (mousexmove/10);\r
+\r
+               if (ob->angle >= ANGLES)\r
+                       ob->angle -= ANGLES;\r
+               if (ob->angle < 0)\r
+                       ob->angle += ANGLES;\r
+\r
+       }\r
+\r
+       //\r
+       // forward/backwards move\r
+       //\r
+       if (!mouseymove)\r
+               speed = 0;\r
+       else if (mouseymove<0)\r
+               speed = -(long)mouseymove*500;\r
+       else\r
+               speed = -(long)mouseymove*200;\r
+\r
+       if (c.yaxis == -1)\r
+       {\r
+               if (running)\r
+                       speed += RUNSPEED*tics;\r
+               else\r
+                       speed += PLAYERSPEED*tics;\r
+       }\r
+       else if (c.yaxis == 1)\r
+       {\r
+               if (running)\r
+                       speed -= RUNSPEED*tics;\r
+               else\r
+                       speed -= PLAYERSPEED*tics;\r
+       }\r
+\r
+       if (speed > 0)\r
+       {\r
+               if (speed >= TILEGLOBAL)\r
+                       speed = TILEGLOBAL-1;\r
+               Thrust (ob->angle,speed);                       // move forwards\r
+       }\r
+       else if (speed < 0)\r
+       {\r
+               if (speed <= -TILEGLOBAL)\r
+                       speed = -TILEGLOBAL+1;\r
+               angle = ob->angle + ANGLES/2;\r
+               if (angle >= ANGLES)\r
+                       angle -= ANGLES;\r
+               Thrust (angle,-speed);                          // move backwards\r
+       }\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= T_Player\r
+=\r
+===============\r
+*/\r
+\r
+void   T_Player (objtype *ob)\r
+{\r
+       int     angle,speed,scroll;\r
+       unsigned        text,tilex,tiley;\r
+       long    lspeed;\r
+\r
+\r
+       ControlMovement (ob);\r
+\r
+\r
+       //\r
+       // firing\r
+       //\r
+       if (boltsleft)\r
+       {\r
+               handheight+=(tics<<2);\r
+               if (handheight>MAXHANDHEIGHT)\r
+                       handheight = MAXHANDHEIGHT;\r
+\r
+               ContinueBolt ();\r
+               lasthand = lasttimecount;\r
+       }\r
+       else\r
+       {\r
+               if (c.button0)\r
+               {\r
+                       handheight+=(tics<<2);\r
+                       if (handheight>MAXHANDHEIGHT)\r
+                               handheight = MAXHANDHEIGHT;\r
+\r
+                       if ((unsigned)TimeCount/FIRETIME != lastfiretime)\r
+                               BuildShotPower ();\r
+                       lasthand = lasttimecount;\r
+               }\r
+               else\r
+               {\r
+                       if (lasttimecount > lasthand+HANDPAUSE)\r
+                       {\r
+                               handheight-=(tics<<1);\r
+                               if (handheight<0)\r
+                                       handheight = 0;\r
+                       }\r
+\r
+                       if (gamestate.shotpower == MAXSHOTPOWER)\r
+                       {\r
+                               lastfiretime = (unsigned)TimeCount/FIRETIME;\r
+                               BigShoot ();\r
+                       }\r
+                       else if (gamestate.shotpower)\r
+                       {\r
+                               lastfiretime = (unsigned)TimeCount/FIRETIME;\r
+                               Shoot ();\r
+                       }\r
+               }\r
+       }\r
+\r
+       //\r
+       // special actions\r
+       //\r
+\r
+       if ( (Keyboard[sc_Space] || Keyboard[sc_H]) && gamestate.body != MAXBODY)\r
+               DrinkPotion ();\r
+\r
+       if (Keyboard[sc_B] && !boltsleft)\r
+               CastBolt ();\r
+\r
+       if ( (Keyboard[sc_Enter] || Keyboard[sc_N]) && TimeCount-lastnuke > NUKETIME)\r
+               CastNuke ();\r
+\r
+       scroll = LastScan-2;\r
+       if ( scroll>=0 && scroll<NUMSCROLLS && gamestate.scrolls[scroll])\r
+               ReadScroll (scroll);\r
+\r
+       DrawText ();\r
+       DrawCompass ();\r
+\r
+}\r
diff --git a/src/lib/hb/c6_act1.c b/src/lib/hb/c6_act1.c
new file mode 100755 (executable)
index 0000000..f94a878
--- /dev/null
@@ -0,0 +1,930 @@
+/* Catacomb Apocalypse Source Code\r
+ * Copyright (C) 1993-2014 Flat Rock Software\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License along\r
+ * with this program; if not, write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+ */\r
+\r
+// C3_PLAY.C\r
+\r
+#include "DEF.H"\r
+#pragma hdrstop\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+#if 0\r
+#define MSHOTDAMAGE    2\r
+#define MSHOTSPEED     10000\r
+\r
+#define ESHOTDAMAGE    1\r
+#define ESHOTSPEED     5000\r
+\r
+#define SSHOTDAMAGE    3\r
+#define SSHOTSPEED     6500\r
+\r
+#define RANDOM_ATTACK 20\r
+#endif\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                GLOBAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+boolean ShootPlayer (objtype *ob, short obclass, short speed, statetype *state);\r
+void T_ShootPlayer(objtype *ob);\r
+\r
+short zombie_base_delay;\r
+\r
+short other_x[] = {0,39,39,0},\r
+               other_y[] = {0,0,27,27};\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
+                                                 BONUS ITEMS\r
+\r
+=============================================================================\r
+*/\r
+\r
+statetype s_boltbonus = {BOLTOBJPIC,8,NULL,&s_boltbonus2};\r
+statetype s_boltbonus2 = {BOLT2OBJPIC,8,NULL,&s_boltbonus3};\r
+statetype s_boltbonus3 = {BOLT3OBJPIC,8,NULL,&s_boltbonus};\r
+\r
+statetype s_nukebonus = {NUKEOBJPIC,8,NULL,&s_nukebonus2};\r
+statetype s_nukebonus2 = {NUKE2OBJPIC,8,NULL,&s_nukebonus3};\r
+statetype s_nukebonus3 = {NUKE3OBJPIC,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_chestbonus = {CHESTOBJPIC,0,NULL,&s_chestbonus};\r
+statetype s_oldchestbonus = {OLD_CHESTPIC,0,NULL,&s_oldchestbonus};\r
+\r
+statetype s_waterchestbonus1 = {O_WATER_CHEST1PIC, 10, NULL, &s_waterchestbonus2};\r
+statetype s_waterchestbonus2 = {O_WATER_CHEST2PIC, 10, NULL, &s_waterchestbonus3};\r
+statetype s_waterchestbonus3 = {O_WATER_CHEST3PIC, 10, NULL, &s_waterchestbonus1};\r
+\r
+statetype s_rgem1bonus = {RGEM1PIC,30,NULL,&s_rgem1bonus};\r
+statetype s_ygem1bonus = {YGEM1PIC,30,NULL,&s_ygem1bonus};\r
+statetype s_ggem1bonus = {GGEM1PIC,30,NULL,&s_ggem1bonus};\r
+statetype s_bgem1bonus = {BGEM1PIC,30,NULL,&s_bgem1bonus};\r
+statetype s_pgem1bonus = {PGEM1PIC,30,NULL,&s_pgem1bonus};\r
+\r
+statetype s_bonus_die = {0,8,NULL,NULL};\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnBonus\r
+=\r
+===============\r
+*/\r
+\r
+void SpawnBonus (int tilex, int tiley, int number)\r
+{\r
+       extern unsigned gcolor;\r
+\r
+       statetype *state;\r
+\r
+       switch (number)\r
+       {\r
+               case B_BOLT:                    state = &s_boltbonus;           break;\r
+               case B_NUKE:                    state = &s_nukebonus;           break;\r
+               case B_POTION:                  state = &s_potionbonus;         break;\r
+\r
+               case B_RKEY:                    state = &s_rkeybonus;           break;\r
+               case B_YKEY:                    state = &s_ykeybonus;           break;\r
+               case B_GKEY:                    state = &s_gkeybonus;           break;\r
+               case B_BKEY:                    state = &s_bkeybonus;           break;\r
+\r
+               case B_RGEM:                    state = &s_rgem1bonus;          break;\r
+               case B_YGEM:                    state = &s_ygem1bonus;          break;\r
+               case B_GGEM:                    state = &s_ggem1bonus;          break;\r
+               case B_BGEM:                    state = &s_bgem1bonus;          break;\r
+               case B_PGEM:                    state = &s_pgem1bonus;          break;\r
+\r
+               case B_CHEST:\r
+                       if (gcolor == 0x0101)\r
+                               state = &s_waterchestbonus1;\r
+                       else\r
+                               state = &s_chestbonus;\r
+               break;\r
+\r
+               case B_OLDCHEST:                state = &s_oldchestbonus;       break;\r
+\r
+\r
+               default:\r
+                       Quit("SpawnBonus(): INVALID BONUS");\r
+               break;\r
+       }\r
+\r
+       SpawnNewObj (tilex,tiley,state,TILEGLOBAL/2);\r
+       new->temp1 = number;\r
+       new->obclass = bonusobj;\r
+\r
+       switch (number)\r
+       {\r
+               case B_POTION:\r
+               case B_OLDCHEST:\r
+               case B_CHEST:\r
+               case B_BOLT:\r
+               case B_NUKE:\r
+                       new->flags |= of_shootable;\r
+               break;\r
+\r
+               default:\r
+                       new->flags &= ~of_shootable;\r
+               break;\r
+       }\r
+}\r
+\r
+\r
+\r
+/*\r
+============================================================================\r
+\r
+                                                                       FREEZE TIME OBJECT\r
+\r
+============================================================================\r
+*/\r
+\r
+extern statetype s_ftimebonus;\r
+extern statetype s_ftimebonus2;\r
+\r
+statetype s_ftimebonus = {TIMEOBJ1PIC,6,NULL,&s_ftimebonus2};\r
+statetype s_ftimebonus2 = {TIMEOBJ2PIC,6,NULL,&s_ftimebonus};\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnFTime\r
+=\r
+===============\r
+*/\r
+void SpawnFTime(int tilex, int tiley)\r
+{\r
+       SpawnNewObj(tilex,tiley,&s_ftimebonus,TILEGLOBAL/2);\r
+//     new->tileobject = true;\r
+       new->obclass = freezeobj;\r
+       new->flags |= of_shootable;\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
+=\r
+= ExplodeWall\r
+=\r
+================\r
+*/\r
+\r
+void ExplodeWall (int tilex, int tiley)\r
+{\r
+       extern unsigned gcolor;\r
+       unsigned tilenum;\r
+\r
+       DSpawnNewObj (tilex,tiley,&s_walldie1,0);\r
+       if (new == &dummyobj)\r
+               return;\r
+       new->obclass = inertobj;\r
+       new->active = always;\r
+       if (gcolor == 0x0101)\r
+               tilenum = WATEREXP;\r
+       else\r
+               tilenum = WALLEXP;\r
+       (unsigned)actorat[new->tilex][new->tiley] = tilemap[new->tilex][new->tiley] =\r
+               *(mapsegs[0]+farmapylookup[new->tiley]+new->tilex) = tilenum;\r
+       *(mapsegs[2]+farmapylookup[new->tiley]+new->tilex) &= 0xFF;\r
+}\r
+\r
+\r
+/*\r
+================\r
+=\r
+= T_WallDie\r
+=\r
+================\r
+*/\r
+\r
+void T_WallDie (objtype *ob)\r
+{\r
+       extern unsigned gcolor;\r
+       unsigned tile,other,spot,x,y;\r
+\r
+       if (++ob->temp1 == 3)\r
+               tile = 0;\r
+       else\r
+               if (gcolor == 0x0101)\r
+                       tile = WATEREXP-1 + ob->temp1;\r
+               else\r
+                       tile = WALLEXP-1 + ob->temp1;\r
+       x = ob->tilex;\r
+       y = ob->tiley;\r
+\r
+       (unsigned)actorat[x][y] = tilemap[x][y] = *(mapsegs[0]+farmapylookup[y]+x) = tile;\r
+\r
+       if (ob->temp1 == 1)\r
+       {\r
+       //\r
+       // blow up nearby walls\r
+       //\r
+               spot = (*(mapsegs[2]+farmapylookup[y]+(x-1))) >> 8;\r
+               if (spot == EXP_WALL_CODE)\r
+                       ExplodeWall (x-1,y);\r
+               spot = (*(mapsegs[2]+farmapylookup[y]+(x+1))) >> 8;\r
+               if (spot == EXP_WALL_CODE)\r
+                       ExplodeWall (x+1,y);\r
+               spot = (*(mapsegs[2]+farmapylookup[y-1]+x)) >> 8;\r
+               if (spot == EXP_WALL_CODE)\r
+                       ExplodeWall (x,y-1);\r
+               spot = (*(mapsegs[2]+farmapylookup[y+1]+x)) >> 8;\r
+               if (spot == EXP_WALL_CODE)\r
+                       ExplodeWall (x,y+1);\r
+       }\r
+}\r
+/*\r
+=============================================================================\r
+\r
+                                                               OBJ_WARP GATE\r
+\r
+=============================================================================\r
+*/\r
+\r
+void T_Gate (objtype *ob);\r
+void T_Gate_Wait (objtype *ob);\r
+\r
+extern statetype s_portal_wait;\r
+statetype s_portal_wait = {0, 10, &T_Gate_Wait, &s_portal_wait};\r
+\r
+statetype s_portal1 = {PORTAL1PIC, 6, &T_Gate, &s_portal2};\r
+statetype s_portal2 = {PORTAL2PIC, 6, &T_Gate, &s_portal3};\r
+statetype s_portal3 = {PORTAL3PIC, 6, &T_Gate, &s_portal4};\r
+statetype s_portal4 = {PORTAL4PIC, 6, &T_Gate, &s_portal5};\r
+statetype s_portal5 = {PORTAL5PIC, 6, &T_Gate, &s_portal6};\r
+statetype s_portal6 = {PORTAL6PIC, 6, &T_Gate, &s_portal1};\r
+\r
+//---------------------------------------------------------------------------\r
+//     SpawnWarp()\r
+//---------------------------------------------------------------------------\r
+void SpawnWarp (int tilex, int tiley)\r
+{\r
+       unsigned spot;\r
+       objtype *ob;\r
+\r
+       spot = (*(mapsegs[2]+farmapylookup[tiley]+tilex+1)) >> 8;\r
+\r
+       if (spot)\r
+       {\r
+               SpawnNewObj (tilex, tiley, &s_portal_wait, TILEGLOBAL/3);\r
+               new->temp1 = spot*70;\r
+       }\r
+       else\r
+               SpawnNewObj (tilex, tiley, &s_portal1, TILEGLOBAL/3);\r
+\r
+       new->obclass = gateobj;\r
+}\r
+\r
+/*\r
+===============\r
+=\r
+= T_Gate_Wait\r
+=\r
+===============\r
+*/\r
+\r
+void T_Gate_Wait (objtype *ob)\r
+{\r
+       if ((ob->temp1 -= tics) <= 0)\r
+       {\r
+               if ((ob->tilex == player->tilex) && (ob->tiley == player->tiley))\r
+                       return;\r
+               if (CheckHandAttack(ob))\r
+                       return;\r
+\r
+               SD_PlaySound(PORTALSND);\r
+               ob->state = &s_portal1;\r
+               ob->ticcount = ob->state->tictime;\r
+\r
+       }\r
+\r
+}\r
+\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= T_Gate\r
+=\r
+===============\r
+*/\r
+\r
+void T_Gate (objtype *ob)\r
+{\r
+       objtype *check;\r
+       unsigned        temp,spot;\r
+\r
+       if (CheckHandAttack (ob) && !playstate)\r
+       {\r
+               //\r
+               // teleport out of level\r
+               //\r
+               playstate = ex_warped;\r
+               spot = (*(mapsegs[2]+farmapylookup[ob->tiley+1]+ob->tilex)) >> 8;\r
+               gamestate.mapon=spot;\r
+               SD_PlaySound(WARPUPSND);\r
+       }\r
+}\r
+\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                                                       AQUAMAN\r
+\r
+=============================================================================\r
+*/\r
+\r
+void T_AquaMan(objtype *ob);\r
+\r
+statetype s_aqua_under1 = {EYESTALKUNDER1PIC, 25, &T_AquaMan, &s_aqua_under2};\r
+statetype s_aqua_under2 = {EYESTALKUNDER2PIC, 20, &T_AquaMan, &s_aqua_under3};\r
+statetype s_aqua_under3 = {EYESTALKUNDER3PIC, 20, &T_AquaMan, &s_aqua_under2};\r
+\r
+statetype s_aqua_left = {EYESTALKUNDER4PIC, 40, NULL, &s_aqua_under3};\r
+statetype s_aqua_right = {EYESTALKUNDER5PIC, 40, NULL, &s_aqua_under3};\r
+\r
+statetype s_aqua_rise1 = {EYESTALKRISE1PIC, 20, NULL, &s_aqua_rise2};\r
+statetype s_aqua_rise2 = {EYESTALKRISE2PIC, 15, NULL, &s_aqua_walk1};\r
+\r
+statetype s_aqua_sink1 = {EYESTALKRISE2PIC, 15, NULL, &s_aqua_sink2};\r
+statetype s_aqua_sink2 = {EYESTALKRISE1PIC, 20, NULL, &s_aqua_under1};\r
+\r
+statetype s_aqua_walk1 = {EYESTALKWALK1PIC, 12, &T_AquaMan, &s_aqua_walk2};\r
+statetype s_aqua_walk2 = {EYESTALKWALK2PIC, 12, &T_AquaMan, &s_aqua_walk1};\r
+\r
+statetype s_aqua_attack1 = {EYESTALKATTACKPIC, 10, NULL, &s_aqua_attack2};\r
+statetype s_aqua_attack2 = {EYESTALKWALK1PIC, 10, &T_DoDamage, &s_aqua_walk1};\r
+\r
+statetype s_aqua_die1 = {EYESTALKDEATH1PIC, 8, NULL, &s_aqua_die2};\r
+statetype s_aqua_die2 = {EYESTALKDEATH2PIC, 8, NULL, &s_aqua_die3};\r
+statetype s_aqua_die3 = {EYESTALKDEATH2PIC, -1, &T_AlternateStates, &s_aqua_die1};\r
+statetype s_aqua_die4 = {EYESTALKDEATH2PIC, 30, NULL, &s_aqua_die5};\r
+statetype s_aqua_die5 = {EYESTALKDEATH3PIC, 40, NULL, &s_aqua_die6};\r
+statetype s_aqua_die6 = {EYESTALKDEATH4PIC, 30, &ExplosionSnd, &s_aqua_die7};\r
+statetype s_aqua_die7 = {EYESTALKDEATH5PIC, 20, NULL, NULL};\r
+\r
+typedef enum {wt_UNDER, wt_WALK} AquaManTypes;\r
+\r
+#define AQ_TIMEREMAIN  (ob->temp1)\r
+#define AQ_STAGE                       (ob->temp2)\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnAquaMan\r
+=\r
+===============\r
+*/\r
+void SpawnAquaMan(int tilex, int tiley)\r
+{\r
+       objtype *ob;\r
+       SpawnNewObj(tilex,tiley,&s_aqua_under1,PIXRADIUS*32);\r
+       ob = new;\r
+\r
+       AQ_STAGE = wt_UNDER;\r
+       AQ_TIMEREMAIN = 60*4+random(60*3);\r
+\r
+       new->obclass = aquamanobj;\r
+       new->speed = 1000;\r
+       new->flags &= ~of_shootable;\r
+       new->hitpoints = EasyHitPoints(15);\r
+}\r
+\r
+void ExplosionSnd(objtype *ob)\r
+{\r
+       if (ob->temp1 != SOUNDPLAYED)\r
+       {\r
+               SD_PlaySound(BODY_EXPLODESND);\r
+               ob->temp1 = SOUNDPLAYED;\r
+\r
+       }\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= T_AquaMan\r
+=\r
+===============\r
+*/\r
+\r
+void T_AquaMan(objtype *ob)\r
+{\r
+       switch (AQ_STAGE)\r
+       {\r
+               case wt_UNDER:\r
+                       ob->flags &= ~of_shootable;\r
+                       if (Chase(ob,true))\r
+                       {\r
+                               // RISE & GOTO WALK STAGE\r
+                               //\r
+\r
+                               AQ_STAGE = wt_WALK;\r
+                               AQ_TIMEREMAIN = 60*5+random(60*5);\r
+                                       ob->state = &s_aqua_rise1;\r
+                               ob->speed = 2200;\r
+                               ob->ticcount = ob->state->tictime;\r
+                       }\r
+                       else\r
+                       {\r
+                               // DEC COUNTER - And check for WALK\r
+                               //\r
+                               if ((AQ_TIMEREMAIN-=realtics) < 0)\r
+                               {\r
+                                       // RISE & GOTO WALK STAGE\r
+                                       //\r
+\r
+                                       if (CheckHandAttack(ob))\r
+                                               break;\r
+\r
+                                       AQ_STAGE = wt_WALK;\r
+                                       AQ_TIMEREMAIN = 60+random(60*2);\r
+                                               ob->state = &s_aqua_rise1;\r
+                                       ob->speed = 2200;\r
+                                       ob->ticcount = ob->state->tictime;\r
+                               }\r
+                               else\r
+                               if (random(1000)<5)\r
+                               {\r
+                                       // RANDOM PEEK UP OUT OF WATER\r
+                                       //\r
+                                               if (random(2) == 0)\r
+                                                       ob->state = &s_aqua_left;\r
+                                               else\r
+                                                       ob->state = &s_aqua_right;\r
+                                       ob->ticcount = ob->state->tictime;\r
+                               }\r
+                       }\r
+                       break;\r
+\r
+\r
+               case wt_WALK:\r
+                       ob->flags |= of_shootable;\r
+                       if (Chase(ob,true) || (random(1000)<RANDOM_ATTACK))\r
+                       {\r
+                                       ob->state = &s_aqua_attack1;\r
+                               ob->ticcount = ob->state->tictime;\r
+                       }\r
+                       else\r
+                       {\r
+                               // DEC COUNTER - And check for SINK\r
+                               //\r
+                               if ((AQ_TIMEREMAIN-=realtics) < 0)\r
+                               {\r
+                                       // SINK & GOTO BUBBLE STAGE\r
+                                       //\r
+\r
+                                       AQ_STAGE = wt_UNDER;\r
+                                       AQ_TIMEREMAIN = 60*4+random(60*3);\r
+                                               ob->state = &s_aqua_sink1;\r
+                                       ob->speed = 1200;\r
+                                       ob->ticcount = ob->state->tictime;\r
+                                       ob->flags &= ~of_shootable;\r
+                               }\r
+\r
+                       }\r
+                       break;\r
+       }\r
+}\r
+\r
+\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                                                       WIZARD\r
+\r
+=============================================================================\r
+*/\r
+\r
+void T_Wizard(objtype *ob);\r
+void T_WizardShoot(objtype *ob);\r
+\r
+statetype s_wizard_walk1 = {WIZARDWALK1PIC, 20, &T_Wizard, &s_wizard_walk2};\r
+statetype s_wizard_walk2 = {WIZARDWALK2PIC, 20, &T_Wizard, &s_wizard_walk3};\r
+statetype s_wizard_walk3 = {WIZARDWALK3PIC, 20, &T_Wizard, &s_wizard_walk4};\r
+statetype s_wizard_walk4 = {WIZARDWALK4PIC, 20, &T_Wizard, &s_wizard_walk1};\r
+\r
+statetype s_wizard_attack1 = {WIZARDATTACK1PIC, 20, NULL, &s_wizard_attack2};\r
+statetype s_wizard_attack2 = {WIZARDATTACK2PIC, 20, &T_DoDamage, &s_wizard_walk1};\r
+\r
+statetype s_wizard_ouch = {WIZARDOUCHPIC, 15, NULL, &s_wizard_walk1};\r
+\r
+statetype s_wizard_die1 = {WIZARDDEATH1PIC, 45, &SmallSound, &s_wizard_die2};\r
+statetype s_wizard_die2 = {WIZARDDEATH2PIC, 30, NULL, &s_wizard_die3};\r
+statetype s_wizard_die3 = {WIZARDDEATH3PIC, 15, NULL, &s_wizard_die4};\r
+statetype s_wizard_die4 = {WIZARDDEATH4PIC, 15, NULL, &s_wizard_die4};\r
+\r
+statetype s_wizard_shoot1 = {WIZARDATTACK1PIC, 20, NULL, &s_wizard_shoot2};\r
+statetype s_wizard_shoot2 = {WIZARDATTACK1PIC, -1, &T_WizardShoot, &s_wizard_shoot3};\r
+statetype s_wizard_shoot3 = {WIZARDATTACK2PIC, 20, NULL, &s_wizard_walk1};\r
+\r
+statetype s_wizard_shot1 = {WIZARD_SHOT1PIC, 8, &T_ShootPlayer, &s_wizard_shot2};\r
+statetype s_wizard_shot2 = {WIZARD_SHOT2PIC, 8, &T_ShootPlayer, &s_wizard_shot1};\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnWizard\r
+=\r
+===============\r
+*/\r
+\r
+void SpawnWizard (int tilex, int tiley)\r
+{\r
+       SpawnNewObj(tilex,tiley,&s_wizard_walk1,TILEGLOBAL/2);\r
+       new->obclass    = wizardobj;\r
+       new->speed              = 1536;\r
+       new->flags |= of_shootable;\r
+       new->hitpoints  = EasyHitPoints(10);\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= T_Wizard\r
+=\r
+===============\r
+*/\r
+\r
+void T_Wizard(objtype *ob)\r
+{\r
+       if (Chase (ob,true))// || (random(1000)<RANDOM_ATTACK))\r
+       {\r
+               ob->state = &s_wizard_attack1;\r
+               ob->ticcount = ob->state->tictime;\r
+               return;\r
+       }\r
+       else\r
+               if (AngleNearPlayer(ob) != -1)\r
+               {\r
+                       ob->state = &s_wizard_shoot1;\r
+                       ob->ticcount = ob->state->tictime;\r
+                       return;\r
+               }\r
+}\r
+\r
+/*\r
+===============\r
+=\r
+= T_Wizard\r
+=\r
+===============\r
+*/\r
+void T_WizardShoot(objtype *ob)\r
+{\r
+       ShootPlayer(ob, wshotobj, 10000, &s_wizard_shot1);\r
+}\r
+\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                                                       RAY\r
+\r
+=============================================================================\r
+*/\r
+\r
+void T_BlobRay(objtype *ob);\r
+void T_RayShoot (objtype *ob);\r
+\r
+statetype s_ray_under = {0, 20, &T_BlobRay, &s_ray_under};\r
+\r
+statetype s_ray_rise = {RAYRISEPIC, 30, NULL, &s_ray_fly1};\r
+\r
+statetype s_ray_sink = {RAYRISEPIC, 30, NULL, &s_ray_under};\r
+\r
+statetype s_ray_fly1 = {RAYFLY1PIC, 10, &T_BlobRay, &s_ray_fly2};\r
+statetype s_ray_fly2 = {RAYFLY2PIC, 10, &T_BlobRay, &s_ray_fly3};\r
+statetype s_ray_fly3 = {RAYFLY1PIC, 10, &T_BlobRay, &s_ray_fly4};\r
+statetype s_ray_fly4 = {RAYFLY3PIC, 10, &T_BlobRay, &s_ray_fly1};\r
+\r
+statetype s_ray_attack1 = {RAYSHOOT1PIC, 15, NULL, &s_ray_attack2};\r
+statetype s_ray_attack2 = {RAYSHOOT2PIC, -1, &T_RayShoot, &s_ray_attack3};\r
+statetype s_ray_attack3 = {RAYSHOOT2PIC, 20, NULL, &s_ray_fly1};\r
+\r
+statetype s_ray_die1 = {RAYDEATH1PIC, 50, &SmallSound, &s_ray_die2};\r
+statetype s_ray_die2 = {RAYDEATH2PIC, 30, NULL, NULL};\r
+\r
+statetype s_ray_shot1 = {RAYSHOT1PIC, 8, &T_ShootPlayer, &s_ray_shot2};\r
+statetype s_ray_shot2 = {RAYSHOT2PIC, 8, &T_ShootPlayer, &s_ray_shot1};\r
+\r
+\r
+typedef enum {br_GND, br_WALK, br_CORNER1, br_CORNER2, br_CORNER3, br_CORNER4} BlobTypes;\r
+\r
+#define BR_TIMEREMAIN  (ob->temp1)\r
+#define BR_STAGE                       (ob->temp2)\r
+#define BLOB_LEAVE             0x04\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnRay\r
+=\r
+===============\r
+*/\r
+void SpawnRay(int tilex, int tiley)\r
+{\r
+       objtype *ob;\r
+       SpawnNewObj(tilex, tiley, &s_ray_under, PIXRADIUS*25);\r
+       ob=new;\r
+\r
+       BR_STAGE = br_GND;\r
+       BR_TIMEREMAIN = random(60)+random(100);\r
+\r
+       new->obclass    = rayobj;\r
+       new->speed              = 1700;\r
+       new->flags      &= ~of_shootable;\r
+       new->hitpoints  = EasyHitPoints(15);\r
+}\r
+\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                                               BLOB\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+statetype s_blob_gnd1 = {BLOBGND1PIC, 13, T_BlobRay, &s_blob_gnd2};\r
+statetype s_blob_gnd2 = {BLOBGND2PIC, 15, T_BlobRay, &s_blob_gnd1};\r
+\r
+statetype s_blob_rise1 = {BLOBRISE1PIC, 20, NULL, &s_blob_rise2};\r
+statetype s_blob_rise2 = {BLOBRISE2PIC, 20, NULL, &s_blob_walk1};\r
+\r
+statetype s_blob_sink1 = {BLOBRISE2PIC, 20, NULL, &s_blob_sink2};\r
+statetype s_blob_sink2 = {BLOBRISE1PIC, 20, NULL, &s_blob_gnd1};\r
+\r
+statetype s_blob_walk1 = {BLOBWALK1PIC, 15, T_BlobRay, &s_blob_walk2};\r
+statetype s_blob_walk2 = {BLOBWALK2PIC, 15, T_BlobRay, &s_blob_walk3};\r
+statetype s_blob_walk3 = {BLOBWALK3PIC, 15, T_BlobRay, &s_blob_walk1};\r
+\r
+statetype s_blob_ouch = {BLOBRISE2PIC, 10, T_BlobRay, &s_blob_walk1};\r
+\r
+statetype s_blob_die1 = {BLOBDEATH1PIC, 30, &ExplosionSnd, &s_blob_die2};\r
+statetype s_blob_die2 = {BLOBDEATH2PIC, 30, NULL, &s_blob_die3};\r
+statetype s_blob_die3 = {BLOBDEATH3PIC, 30, NULL, NULL};\r
+\r
+statetype s_blob_shot1 = {BLOB_SHOT1PIC, 8, &T_ShootPlayer, &s_blob_shot2};\r
+statetype s_blob_shot2 = {BLOB_SHOT2PIC, 8, &T_ShootPlayer, &s_blob_shot1};\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnBlob\r
+=\r
+===============\r
+*/\r
+void SpawnBlob(int tilex, int tiley)\r
+{\r
+       objtype *ob;\r
+       SpawnNewObj(tilex, tiley, &s_blob_gnd1, PIXRADIUS*14);\r
+       ob=new;\r
+\r
+       BR_STAGE = br_GND;\r
+       BR_TIMEREMAIN = random(60)+random(100);\r
+\r
+       new->obclass    = blobobj;\r
+       new->speed              = 1200;\r
+       new->flags      &= ~of_shootable;\r
+       new->hitpoints  = EasyHitPoints(13);\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= T_BlobRay\r
+=\r
+===============\r
+*/\r
+\r
+void T_BlobRay(objtype *ob)\r
+{\r
+       switch (BR_STAGE)\r
+       {\r
+               case br_GND:\r
+                       ob->flags &= ~of_shootable;\r
+                       if (Chase(ob,true))\r
+                       {\r
+                               // RISE & GOTO WALK STAGE\r
+                               //\r
+\r
+                               BR_STAGE                        = br_WALK;\r
+                               BR_TIMEREMAIN   = 60*8+random(60*5);\r
+                               if (ob->obclass == blobobj)\r
+                                       ob->state       = &s_blob_rise1;\r
+                               else\r
+                                       ob->state       = &s_ray_rise;\r
+                               ob->speed               = 2200;\r
+                               ob->ticcount    = ob->state->tictime;\r
+                       }\r
+                       else\r
+                       {\r
+                               // DEC COUNTER - And check for WALK\r
+                               //\r
+                               if ((BR_TIMEREMAIN -= realtics) < 0)\r
+                               {\r
+                                       // RISE & GOTO WALK STAGE\r
+                                       //\r
+\r
+                                       BR_STAGE                        = br_WALK;\r
+                                       BR_TIMEREMAIN   = 60*8+random(60*5);\r
+                                       if (ob->obclass == blobobj)\r
+                                               ob->state       = &s_blob_rise1;\r
+                                       else\r
+                                               ob->state       = &s_ray_rise;\r
+                                       ob->speed               = 2200;\r
+                                       ob->ticcount    = ob->state->tictime;\r
+                               }\r
+                       }\r
+                       break;\r
+\r
+\r
+               case br_WALK:\r
+                       ob->flags |= of_shootable;\r
+\r
+                       if (Chase(ob,true) || (CheckHandAttack(ob)))\r
+\r
+                       {\r
+                                       ob->flags               |= BLOB_LEAVE;\r
+                                       BR_STAGE                        = random(br_CORNER3) + 2;\r
+                                       BR_TIMEREMAIN   = 60*2+(random(6)*60);\r
+                                       if (ob->obclass == blobobj)\r
+                                               ob->state       = &s_blob_gnd1;\r
+                                       else\r
+                                               ob->state       = &s_ray_under;\r
+                                       ob->ticcount    = ob->state->tictime;\r
+                       }\r
+                       else\r
+                               if (AngleNearPlayer(ob) != -1)\r
+                               {\r
+                                       if (ob->obclass == blobobj)\r
+                                       {\r
+                                               if (!(random(15)))\r
+                                                               ShootPlayer(ob, bshotobj, 10000, &s_blob_shot1);\r
+                                       }\r
+                                       else\r
+                                               if (!(random(7)))\r
+                                               {\r
+                                                       ob->state = &s_ray_attack1;\r
+                                                       ob->ticcount = ob->state->tictime;\r
+                                               }\r
+                               }\r
+\r
+                       else\r
+                       {\r
+                               // DEC COUNTER - And check for SINK\r
+                               //\r
+                               if ((BR_TIMEREMAIN -= realtics) < 0)\r
+                               {\r
+                                       // SINK & GOTO GROUND STAGE\r
+                                       //\r
+\r
+                                       BR_STAGE                        = br_GND;\r
+                                       BR_TIMEREMAIN   = 60*2+random(60*2);\r
+                                       if (ob->obclass == blobobj)\r
+                                       {\r
+                                               ob->state               = &s_blob_sink1;\r
+                                               ob->speed               = 1200;\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               ob->state               = &s_ray_sink;\r
+                                               ob->speed               = 1700;\r
+                                       }\r
+                                       ob->ticcount    = ob->state->tictime;\r
+                                       ob->flags               &= ~of_shootable;\r
+                               }\r
+\r
+                       }\r
+                       break;\r
+               case br_CORNER1:\r
+               case br_CORNER2:\r
+               case br_CORNER3:\r
+               case br_CORNER4:\r
+                       ob->flags &= ~of_shootable;\r
+                       if ((BR_TIMEREMAIN -= realtics) < 0)\r
+                       {\r
+                               BR_STAGE = br_GND;\r
+                               ob->flags &= ~BLOB_LEAVE;\r
+                       }\r
+                       else\r
+                       {\r
+                               fixed tempx,tempy;\r
+                               unsigned temp_tilex,temp_tiley;\r
+\r
+                               tempx                   = player->x;\r
+                               tempy                   = player->y;\r
+                               temp_tilex      = player->tilex;\r
+                               temp_tiley      = player->tiley;\r
+\r
+                               player->x = ((long)other_x[BR_STAGE-2]<<TILESHIFT)+TILEGLOBAL/2;\r
+                               player->y = ((long)other_y[BR_STAGE-2]<<TILESHIFT)+TILEGLOBAL/2;\r
+                               player->tilex = other_x[BR_STAGE-2];\r
+                               player->tiley = other_y[BR_STAGE-2];\r
+\r
+\r
+                               Chase(ob,true);\r
+\r
+                               player->x               = tempx;\r
+                               player->y               = tempy;\r
+                               player->tilex   = temp_tilex;\r
+                               player->tiley   = temp_tiley;\r
+                       }\r
+                       break;\r
+       }\r
+}\r
+\r
+/*\r
+===============\r
+=\r
+= T_RayShoot\r
+=\r
+===============\r
+*/\r
+void T_RayShoot (objtype *ob)\r
+{\r
+       ShootPlayer(ob, rshotobj, 10000, &s_ray_shot1);\r
+}
\ No newline at end of file
diff --git a/src/lib/hb/c6_act2.c b/src/lib/hb/c6_act2.c
new file mode 100755 (executable)
index 0000000..803fe8b
--- /dev/null
@@ -0,0 +1,891 @@
+/* Catacomb Apocalypse Source Code\r
+ * Copyright (C) 1993-2014 Flat Rock Software\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License along\r
+ * with this program; if not, write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+ */\r
+\r
+// C3_PLAY.C\r
+\r
+#include "DEF.H"\r
+#pragma hdrstop\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                GLOBAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+boolean ShootPlayer (objtype *ob, short obclass, short speed, statetype *state);\r
+void T_ShootPlayer(objtype *ob);\r
+\r
+short head_base_delay;\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+void T_ShooterObj(objtype *ob);\r
+\r
+void SpawnRamBone(int tilex, int tiley);\r
+void T_SkeletonShoot(objtype *ob);\r
+void SpawnFutureMage (int tilex, int tiley);\r
+void T_FMageShoot(objtype *ob);\r
+void SpawnRoboTank(int tilex, int tiley);\r
+void T_RoboTankShoot(objtype *ob);\r
+void SpawnStompy(int tilex, int tiley);\r
+void T_StompyShoot(objtype *ob);\r
+void SpawnBug(int tilex, int tiley);\r
+void T_BugShoot(objtype *ob);\r
+void SpawnShooterEye(int tilex, int tiley);\r
+void T_EyeShootPlayer(objtype *ob);\r
+void SpawnRunningEye(int tilex, int tiley);\r
+void T_RunningEye(objtype *ob);\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                                               LARGE SOUND\r
+\r
+=============================================================================\r
+*/\r
+void LargeSound (objtype *ob)\r
+{\r
+       if (ob->temp1 != SOUNDPLAYED)\r
+       {\r
+               SD_PlaySound(LARGEMONSTERSND);\r
+               ob->temp1 = SOUNDPLAYED;\r
+\r
+       }\r
+}\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                                               SMALL SOUND\r
+\r
+=============================================================================\r
+*/\r
+void SmallSound (objtype *ob)\r
+{\r
+       if (ob->temp1 != SOUNDPLAYED)\r
+       {\r
+               SD_PlaySound(SMALLMONSTERSND);\r
+               ob->temp1 = SOUNDPLAYED;\r
+\r
+       }\r
+}\r
+\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                                               RAMBONE\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+statetype s_skel_1 = {RAMBONEWALK1PIC, 10, &T_ShooterObj, &s_skel_2};\r
+statetype s_skel_2 = {RAMBONEWALK2PIC, 10, &T_ShooterObj, &s_skel_3};\r
+statetype s_skel_3 = {RAMBONEWALK3PIC, 10, &T_ShooterObj, &s_skel_4};\r
+statetype s_skel_4 = {RAMBONEWALK4PIC, 10, &T_ShooterObj, &s_skel_1};\r
+\r
+statetype s_skel_attack1 = {RAMBONEATTACK1PIC, 12, NULL, &s_skel_attack2};\r
+statetype s_skel_attack2 = {RAMBONEATTACK2PIC, 20, NULL, &s_skel_attack3};\r
+statetype s_skel_attack3 = {RAMBONEATTACK2PIC, -1, T_SkeletonShoot, &s_skel_attack4};\r
+statetype s_skel_attack4 = {RAMBONEATTACK3PIC, 20, NULL, &s_skel_ouch};\r
+\r
+statetype s_skel_ouch = {RAMBONEATTACK1PIC, 10, NULL, &s_skel_1};\r
+\r
+statetype s_skel_die1 = {RAMBONEDEATH1PIC, 40, NULL, &s_skel_die2};\r
+statetype s_skel_die2 = {RAMBONEDEATH2PIC, 30, NULL, &s_skel_die3};\r
+statetype s_skel_die3 = {RAMBONEDEATH3PIC, 20, &LargeSound, NULL};\r
+\r
+statetype s_skel_shot1 = {RAMBONESHOT1PIC, 10, &T_ShootPlayer, &s_skel_shot2};\r
+statetype s_skel_shot2 = {RAMBONESHOT2PIC, 10, &T_ShootPlayer, &s_skel_shot1};\r
+\r
+#define shooter_mode           ob->temp1\r
+#define shooter_delay  ob->temp2\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnSkeleton\r
+=\r
+===============\r
+*/\r
+void SpawnRamBone(int tilex, int tiley)\r
+{\r
+       SpawnNewObj(tilex, tiley, &s_skel_1,PIXRADIUS*20);\r
+       new->obclass    = ramboneobj;\r
+       new->speed              = 2036;\r
+       new->flags              |= of_shootable;\r
+       new->hitpoints  = EasyHitPoints(12);\r
+}\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= T_SkeletonShoot\r
+=\r
+=================\r
+*/\r
+void T_SkeletonShoot(objtype *ob)\r
+{\r
+       ShootPlayer(ob, rbshotobj, MSHOTSPEED, &s_skel_shot1);\r
+}\r
+\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                                               FUTURE MAGE\r
+\r
+=============================================================================\r
+*/\r
+\r
+statetype s_fmage1 = {FMAGEWALK1PIC, 20, &T_ShooterObj, &s_fmage2};\r
+statetype s_fmage2 = {FMAGEWALK2PIC, 20, &T_ShooterObj, &s_fmage3};\r
+statetype s_fmage3 = {FMAGEWALK3PIC, 20, &T_ShooterObj, &s_fmage1};\r
+\r
+statetype s_fmageattack1 = {FMAGEATTACK1PIC, 20, NULL, &s_fmageattack2};\r
+statetype s_fmageattack2 = {FMAGEATTACK1PIC, -1, &T_FMageShoot, &s_fmageattack3};\r
+statetype s_fmageattack3 = {FMAGEATTACK2PIC, 30, NULL, &s_fmage1};\r
+\r
+statetype s_fmageouch = {FMAGEATTACK1PIC, 10, NULL, &s_fmage1};\r
+\r
+statetype s_fmagedie1 = {FMAGEDEATH1PIC, 40, NULL, &s_fmagedie2};\r
+statetype s_fmagedie2 = {FMAGEDEATH2PIC, 30, &SmallSound, &s_fmagedie3};\r
+statetype s_fmagedie3 = {FMAGEDEATH3PIC, 0, NULL, &s_fmagedie3};\r
+\r
+statetype s_fmshot1 = {FMAGESHOT1PIC, 8, &T_ShootPlayer, &s_fmshot2};\r
+statetype s_fmshot2 = {FMAGESHOT2PIC, 8, &T_ShootPlayer, &s_fmshot1};\r
+\r
+/*\r
+=================\r
+=\r
+= SpawnFutureMage\r
+=\r
+=================\r
+*/\r
+\r
+void SpawnFutureMage (int tilex, int tiley)\r
+{\r
+       SpawnNewObj(tilex, tiley, &s_fmage1, PIXRADIUS*15);\r
+       new->obclass    = fmageobj;\r
+       new->speed              = 3072;\r
+       new->flags              |= of_shootable;\r
+       new->hitpoints  = EasyHitPoints(12);\r
+}\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= T_FMageShoot\r
+=\r
+=================\r
+*/\r
+void T_FMageShoot(objtype *ob)\r
+{\r
+       ShootPlayer(ob, fmshotobj, MSHOTSPEED, &s_fmshot1);\r
+}\r
+\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                                               ROBO TANK\r
+\r
+=============================================================================\r
+*/\r
+\r
+statetype s_robotank_walk1 = {ROBOTANKWALK1PIC, 15, &T_ShooterObj, &s_robotank_walk2};\r
+statetype s_robotank_walk2 = {ROBOTANKWALK2PIC, 15, &T_ShooterObj, &s_robotank_walk3};\r
+statetype s_robotank_walk3 = {ROBOTANKWALK3PIC, 15, &T_ShooterObj, &s_robotank_walk4};\r
+statetype s_robotank_walk4 = {ROBOTANKWALK4PIC, 15, &T_ShooterObj, &s_robotank_walk1};\r
+\r
+statetype s_robotank_attack1 = {ROBOTANKWALK1PIC, 15, NULL, &s_robotank_attack2};\r
+statetype s_robotank_attack2 = {ROBOTANKATTACK1PIC, 15, NULL, &s_robotank_attack3};\r
+statetype s_robotank_attack3 = {ROBOTANKATTACK1PIC, -1, &T_RoboTankShoot, &s_robotank_attack4};\r
+statetype s_robotank_attack4 = {ROBOTANKWALK1PIC, 15, NULL, &s_robotank_walk1};\r
+\r
+statetype s_robotank_death1 = {ROBOTANKDEATH1PIC, 8, NULL, &s_robotank_death2};\r
+statetype s_robotank_death2 = {ROBOTANKDEATH2PIC, 8, NULL, &s_robotank_death3};\r
+statetype s_robotank_death3 = {ROBOTANKDEATH2PIC, -1, &T_AlternateStates, &s_robotank_death1};\r
+statetype s_robotank_death4 = {ROBOTANKDEATH3PIC, 25, &ExplosionSnd, &s_robotank_death5};\r
+statetype s_robotank_death5 = {ROBOTANKDEATH4PIC, 20, NULL, &s_robotank_death5};\r
+\r
+statetype s_robotank_shot1 = {PSHOT1PIC, 10, &T_ShootPlayer, &s_robotank_shot2};\r
+statetype s_robotank_shot2 = {PSHOT2PIC, 10, &T_ShootPlayer, &s_robotank_shot1};\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= SpawnRoboTank\r
+=\r
+=================\r
+*/\r
+void SpawnRoboTank(int tilex, int tiley)\r
+{\r
+       SpawnNewObj(tilex, tiley, &s_robotank_walk1, PIXRADIUS*35);\r
+       new->obclass    = robotankobj;\r
+       new->speed              = 1700;\r
+       new->flags              |= of_shootable;\r
+       new->hitpoints  = EasyHitPoints(25);\r
+}\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= T_RoboTankShoot\r
+=\r
+=================\r
+*/\r
+void T_RoboTankShoot(objtype *ob)\r
+{\r
+       ShootPlayer(ob, rtshotobj, 7000, &s_robotank_shot1);\r
+}\r
+\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= T_AlternateStates\r
+=\r
+====================\r
+*/\r
+void T_AlternateStates(objtype *ob)\r
+{\r
+       if (ob->temp1--)\r
+       {\r
+               ob->state = ob->state->next;\r
+       }\r
+       else\r
+       {\r
+               if (ob->state == &s_robotank_death3)\r
+                       ob->state = &s_robotank_death4;\r
+               else\r
+                       ob->state = &s_aqua_die4;\r
+       }\r
+       ob->ticcount    = ob->state->tictime;\r
+}\r
+\r
+\r
+\r
+\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                                                       STOMPY\r
+\r
+=============================================================================\r
+*/\r
+\r
+statetype s_stompy_walk1 = {STOMPYWALK1PIC, 15, &T_ShooterObj, &s_stompy_walk2};\r
+statetype s_stompy_walk2 = {STOMPYWALK2PIC, 15, &T_ShooterObj, &s_stompy_walk3};\r
+statetype s_stompy_walk3 = {STOMPYWALK3PIC, 15, &T_ShooterObj, &s_stompy_walk4};\r
+statetype s_stompy_walk4 = {STOMPYWALK4PIC, 15, &T_ShooterObj, &s_stompy_walk1};\r
+\r
+statetype s_stompy_attack1 = {STOMPYATTACK1PIC, 10, NULL, &s_stompy_attack2};\r
+statetype s_stompy_attack2 = {STOMPYATTACK2PIC, 15, NULL, &s_stompy_attack3};\r
+statetype s_stompy_attack3 = {STOMPYATTACK2PIC, -1, T_StompyShoot, &s_stompy_attack4};\r
+statetype s_stompy_attack4 = {STOMPYATTACK1PIC, 10, NULL, &s_stompy_walk1};\r
+\r
+statetype s_stompy_ouch = {STOMPYATTACK1PIC, 10, NULL, &s_stompy_walk2};\r
+\r
+statetype s_stompy_death1 = {STOMPYDEATH1PIC, 45, &ExplosionSnd, &s_stompy_death2};\r
+statetype s_stompy_death2 = {STOMPYDEATH2PIC, 30, NULL, &s_stompy_death3};\r
+statetype s_stompy_death3 = {STOMPYDEATH3PIC, 25, NULL, &s_stompy_death4};\r
+statetype s_stompy_death4 = {STOMPYDEATH4PIC, 20, NULL, NULL};\r
+\r
+statetype s_stompy_shot1 = {STOMPYSHOT1PIC, 6, &T_ShootPlayer, &s_stompy_shot2};\r
+statetype s_stompy_shot2 = {STOMPYSHOT2PIC, 6, &T_ShootPlayer, &s_stompy_shot3};\r
+statetype s_stompy_shot3 = {STOMPYSHOT1PIC, 6, &T_ShootPlayer, &s_stompy_shot4};\r
+statetype s_stompy_shot4 = {STOMPYSHOT3PIC, 6, &T_ShootPlayer, &s_stompy_shot5};\r
+statetype s_stompy_shot5 = {STOMPYSHOT4PIC, 6, &T_ShootPlayer, &s_stompy_shot4};\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= SpawnStompy\r
+=\r
+=================\r
+*/\r
+void SpawnStompy(int tilex, int tiley)\r
+{\r
+       SpawnNewObj(tilex, tiley, &s_stompy_walk1, PIXRADIUS*25);\r
+       new->obclass    = stompyobj;\r
+       new->speed              = 1800;\r
+       new->flags              |= of_shootable;\r
+       new->hitpoints  = EasyHitPoints(20);\r
+}\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= T_StompyShoot\r
+=\r
+=================\r
+*/\r
+void T_StompyShoot(objtype *ob)\r
+{\r
+       ShootPlayer(ob, syshotobj, 8500, &s_stompy_shot1);\r
+}\r
+\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                                                               BUG\r
+\r
+=============================================================================\r
+*/\r
+\r
+statetype s_bug_walk1 = {BUG_WALK1PIC, 15, &T_ShooterObj, &s_bug_walk2};\r
+statetype s_bug_walk2 = {BUG_WALK2PIC, 15, &T_ShooterObj, &s_bug_walk3};\r
+statetype s_bug_walk3 = {BUG_WALK3PIC, 15, &T_ShooterObj, &s_bug_walk1};\r
+\r
+statetype s_bug_attack1 = {BUG_ATTACK1PIC, 20, NULL, &s_bug_attack2};\r
+statetype s_bug_attack2 = {BUG_ATTACK2PIC, 20, NULL, &s_bug_attack3};\r
+statetype s_bug_attack3 = {BUG_ATTACK2PIC, -1, &T_BugShoot, &s_bug_attack4};\r
+statetype s_bug_attack4 = {BUG_ATTACK1PIC, 15, NULL, &s_bug_walk1};\r
+\r
+statetype s_bug_ouch = {BUG_WALK1PIC, 10, NULL, &s_bug_walk2};\r
+\r
+statetype s_bug_death1 = {BUG_DEATH1PIC, 35, &SmallSound, &s_bug_death2};\r
+statetype s_bug_death2 = {BUG_DEATH2PIC, 10, NULL, &s_bug_death2};\r
+\r
+statetype s_bug_shot1 = {BUG_SHOT1PIC, 10, &T_ShootPlayer, &s_bug_shot2};\r
+statetype s_bug_shot2 = {BUG_SHOT2PIC, 10, &T_ShootPlayer, &s_bug_shot1};\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= SpawnBug\r
+=\r
+=================\r
+*/\r
+void SpawnBug(int tilex, int tiley)\r
+{\r
+       SpawnNewObj(tilex, tiley, &s_bug_walk1, PIXRADIUS*20);\r
+       new->obclass    = bugobj;\r
+       new->speed              = 1500;\r
+       new->flags              |= of_shootable;\r
+       new->hitpoints  = EasyHitPoints(10);\r
+}\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= T_BugShoot\r
+=\r
+=================\r
+*/\r
+void T_BugShoot(objtype *ob)\r
+{\r
+       ShootPlayer(ob, bgshotobj, 8000, &s_bug_shot1);\r
+}\r
+\r
+\r
+\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                                       MEC EYE\r
+\r
+=============================================================================\r
+*/\r
+\r
+void T_EyeShootPlayer (objtype *ob);\r
+\r
+statetype s_eye_pause = {EYE_WALK1PIC,40,NULL,&s_eye_2};\r
+\r
+statetype s_eye_1 = {EYE_WALK1PIC,20,T_ShooterObj,&s_eye_2};\r
+statetype s_eye_2 = {EYE_WALK2PIC,20,T_ShooterObj,&s_eye_3};\r
+statetype s_eye_3 = {EYE_WALK3PIC,20,T_ShooterObj,&s_eye_4};\r
+statetype s_eye_4 = {EYE_WALK2PIC,20,T_ShooterObj,&s_eye_1};\r
+statetype s_eye_shootplayer_1 = {EYE_WALK1PIC,1,T_EyeShootPlayer,&s_eye_shootplayer_2};\r
+statetype s_eye_shootplayer_2 = {EYE_WALK1PIC,20,NULL,&s_eye_1};\r
+\r
+statetype s_eye_ouch = {EYE_OUCH1PIC,8,NULL,&s_eye_ouch2};\r
+statetype s_eye_ouch2 = {EYE_OUCH2PIC,8,NULL,&s_eye_1};\r
+\r
+statetype s_eye_die1 = {EYE_DEATH1PIC,22,NULL,&s_eye_die2};\r
+statetype s_eye_die2 = {EYE_DEATH2PIC,22,&SmallSound,&s_eye_die3};\r
+statetype s_eye_die3 = {EYE_DEATH3PIC,22,NULL,&s_eye_die4};\r
+statetype s_eye_die4 = {EYE_DEATH4PIC,22,NULL,&s_eye_die4};\r
+\r
+statetype s_eshot1 = {EYE_SHOT1PIC,8,&T_ShootPlayer,&s_eshot2};\r
+statetype s_eshot2 = {EYE_SHOT2PIC,8,&T_ShootPlayer,&s_eshot1};\r
+\r
+\r
+//-------------------------------------------------------------------------\r
+// SpawnEye()\r
+//-------------------------------------------------------------------------\r
+void SpawnShooterEye(int tilex, int tiley)\r
+{\r
+       objtype *ob;\r
+\r
+       SpawnNewObj(tilex,tiley,&s_eye_1,PIXRADIUS*10);\r
+       ob = new;\r
+       new->obclass = eyeobj;\r
+       new->speed = 3000;\r
+       new->flags |= of_shootable;\r
+       new->hitpoints = EasyHitPoints(15);\r
+       shooter_mode = sm_other1;\r
+}\r
+\r
+\r
+//---------------------------------------------------------------------------\r
+// T_EyeShootPlayer\r
+//---------------------------------------------------------------------------\r
+void T_EyeShootPlayer (objtype *ob)\r
+{\r
+       ShootPlayer(ob, eshotobj, ESHOTSPEED, &s_eshot1);\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= T_ShooterObj\r
+=\r
+= **********\r
+= ***NOTE*** This routine controls the thinks for the RamBone, RoboTank,\r
+= **********   Stompy, Future Mage, Bug, and Old Mage\r
+=\r
+===============\r
+*/\r
+\r
+void T_ShooterObj(objtype *ob)\r
+{\r
+       fixed tempx,tempy;\r
+       unsigned temp_tilex,temp_tiley;\r
+       int angle;\r
+\r
+       shooter_delay -= realtics;\r
+       if (shooter_delay < 0)\r
+       {\r
+               shooter_mode = random(sm_dummy);\r
+               shooter_delay = random(10*60)+random(50);\r
+       }\r
+\r
+       tempx = player->x;\r
+       tempy = player->y;\r
+       temp_tilex = player->tilex;\r
+       temp_tiley = player->tiley;\r
+\r
+\r
+       switch (shooter_mode)\r
+       {\r
+               case sm_other1:\r
+               case sm_other2:\r
+               case sm_other3:\r
+               case sm_other4:\r
+                       player->x = ((long)other_x[shooter_mode]<<TILESHIFT)+TILEGLOBAL/2;\r
+                       player->y = ((long)other_y[shooter_mode]<<TILESHIFT)+TILEGLOBAL/2;\r
+                       player->tilex = other_x[shooter_mode];\r
+                       player->tiley = other_y[shooter_mode];\r
+               break;\r
+       }\r
+\r
+       if (Chase(ob,true))\r
+               shooter_delay = 0;\r
+\r
+       player->x = tempx;\r
+       player->y = tempy;\r
+       player->tilex = temp_tilex;\r
+       player->tiley = temp_tiley;\r
+\r
+       angle = AngleNearPlayer(ob);\r
+\r
+\r
+  // Handle shooting for the different characters controlled by this think.\r
+       switch (ob->obclass)\r
+       {\r
+               case ramboneobj:\r
+                       if (!random(2) && (angle != -1))\r
+                       {\r
+                               ob->state = &s_skel_attack1;\r
+                               ob->ticcount = ob->state->tictime;\r
+                       }\r
+               break;\r
+\r
+               case fmageobj:\r
+                       if (!random(8) && (angle != -1))\r
+                       {\r
+                               ob->state = &s_fmageattack1;\r
+                               ob->ticcount = ob->state->tictime;\r
+                       }\r
+               break;\r
+\r
+               case robotankobj:\r
+                       if (!random(15) && (angle != -1))\r
+                       {\r
+                               ob->state = &s_robotank_attack1;\r
+                               ob->ticcount = ob->state->tictime;\r
+                       }\r
+               break;\r
+\r
+               case stompyobj:\r
+                       if (angle != -1)\r
+                       {\r
+                               ob->state = &s_stompy_attack1;\r
+                               ob->ticcount = ob->state->tictime;\r
+                       }\r
+               break;\r
+\r
+               case bugobj:\r
+                       if (!random(5) && (angle != -1))\r
+                       {\r
+                               ob->state = &s_bug_attack1;\r
+                               ob->ticcount = ob->state->tictime;\r
+                       }\r
+               break;\r
+\r
+               case eyeobj:\r
+                       if (!random(2) && (angle != -1))\r
+                       {\r
+                               ob->state = &s_eye_shootplayer_1;\r
+                               ob->ticcount = ob->state->tictime;\r
+                       }\r
+               break;\r
+       }\r
+}\r
+\r
+\r
+\r
+\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                                               RUNNING EYE\r
+\r
+=============================================================================\r
+*/\r
+\r
+statetype s_reye_1 = {EYE_WALK1PIC, 20, &T_RunningEye, &s_reye_2};\r
+statetype s_reye_2 = {EYE_WALK2PIC, 20, &T_RunningEye, &s_reye_3};\r
+statetype s_reye_3 = {EYE_WALK3PIC, 20, &T_RunningEye, &s_reye_4};\r
+statetype s_reye_4 = {EYE_WALK2PIC, 20, &T_RunningEye, &s_reye_1};\r
+\r
+statetype s_reye_ouch = {EYE_OUCH1PIC, 8, NULL, &s_reye_ouch2};\r
+statetype s_reye_ouch2 = {EYE_OUCH2PIC, 8, NULL, &s_reye_1};\r
+\r
+statetype s_reye_die1 = {EYE_DEATH1PIC, 22, NULL, &s_reye_die2};\r
+statetype s_reye_die2 = {EYE_DEATH2PIC, 22, &SmallSound, &s_reye_die3};\r
+statetype s_reye_die3 = {EYE_DEATH3PIC, 22, NULL, &s_reye_die4};\r
+statetype s_reye_die4 = {EYE_DEATH4PIC, 22, NULL, &s_reye_die4};\r
+\r
+/*\r
+====================\r
+=\r
+= SpawnRunningEye()\r
+=\r
+====================\r
+*/\r
+void SpawnRunningEye(int tilex, int tiley)\r
+{\r
+       SpawnNewObj(tilex,tiley,&s_reye_1,PIXRADIUS*25);\r
+       new->obclass = reyeobj;\r
+       new->speed = 3500;\r
+       new->flags |= of_shootable;\r
+       new->hitpoints = EasyHitPoints(15);\r
+       new->temp2 = (*(mapsegs[2]+farmapylookup[tiley+1]+tilex))>>8;\r
+       *(mapsegs[2]+farmapylookup[tiley+1]+tilex) = 0;\r
+\r
+       new->temp1 = 2;\r
+\r
+       if (!new->temp2)\r
+               Quit("Initialize the running eye!\n");\r
+}\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= T_RunningEye\r
+=\r
+====================\r
+*/\r
+void T_RunningEye(objtype *ob)\r
+{\r
+       int x, y, dir_num, switch_num;\r
+       fixed tempx,tempy;\r
+       unsigned temp_tilex,temp_tiley;\r
+\r
+       dir_num = *(mapsegs[2]+farmapylookup[ob->tiley]+ob->tilex);\r
+       dir_num = dir_num>>8;\r
+\r
+       if (!dir_num)\r
+               dir_num = ob->temp2;\r
+\r
+       if (dir_num == 5)\r
+       {\r
+               if (ob->temp1)\r
+               {\r
+                       ob->temp1--;\r
+               }\r
+               else\r
+               {\r
+                       ob->temp1 = 2;\r
+                       actorat[ob->tilex][ob->tiley] = 0;\r
+                       switch (ob->temp2)\r
+                       {\r
+                               case 1:\r
+                                       ob->tiley = ob->tiley-1;\r
+                                       ob->y = ((long)(ob->tiley)<<TILESHIFT)+TILEGLOBAL/2;\r
+                               break;\r
+\r
+                               case 2:\r
+                                       ob->tilex = ob->tilex+1;\r
+                                       ob->x = ((long)(ob->tilex)<<TILESHIFT)+TILEGLOBAL/2;\r
+                               break;\r
+\r
+                               case 3:\r
+                                       ob->tiley = ob->tiley+1;\r
+                                       ob->y = ((long)(ob->tiley)<<TILESHIFT)+TILEGLOBAL/2;\r
+                               break;\r
+\r
+                               case 0:\r
+                               case 4:\r
+                                       ob->tilex = ob->tilex-1;\r
+                                       ob->x = ((long)(ob->tilex)<<TILESHIFT)+TILEGLOBAL/2;\r
+                               break;\r
+                       }\r
+                       CalcBounds (ob);\r
+                       ChaseThink(ob,false);\r
+                       actorat[ob->tilex][ob->tiley] = ob;\r
+                       return;\r
+               }\r
+       }\r
+\r
+       tempx = player->x;\r
+       tempy = player->y;\r
+       temp_tilex = player->tilex;\r
+       temp_tiley = player->tiley;\r
+\r
+       if (dir_num == 5)\r
+               switch_num = ob->temp2;\r
+       else\r
+               switch_num = dir_num;\r
+\r
+       switch (switch_num)\r
+       {\r
+               case 1:\r
+                       player->x = ((long)ob->tilex<<TILESHIFT)+TILEGLOBAL/2;\r
+                       player->y = ((long)(ob->tiley-2)<<TILESHIFT)+TILEGLOBAL/2;\r
+                       player->tilex = ob->tilex;\r
+                       player->tiley = ob->tiley-2;\r
+               break;\r
+\r
+               case 2:\r
+                       player->x = ((long)(ob->tilex+2)<<TILESHIFT)+TILEGLOBAL/2;\r
+                       player->y = ((long)ob->tiley<<TILESHIFT)+TILEGLOBAL/2;\r
+                       player->tilex = ob->tilex+2;\r
+                       player->tiley = ob->tiley;\r
+               break;\r
+\r
+               case 3:\r
+                       player->x = ((long)ob->tilex<<TILESHIFT)+TILEGLOBAL/2;\r
+                       player->y = ((long)(ob->tiley+2)<<TILESHIFT)+TILEGLOBAL/2;\r
+                       player->tilex = ob->tilex;\r
+                       player->tiley = ob->tiley+2;\r
+               break;\r
+\r
+               case 0:\r
+               case 4:\r
+                       player->x = ((long)(ob->tilex-2)<<TILESHIFT)+TILEGLOBAL/2;\r
+                       player->y = ((long)ob->tiley<<TILESHIFT)+TILEGLOBAL/2;\r
+                       player->tilex = ob->tilex-2;\r
+                       player->tiley = ob->tiley;\r
+               break;\r
+       }\r
+\r
+       Chase(ob, false);\r
+\r
+       player->x = tempx;\r
+       player->y = tempy;\r
+       player->tilex = temp_tilex;\r
+       player->tiley = temp_tiley;\r
+\r
+       if (dir_num != 5)\r
+               ob->temp2 = dir_num;\r
+}\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                                               EGYPTIAN HEAD\r
+\r
+=============================================================================\r
+*/\r
+\r
+void T_Head(objtype *ob);\r
+\r
+statetype s_head = {HEADPIC, 20, &T_Head, &s_head};\r
+\r
+statetype s_head_shot1 = {PSHOT1PIC, 10, &T_ShootPlayer, &s_head_shot2};\r
+statetype s_head_shot2 = {PSHOT2PIC, 10, &T_ShootPlayer, &s_head_shot1};\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= SpawnEgyptianHead\r
+=\r
+===================\r
+*/\r
+\r
+void SpawnEgyptianHead (int tilex, int tiley)\r
+{\r
+       objtype *ob;\r
+       short current_head_delay;\r
+       unsigned tile;\r
+\r
+       SpawnNewObj(tilex, tiley, &s_head, PIXRADIUS*35);\r
+       ob = new;\r
+       head_mode = h_wait_to_rise;\r
+\r
+       tile = *(mapsegs[2]+farmapylookup[tiley+1]+tilex);\r
+       if (tile)\r
+               head_delay = (tile>>8)*30;\r
+       else\r
+       {\r
+               current_head_delay = (3*60)+random(3*60);\r
+               head_delay = head_base_delay+current_head_delay;\r
+               head_base_delay += current_head_delay;\r
+               if (head_base_delay > 8*60)\r
+                       head_base_delay = 0;\r
+       }\r
+\r
+       new->obclass    = realsolidobj;\r
+       new->speed              = 3000;\r
+       new->flags        |= of_shootable;\r
+}\r
+\r
+\r
+\r
+//--------------------------------------------------------------------------\r
+// T_Head()\r
+//--------------------------------------------------------------------------\r
+void T_Head(objtype *ob)\r
+{\r
+       fixed tempx,tempy;\r
+       unsigned temp_tilex,temp_tiley;\r
+       int angle;\r
+\r
+       switch (head_mode)\r
+       {\r
+               case h_wait_to_rise:\r
+                       if (head_delay < 0)\r
+                       {\r
+                               if ((ob->tilex == player->tilex) && (ob->tiley == player->tiley))\r
+                                       break;\r
+                               if (CheckHandAttack(ob))\r
+                                       break;\r
+\r
+                               ob->obclass     = headobj;\r
+                               ob->active      = always;\r
+                               head_mode       = h_active;\r
+                               head_delay      = random(100)+random(60);\r
+                               ob->hitpoints = EasyHitPoints(16);\r
+                       }\r
+                       else\r
+                               head_delay -= tics;\r
+\r
+               break;\r
+\r
+               case h_player1:\r
+               case h_player2:\r
+               case h_player3:\r
+               case h_player4:\r
+               case h_active:\r
+                       Chase (ob,true);\r
+\r
+                       if (!random(2) && (angle != -1))\r
+                               ShootPlayer(ob, hshotobj, 10000, &s_head_shot1);\r
+\r
+                       head_delay -= tics;\r
+                       if (head_delay < 0)\r
+                       {\r
+                               head_mode = random(h_other4)+1;\r
+                               head_delay = random(10*60)+random(50);\r
+                       }\r
+               break;\r
+\r
+               case h_other1:\r
+               case h_other2:\r
+               case h_other3:\r
+               case h_other4:\r
+\r
+                       tempx = player->x;\r
+                       tempy = player->y;\r
+                       temp_tilex = player->tilex;\r
+                       temp_tiley = player->tiley;\r
+\r
+                       player->x = ((long)other_x[head_mode]<<TILESHIFT)+TILEGLOBAL/2;\r
+                       player->y = ((long)other_y[head_mode]<<TILESHIFT)+TILEGLOBAL/2;\r
+                       player->tilex = other_x[head_mode];\r
+                       player->tiley = other_y[head_mode];\r
+\r
+                       if (Chase(ob,true))\r
+                               head_delay = 0;\r
+\r
+                       player->x = tempx;\r
+                       player->y = tempy;\r
+                       player->tilex = temp_tilex;\r
+                       player->tiley = temp_tiley;\r
+\r
+                       head_delay -= tics;\r
+                       if (head_delay <= 0)\r
+                       {\r
+                               head_mode = h_active;\r
+                               head_delay = random(10*60)+random(50);\r
+                       }\r
+               break;\r
+       }\r
+}\r
diff --git a/src/lib/hb/c6_act3.c b/src/lib/hb/c6_act3.c
new file mode 100755 (executable)
index 0000000..3740289
--- /dev/null
@@ -0,0 +1,802 @@
+/* Catacomb Apocalypse Source Code\r
+ * Copyright (C) 1993-2014 Flat Rock Software\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License along\r
+ * with this program; if not, write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+ */\r
+\r
+// C3_PLAY.C\r
+\r
+#include "DEF.H"\r
+#pragma hdrstop\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                GLOBAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+boolean ShootPlayer (objtype *ob, short obclass, short speed, statetype *state);\r
+void T_ShootPlayer(objtype *ob);\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                       DEMON\r
+\r
+=============================================================================\r
+*/\r
+\r
+void T_TrollDemon (objtype *ob);\r
+\r
+statetype s_demonpause = {DEMON1PIC,40,NULL,&s_demon2};\r
+\r
+statetype s_demon1 = {DEMON1PIC,20,&T_TrollDemon,&s_demon2};\r
+statetype s_demon2 = {DEMON2PIC,20,&T_TrollDemon,&s_demon3};\r
+statetype s_demon3 = {DEMON3PIC,20,&T_TrollDemon,&s_demon4};\r
+statetype s_demon4 = {DEMON4PIC,20,&T_TrollDemon,&s_demon1};\r
+\r
+statetype s_demonattack1 = {DEMONATTACK1PIC,20,NULL,&s_demonattack2};\r
+statetype s_demonattack2 = {DEMONATTACK2PIC,20,NULL,&s_demonattack3};\r
+statetype s_demonattack3 = {DEMONATTACK3PIC,30,&T_DoDamage,&s_demonpause};\r
+\r
+statetype s_demonouch = {DEMONOUCHPIC,15,&T_TrollDemon,&s_demon1};\r
+\r
+statetype s_demondie1 = {DEMONDIE1PIC,40,NULL,&s_demondie2};\r
+statetype s_demondie2 = {DEMONDIE2PIC,30,&LargeSound,&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,PIXRADIUS*35);\r
+       new->obclass = demonobj;\r
+       new->speed = 2048;\r
+       new->flags |= of_shootable;\r
+       new->hitpoints = EasyHitPoints(30);\r
+}\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                                               TROLL\r
+\r
+=============================================================================\r
+*/\r
+\r
+statetype s_trollpause = {TROLL1PIC, 30, &T_DoDamage, &s_troll2};\r
+\r
+statetype s_troll1 = {TROLL1PIC, 13, &T_TrollDemon, &s_troll2};\r
+statetype s_troll2 = {TROLL2PIC, 13, &T_TrollDemon, &s_troll3};\r
+statetype s_troll3 = {TROLL3PIC, 13, &T_TrollDemon, &s_troll4};\r
+statetype s_troll4 = {TROLL4PIC, 13, &T_TrollDemon, &s_troll1};\r
+\r
+statetype s_trollattack1 = {TROLLATTACK1PIC, 15, NULL, &s_trollattack2};\r
+statetype s_trollattack2 = {TROLLATTACK2PIC, 20, NULL, &s_trollpause};\r
+\r
+statetype s_trollouch = {TROLLOUCHPIC, 14, &T_TrollDemon, &s_troll1};\r
+\r
+statetype s_trolldie1 = {TROLLDIE1PIC, 18, NULL, &s_trolldie2};\r
+statetype s_trolldie2 = {TROLLDIE2PIC, 15, &LargeSound, &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,35*PIXRADIUS);\r
+       new->speed = 2500;\r
+       new->obclass = trollobj;\r
+       new->flags |= of_shootable;\r
+       new->hitpoints = EasyHitPoints(15);\r
+}\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                                               CYBORG DEMON\r
+\r
+=============================================================================\r
+*/\r
+\r
+void T_Demon (objtype *ob);\r
+\r
+statetype s_cyborg_demon1 = {CYBORG1PIC, 20, T_TrollDemon, &s_cyborg_demon2};\r
+statetype s_cyborg_demon2 = {CYBORG2PIC, 20, T_TrollDemon, &s_cyborg_demon3};\r
+statetype s_cyborg_demon3 = {CYBORG3PIC, 20, T_TrollDemon, &s_cyborg_demon4};\r
+statetype s_cyborg_demon4 = {CYBORG4PIC, 20, T_TrollDemon, &s_cyborg_demon1};\r
+\r
+statetype s_cyborg_demonattack1 = {CYBORGATTACK1PIC, 20, NULL, &s_cyborg_demonattack2};\r
+statetype s_cyborg_demonattack2 = {CYBORGATTACK2PIC, 20, NULL, &s_cyborg_demonattack3};\r
+statetype s_cyborg_demonattack3 = {CYBORGATTACK3PIC, 30, T_DoDamage, &s_cyborg_demon2};\r
+\r
+statetype s_cyborg_demonouch = {CYBORGOUCHPIC, 30, NULL, &s_cyborg_demon1};\r
+\r
+statetype s_cyborg_demondie1 = {CYBORGOUCHPIC, 40, NULL, &s_cyborg_demondie2};\r
+statetype s_cyborg_demondie2 = {CYBORGDIE1PIC, 30, &LargeSound, &s_cyborg_demondie3};\r
+statetype s_cyborg_demondie3 = {CYBORGDIE2PIC, 20, NULL, &s_cyborg_demondie3};\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnCyborgDemon\r
+=\r
+===============\r
+*/\r
+\r
+void SpawnCyborgDemon (int tilex, int tiley)\r
+{\r
+       SpawnNewObj(tilex, tiley, &s_cyborg_demon1, PIXRADIUS*35);\r
+       new->obclass    = cyborgdemonobj;\r
+       new->speed = 2048;\r
+       new->flags |= of_shootable;\r
+       new->hitpoints = EasyHitPoints(30);\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= T_TrollDemon\r
+=\r
+===============\r
+*/\r
+\r
+void T_TrollDemon (objtype *ob)\r
+{\r
+       if (Chase (ob,true) || (random(1000)<RANDOM_ATTACK))\r
+       {\r
+               if (ob->obclass == cyborgdemonobj)\r
+                       ob->state = &s_cyborg_demonattack1;\r
+               else\r
+                       if (ob->obclass == trollobj)\r
+                               ob->state = &s_trollattack1;\r
+                       else\r
+                               ob->state = &s_demonattack1;\r
+               ob->ticcount = ob->state->tictime;\r
+       }\r
+}\r
+\r
+\r
+\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                                               INVISIBLE DUDE!\r
+\r
+=============================================================================\r
+*/\r
+\r
+void T_InvisibleDude (objtype *ob);\r
+\r
+statetype s_invis_fizz1 = {INVIS_FIZZ1PIC, 8, &T_InvisibleDude, &s_invis_fizz2};\r
+statetype s_invis_fizz2 = {INVIS_FIZZ2PIC, 8, &T_InvisibleDude, &s_invis_fizz3};\r
+statetype s_invis_fizz3 = {INVIS_FIZZ3PIC, 8, &T_InvisibleDude, &s_invis_walk};\r
+\r
+statetype s_invis_walk = {0, 25, &T_InvisibleDude, &s_invis_walk};\r
+statetype s_invis_attack = {0, -1, &T_DoDamage, &s_invis_pause};\r
+statetype s_invis_pause = {0, 40, NULL, &s_invis_walk};\r
+\r
+statetype s_invis_flash1 = {INVIS_FIZZ1PIC, 8, &T_InvisibleDude, &s_invis_walk};\r
+statetype s_invis_flash2 = {INVIS_FIZZ2PIC, 8, &T_InvisibleDude, &s_invis_walk};\r
+statetype s_invis_flash3 = {INVIS_FIZZ3PIC, 8, &T_InvisibleDude, &s_invis_walk};\r
+\r
+statetype s_invis_death1 = {INVIS_DEATH1PIC, 40, NULL, &s_invis_death2};\r
+statetype s_invis_death2 = {INVIS_DEATH2PIC, 30, &LargeSound, &s_invis_death3};\r
+statetype s_invis_death3 = {INVIS_DEATH3PIC, 20, NULL, &s_invis_death3};\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnInvisDude\r
+=\r
+===============\r
+*/\r
+void SpawnInvisDude(int tilex, int tiley)\r
+{\r
+       SpawnNewObj(tilex, tiley, &s_invis_walk, PIXRADIUS*20);\r
+       new->obclass    = invisdudeobj;\r
+       new->speed              = 2048;\r
+       new->flags              |= of_shootable;\r
+       new->hitpoints  = EasyHitPoints(20);\r
+       new->temp1              = 0;            // for random flashing of pictures\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= T_InvisibleDude\r
+=\r
+===============\r
+*/\r
+void T_InvisibleDude (objtype *ob)\r
+{\r
+       if (!random(100))\r
+       {\r
+               switch (ob->temp1++)\r
+               {\r
+                       case 0:\r
+                               ob->state = &s_invis_flash1;\r
+                       break;\r
+\r
+                       case 1:\r
+                               ob->state = &s_invis_flash2;\r
+                       break;\r
+\r
+                       case 2:\r
+                               ob->state = &s_invis_flash3;\r
+                               ob->temp1 = 0;\r
+                       break;\r
+               }\r
+               ob->ticcount = ob->state->tictime;\r
+       }\r
+\r
+\r
+       if (Chase (ob,true))\r
+       {\r
+               ob->state = &s_invis_attack;\r
+               ob->ticcount = ob->state->tictime;\r
+       }\r
+\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
+void T_Bounce_Death (objtype *ob);\r
+\r
+statetype s_bounce1 = {PSHOT1PIC, 8, &T_Bounce, &s_bounce2};\r
+statetype s_bounce2 = {PSHOT2PIC, 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
+       new->hitpoints = EasyHitPoints(10);\r
+       new->flags |= of_shootable;\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
+\r
+/*\r
+=============================================================================\r
+\r
+                                                       GRELMINAR\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+void T_Grelminar (objtype *ob);\r
+void T_GrelminarShoot (objtype *ob);\r
+void T_Grelm_DropKey(objtype *ob);\r
+\r
+statetype s_grelpause = {GREL1PIC,50,NULL,&s_grel2};\r
+\r
+statetype s_grel1 = {GREL1PIC,20,T_Grelminar,&s_grel2};\r
+statetype s_grel2 = {GREL2PIC,20,T_Grelminar,&s_grel1};\r
+\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,22,NULL,&s_greldie2};\r
+statetype s_greldie2 = {GRELDIE2PIC,22,NULL,&s_greldie3};\r
+statetype s_greldie3 = {GRELDIE3PIC,22,NULL,&s_greldie4};\r
+statetype s_greldie4 = {GRELDIE4PIC,22,NULL,&s_greldie5};\r
+statetype s_greldie5 = {GRELDIE5PIC,22,NULL,&s_greldie5a};\r
+statetype s_greldie5a = {GRELDIE5PIC,-1,T_Grelm_DropKey,&s_greldie6};\r
+statetype s_greldie6 = {GRELDIE6PIC,0,NULL,&s_greldie6};\r
+\r
+statetype s_gshot1 = {SKULL_SHOTPIC,8,T_ShootPlayer,&s_gshot1};\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnGrelminar\r
+=\r
+===============\r
+*/\r
+\r
+void SpawnGrelminar (int tilex, int tiley)\r
+{\r
+       unsigned Grel_Hard;\r
+       unsigned DropKey;\r
+\r
+       SpawnNewObj(tilex,tiley,&s_grel1,PIXRADIUS*25);\r
+       new->obclass = grelmobj;\r
+       new->speed = 2048;\r
+       new->flags |= of_shootable;\r
+\r
+       //\r
+       // if Grelminar is to drop a key the info-plane byte to the right\r
+       //              should have a 1 in the highbyte, else he will not drop the key.\r
+       //\r
+       DropKey = *(mapsegs[2]+farmapylookup[tiley]+tilex+1);\r
+       if (DropKey)\r
+               new->temp1 = DropKey>>8;\r
+       else\r
+               new->temp1 = 0;\r
+\r
+       //\r
+       // The info-plane byte below Grelminar will determine how powerful\r
+       //              Grelminar is.  If nothing is there, he is the most powerful.\r
+       //                      -- affected are the hit points and the shot damage.\r
+       //      The hit points are controlled here, the shot damage is controlled\r
+       //      within the spawning of the shot.  See ShootPlayer for more info.\r
+       //\r
+       Grel_Hard = *(mapsegs[2]+farmapylookup[tiley+1]+tilex);\r
+       if (Grel_Hard)\r
+       {\r
+               new->temp2 = Grel_Hard>>8;\r
+               new->hitpoints = EasyHitPoints((new->temp2 * 10));\r
+       }\r
+       else\r
+       {\r
+               new->hitpoints = EasyHitPoints(100);\r
+               new->temp2 = 10;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= T_Grelminar\r
+=\r
+===============\r
+*/\r
+\r
+void T_Grelminar (objtype *ob)\r
+{\r
+       Chase (ob,false);\r
+\r
+       if (!random(10))\r
+               if (ShootPlayer(ob,gshotobj,ob->temp2,&s_gshot1))\r
+               {\r
+                       ob->state = &s_grelattack3;\r
+                       ob->ticcount = ob->state->tictime;\r
+               }\r
+       if (CheckHandAttack(ob))\r
+               TakeDamage (ob->temp2*3);\r
+\r
+}\r
+\r
+\r
+//=================================\r
+//\r
+// T_Grelm_DropKey\r
+//\r
+//=================================\r
+void T_Grelm_DropKey(objtype *ob)\r
+{\r
+       if (!(ob->temp1))\r
+       {\r
+               ob->state = NULL;\r
+               return;\r
+       }\r
+\r
+       SpawnBonus(ob->tilex,ob->tiley,B_RKEY);\r
+       SD_PlaySound(GRELM_DEADSND);\r
+       ob->temp1 = false;\r
+}\r
+\r
+\r
+\r
+//--------------------------------------------------------------------------\r
+// ShootPlayer()\r
+//--------------------------------------------------------------------------\r
+boolean ShootPlayer(objtype *ob, short obclass, short speed, statetype *state)\r
+{\r
+       int angle = AngleNearPlayer(ob);\r
+\r
+       if (angle == -1)\r
+               return(false);\r
+\r
+       DSpawnNewObjFrac (ob->x,ob->y,state,PIXRADIUS*14);\r
+       new->obclass = obclass;\r
+       new->active = always;\r
+       new->angle = angle;\r
+\r
+       //\r
+       //      If the shot is Grelminar's, then determine the power of the shot.\r
+       //      The shot speed is hard-wired as 10000.  But the shot power is\r
+       //              determined by speed.  Speed now contains "Grelminar's level of\r
+       //              hardness" and this is multiplied by 3 to get the shot power.\r
+       //\r
+       if (obclass == gshotobj)\r
+       {\r
+               new->speed = 10000;\r
+               new->temp1 = speed*3;\r
+       }\r
+       else\r
+               new->speed = speed;\r
+\r
+\r
+       return(true);\r
+}\r
+\r
+//--------------------------------------------------------------------------\r
+// T_ShootPlayer()\r
+//--------------------------------------------------------------------------\r
+void T_ShootPlayer(objtype *ob)\r
+{\r
+       objtype *check;\r
+       long xmove,ymove,speed;\r
+\r
+       speed = ob->speed*tics;\r
+\r
+       xmove = FixedByFrac(speed,costable[ob->angle]);\r
+       ymove = -FixedByFrac(speed,sintable[ob->angle]);\r
+\r
+       if (ShotClipMove(ob,xmove,ymove))\r
+       {\r
+               ob->state = &s_pshot_exp1;\r
+               ob->ticcount = ob->state->tictime;\r
+               return;\r
+       }\r
+\r
+       ob->tilex = ob->x >> TILESHIFT;\r
+       ob->tiley = ob->y >> TILESHIFT;\r
+\r
+\r
+// check for collision with wall\r
+//\r
+       if (tilemap[ob->tilex][ob->tiley])\r
+       {\r
+//             SD_PlaySound (SHOOTWALLSND);\r
+               ob->state = &s_pshot_exp1;\r
+               ob->ticcount = s_pshot_exp1.tictime;\r
+               return;\r
+       }\r
+\r
+\r
+\r
+// check for collision with player\r
+//\r
+       if ( ob->xl <= player->xh\r
+       && ob->xh >= player->xl\r
+       && ob->yl <= player->yh\r
+       && ob->yh >= player->yl)\r
+       {\r
+               switch (ob->obclass)\r
+               {\r
+                       case wshotobj:                                          // Wizard's shot\r
+                               TakeDamage (7);\r
+                       break;\r
+\r
+                       case hshotobj:                                          // Egyptian Head's shot\r
+                               TakeDamage (5);\r
+                       break;\r
+\r
+                       case bshotobj:                                          // Blob's shot\r
+                               TakeDamage (5);\r
+                       break;\r
+\r
+                       case rshotobj:                                          // Ray's shot\r
+                               TakeDamage (5);\r
+                       break;\r
+\r
+                       case rbshotobj:                                 // RamBone's shot\r
+                               TakeDamage(7);\r
+                       break;\r
+\r
+                       case fmshotobj:                                 // Future Mage's shot\r
+                               TakeDamage(7);\r
+                       break;\r
+\r
+                       case rtshotobj:                                 // RoboTank's shot\r
+                               TakeDamage(15);\r
+                       break;\r
+\r
+                       case syshotobj:                                 // Stompy's shot\r
+                               TakeDamage(7);\r
+                       break;\r
+\r
+                       case bgshotobj:                                 // Bug's shot\r
+                               TakeDamage(7);\r
+                       break;\r
+\r
+                       case eshotobj:                                          // Eye's shot\r
+                               TakeDamage(5);\r
+                       break;\r
+\r
+                       case gshotobj:\r
+                               TakeDamage (ob->temp1);         // the damage of Grelminar's shot -\r
+                       break;                                                          //   see Grelminar's spawning\r
+\r
+               }\r
+               ob->state = NULL;\r
+               return;\r
+       }\r
+\r
+// check for collision with other solid and realsolid objects.\r
+//  Great terminology!! -- solid objects really aren't solid\r
+//                      -- realsolid objects ARE solid\r
+//     if ((actorat[ob->tilex][ob->tiley]) && (actorat[ob->tilex][ob->tiley]->obclass != ob->obclass))\r
+       if (((actorat[ob->tilex][ob->tiley]->obclass == realsolidobj) ||\r
+                (actorat[ob->tilex][ob->tiley]->obclass == solidobj)) &&\r
+                (actorat[ob->tilex][ob->tiley]->flags & of_shootable))\r
+       {\r
+                       ob->state = &s_pshot_exp1;\r
+                       ob->ticcount = s_pshot_exp1.tictime;\r
+                       return;\r
+       }\r
+\r
+\r
+// check for collision with player\r
+//\r
+       for (check = player->next; check; check=check->next)\r
+               if ((ob->flags & of_shootable)\r
+               && ob->xl <= check->xh\r
+               && ob->xh >= check->xl\r
+               && ob->yl <= check->yh\r
+               && ob->yh >= check->yl)\r
+               {\r
+                       switch (ob->obclass)\r
+                       {\r
+// APOCALYPSE\r
+                               case wshotobj:                                          // Wizard's shot\r
+                                       ShootActor (check, 3);\r
+                               break;\r
+\r
+                               case hshotobj:                                          // Egyptian Head's shot\r
+                                       ShootActor (check, 5);\r
+                               break;\r
+\r
+                               case bshotobj:                                          // Blob's shot\r
+                                       ShootActor (check, 2);\r
+                               break;\r
+\r
+                               case rshotobj:                                          // Ray's shot\r
+                                       ShootActor (check, 5);\r
+                               break;\r
+\r
+                               case rbshotobj:                                 // RamBone's shot\r
+                                       ShootActor (check, 5);\r
+                               break;\r
+\r
+                               case fmshotobj:                                 // Future Mage's shot\r
+                                       ShootActor (check, 5);\r
+                               break;\r
+\r
+                               case rtshotobj:                                 // RoboTank's shot\r
+                                       ShootActor (check, 15);\r
+                               break;\r
+\r
+                               case syshotobj:                                 // Stompy's shot\r
+                                       ShootActor (check, 5);\r
+                               break;\r
+\r
+                               case bgshotobj:                                 // Bug's shot\r
+                                       ShootActor (check, 3);\r
+                               break;\r
+\r
+                               case eshotobj:                                          // Eye's shot\r
+                                       ShootActor (check, 2);\r
+                               break;\r
+\r
+                               case gshotobj:\r
+                                       ShootActor (check,25);          //NOLAN--check on me!!!!!!!\r
+                               break;\r
+\r
+                               case pshotobj:\r
+                                       ShootActor (check,25);\r
+                               break;\r
+\r
+                       }\r
+                       ob->state = &s_pshot_exp1;\r
+                       ob->ticcount = s_pshot_exp1.tictime;\r
+                       return;\r
+               }\r
+}\r
+\r
+//-------------------------------------------------------------------------\r
+// AngleNearPlayer()\r
+//-------------------------------------------------------------------------\r
+int AngleNearPlayer(objtype *ob)\r
+{\r
+       int angle=-1;\r
+       int xdiff = ob->tilex-player->tilex;\r
+       int ydiff = ob->tiley-player->tiley;\r
+\r
+       if (ob->tiley == player->tiley)\r
+       {\r
+               if (ob->tilex < player->tilex)\r
+                       angle = 0;\r
+               else\r
+                       angle = 180;\r
+       }\r
+       else\r
+       if (ob->tilex == player->tilex)\r
+       {\r
+               if (ob->tiley < player->tiley)\r
+                       angle = 270;\r
+               else\r
+                       angle = 90;\r
+       }\r
+       else\r
+       if (xdiff == ydiff)\r
+               if (ob->tilex < player->tilex)\r
+               {\r
+                       if (ob->tiley < player->tiley)\r
+                               angle = 315;\r
+                       else\r
+                               angle = 45;\r
+               }\r
+               else\r
+               {\r
+                       if (ob->tiley < player->tiley)\r
+                               angle = 225;\r
+                       else\r
+                               angle = 135;\r
+               }\r
+\r
+       return(angle);\r
+}\r
+\r
+\r
diff --git a/src/lib/hb/c6_act4.c b/src/lib/hb/c6_act4.c
new file mode 100755 (executable)
index 0000000..ced1178
--- /dev/null
@@ -0,0 +1,260 @@
+/* Catacomb Apocalypse Source Code\r
+ * Copyright (C) 1993-2014 Flat Rock Software\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License along\r
+ * with this program; if not, write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+ */\r
+\r
+// C4_PLAY.C\r
+\r
+#include "DEF.H"\r
+#pragma hdrstop\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+//-------------------------------------------------------------------------\r
+//\r
+//                             MISC OBJECTS\r
+//\r
+//-------------------------------------------------------------------------\r
+\r
+\r
+//-------------------------------------------------------------------------\r
+//             COLUMN, SULPHUR GAS HOLE, FIRE POT, FOUNTAIN\r
+//-------------------------------------------------------------------------\r
+\r
+\r
+void SpawnMiscObjects(int tilex, int tiley, int num);\r
+\r
+statetype s_column1 = {COLUMN1PIC, 20, NULL, &s_column1};\r
+statetype s_column2 = {COLUMN2PIC, 20, NULL, &s_column2};\r
+statetype s_column3 = {COLUMN3PIC, 20, NULL, &s_column3};\r
+statetype s_column4 = {COLUMN4PIC, 20, NULL, &s_column4};\r
+statetype s_column5 = {COLUMN5PIC, 20, NULL, &s_column5};\r
+statetype s_ffire_pot = {FFIRE_POTPIC, 20, NULL, &s_ffire_pot};\r
+statetype s_ofire_pot1 = {OFIRE_POT1PIC, 20, NULL, &s_ofire_pot2};\r
+statetype s_ofire_pot2 = {OFIRE_POT2PIC, 20, NULL, &s_ofire_pot1};\r
+statetype s_tomb1 = {TOMB1PIC, 20, NULL, &s_tomb1};\r
+statetype s_tomb2 = {TOMB2PIC, 20, NULL, &s_tomb2};\r
+void SpawnMiscObjects(int tilex, int tiley, int num)\r
+{\r
+       statetype       *objstate;\r
+\r
+       switch (num)\r
+       {\r
+               case 1:\r
+                       objstate = &s_column1;\r
+               break;\r
+\r
+               case 2:\r
+                       objstate = &s_column2;\r
+               break;\r
+\r
+               case 3:\r
+                       objstate = &s_column3;\r
+               break;\r
+\r
+               case 4:\r
+                       objstate = &s_ffire_pot;\r
+               break;\r
+\r
+               case 5:\r
+                       objstate = &s_column4;\r
+               break;\r
+\r
+               case 6:\r
+                       objstate = &s_ofire_pot1;\r
+               break;\r
+\r
+               case 7:\r
+                       objstate = &s_tomb1;\r
+               break;\r
+\r
+               case 8:\r
+                       objstate = &s_tomb2;\r
+               break;\r
+\r
+               case 9:\r
+                       objstate = &s_column5;\r
+               break;\r
+       }\r
+\r
+       SpawnNewObj(tilex, tiley, objstate, PIXRADIUS*10);\r
+       new->obclass = realsolidobj;\r
+       new->flags |= of_shootable;\r
+}\r
+\r
+\r
+\r
+//------------------------------------------------------------------------\r
+//                             FORCE FIELD\r
+//------------------------------------------------------------------------\r
+\r
+void SpawnForceField(int tilex, int tiley);\r
+void T_ForceField(objtype *ob);\r
+void T_ForceFieldRemove(objtype *ob);\r
+\r
+statetype s_force_field_1 = {FORCE_FIELD_1PIC, 10, T_ForceField, &s_force_field_2};\r
+statetype s_force_field_2 = {FORCE_FIELD_2PIC, 10, T_ForceField, &s_force_field_3};\r
+statetype s_force_field_3 = {FORCE_FIELD_3PIC, 10, T_ForceField, &s_force_field_4};\r
+statetype s_force_field_4 = {FORCE_FIELD_4PIC, 10, T_ForceField, &s_force_field_1};\r
+\r
+statetype s_force_field_die = {0,0,T_ForceFieldRemove,&s_force_field_die1};\r
+statetype s_force_field_die1 = {0,0,NULL,NULL};\r
+\r
+void SpawnForceField(int tilex, int tiley)\r
+{\r
+       SpawnNewObj(tilex,tiley,&s_force_field_1,PIXRADIUS*35);\r
+       new->obclass = solidobj;\r
+       new->hitpoints = EasyHitPoints(20);\r
+       new->temp1 = 0;\r
+       new->flags |= of_forcefield;            //sets bit 7 :: makes it nonsolid, but also detectable\r
+                                               //              without adding another object type!\r
+       new->flags |= of_shootable;\r
+}\r
+\r
+void T_ForceField(objtype *ob)\r
+{\r
+       long move,deltax,deltay,size;\r
+\r
+       size = (long)ob->size + player->size;\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)\r
+               if (!new->temp1)\r
+               {\r
+                       TakeDamage (94);\r
+                       new->temp1 = 1;\r
+                       return;\r
+               }\r
+               else\r
+                       return;\r
+       new->temp1 = 0;\r
+}\r
+\r
+void T_ForceFieldRemove(objtype *ob)\r
+{\r
+       actorat[ob->tilex][ob->tiley] = 0;\r
+}\r
+\r
+\r
+\r
+\r
+//-------------------------------------------------------------------------\r
+//\r
+//                                                             INVISIBLE WALL CONTROLLER\r
+//\r
+//-------------------------------------------------------------------------\r
+\r
+void SpawnInvisWallCntroller(int x, int y);\r
+void T_InvisWall(objtype *ob);\r
+\r
+extern statetype s_invis_wall_control;\r
+\r
+statetype s_invis_wall_control = {0, 10, T_InvisWall, &s_invis_wall_control};\r
+\r
+void SpawnInvisWallCntroller(int tilex, int tiley)\r
+{\r
+       SpawnNewObj(tilex,tiley,&s_invis_wall_control,PIXRADIUS*35);\r
+       new->obclass = solidobj;\r
+       new->flags &= ~of_shootable;\r
+       new->temp1 = tilemap[tilex][tiley];             // Number for the wall tile here\r
+                                                                                                               // Used for replacing the wall tile\r
+}\r
+\r
+void T_InvisWall(objtype *ob)\r
+{\r
+       long move,deltax,deltay,size;\r
+\r
+       size = (long)ob->size + player->size;\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) ||\r
+               (ob->tilex == player->tilex) && (ob->tiley == player->tiley))\r
+       {\r
+         // Get rid of the wall tile if you are on it\r
+               tilemap[ob->tilex][ob->tiley] = 0;\r
+       }\r
+       else\r
+       {\r
+         // Replace wall tile\r
+               tilemap[ob->tilex][ob->tiley] = ob->temp1;\r
+       }\r
+}\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     EasyHitPoints\r
+//\r
+//     Checks to see if the player has selected the easy mode for playing.\r
+//     If so then the normal hit points are cut in half.\r
+//     This is when the object is spawned.\r
+//\r
+//     Parms\r
+//             NrmHitPts - the normal hit points\r
+//\r
+//     Returns\r
+//             Half of NrmHitPts\r
+//\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+int EasyHitPoints(int NrmHitPts)\r
+{\r
+       if (EASYMODEON)                         // Wimpy, Wimpy, Wimpy!!!!!\r
+       {\r
+               return(NrmHitPts/4);\r
+       }\r
+       else\r
+               return(NrmHitPts);\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     EasyDoDamage\r
+//\r
+//     Checks to see if the player has selected the easy mode for playing.\r
+//     If so then the normal amount of damage is cut in half.\r
+//     This is called each time a monster does damage.\r
+//\r
+//     Parms\r
+//             Damage - the normal damage taken\r
+//\r
+//     Returns\r
+//             Half of Damage\r
+//\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+int EasyDoDamage(int Damage)\r
+{\r
+       if (EASYMODEON)                         // Wimpy, Wimpy, Wimpy!!!!!\r
+               return(Damage/2);\r
+       else\r
+               return(Damage);\r
+}\r
+\r
diff --git a/src/lib/hb/c6_asm.asm b/src/lib/hb/c6_asm.asm
new file mode 100755 (executable)
index 0000000..004c20a
--- /dev/null
@@ -0,0 +1,248 @@
+; Catacomb Apocalypse Source Code\r
+; Copyright (C) 1993-2014 Flat Rock Software\r
+;\r
+; This program is free software; you can redistribute it and/or modify\r
+; it under the terms of the GNU General Public License as published by\r
+; the Free Software Foundation; either version 2 of the License, or\r
+; (at your option) any later version.\r
+;\r
+; This program is distributed in the hope that it will be useful,\r
+; but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+; GNU General Public License for more details.\r
+;\r
+; You should have received a copy of the GNU General Public License along\r
+; with this program; if not, write to the Free Software Foundation, Inc.,\r
+; 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+\r
+IDEAL\r
+\r
+MODEL  MEDIUM,C\r
+\r
+INCLUDE        "ID_ASM.EQU"\r
+\r
+VIEWWIDTH      =       (40*8)                  ;33\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
+EXTRN ylookup:WORD\r
+EXTRN screenpage:WORD\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
+;\r
+; RadarBlip()\r
+;\r
+; Displays a 'blip' (1 pixel wide X 2 pixel high) on the radar at\r
+; an (X,Y) relative to (RADAR_X,RADAR_Y) (defined below...)\r
+;\r
+;---------------------------------------------------------------------------\r
+\r
+PROC   RadarBlip x:WORD, y:WORD, color:WORD\r
+USES   SI,DI\r
+PUBLIC RadarBlip\r
+\r
+       mov     ax,[screenseg]\r
+\r
+       mov     es,ax\r
+       xor     di,di\r
+\r
+       lea     si,[ylookup]\r
+       add     si,[y]\r
+       add     si,[y]\r
+       add     di,[si]\r
+\r
+       mov     ax,[x]\r
+       shr     ax,1\r
+       shr     ax,1\r
+       shr     ax,1\r
+       add     di,ax\r
+\r
+       mov     ax,[x]\r
+       and     ax,7\r
+       mov     cl,al\r
+       mov     ah,080h\r
+       shr     ah,cl\r
+       cli\r
+       mov     al,GC_BITMASK\r
+       mov     dx,GC_INDEX\r
+       out     dx,ax\r
+       sti\r
+\r
+       mov     ax,[color]\r
+       mov     ah,[es:di]                                              ; read into latches\r
+       mov     [es:di],al                                              ; write latches / color bit\r
+\r
+       ret\r
+\r
+ENDP\r
+\r
+END\r
+\r
diff --git a/src/lib/hb/c6_debug.c b/src/lib/hb/c6_debug.c
new file mode 100755 (executable)
index 0000000..f3ce665
--- /dev/null
@@ -0,0 +1,799 @@
+/* Catacomb Apocalypse Source Code\r
+ * Copyright (C) 1993-2014 Flat Rock Software\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License along\r
+ * with this program; if not, write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+ */\r
+\r
+// C3_DEBUG.C\r
+\r
+#include "DEF.H"\r
+#include "gelib.h"\r
+#pragma hdrstop\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+#define DEBUG_OVERHEAD 0\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
+short colordelay=0;\r
+//boolean autofire=false;\r
+int    maporgx;\r
+int    maporgy;\r
+enum {mapview,tilemapview,actoratview,visview,mapseg2,lastview}        viewtype;\r
+\r
+void ViewMap (void);\r
+\r
+//===========================================================================\r
+\r
+#if 0\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
+#endif\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 DEBUG_KEYS_AVAILABLE\r
+       if (Keyboard[sc_R])\r
+       {\r
+               CenterWindow (12,2);\r
+               if (autofire)\r
+                 US_PrintCentered ("Rapid-Fire OFF");\r
+               else\r
+                 US_PrintCentered ("Rapid-Fire ON");\r
+               VW_UpdateScreen();\r
+               IN_Ack();\r
+               autofire ^= 1;\r
+               return 1;\r
+       }\r
+#endif\r
+\r
+#if DEBUG_KEYS_AVAILABLE\r
+       if (Keyboard[sc_A])\r
+       {\r
+               char levelstr[50];\r
+               unsigned org_tile,org_mapon,msgnum;\r
+               boolean newmsg=true,newlevel=false;\r
+\r
+               VW_FixRefreshBuffer ();\r
+               CenterWindow (16,3);\r
+               US_Print("\n");\r
+               US_CPrint("Message Test");\r
+               VW_UpdateScreen();\r
+\r
+               org_mapon = mapon;\r
+               msgnum = (org_tile = *(mapsegs[0]+farmapylookup[player->tiley]+player->tilex))-NAMESTART;\r
+               while (1)\r
+               {\r
+       // Get outta' here\r
+       //\r
+                       if (Keyboard[sc_Escape])\r
+                       {\r
+                               while (Keyboard[sc_Escape]);\r
+                               break;\r
+                       }\r
+\r
+       // Move to previous message\r
+       //\r
+                       if (Keyboard[sc_UpArrow])\r
+                       {\r
+                               if (msgnum)\r
+                               {\r
+                                       msgnum--;\r
+                                       newmsg = true;\r
+                               }\r
+                       }\r
+\r
+       // Move to next message\r
+       //\r
+                       if (Keyboard[sc_DownArrow])\r
+                       {\r
+                               if (msgnum < 24)\r
+                               {\r
+                                       msgnum++;\r
+                                       newmsg = true;\r
+                               }\r
+                       }\r
+\r
+       // Move to previous level\r
+       //\r
+                       if (Keyboard[sc_LeftArrow])\r
+                       {\r
+                               if (mapon)\r
+                               {\r
+                                       MM_SetPurge(&grsegs[LEVEL1TEXT+mapon],3);\r
+                                       mapon--;\r
+                                       newlevel = true;\r
+                               }\r
+                       }\r
+\r
+       // Move to next level\r
+       //\r
+                       if (Keyboard[sc_RightArrow])\r
+                       {\r
+                               if (mapon < LASTMAP-1)\r
+                               {\r
+                                       MM_SetPurge(&grsegs[LEVEL1TEXT+mapon],3);\r
+                                       mapon++;\r
+                                       newlevel = true;\r
+                               }\r
+                       }\r
+\r
+       // Load new level text\r
+       //\r
+                       if (newlevel)\r
+                       {\r
+                               CA_CacheGrChunk(LEVEL1TEXT+mapon);\r
+                               ScanText();\r
+                               newmsg = true;\r
+                               newlevel=false;\r
+                       }\r
+\r
+       // Display new message text\r
+       //\r
+                       if (newmsg)\r
+                       {\r
+                               *(mapsegs[0]+farmapylookup[player->tiley]+player->tilex) = msgnum+NAMESTART;\r
+                               DrawText(true);\r
+                               strcpy(levelstr,"Level: ");\r
+                               itoa(mapon,levelstr+strlen(levelstr),10);\r
+                               strcat(levelstr,"  Msg: ");\r
+                               itoa(msgnum,levelstr+strlen(levelstr),10);\r
+                               DisplaySMsg(levelstr,NULL);\r
+                               newmsg = false;\r
+\r
+                               if (Keyboard[sc_UpArrow] || Keyboard[sc_DownArrow] || Keyboard[sc_LeftArrow] || Keyboard[sc_RightArrow])\r
+                                       VW_WaitVBL(6);\r
+                       }\r
+\r
+               }\r
+// Restore game\r
+//\r
+               MM_SetPurge(&grsegs[LEVEL1TEXT+mapon],3);\r
+               mapon = org_mapon;\r
+               CA_CacheGrChunk(LEVEL1TEXT+mapon);\r
+               ScanText();\r
+               *(mapsegs[0]+farmapylookup[player->tiley]+player->tilex) = org_tile;\r
+               DrawText(true);\r
+               status_flag = 0;\r
+       }\r
+\r
+\r
+       if (Keyboard[sc_V])\r
+       {\r
+               displayofs = bufferofs = screenloc[screenpage];\r
+               CenterWindow (16,4);\r
+               US_CPrint("\n"GAMENAME);\r
+               US_CPrint(VERSION);\r
+               US_CPrint(REVISION);\r
+               VW_UpdateScreen();\r
+               IN_Ack ();\r
+       }\r
+\r
+#endif\r
+       if (Keyboard[sc_Q])                     // Q = Insta-Quit!\r
+               Quit("Insta-Quit!");\r
+#if 0\r
+       if (Keyboard[sc_Z])             // Z = freeze Time\r
+       {\r
+               if (FreezeTime)\r
+                 FreezeTime = 1;               // Allow refresh to dec to zero..\r
+               else\r
+                       StopTime();\r
+\r
+               IN_Ack();\r
+               return 1;\r
+       }\r
+#endif\r
+\r
+\r
+//     if (Keyboard[sc_E])\r
+//             FaceDoor((player->x>>16l)+1,(player->y>>16l));\r
+//             FaceAngle(90);\r
+\r
+#if 0\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
+#endif\r
+\r
+\r
+#if 1//DEBUG_KEYS_AVAILABLE\r
+       if (Keyboard[sc_O])\r
+       {\r
+               extern unsigned objectcount,latchmemavail;\r
+               unsigned unused,total;\r
+\r
+               CenterWindow (30,13);\r
+               US_Print ("Objects: ");\r
+               US_PrintUnsigned (objectcount);\r
+\r
+               US_Print("\n\nTics: ");\r
+               US_PrintUnsigned (tics);\r
+               US_Print("      Real Tics: ");\r
+               US_PrintUnsigned(realtics);\r
+\r
+               US_Print ("\n\n    Total Available: ");\r
+               US_PrintUnsigned (mminfo.mainmem/1024);\r
+               US_Print ("k\n        Mem In Use: ");\r
+               unused=MM_UnusedMemory()/1024;\r
+               US_PrintUnsigned (unused);\r
+               US_Print ("k\n Mem After Purge: ");\r
+               total=MM_TotalFree()/1024;\r
+               US_PrintUnsigned (total);\r
+               US_Print ("k (");\r
+               US_PrintUnsigned (total-unused);\r
+\r
+               US_Print (")\n\nLatch Mem Free: ");\r
+               US_PrintUnsigned (latchmemavail);\r
+               US_Print ("\n");\r
+               VW_UpdateScreen();\r
+               IN_Ack();\r
+       }\r
+\r
+       if (colordelay<1)\r
+       {\r
+               if (Keyboard[26])\r
+               {\r
+                       extern unsigned *groundcolor,debug_gnd;\r
+\r
+                       groundcolor = &debug_gnd;\r
+                       debug_gnd += 0x0101;\r
+                       if (debug_gnd == 0x1010)\r
+                               debug_gnd = 0;\r
+                       colordelay = 10;\r
+               }\r
+\r
+               if (Keyboard[27])\r
+               {\r
+                       extern unsigned *skycolor,debug_sky;\r
+\r
+                       skycolor = &debug_sky;\r
+                       debug_sky += 0x0101;\r
+                       if (debug_sky == 0x1010)\r
+                               debug_sky = 0;\r
+                       colordelay = 10;\r
+               }\r
+       }\r
+       else\r
+               colordelay -= realtics;\r
+#endif\r
+\r
+\r
+#if 0\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
+#endif\r
+\r
+#if 0\r
+       if (Keyboard[sc_E])             // E = quit level\r
+       {\r
+               if (tedlevel)\r
+                       TEDDeath();\r
+               playstate = ex_warped;\r
+               gamestate.mapon++;\r
+       }\r
+#endif\r
+\r
+#if 0\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
+#endif\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
+\r
+#if 0\r
+       if (Keyboard[sc_H])             // H = hurt self\r
+       {\r
+               TakeDamage (5);\r
+       }\r
+#endif\r
+\r
+       if (Keyboard[sc_I])                     // I = item cheat\r
+       {\r
+               extern boolean redraw_gems;\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
+                       gamestate.gems[i] = GEM_DELAY_TIME;\r
+               }\r
+               gamestate.gems[4] = GEM_DELAY_TIME;\r
+               redraw_gems = true;\r
+/////////              for (i=0;i<8;i++)\r
+/////////                      GiveScroll (i,false);\r
+\r
+               IN_Ack ();\r
+               return 1;\r
+       }\r
+\r
+#if DEBUG_OVERHEAD\r
+       if (Keyboard[sc_Z])                     // O is used elsewhere...\r
+       {\r
+               ViewMap();\r
+               return 1;\r
+       }\r
+#endif\r
+\r
+#if 0\r
+       if (Keyboard[sc_P])                     // P = pause with no screen disruptioon\r
+       {\r
+               PicturePause ();\r
+               return 1;\r
+       }\r
+#endif\r
+\r
+#if 0\r
+       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
+#endif\r
+\r
+#if 0\r
+       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
+#endif\r
+\r
+       if (Keyboard[sc_W])     // W = warp to level\r
+       {\r
+               CenterWindow(26,3);\r
+               PrintY+=6;\r
+               US_Print("  Warp to which level(0-17):");\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<=LASTMAP-1)\r
+                       {\r
+                               gamestate.mapon = level;\r
+                               playstate = ex_warped;\r
+                               lasttext = -1;\r
+                       }\r
+               }\r
+               return 1;\r
+       }\r
+\r
+#if 0\r
+       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
+#endif\r
+\r
+////////       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
+#if DEBUG_OVERHEAD\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
+#endif\r
+\r
+\r
+#if DEBUG_OVERHEAD\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
+#endif\r
+\r
+\r
+#if DEBUG_OVERHEAD\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
+                       case mapseg2:\r
+                               tile = *(mapsegs[2]+farmapylookup[y]+x);\r
+                               if (tile < 256)\r
+                                       tile = *(mapsegs[0]+farmapylookup[y]+x);\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,&control);\r
+               if (control.xaxis == -1 && maporgx>0)\r
+                       maporgx--;\r
+               if (control.xaxis == 1 && maporgx<mapwidth-VIEWTILEX)\r
+                       maporgx++;\r
+               if (control.yaxis == -1 && maporgy>0)\r
+                       maporgy--;\r
+               if (control.yaxis == 1 && maporgy<mapheight-VIEWTILEY)\r
+                       maporgy++;\r
+\r
+               if (control.button0 && !button0held)\r
+               {\r
+                       button0held = true;\r
+                       viewtype++;\r
+                       if (viewtype==lastview)\r
+                               viewtype = mapview;\r
+               }\r
+               if (!control.button0)\r
+                       button0held = false;\r
+\r
+\r
+               OverheadRefresh ();\r
+\r
+       } while (!Keyboard[sc_Escape]);\r
+\r
+       IN_ClearKeysDown ();\r
+       DrawPlayScreen ();\r
+}\r
+#endif\r
+\r
diff --git a/src/lib/hb/c6_draw.c b/src/lib/hb/c6_draw.c
new file mode 100755 (executable)
index 0000000..9d261a0
--- /dev/null
@@ -0,0 +1,1970 @@
+/* Catacomb Apocalypse Source Code\r
+ * Copyright (C) 1993-2014 Flat Rock Software\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License along\r
+ * with this program; if not, write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+ */\r
+\r
+// C3_DRAW.C\r
+\r
+#include "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]= {PAGE1START,PAGE2START,PAGE3START};\r
+unsigned freelatch = FREESTART;\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
+#if 0\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
+#endif\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
+char wall_anim_pos[NUMFLOORS];\r
+\r
+// EAST / WEST WALLS\r
+//\r
+int     far walllight1[NUMFLOORS] = {0,\r
+\r
+       0,//CRYSTAL1LIGHTPIC,\r
+       0,//EGYPT1LIGHTPIC,\r
+       EGYPT2LIGHTPIC,\r
+       EGYPT3LIGHTPIC,\r
+\r
+       FIREWALL1PIC,\r
+       FIREWALL2PIC,\r
+       FIREWALL3PIC,\r
+       FIREWALL4PIC,\r
+\r
+\r
+       NEMESISPIC,\r
+\r
+       ALTARLEFTPIC,\r
+       ALTARRIGHTPIC,\r
+\r
+       TEMPLEWALLLIGHTPIC,\r
+\r
+       TORCHWALL1PIC,\r
+       TORCHWALL2PIC,\r
+\r
+       BRNBRKLIGHTPIC,\r
+       BRNBRKEMLIGHTPIC,\r
+\r
+       IRONGATEPIC,\r
+\r
+       BRNFLGLIGHTPIC,\r
+       BRNFLGWINDOWLIGHTPIC,\r
+       BRNFLGVINELIGHTPIC,\r
+       BRNFLGDMGLIGHTPIC,\r
+\r
+       SPACEDMG1LIGHTPIC,\r
+       SPACEDMG2LIGHTPIC,\r
+\r
+       SPACE1LIGHTPIC,\r
+       SPACE2LIGHTPIC,\r
+       SPACE3LIGHTPIC,\r
+       SPACE4LIGHTPIC,\r
+\r
+       SPACE5LIGHTPIC,\r
+       SPACE6LIGHTPIC,\r
+       SPACE7LIGHTPIC,\r
+       SPACE8LIGHTPIC,\r
+\r
+       0,//SPACE9LIGHTPIC,\r
+       0,//SPACEDMG9LIGHTPIC,\r
+       SPACE10LIGHTPIC,\r
+       RUSTDOORLIGHTPIC,\r
+\r
+       SPACE11LIGHTPIC,\r
+       SPACE12LIGHTPIC,\r
+       SPACE13LIGHTPIC,\r
+       SPACE14LIGHTPIC,\r
+\r
+       SPACEDMG5LIGHTPIC,\r
+       SPACEDMG6LIGHTPIC,\r
+\r
+       TAP1PIC,\r
+       TAP2PIC,\r
+       ENDPIC,\r
+       0,//SIRONLIGHTPIC,\r
+\r
+       SPCDOOR1LIGHTPIC,\r
+       SPCDOOR2LIGHTPIC,\r
+       SPCDOOR3LIGHTPIC,\r
+       SPCDOOR4LIGHTPIC,\r
+\r
+       COLUMNSLIGHTPIC,\r
+\r
+       DEMONSTATUELIGHTPIC,\r
+\r
+       0,//CRYSTALBWALL1LIGHTPIC,\r
+\r
+       0,//SRUSTLIGHTPIC,\r
+\r
+       TROLLSTATUELIGHTPIC,\r
+\r
+       BRNDMGVINELIGHTPIC,\r
+       TAP3PIC,\r
+       HORNDOORPIC,\r
+       RUNEDOORPIC,\r
+\r
+       EXP_WALL_1PIC,\r
+       EXP_WALL_2PIC,\r
+       EXP_WALL_3PIC,\r
+       WATER_EXP_WALL_1PIC,\r
+       WATER_EXP_WALL_2PIC,\r
+       WATER_EXP_WALL_3PIC,\r
+\r
+       IRONDMGLIGHTPIC,\r
+       IRONLIGHTPIC,\r
+       0,\r
+       TROLLBLOODYLIGHTPIC,\r
+       TROLLLIGHTPIC,\r
+\r
+       0,                                                                                              // INVISIBLE WALL\r
+\r
+       STONEDOORLIGHTPIC,\r
+       0,\r
+\r
+       IRONWTR1LIGHTPIC,\r
+       IRONWTR2LIGHTPIC,\r
+       IRONWTR3LIGHTPIC,\r
+\r
+       RUSTWTR1LIGHTPIC,\r
+       RUSTWTR2LIGHTPIC,\r
+       RUSTWTR3LIGHTPIC,\r
+\r
+       CEMETARYLIGHTPIC,\r
+       0,      //      STAIRDWNLIGHTPIC,\r
+\r
+       WGRATE1LIGHTPIC,\r
+       WGRATE2LIGHTPIC,\r
+       WGRATE3LIGHTPIC,\r
+\r
+       MAS_WIN_LIGHTPIC,\r
+       MAS_DOOR_LIGHTPIC,\r
+       MAS_VINE1_LIGHTPIC,\r
+       MAS_VINE2_LIGHTPIC,\r
+\r
+  // Start of non-solid walls\r
+       0,\r
+       0,\r
+       0,\r
+       0,\r
+       0,\r
+       0,\r
+\r
+  // solid walls\r
+       SGRATEPIC,\r
+};\r
+\r
+// NORTH / SOUTH WALLS\r
+//\r
+int     far walldark1[NUMFLOORS] = {0,\r
+\r
+       0,//CRYSTAL1DARKPIC,\r
+       0,//EGYPT1DARKPIC,\r
+       EGYPT2DARKPIC,\r
+       EGYPT3DARKPIC,\r
+\r
+       FIREWALL1PIC,\r
+       FIREWALL2PIC,\r
+       FIREWALL3PIC,\r
+       FIREWALL4PIC,\r
+\r
+       NEMESISPIC,\r
+\r
+       ALTARLEFTPIC,\r
+       ALTARRIGHTPIC,\r
+\r
+       TEMPLEWALLDARKPIC,\r
+\r
+       TORCHWALL1PIC,\r
+       TORCHWALL2PIC,\r
+\r
+       BRNBRKDARKPIC,\r
+       BRNBRKEMDARKPIC,\r
+\r
+       IRONGATEPIC,\r
+\r
+       BRNFLGDARKPIC,\r
+       BRNFLGWINDOWDARKPIC,\r
+       BRNFLGVINEDARKPIC,\r
+       BRNFLGDMGDARKPIC,\r
+\r
+       SPACEDMG1DARKPIC,\r
+       SPACEDMG2DARKPIC,\r
+\r
+       SPACE1DARKPIC,\r
+       SPACE2DARKPIC,\r
+       SPACE3DARKPIC,\r
+       SPACE4DARKPIC,\r
+\r
+       SPACE5DARKPIC,\r
+       SPACE6DARKPIC,\r
+       SPACE7DARKPIC,\r
+       SPACE8DARKPIC,\r
+\r
+       0,//SPACE9DARKPIC,\r
+       0,//SPACEDMG9DARKPIC,\r
+       SPACE10DARKPIC,\r
+       RUSTDOORDARKPIC,\r
+\r
+       SPACE11DARKPIC,\r
+       SPACE12DARKPIC,\r
+       SPACE13DARKPIC,\r
+       SPACE14DARKPIC,\r
+\r
+       SPACEDMG5DARKPIC,\r
+       SPACEDMG6DARKPIC,\r
+\r
+       TAP1PIC,\r
+       TAP2PIC,\r
+       ENDPIC,\r
+       0,//SIRONDARKPIC,\r
+\r
+       SPCDOOR1DARKPIC,\r
+       SPCDOOR2DARKPIC,\r
+       SPCDOOR3DARKPIC,\r
+       SPCDOOR4DARKPIC,\r
+\r
+       COLUMNSDARKPIC,\r
+\r
+       DEMONSTATUEDARKPIC,\r
+\r
+       0,//CRYSTALBWALL1DARKPIC,\r
+\r
+       0,//SRUSTDARKPIC,\r
+\r
+       TROLLSTATUEDARKPIC,\r
+\r
+       BRNDMGVINEDARKPIC,\r
+       TAP3PIC,\r
+       HORNDOORPIC,\r
+       RUNEDOORPIC,\r
+\r
+       EXP_WALL_1PIC,\r
+       EXP_WALL_2PIC,\r
+       EXP_WALL_3PIC,\r
+\r
+       WATER_EXP_WALL_1PIC,\r
+       WATER_EXP_WALL_2PIC,\r
+       WATER_EXP_WALL_3PIC,\r
+\r
+       IRONDMGDARKPIC,\r
+       IRONDARKPIC,\r
+       0,\r
+       TROLLBLOODYDARKPIC,\r
+\r
+       TROLLDARKPIC,\r
+\r
+       0,                                                                                      // INVISIBLE WALL\r
+\r
+       STONEDOORDARKPIC,\r
+       0,\r
+\r
+       IRONWTR1DARKPIC,\r
+       IRONWTR2DARKPIC,\r
+       IRONWTR3DARKPIC,\r
+\r
+       RUSTWTR1DARKPIC,\r
+       RUSTWTR2DARKPIC,\r
+       RUSTWTR3DARKPIC,\r
+\r
+       CEMETARYDARKPIC,\r
+       0,\r
+\r
+       WGRATE1DARKPIC,\r
+       WGRATE2DARKPIC,\r
+       WGRATE3DARKPIC,\r
+\r
+       MAS_WIN_DARKPIC,\r
+       MAS_DOOR_DARKPIC,\r
+       MAS_VINE1_DARKPIC,\r
+       MAS_VINE2_DARKPIC,\r
+\r
+  // Start of non-solid walls\r
+       0,\r
+       0,\r
+       0,\r
+       0,\r
+       0,\r
+       0,\r
+\r
+  // solid walls\r
+       SGRATEPIC,\r
+};\r
+\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
+       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
+\r
+               wallpic = walllight1[wallptr->color+wall_anim_pos[wallptr->color]];\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
+\r
+               wallpic = walldark1[wallptr->color+wall_anim_pos[wallptr->color]];\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
+#if 0\r
+/*\r
+=========================\r
+=\r
+= FixedAdd\r
+=\r
+= add two 16 bit fixed point numbers\r
+= to subtract, invert the sign of B before invoking\r
+=\r
+=========================\r
+*/\r
+\r
+fixed FixedAdd (fixed a, fixed b)\r
+{\r
+  fixed value;\r
+\r
+asm     mov     ax,[WORD PTR a]\r
+asm     mov     dx,[WORD PTR a+2]\r
+\r
+asm     mov     bx,[WORD PTR b]\r
+asm     mov     cx,[WORD PTR b+2]\r
+\r
+asm     or      dx,dx\r
+asm     jns     aok:            // negative?\r
+asm     and     dx,0x7fff\r
+asm     not     ax              // convert a from signed magnitude to 2's compl\r
+asm     not     dx\r
+asm     add     ax,1\r
+asm     adc     dx,0\r
+aok:\r
+\r
+asm     or      cx,cx\r
+asm     jns     bok:            // negative?\r
+asm     and     cx,0x7fff\r
+asm     not     bx              // convert b from signed magnitude to 2's compl\r
+asm     not     cx\r
+asm     add     bx,1\r
+asm     adc     cx,0\r
+bok:\r
+\r
+asm     add     ax,bx           // perform the addition\r
+asm     adc     dx,cx\r
+asm     jns     done\r
+\r
+asm     and     dx,0x7fff       // value was negative\r
+asm     not     ax              // back to signed magnitude\r
+asm     not     dx\r
+asm     add     ax,1\r
+asm     adc     dx,0\r
+\r
+done:\r
+\r
+asm     mov     [WORD PTR value],ax\r
+asm     mov     [WORD PTR value+2],dx\r
+\r
+  return value;\r
+}\r
+#endif\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
+       unsigned topcolor=*skycolor, bottomcolor=*groundcolor;\r
+       unsigned topimage=topcolor&0xf0,bottomimage=bottomcolor&0xf0;\r
+       unsigned pfoffset=0;\r
+\r
+\r
+#if USE_STRIPS\r
+       if (topimage == 0x20)           // special code for lightning\r
+               topimage = topcolor = 0;\r
+\r
+// Manually wipe screen with solid color.\r
+// If BOTH sky and ground are 'images' don't manually clear it!\r
+//\r
+       if ((!topimage) || (!bottomimage))\r
+       {\r
+#endif\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                                    // dx = modulo\r
+asm     mov     bl,VIEWWIDTH/16\r
+asm     mov     bh,CENTERY+1\r
+\r
+asm     mov     ax,topcolor\r
+asm     mov     es,[screenseg]\r
+asm     mov     di,[bufferofs]\r
+asm     add     di,((SCREENWIDTH*VIEWY)+(VIEWX/8))\r
+\r
+toploop:\r
+asm     mov     cl,bl\r
+asm     rep     stosw\r
+asm     stosb\r
+//asm     add     di,dx                                        // no need to add "0" modulo\r
+asm     dec     bh\r
+asm     jnz     toploop\r
+\r
+asm     mov     bh,CENTERY+1\r
+asm     mov     ax,bottomcolor\r
+\r
+bottomloop:\r
+asm     mov     cl,bl\r
+asm     rep     stosw\r
+asm     stosb\r
+//asm     add     di,dx                                        // no need to add "0" modulo\r
+asm     dec     bh\r
+asm     jnz     bottomloop\r
+\r
+#if USE_STRIPS\r
+       }\r
+\r
+\r
+//\r
+// code to test parallax turning\r
+//\r
+\r
+       if (topimage)\r
+       {\r
+               topimage -= 16;\r
+               pfoffset = LONG_PERCENTAGE(3200,359,(359-player->angle),12);\r
+               while (pfoffset >= 640)\r
+                       pfoffset -= 640;\r
+               LatchDrawPicStrip(0,0,SKY1PIC+topimage,pfoffset+8);\r
+       }\r
+\r
+       if (bottomimage)\r
+       {\r
+////           pfoffset = LONG_PERCENTAGE(3200,359,(359-player->angle),12)+320;\r
+//             pfoffset += 320;\r
+//             while (pfoffset >= 640)\r
+//                     pfoffset -= 640;\r
+//             LatchDrawPicStrip(0,64,SKY1PIC+topimage,pfoffset+8);\r
+               bottomimage -= 16;\r
+               LatchDrawPic(0,64,GND1PIC+bottomimage);\r
+       }\r
+#endif\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
+#if USE_INERT_LIST\r
+               extern inertobjtype inertobjlist[], *inert;\r
+\r
+               boolean inertlist=false;\r
+#endif\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
+       obj = player->next;\r
+       while (obj)\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
+#if USE_INERT_LIST\r
+                       if (!inertlist)\r
+#endif\r
+                               if ((obj->active == noalways) || (obj->active == always))\r
+                                       obj->active = always;\r
+                               else\r
+                                       obj->active = yes;\r
+                       TransformActor (obj);\r
+                       if (!obj->viewheight || obj->viewheight > VIEWWIDTH)\r
+                               goto cont;                       // too close or far away\r
+\r
+                       if (!obj->state->shapenum)\r
+                               goto cont;\r
+\r
+                       *vislist++ = obj;\r
+                       numvisable++;\r
+               }\r
+               else\r
+#if USE_INERT_LIST\r
+                       if (!inertlist)\r
+#endif\r
+                               if ((obj->active != always) && (obj->active != noalways))\r
+                                       obj->active = no;\r
+\r
+cont:;\r
+               obj = obj->next;\r
+#if USE_INERT_LIST\r
+               if ((!obj) && (!inertlist))\r
+               {\r
+                       if (inert != inertobjlist)\r
+                               obj = (objtype *)inertobjlist;\r
+                       inertlist = true;\r
+               }\r
+#endif\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 0\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
+               realtics = tics = DEMOTICS;\r
+       }\r
+       else\r
+#endif\r
+       {\r
+//\r
+// non demo, so report actual time\r
+//\r
+               newtime = TimeCount;\r
+               realtics = 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
+               if (realtics>MAXREALTICS)\r
+                       realtics = MAXREALTICS;\r
+       }\r
+}\r
+\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+========================\r
+=\r
+= DrawHand\r
+=\r
+========================\r
+*/\r
+\r
+void    DrawHand (void)\r
+{\r
+       #define HAND_X_POS      ((VIEWWIDTH/16)-(10/2))         // "10" = hand width in bytes\r
+\r
+       #define picnum HAND1PICM\r
+\r
+       memptr source;\r
+       unsigned dest,width,height;\r
+\r
+//      if (gamestate.shotpower || boltsleft)\r
+//              picnum += (((unsigned)TimeCount>>3)&1);\r
+\r
+       source = grsegs[picnum];\r
+       dest = ylookup[VIEWHEIGHT-handheight]+HAND_X_POS+bufferofs;                     // 12\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
+       AnimateWallList();\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/src/lib/hb/c6_game.c b/src/lib/hb/c6_game.c
new file mode 100755 (executable)
index 0000000..d31a047
--- /dev/null
@@ -0,0 +1,1599 @@
+/* Catacomb Apocalypse Source Code\r
+ * Copyright (C) 1993-2014 Flat Rock Software\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License along\r
+ * with this program; if not, write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+ */\r
+\r
+// C3_GAME.C\r
+\r
+#include <stdlib.h>\r
+\r
+#include "DEF.H"\r
+#include "gelib.h"\r
+#pragma hdrstop\r
+\r
+#ifdef PROFILE\r
+#include "TIME.H"\r
+#endif\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+#define NUMLUMPS                               45\r
+\r
+#define EYESTALKLUMP                   0\r
+#define BLOBLUMP                               1\r
+#define BOLTLUMP                               2\r
+#define NUKELUMP                               3\r
+#define POTIONLUMP                     4\r
+#define RKEYLUMP                               5\r
+#define YKEYLUMP                               6\r
+#define GKEYLUMP                               7\r
+#define BKEYLUMP                               8\r
+#define RGEMLUMP                               9\r
+#define GGEMLUMP                               10\r
+#define BGEMLUMP                               11\r
+#define YGEMLUMP                               12\r
+#define PGEMLUMP                               13\r
+#define CHESTLUMP                              14\r
+#define PLAYERLUMP                     15\r
+#define FTIMELUMP                              16\r
+#define PORTALLUMP                     17\r
+#define COLUMN1LUMP                    18\r
+#define FIREPOTLUMP                    19\r
+#define COLUMN2LUMP                    20\r
+#define EYELUMP                                21\r
+#define FUTUREMAGELUMP         22\r
+#define FORCEFIELDLUMP         23\r
+#define ROBOTANKLUMP                   24\r
+#define RAMBONELUMP                    25\r
+#define STOMPYLUMP                     26\r
+#define TROLLLUMP                              27\r
+#define WIZARDLUMP                     28\r
+#define HEADLUMP                               29\r
+#define INVISDUDELUMP          30\r
+#define BUGLUMP                                31\r
+#define CYBORGLUMP                     32\r
+#define WATERCHESTLUMP         33\r
+#define GRELLUMP                               34\r
+#define RAYLUMP                                35\r
+#define COLUMN3LUMP                    36\r
+#define OLDCHESTLUMP                   37\r
+#define OLDFIREPOTLUMP         38\r
+#define COLUMN4LUMP                    39\r
+#define TOMB1LUMP                              40\r
+#define TOMB2LUMP                              41\r
+#define DEMONLUMP                              42\r
+#define COLUMN5LUMP                    43\r
+\r
+int     lumpstart[NUMLUMPS] = {\r
+EYESTALK_LUMP_START,\r
+BLOB_LUMP_START,\r
+BOLT_LUMP_START,\r
+NUKE_LUMP_START,\r
+POTION_LUMP_START,\r
+RKEY_LUMP_START,\r
+YKEY_LUMP_START,\r
+GKEY_LUMP_START,\r
+BKEY_LUMP_START,\r
+RGEM_LUMP_START,\r
+GGEM_LUMP_START,\r
+BGEM_LUMP_START,\r
+YGEM_LUMP_START,\r
+PGEM_LUMP_START,\r
+CHEST_LUMP_START,\r
+PLAYER_LUMP_START,\r
+TIME_LUMP_START,\r
+PORTAL_LUMP_START,\r
+COLUMN1_LUMP_START,\r
+FFIREPOT_LUMP_START,\r
+COLUMN2_LUMP_START,\r
+EYE_LUMP_START,\r
+FUTUREMAGE_LUMP_START,\r
+FORCEFIELD_LUMP_START,\r
+ROBOTANK_LUMP_START,\r
+RAMBONE_LUMP_START,\r
+STOMPY_LUMP_START,\r
+TROLL_LUMP_START,\r
+WIZARD_LUMP_START,\r
+HEAD_LUMP_START,\r
+INVISDUDE_LUMP_START,\r
+BUG_LUMP_START,\r
+CYBORG_LUMP_START,\r
+O_WATER_CHEST_LUMP_START,\r
+GREL_LUMP_START,\r
+RAY_LUMP_START,\r
+COLUMN3_LUMP_START,\r
+OLD_CHEST_LUMP_START,\r
+OFIREPOT_LUMP_START,\r
+COLUMN4_LUMP_START,\r
+TOMB1_LUMP_START,\r
+TOMB2_LUMP_START,\r
+DEMON_LUMP_START,\r
+COLUMN5_LUMP_START,\r
+};\r
+\r
+\r
+int     lumpend[NUMLUMPS] = {\r
+EYESTALK_LUMP_END,\r
+BLOB_LUMP_END,\r
+BOLT_LUMP_END,\r
+NUKE_LUMP_END,\r
+POTION_LUMP_END,\r
+RKEY_LUMP_END,\r
+YKEY_LUMP_END,\r
+GKEY_LUMP_END,\r
+BKEY_LUMP_END,\r
+RGEM_LUMP_END,\r
+GGEM_LUMP_END,\r
+BGEM_LUMP_END,\r
+YGEM_LUMP_END,\r
+PGEM_LUMP_END,\r
+CHEST_LUMP_END,\r
+PLAYER_LUMP_END,\r
+TIME_LUMP_END,\r
+PORTAL_LUMP_END,\r
+COLUMN1_LUMP_END,\r
+FFIREPOT_LUMP_END,\r
+COLUMN2_LUMP_END,\r
+EYE_LUMP_END,\r
+FUTUREMAGE_LUMP_END,\r
+FORCEFIELD_LUMP_END,\r
+ROBOTANK_LUMP_END,\r
+RAMBONE_LUMP_END,\r
+STOMPY_LUMP_END,\r
+TROLL_LUMP_END,\r
+WIZARD_LUMP_END,\r
+HEAD_LUMP_END,\r
+INVISDUDE_LUMP_END,\r
+BUG_LUMP_END,\r
+CYBORG_LUMP_END,\r
+O_WATER_CHEST_LUMP_END,\r
+GREL_LUMP_END,\r
+RAY_LUMP_END,\r
+COLUMN3_LUMP_END,\r
+OLD_CHEST_LUMP_END,\r
+OFIREPOT_LUMP_END,\r
+COLUMN4_LUMP_END,\r
+TOMB1_LUMP_END,\r
+TOMB2_LUMP_END,\r
+DEMON_LUMP_END,\r
+COLUMN5_LUMP_END,\r
+};\r
+\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                GLOBAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+unsigned        latchpics[NUMLATCHPICS];\r
+unsigned        tileoffsets[NUMTILE16];\r
+unsigned        textstarts[27];\r
+\r
+boolean splitscreen=false;\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+boolean lumpneeded[NUMLUMPS];\r
+\r
+\r
+//===========================================================================\r
+\r
+\r
+\r
+/*\r
+==========================\r
+=\r
+= ScanInfoPlane\r
+=\r
+= Spawn all actors and mark down special places\r
+=\r
+==========================\r
+*/\r
+\r
+void ScanInfoPlane (void)\r
+{\r
+       unsigned char hibyte;\r
+       unsigned        x,y,i,j;\r
+       unsigned int tile;\r
+       unsigned        far     *start;\r
+\r
+       InitObjList();                  // start spawning things with a clean slate\r
+\r
+       scolor = gcolor = 0;\r
+       skycolor = &scolor;\r
+       groundcolor = &gcolor;\r
+\r
+\r
+       memset (lumpneeded,0,sizeof(lumpneeded));\r
+\r
+       start = mapsegs[2];\r
+       for (y=0;y<mapheight;y++)\r
+               for (x=0;x<mapwidth;x++)\r
+               {\r
+                       tile = *start++;\r
+                       hibyte = tile >> 8;\r
+                       tile &= 0xff;\r
+\r
+                       switch (hibyte)\r
+                       {\r
+                               char hi;\r
+\r
+                               case 0xFB:\r
+                                       wall_anim_time = tile;\r
+                                       tile = 0;\r
+                                       break;\r
+\r
+                               case 0xfa:                                                              // sky/ground color\r
+                                       x++;\r
+                                       tile = *start++;\r
+                                       hi = tile >> 8;\r
+                                       tile &= 0xff;\r
+                                       switch (hibyte)\r
+                                       {\r
+                                               case 0xfa:                      // sky / ground color\r
+                                                       scolor = ((hi)|(hi<<8));\r
+                                                       gcolor = ((tile)|(tile<<8));\r
+                                                       skycolor = &scolor;\r
+                                                       groundcolor = &gcolor;\r
+                                               break;\r
+\r
+                                       }\r
+                               break;\r
+                       }\r
+\r
+                       if ((!tile) || (hibyte))\r
+                               continue;\r
+\r
+                       switch (tile)\r
+                       {\r
+                       case 1:\r
+                       case 2:\r
+                       case 3:\r
+                       case 4:\r
+                               lumpneeded[PLAYERLUMP] = true;\r
+                               SpawnPlayer(x,y,NORTH+tile-1);\r
+                       break;\r
+\r
+                       case 5:\r
+                       case 6:\r
+                       case 7:\r
+                       case 8:\r
+                       case 9:\r
+                       case 10:\r
+                       case 11:\r
+                               lumpneeded[tile-5+BOLTLUMP] = true;\r
+                               SpawnBonus(x,y,tile-5);\r
+                       break;\r
+\r
+                       case 12:\r
+                               lumpneeded[EYESTALKLUMP] = true;\r
+                               SpawnAquaMan(x, y);\r
+                       break;\r
+\r
+\r
+                       case 13:\r
+                               lumpneeded[BLOBLUMP] = true;\r
+                               SpawnBlob(x, y);\r
+                       break;\r
+\r
+\r
+                       case 14:\r
+                               lumpneeded[BUGLUMP] = true;\r
+                               SpawnBug(x, y);\r
+                       break;\r
+\r
+                       case 15:\r
+                               lumpneeded[CYBORGLUMP] = true;\r
+                               SpawnCyborgDemon(x, y);\r
+                       break;\r
+\r
+                       case 16:\r
+                               lumpneeded[EYELUMP] = true;\r
+                               SpawnShooterEye(x, y);\r
+                       break;\r
+\r
+                       case 17:\r
+                               lumpneeded[FUTUREMAGELUMP] = true;\r
+                               SpawnFutureMage(x, y);\r
+                       break;\r
+\r
+                       case 18:\r
+                               lumpneeded[INVISDUDELUMP] = true;\r
+                               SpawnInvisDude(x, y);\r
+                       break;\r
+\r
+                       case 19:\r
+                               lumpneeded[ROBOTANKLUMP] = true;\r
+                               SpawnRoboTank(x, y);\r
+                       break;\r
+\r
+                       case 20:\r
+                               lumpneeded[RAMBONELUMP] = true;\r
+                               SpawnRamBone(x, y);\r
+                       break;\r
+\r
+                       case 21:\r
+                               lumpneeded[STOMPYLUMP] = true;\r
+                               SpawnStompy(x, y);\r
+                       break;\r
+\r
+                       case 22:\r
+                               lumpneeded[TROLLLUMP] = true;\r
+                               SpawnTroll(x, y);\r
+                       break;\r
+\r
+                       case 23:\r
+                               lumpneeded[WIZARDLUMP] = true;\r
+                               SpawnWizard(x, y);\r
+                       break;\r
+\r
+                       case 24:\r
+                               SpawnBounce(x, y, 0);\r
+                       break;\r
+\r
+                       case 25:\r
+                               SpawnBounce(x, y, 1);\r
+                       break;\r
+\r
+                       case 26:\r
+                               lumpneeded[RKEYLUMP] = lumpneeded[GRELLUMP] = true;\r
+                               SpawnGrelminar (x,y);\r
+                       break;\r
+\r
+                       case 27:\r
+                               lumpneeded[EYELUMP] = true;\r
+                               SpawnRunningEye(x,y);\r
+                       break;\r
+\r
+                       case 28:\r
+                               lumpneeded[RAYLUMP] = true;\r
+                               SpawnRay(x, y);\r
+                       break;\r
+\r
+                       case 29:\r
+                               lumpneeded[HEADLUMP] = true;\r
+                               SpawnEgyptianHead(x, y);\r
+                       break;\r
+\r
+                       case 30:\r
+                               lumpneeded[DEMONLUMP] = true;\r
+                               SpawnDemon(x, y);\r
+                       break;\r
+\r
+                       case 31:\r
+                               lumpneeded[COLUMN5LUMP] = true;\r
+                               SpawnMiscObjects(x, y, 9);\r
+                       break;\r
+\r
+                       case 32:\r
+                               SpawnInvisWallCntroller(x, y);\r
+                       break;\r
+\r
+                       case 33:\r
+                       break;\r
+\r
+                       case 34:\r
+                       break;\r
+\r
+                       case 35:\r
+                       break;\r
+\r
+                       case 36:\r
+                               lumpneeded[COLUMN1LUMP] = true;\r
+                               SpawnMiscObjects(x, y, 1);\r
+                       break;\r
+\r
+                       case 37:\r
+                               lumpneeded[FIREPOTLUMP] = true;\r
+                               SpawnMiscObjects(x, y, 4);\r
+                       break;\r
+\r
+                       case 38:\r
+                               lumpneeded[PORTALLUMP] = true;\r
+                               SpawnWarp(x, y);\r
+                       break;\r
+\r
+                       case 39:\r
+                               lumpneeded[FTIMELUMP] = true;\r
+                               SpawnFTime(x,y);\r
+                       break;\r
+\r
+\r
+                       case 40:\r
+                       case 41:\r
+                       case 42:\r
+                       case 43:\r
+                       case 44:\r
+                               lumpneeded[tile-40+RGEMLUMP] = true;\r
+                               SpawnBonus(x,y,tile-40+B_RGEM);\r
+                       break;\r
+\r
+                       case 45:\r
+                               lumpneeded[COLUMN2LUMP] = true;\r
+                               SpawnMiscObjects(x, y, 2);\r
+                       break;\r
+\r
+                       case 46:\r
+                               lumpneeded[COLUMN3LUMP] = true;\r
+                               SpawnMiscObjects(x, y, 3);\r
+                       break;\r
+\r
+                       case 47:\r
+                               lumpneeded[FORCEFIELDLUMP] = true;\r
+                               SpawnForceField(x, y);\r
+                       break;\r
+\r
+                       case 48:\r
+                               lumpneeded[OLDCHESTLUMP] = true;\r
+                               SpawnBonus(x, y, B_OLDCHEST);\r
+                       break;\r
+\r
+                       case 49:        // chest\r
+                               if (gcolor == 0x0101)\r
+                                       lumpneeded[WATERCHESTLUMP] = true;\r
+                               else\r
+                                       lumpneeded[CHESTLUMP] = true;\r
+                               SpawnBonus(x,y,B_CHEST);\r
+                       break;\r
+\r
+                       case 50:\r
+                               lumpneeded[COLUMN4LUMP] = true;\r
+                               SpawnMiscObjects(x, y, 5);\r
+                       break;\r
+\r
+                       case 51:\r
+                               lumpneeded[OLDFIREPOTLUMP] = true;\r
+                               SpawnMiscObjects(x, y, 6);\r
+                       break;\r
+\r
+                       case 52:\r
+                               lumpneeded[TOMB1LUMP] = true;\r
+                               SpawnMiscObjects(x, y, 7);\r
+                       break;\r
+\r
+                       case 53:\r
+                               lumpneeded[TOMB2LUMP] = true;\r
+                               SpawnMiscObjects(x, y, 8);\r
+                       break;\r
+\r
+                       case 54:\r
+                       break;\r
+\r
+                       case 55:\r
+                       break;\r
+\r
+                       case 56:\r
+                       break;\r
+\r
+                       case 57:\r
+                       break;\r
+\r
+                       case 58:\r
+                       break;\r
+\r
+                       case 59:\r
+                       break;\r
+\r
+                       case 60:\r
+                       break;\r
+\r
+                       case 61:\r
+                       break;\r
+\r
+                       case 62:\r
+                       break;\r
+\r
+                       case 63:\r
+                       break;\r
+\r
+                       case 64:\r
+                       break;\r
+\r
+                       case 65:\r
+                       break;\r
+\r
+                       case 66:\r
+                       break;\r
+\r
+                       case 67:\r
+                       break;\r
+\r
+                       case 68:\r
+                       break;\r
+\r
+                       case 69:\r
+                       break;\r
+\r
+                       case 70:\r
+                       break;\r
+\r
+                       case 71:\r
+                       break;\r
+\r
+                       }\r
+               }\r
+\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+==================\r
+=\r
+= ScanText\r
+=\r
+==================\r
+*/\r
+\r
+void ScanText (void)\r
+{\r
+       int     i;\r
+       char far *text;\r
+\r
+       text = (char _seg *)grsegs[LEVEL1TEXT+mapon];\r
+\r
+       textstarts[0] = 0;\r
+\r
+       for (i=1;i<=26;i++)\r
+       {\r
+               while (*text != '\n')\r
+               {\r
+                       if (*text == '\r')\r
+                               *text = 0;\r
+                       text++;\r
+               }\r
+               text++;\r
+               textstarts[i] = FP_OFF(text);\r
+       }\r
+\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+==================\r
+=\r
+= DrawEnterScreen\r
+=\r
+==================\r
+*/\r
+#if 0\r
+static  char    *levelnames[] =\r
+                               {\r
+                                       "Programmers Test Map",\r
+                                       "The Garden of Tears",\r
+                                       "The Den of Zombies",\r
+                                       "The Mausoleum Grounds",\r
+                                       "The Main Floor of the Mausoleum",\r
+                                       "Mike's Blastable Passage",\r
+                                       "The Crypt of Nemesis the Undead",\r
+                                       "The Subterranean Vault",\r
+                                       "The Ancient Aqueduct",\r
+                                       "The Orc Mines",\r
+                                       "The Lair of the Troll",\r
+                                       "The Demon's Inferno",\r
+                                       "The Battleground of the Titans",\r
+                                       "The Coven of Mages",\r
+                                       "The Inner Sanctum",\r
+                                       "The Haunt of Nemesis",\r
+                                       "The Passage to the Surface",\r
+                                       "Big Jim's Domain",\r
+                                       "Nolan",\r
+                                       "19",\r
+                                       "20",\r
+                                       "21",\r
+                                       "22",\r
+                                       "23",\r
+                                       "24",\r
+                                       "25",\r
+                                       "26",\r
+                                       "27",\r
+                                       "28",\r
+                                       "29",\r
+                                       "30",\r
+                                       "31",\r
+                                       "32",\r
+                                       "33",\r
+                                       "34",\r
+                                       "35",\r
+                                       "36",\r
+                                       "37",\r
+                                       "38",\r
+                                       "39",\r
+                               };\r
+#endif\r
+\r
+void DrawEnterScreen ()\r
+{\r
+       int width;\r
+\r
+       bufferofs = displayofs = screenloc[screenpage];\r
+       VW_Bar(0,0,VIEWWIDTH,VIEWHEIGHT,0);\r
+\r
+//     width = strlen(levelnames[gamestate.mapon]);\r
+       width = strlen("A new challenge awaits you.");\r
+       if (width < 20)\r
+               width = 20;\r
+       CenterWindow(width,3);\r
+       US_CPrint("\nA new challenge awaits you.\n");\r
+//     US_CPrint(levelnames[gamestate.mapon]);\r
+}\r
+\r
+//==========================================================================\r
+\r
+boolean tileneeded[NUMFLOORS];\r
+\r
+\r
+/*\r
+==================\r
+=\r
+= CacheScaleds\r
+=\r
+==================\r
+*/\r
+\r
+void CacheScaleds (void)\r
+{\r
+       int     i,j;\r
+       unsigned        source,dest;\r
+\r
+       FreeUpMemory ();\r
+       CA_CacheGrChunk(LEVEL1TEXT+mapon);\r
+       ScanText ();\r
+\r
+//\r
+// make sure we are displaying screenpage 0\r
+//\r
+       if (screenpage)\r
+       {\r
+               source = screenloc[screenpage];\r
+               dest = screenloc[0];\r
+               VW_ScreenToScreen (source,dest,40,VIEWHEIGHT);\r
+               screenpage = 0;\r
+               VW_SetScreen (dest,0);\r
+               displayofs = dest;\r
+       }\r
+\r
+//\r
+// cache wall pictures\r
+//\r
+       for (i=1;i<NUMFLOORS;i++)\r
+               if (tileneeded[i])\r
+               {\r
+                       SetupScaleWall (walllight1[i]);\r
+                       SetupScaleWall (walldark1[i]);\r
+               }\r
+\r
+//\r
+// cache the actor pictures\r
+//\r
+       for (i=0;i<NUMLUMPS;i++)\r
+               if (lumpneeded[i])\r
+                       for (j=lumpstart[i];j<=lumpend[i];j++)\r
+                               SetupScalePic(j);\r
+\r
+       source = screenloc[0];\r
+       for (i=1;i<=2;i++)\r
+       {\r
+               dest = screenloc[i];\r
+               VW_ScreenToScreen (source,dest,40,VIEWHEIGHT);\r
+       }\r
+\r
+       screenpage = 1;\r
+}\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+==================\r
+=\r
+= SetupGameLevel\r
+=\r
+==================\r
+*/\r
+\r
+void SetupGameLevel ()\r
+{\r
+       int     x,y,i,loop;\r
+       unsigned        far *map,tile,far *spotptr,spot;\r
+       unsigned                search_tile;\r
+       boolean         exploding_walls_present = false;\r
+\r
+       memset (tileneeded,0,sizeof(tileneeded));\r
+//\r
+// randomize if not a demo\r
+//\r
+#if 0\r
+       if (DemoMode)\r
+       {\r
+               US_InitRndT(false);\r
+               gamestate.difficulty = gd_Normal;\r
+       }\r
+       else\r
+#endif\r
+               US_InitRndT(true);\r
+\r
+//\r
+// load the level\r
+//\r
+       CA_CacheMap (gamestate.mapon);\r
+\r
+       mapwidth = mapheaderseg[mapon]->width;\r
+       mapheight = mapheaderseg[mapon]->height;\r
+\r
+//\r
+// make a lookup table for the maps left edge\r
+//\r
+       spot = 0;\r
+       for (y=0;y<mapheight;y++)\r
+       {\r
+         farmapylookup[y] = spot;\r
+         spot += mapwidth;\r
+       }\r
+\r
+\r
+//\r
+// copy the wall data to a data segment array\r
+//\r
+       memset (tilemap,0,sizeof(tilemap));\r
+       memset (actorat,0,sizeof(actorat));\r
+       map = mapsegs[0];\r
+       spotptr = mapsegs[2];\r
+       for (y=0;y<mapheight;y++)\r
+               for (x=0;x<mapwidth;x++)\r
+               {\r
+                       tile = *map++;\r
+\r
+                       if (((*spotptr)>>8) == EXP_WALL_CODE)\r
+                       {\r
+                               exploding_walls_present = true;\r
+                       }\r
+\r
+                       if (tile<NUMFLOORS)\r
+                       {\r
+#if 0\r
+                               if (tile == WALL_SKELETON_CODE)\r
+                               {\r
+                                       tileneeded[tile+1] = tileneeded[tile+2] = true;\r
+                                       tilemap[x][y] = tile;\r
+                               }\r
+#endif\r
+                               if ((tile == 66) || (tile == 67) || (tile == 68) || (tile == 69))\r
+                               {\r
+                                       if ((tile == 66) || (tile == 67))\r
+                                               tileneeded[tile+2] = true;\r
+                                       tileneeded[21] = tileneeded[tile] = true;\r
+                                       tilemap[x][y] = tile;\r
+                               }\r
+                               else\r
+                               if (tile != INVISIBLEWALL)\r
+                               {\r
+                                       tileneeded[tile] = true;\r
+                                       tilemap[x][y] = tile;\r
+                                       if (ANIM_FLAGS(tile))\r
+                                       {\r
+                                               search_tile = tile+(char signed)ANIM_FLAGS(tile);\r
+\r
+                                               if (!tileneeded[search_tile])\r
+                                                       while (search_tile != tile)\r
+                                                       {\r
+                                                               tileneeded[search_tile] = true;\r
+                                                               if (ANIM_FLAGS(search_tile))\r
+                                                                       search_tile += (char signed)ANIM_FLAGS(search_tile);\r
+                                                               else\r
+                                                                       TrashProg("Unending Tile Animation!");\r
+                                                       }\r
+                                       }\r
+\r
+                               }\r
+                               if (tile>0)\r
+                                       (unsigned)actorat[x][y] = tile;\r
+                       }\r
+                       spotptr++;\r
+               }\r
+\r
+\r
+       //\r
+       // Mark any gfx chunks needed\r
+       //\r
+\r
+//      CA_MarkGrChunk(NORTHICONSPR);\r
+//      CA_CacheMarks(NULL);\r
+\r
+\r
+//\r
+// decide which graphics are needed and spawn actors\r
+//\r
+       head_base_delay = 0;  // (1*60) + random(1*60);\r
+       ScanInfoPlane ();\r
+       _fmemset(wall_anim_pos,0,sizeof(wall_anim_pos));\r
+\r
+\r
+//\r
+// mark which exploding walls are needed ---- the check for floor color\r
+// is preformed in ScanInfoPlane.\r
+//\r
+\r
+       if (exploding_walls_present)\r
+       {\r
+                               extern unsigned gnd_colors[];\r
+\r
+                               if (gcolor == 0x0101)\r
+                                       tileneeded[WATEREXP] = tileneeded[WATEREXP+1] = tileneeded[WATEREXP+2] = true;\r
+                               else\r
+                                       tileneeded[WALLEXP] = tileneeded[WALLEXP+1] = tileneeded[WALLEXP+2] = true;\r
+\r
+       }\r
+\r
+\r
+//\r
+// have the caching manager load and purge stuff to make sure all marks\r
+// are in memory\r
+//\r
+       CA_LoadAllSounds ();\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+=====================\r
+=\r
+= LatchDrawPic\r
+=\r
+=====================\r
+*/\r
+\r
+void LatchDrawPic (unsigned x, unsigned y, unsigned picnum)\r
+{\r
+       unsigned height, source, dest;\r
+       unsigned wide;\r
+\r
+       wide = pictable[picnum-STARTPICS].width;\r
+       height = pictable[picnum-STARTPICS].height;\r
+       dest = bufferofs + ylookup[y]+x;\r
+       source = latchpics[picnum-FIRSTLATCHPIC];\r
+\r
+       EGAWRITEMODE(1);\r
+       EGAMAPMASK(15);\r
+\r
+asm     mov     bx,[linewidth]\r
+asm     sub     bx,[wide]\r
+\r
+asm     mov     ax,[screenseg]\r
+asm     mov     es,ax\r
+asm     mov     ds,ax\r
+\r
+asm     mov     si,[source]\r
+asm     mov     di,[dest]\r
+asm     mov     dx,[height]                             // scan lines to draw\r
+asm     mov     ax,[wide]\r
+\r
+lineloop:\r
+asm     mov     cx,ax\r
+asm     rep     movsb\r
+asm     add     di,bx\r
+\r
+asm     dec     dx\r
+asm     jnz     lineloop\r
+\r
+asm     mov     ax,ss\r
+asm     mov     ds,ax                                   // restore turbo's data segment\r
+\r
+       EGAWRITEMODE(0);\r
+}\r
+\r
+#if USE_STRIPS\r
+\r
+//--------------------------------------------------------------------------\r
+// LatchDrawPicStrip() - srcoff is distance into source file (in PIXELS!)\r
+//--------------------------------------------------------------------------\r
+void LatchDrawPicStrip (unsigned x, unsigned y, unsigned picnum, unsigned srcoff)\r
+{\r
+       unsigned wide, height, source, dest, shift, srcmod;\r
+\r
+       shift = (srcoff & 7) >> 1;\r
+       srcoff >>= 3;\r
+       wide = pictable[picnum-STARTPICS].width;\r
+       srcmod = wide - linewidth + (shift != 3);\r
+       if (wide > linewidth)\r
+               wide = linewidth;\r
+       height = pictable[picnum-STARTPICS].height;\r
+       dest = bufferofs + ylookup[y]+x;\r
+\r
+       picnum = ((picnum - (FIRSTSTRIPPIC+1)) >> 2) + (shift);\r
+       source = latchpics[(FIRSTSTRIPPIC-FIRSTLATCHPIC+1)+picnum];\r
+\r
+       EGAWRITEMODE(1);\r
+       EGAMAPMASK(15);\r
+\r
+asm     mov     bx,[linewidth]\r
+asm     sub     bx,[wide]\r
+\r
+asm     mov     ax,[screenseg]\r
+asm     mov     es,ax\r
+asm     mov     ds,ax\r
+\r
+asm     mov     si,[source]\r
+asm      add            si,[srcoff]\r
+asm     mov     di,[dest]\r
+asm     mov     dx,[height]                             // scan lines to draw\r
+asm     mov     ax,[wide]\r
+\r
+lineloop:\r
+asm     mov     cx,ax\r
+asm     rep     movsb\r
+asm     add     di,bx\r
+asm      add     si,[srcmod]\r
+\r
+asm     dec     dx\r
+asm     jnz     lineloop\r
+\r
+asm     mov     ax,ss\r
+asm     mov     ds,ax                                   // restore turbo's data segment\r
+\r
+       EGAWRITEMODE(0);\r
+}\r
+\r
+#endif\r
+\r
+\r
+//==========================================================================\r
+\r
+/*\r
+=====================\r
+=\r
+= Victory\r
+=\r
+=====================\r
+*/\r
+\r
+void Victory (boolean playsounds)\r
+{\r
+       struct Shape shape;\r
+\r
+       if (playsounds)\r
+       {\r
+               SD_PlaySound (GETBOLTSND);\r
+               SD_WaitSoundDone ();\r
+               SD_PlaySound (GETNUKESND);\r
+               SD_WaitSoundDone ();\r
+               SD_PlaySound (GETPOTIONSND);\r
+               SD_WaitSoundDone ();\r
+               SD_PlaySound (GETKEYSND);\r
+               SD_WaitSoundDone ();\r
+//             SD_PlaySound (GETSCROLLSND);\r
+//             SD_WaitSoundDone ();\r
+               SD_PlaySound (GETPOINTSSND);\r
+       }\r
+\r
+       FreeUpMemory();\r
+\r
+       if (!screenfaded)\r
+               VW_FadeOut();\r
+\r
+       NormalScreen ();\r
+\r
+       screenpage = bufferofs = 0;\r
+\r
+       CA_CacheGrChunk (FINALEPIC);\r
+       UNMARKGRCHUNK(FINALEPIC);\r
+       VW_DrawPic(0, 0, FINALEPIC);\r
+\r
+       VW_FadeIn();\r
+\r
+}\r
+\r
+//==========================================================================\r
+\r
+#if 0\r
+/*\r
+===================\r
+=\r
+= Died\r
+=\r
+===================\r
+*/\r
+\r
+void Died (void)\r
+{\r
+       unsigned page1,page2;\r
+//\r
+// fizzle fade screen to grey\r
+//\r
+       FreeUpMemory ();\r
+       SD_PlaySound (GAMEOVERSND);\r
+       bufferofs = screenloc[(screenpage+1)%3];\r
+       DisplayMsg("Though fallen, your Spirit ...",NULL);\r
+//      LatchDrawPic(0,0,DEADPIC);\r
+//      FizzleFade(bufferofs,displayofs,VIEWWIDTH,VIEWHEIGHT,false);\r
+       IN_ClearKeysDown();\r
+       while (!Keyboard[sc_Enter]);\r
+//      IN_Ack();\r
+       VW_SetScreen (bufferofs,0);\r
+       VW_ColorBorder(0);\r
+}\r
+#endif\r
+\r
+//==========================================================================\r
+\r
+/*\r
+===================\r
+=\r
+= NormalScreen\r
+=\r
+===================\r
+*/\r
+\r
+void NormalScreen (void)\r
+{\r
+        VW_SetSplitScreen (200);\r
+        bufferofs = displayofs = SCREEN1START;\r
+        VW_Bar(0,0,320,200,0);\r
+        bufferofs = SCREEN2START;\r
+        VW_Bar(0,0,320,200,0);\r
+        VW_SetScreen (displayofs,0);\r
+        splitscreen = false;\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+===================\r
+=\r
+= DrawPlayScreen\r
+=\r
+===================\r
+*/\r
+\r
+void DrawPlayScreen (void)\r
+{\r
+       int     i,j,p,m;\r
+\r
+       screenpage = 0;\r
+\r
+       bufferofs = 0;\r
+       VW_Bar (0,0,320,STATUSLINES,0);\r
+       for (i=0;i<3;i++)\r
+       {\r
+               bufferofs = screenloc[i];\r
+               VW_Bar (0,0,320,VIEWHEIGHT,0);\r
+       }\r
+\r
+       splitscreen = true;\r
+       VW_SetSplitScreen(120);\r
+       VW_SetScreen(screenloc[0],0);\r
+\r
+       CA_CacheGrChunk (STATUSPIC);\r
+\r
+       bufferofs = 0;\r
+       VW_DrawPic (0,0,STATUSPIC);\r
+\r
+       grneeded[STATUSPIC] &= ~ca_levelbit;\r
+       MM_SetPurge(&grsegs[STATUSPIC],3);\r
+\r
+//     RedrawStatusWindow ();\r
+       bufferofs = displayofs = screenloc[0];\r
+}\r
+\r
+\r
+//==========================================================================\r
+\r
+/*\r
+===================\r
+=\r
+= LoadLatchMem\r
+=\r
+===================\r
+*/\r
+\r
+unsigned latchmemavail;\r
+\r
+void LoadLatchMem (void)\r
+{\r
+       static unsigned base_destoff=0;\r
+       static int base_numpics=0;\r
+       int     i,j,p,m,numpics;\r
+       byte    far *src, far *dest;\r
+       unsigned        destoff;\r
+\r
+       EGAWRITEMODE(0);\r
+\r
+//\r
+// draw some pics into latch memory\r
+//\r
+\r
+  if (!base_numpics)\r
+  {\r
+\r
+//\r
+// tile 8s\r
+//\r
+       latchpics[0] = freelatch;\r
+       src = (byte _seg *)grsegs[STARTTILE8];\r
+       dest = MK_FP(0xa000,freelatch);\r
+\r
+       for (i=0;i<NUMTILE8;i++)\r
+       {\r
+               for (p=0;p<4;p++)\r
+               {\r
+                       m = 1<<p;\r
+                       asm     mov     dx,SC_INDEX\r
+                       asm     mov     al,SC_MAPMASK\r
+                       asm     mov     ah,[BYTE PTR m]\r
+                       asm     out     dx,ax\r
+                       for (j=0;j<8;j++)\r
+                               *(dest+j)=*src++;\r
+               }\r
+               dest+=8;\r
+       }\r
+\r
+//\r
+// tile 16s\r
+//\r
+       src = (byte _seg *)grsegs[STARTTILE16];\r
+\r
+       for (i=0;i<NUMTILE16;i++)\r
+       {\r
+               CA_CacheGrChunk (STARTTILE16+i);\r
+               src = (byte _seg *)grsegs[STARTTILE16+i];\r
+               if (src)\r
+               {\r
+                       tileoffsets[i] = FP_OFF(dest);\r
+                       for (p=0;p<4;p++)\r
+                       {\r
+                               m = 1<<p;\r
+                               asm     mov     dx,SC_INDEX\r
+                               asm     mov     al,SC_MAPMASK\r
+                               asm     mov     ah,[BYTE PTR m]\r
+                               asm     out     dx,ax\r
+                               for (j=0;j<32;j++)\r
+                                       *(dest+j)=*src++;\r
+                       }\r
+                       dest+=32;\r
+                       MM_FreePtr (&grsegs[STARTTILE16+i]);\r
+                       UNMARKGRCHUNK(STARTTILE16+i);\r
+               }\r
+               else\r
+                       tileoffsets[i] = 0;\r
+       }\r
+\r
+\r
+//\r
+// pics\r
+//\r
+       numpics=1;\r
+       destoff = FP_OFF(dest);\r
+       for (i=FIRSTLATCHPIC+1;i<FIRSTGROUNDPIC;i++)\r
+       {\r
+               latchpics[numpics++] = destoff;\r
+               CA_CacheGrChunk (i);\r
+               j = pictable[i-STARTPICS].width * pictable[i-STARTPICS].height;\r
+               VW_MemToScreen (grsegs[i],destoff,j,1);\r
+               destoff+=j;\r
+               MM_FreePtr (&grsegs[i]);\r
+               UNMARKGRCHUNK(i);\r
+       }\r
+\r
+       base_numpics = numpics;\r
+       base_destoff = destoff;\r
+\r
+  }\r
+\r
+       numpics = base_numpics;\r
+       destoff = base_destoff;\r
+\r
+#if USE_STRIPS\r
+//\r
+// ground pics\r
+//\r
+       numpics++;\r
+       for (i=FIRSTGROUNDPIC+1;i<FIRSTSTRIPPIC;i++)\r
+       {\r
+               int shape = (*groundcolor & 0xf0) - 16;\r
+\r
+       // Is current shape needed?\r
+       //\r
+               if (shape != (i-(FIRSTGROUNDPIC+1)))\r
+               {\r
+                       numpics++;\r
+                       continue;\r
+               }\r
+\r
+               latchpics[numpics++] = destoff;\r
+               CA_CacheGrChunk (i);\r
+               j = pictable[i-STARTPICS].width * pictable[i-STARTPICS].height;\r
+               VW_MemToScreen (grsegs[i],destoff,j,1);\r
+               destoff+=j;\r
+               MM_FreePtr (&grsegs[i]);\r
+               UNMARKGRCHUNK(i);\r
+       }\r
+\r
+\r
+//\r
+// 'parallax' strips - used in place of a sky color\r
+//\r
+// Under current setup, each strip takes about 7k in latch memory.\r
+// To create 2 pixel scrolling, 4 strips are needed, that's 28k of\r
+// latch memory needed to produce this effect.\r
+//\r
+       numpics++;\r
+       for (i=FIRSTSTRIPPIC+1;i<FIRSTSCALEPIC;i++)\r
+       {\r
+               memptr work;\r
+               unsigned workdest,stripsize,planesize;\r
+               short loop,pic=i-STARTPICS;\r
+               int shape = (*skycolor & 0xf0) - 16;\r
+\r
+       // Is current shape needed?\r
+       //\r
+               if (shape != (i-(FIRSTSTRIPPIC+1)))\r
+               {\r
+                       numpics++;\r
+                       continue;\r
+               }\r
+\r
+       // CAL_ShiftSprite() works with the SRC and DST in the same\r
+       // segment. So we must allocate memory for two strips, and\r
+       // move the base strip into that segment. Then we can use the\r
+       // 2nd half of that memory for each shifted strip.\r
+       //\r
+               CA_CacheGrChunk (i);\r
+               planesize = (pictable[pic].width+1) * pictable[pic].height;\r
+               stripsize = planesize * 4;\r
+//             MM_GetPtr(&work,(stripsize*2)+0000);\r
+               MM_GetPtr(&work,65536);\r
+               movedata((unsigned)grsegs[i],0,(unsigned)work,0,stripsize);\r
+               workdest = 32768; //(stripsize+15) & 0xFFF0;\r
+\r
+       // Free base strip\r
+       //\r
+               MM_FreePtr (&grsegs[i]);\r
+               UNMARKGRCHUNK(i);\r
+\r
+       // Create three shifted strips and move 'em to latch!\r
+       //\r
+               for (loop=3; loop; loop--)\r
+               {\r
+               // Produce current shift for this strip\r
+               //\r
+                       latchpics[numpics++] = destoff;\r
+                       CAL_ShiftSprite ((unsigned)work,0,workdest,pictable[pic].width,\r
+                                                                 pictable[pic].height,loop*2,false);\r
+\r
+               // Copy this shift to latch memory\r
+               //\r
+                       VW_MemToScreen ((memptr)((unsigned)work+(workdest>>4)),destoff,planesize,1);\r
+                       destoff+=planesize;\r
+               }\r
+\r
+       // Copy unshifted strip to latch\r
+       //\r
+               latchpics[numpics++] = destoff;\r
+               planesize = pictable[pic].width * pictable[pic].height;\r
+               VW_MemToScreen (work,destoff,planesize,1);\r
+               destoff+=planesize;\r
+\r
+       // Free work buffer\r
+       //\r
+               MM_FreePtr(&work);\r
+       }\r
+#endif\r
+\r
+// Keep track of how much latch memory we have...\r
+//\r
+       latchmemavail = 65535-destoff;\r
+\r
+       EGAMAPMASK(15);\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+===================\r
+=\r
+= FizzleOut\r
+=\r
+===================\r
+*/\r
+\r
+void FizzleOut (int showlevel)\r
+{\r
+       unsigned page1,page2;\r
+//\r
+// fizzle fade screen to grey\r
+//\r
+       bufferofs = screenloc[(screenpage+1)%3];\r
+       if (showlevel)\r
+               DrawEnterScreen ();\r
+       FizzleFade(bufferofs,displayofs,VIEWWIDTH,VIEWHEIGHT,false);\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+====================\r
+=\r
+= FreeUpMemory\r
+=\r
+====================\r
+*/\r
+\r
+void FreeUpMemory (void)\r
+{\r
+       int     i;\r
+\r
+       for (i=0;i<NUMSCALEPICS;i++)\r
+               if (shapedirectory[i])\r
+                       MM_SetPurge (&(memptr)shapedirectory[i],3);\r
+\r
+       for (i=0;i<NUMSCALEWALLS;i++)\r
+               if (walldirectory[i])\r
+                       MM_SetPurge (&(memptr)walldirectory[i],3);\r
+}\r
+\r
+//==========================================================================\r
+\r
+#if 0\r
+\r
+/*\r
+==================\r
+=\r
+= DrawHighScores\r
+=\r
+==================\r
+*/\r
+\r
+void    DrawHighScores(void)\r
+{\r
+       char            buffer[16],*str;\r
+       word            i,j,\r
+                               w,h,\r
+                               x,y;\r
+       HighScore       *s;\r
+\r
+\r
+       CA_CacheGrChunk (HIGHSCORESPIC);\r
+       VWB_DrawPic (0,0,HIGHSCORESPIC);\r
+       MM_SetPurge (&grsegs[HIGHSCORESPIC],3);\r
+       UNMARKGRCHUNK(HIGHSCORESPIC);\r
+\r
+       for (i = 0,s = Scores;i < MaxScores;i++,s++)\r
+       {\r
+               PrintY = 68 + (16 * i);\r
+\r
+               //\r
+               // name\r
+               //\r
+               PrintX = 60;\r
+               US_Print(s->name);\r
+\r
+               //\r
+               // level\r
+               //\r
+               ultoa(s->completed,buffer,10);\r
+               for (str = buffer;*str;str++)\r
+                       *str = *str + (129 - '0');      // Used fixed-width numbers (129...)\r
+               USL_MeasureString(buffer,&w,&h);\r
+               PrintX = (25 * 8) - 8 - w;\r
+               US_Print(buffer);\r
+\r
+               //\r
+               // score\r
+               //\r
+               ultoa(s->score,buffer,10);\r
+               for (str = buffer;*str;str++)\r
+                       *str = *str + (129 - '0');      // Used fixed-width numbers (129...)\r
+               USL_MeasureString(buffer,&w,&h);\r
+               PrintX = (34 * 8) - 8 - w;\r
+               US_Print(buffer);\r
+       }\r
+\r
+       fontcolor = F_BLACK;\r
+}\r
+\r
+\r
+\r
+/*\r
+=======================\r
+=\r
+= CheckHighScore\r
+=\r
+=======================\r
+*/\r
+\r
+void    CheckHighScore (long score,word other)\r
+{\r
+       word            i,j;\r
+       int                     n;\r
+       HighScore       myscore;\r
+\r
+       strcpy(myscore.name,"");\r
+       myscore.score = score;\r
+       myscore.completed = other;\r
+\r
+       for (i = 0,n = -1;i < MaxScores;i++)\r
+       {\r
+               if\r
+               (\r
+                       (myscore.score > Scores[i].score)\r
+               ||      (\r
+                               (myscore.score == Scores[i].score)\r
+                       &&      (myscore.completed > Scores[i].completed)\r
+                       )\r
+               )\r
+               {\r
+                       for (j = MaxScores;--j > i;)\r
+                               Scores[j] = Scores[j - 1];\r
+                       Scores[i] = myscore;\r
+                       n = i;\r
+                       HighScoresDirty = true;\r
+                       break;\r
+               }\r
+       }\r
+\r
+       if (n != -1)\r
+       {\r
+       //\r
+       // got a high score\r
+       //\r
+               DrawHighScores ();\r
+               PrintY = 68 + (16 * n);\r
+               PrintX = 60;\r
+               US_LineInput(PrintX,PrintY,Scores[n].name,nil,true,MaxHighName,100);\r
+       }\r
+}\r
+\r
+#endif\r
+\r
+\r
+//==========================================================================\r
+\r
+/*\r
+===================\r
+=\r
+= GameLoop\r
+=\r
+===================\r
+*/\r
+\r
+void GameLoop (void)\r
+{\r
+       boolean wait = false;\r
+       int i,xl,yl,xh,yh;\r
+       char num[20];\r
+#ifdef PROFILE\r
+       clock_t start,end;\r
+#endif\r
+\r
+       DrawPlayScreen ();\r
+       IN_ClearKeysDown();\r
+\r
+restart:\r
+       if (!loadedgame)\r
+       {\r
+               gamestate.difficulty = restartgame;\r
+               restartgame = gd_Continue;\r
+               DrawEnterScreen ();\r
+               if (gamestate.mapon != 8)\r
+                       fizzlein = true;\r
+               wait = true;\r
+       }\r
+\r
+       do\r
+       {\r
+               playstate = gd_Continue;\r
+               if (!loadedgame)\r
+                       SetupGameLevel ();\r
+               else\r
+                       loadedgame = false;\r
+\r
+               FreeUpMemory();\r
+               LoadLatchMem();\r
+               CacheScaleds ();\r
+\r
+               if (EASYMODEON)\r
+                       DisplaySMsg("*** NOVICE ***", NULL);\r
+               else\r
+                       DisplaySMsg("*** WARRIOR ***", NULL);\r
+\r
+               status_delay = 250;\r
+\r
+               RedrawStatusWindow();\r
+               if (wait)\r
+               {\r
+                       VW_WaitVBL(120);\r
+                       wait = false;\r
+               }\r
+\r
+#ifdef PROFILE\r
+start = clock();\r
+while (start == clock());\r
+start++;\r
+#endif\r
+\r
+               PlayLoop ();\r
+\r
+#ifdef PROFILE\r
+end = clock();\r
+itoa(end-start,str,10);\r
+               Quit (str);\r
+#endif\r
+\r
+\r
+               switch (playstate)\r
+               {\r
+               case ex_abort:\r
+                       FreeUpMemory ();\r
+                       return;\r
+               case ex_resetgame:\r
+                       NewGame();\r
+               case ex_loadedgame:\r
+               case ex_warped:\r
+                       FreeUpMemory();\r
+                       if (playstate != ex_resetgame)\r
+                               DisplayMsg("                                      ", NULL);\r
+                       DisplaySMsg("                  ", NULL);\r
+                       goto restart;\r
+               case ex_victorious:\r
+                       screenpage = 0;\r
+                       bufferofs = 0;\r
+                       status_flag = 0;\r
+                       return;\r
+               }\r
+\r
+       } while (1);\r
+\r
+}\r
+\r
+\r
+#if 0\r
+//\r
+// make wall pictures purgable\r
+//\r
+       for (i=0;i<NUMSCALEWALLS;i++)\r
+               if (walldirectory[i])\r
+                       MM_SetPurge (&(memptr)walldirectory[i],3);\r
+\r
+\r
+//\r
+// cache wall pictures back in\r
+//\r
+       for (i=1;i<NUMFLOORS;i++)\r
+               if (tileneeded[i])\r
+               {\r
+                       SetupScaleWall (walllight1[i]);\r
+                       SetupScaleWall (walllight2[i]);\r
+                       SetupScaleWall (walldark1[i]);\r
+                       SetupScaleWall (walldark2[i]);\r
+               }\r
+#endif\r
diff --git a/src/lib/hb/c6_main.c b/src/lib/hb/c6_main.c
new file mode 100755 (executable)
index 0000000..9e284ee
--- /dev/null
@@ -0,0 +1,1083 @@
+/* Catacomb Apocalypse Source Code\r
+ * Copyright (C) 1993-2014 Flat Rock Software\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License along\r
+ * with this program; if not, write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+ */\r
+\r
+// C3_MAIN.C\r
+\r
+#define CATALOG\r
+\r
+#include <time.h>\r
+#include <stdarg.h>\r
+\r
+#include "DEF.H"\r
+#include "GELIB.H"\r
+#pragma hdrstop\r
+#include <dir.h>\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                GLOBAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+typedef enum demo_screens {sc_logo,sc_title,sc_credits1,sc_credits2,sc_credits3,sc_credits4,sc_end} demo_screens;\r
+struct Shape   shape,\r
+                                       SdLogoShp,\r
+                                       TitleShp,\r
+                                       CreditBKShp,\r
+                                       Credit1Shp,\r
+                                       Credit2Shp,\r
+                                       Credit3Shp,\r
+                                       Credit4Shp,\r
+                                       Credit5Shp,\r
+                                       Credit6Shp,\r
+                                       Credit7Shp,\r
+                                       Credit8Shp,\r
+                                       Credit9Shp,\r
+                                       Credit10Shp;\r
+\r
+\r
+PresenterInfo MainHelpText;\r
+\r
+GameDiff restartgame;\r
+boolean loadedgame,abortgame,ingame;\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
+char   SlowMode = 0;\r
+int starting_level;\r
+\r
+short NumGames=0;\r
+unsigned Flags=0;\r
+\r
+boolean LoadShapes = true;\r
+boolean EASYMODEON = false;\r
+\r
+void DisplayIntroText(void);\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+\r
+//===========================================================================\r
+\r
+#if 0\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
+#endif\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
+       if (!loadedgame)\r
+       {\r
+               memset (&gamestate,0,sizeof(gamestate));\r
+               gamestate.mapon = starting_level;\r
+               gamestate.body = MAXBODY;\r
+       }\r
+\r
+       BGFLAGS = BGF_NOT_LIGHTNING;\r
+       Flags &= FL_CLEAR;\r
+\r
+       boltsleft = bolttimer = 0;\r
+\r
+//     memset (gamestate.levels,-1,sizeof(gamestate.levels));\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
+       // save the sky and ground colors\r
+       if (!CA_FarWrite(file,(void far *)&skycolor,sizeof(skycolor)))\r
+               return(false);\r
+       if (!CA_FarWrite(file,(void far *)&groundcolor,sizeof(groundcolor)))\r
+               return(false);\r
+\r
+       if (!CA_FarWrite(file,(void far *)&FreezeTime,sizeof(FreezeTime)))\r
+               return(false);\r
+\r
+       if (!CA_FarWrite(file,(void far *)&gamestate,sizeof(gamestate)))\r
+               return(false);\r
+\r
+       if (!CA_FarWrite(file,(void far *)&EASYMODEON,sizeof(EASYMODEON)))\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
+=\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
+       screenpage = 0;\r
+       FreeUpMemory();\r
+\r
+       playstate = ex_loadedgame;\r
+       // load the sky and ground colors\r
+       if (!CA_FarRead(file,(void far *)&skycolor,sizeof(skycolor)))\r
+               return(false);\r
+       if (!CA_FarRead(file,(void far *)&groundcolor,sizeof(groundcolor)))\r
+               return(false);\r
+\r
+       if (!CA_FarRead(file,(void far *)&FreezeTime,sizeof(FreezeTime)))\r
+               return(false);\r
+\r
+       if (!CA_FarRead(file,(void far *)&gamestate,sizeof(gamestate)))\r
+               return(false);\r
+\r
+       if (!CA_FarRead(file,(void far *)&EASYMODEON,sizeof(EASYMODEON)))\r
+               return(false);\r
+\r
+       SetupGameLevel ();              // load in and cache the base old level\r
+\r
+       if (!FindFile(Filename,"SAVE GAME",-1))\r
+               Quit("Error: Can't find saved game file!");\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
+                               if (tile != INVISIBLEWALL)\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
+       CA_Startup ();\r
+\r
+       US_Setup ();\r
+\r
+       US_SetLoadSaveHooks(LoadTheGame,SaveTheGame,ResetGame);\r
+\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
+\r
+       CA_MarkGrChunk(NORTHICONSPR);\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
+\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
+#if 0\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
+       MML_UseSpace (segstart,seglength);\r
+#endif\r
+\r
+       VW_SetScreenMode (GRMODE);\r
+       ge_textmode = false;\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
+       short exit_code=0;\r
+       unsigned        finscreen;\r
+\r
+       va_list ap;\r
+\r
+       va_start(ap,error);\r
+\r
+#ifndef CATALOG\r
+       if (!error)\r
+       {\r
+               CA_SetAllPurge ();\r
+               CA_CacheGrChunk (PIRACY);\r
+               finscreen = (unsigned)grsegs[PIRACY];\r
+       }\r
+#endif\r
+\r
+       ShutdownId ();\r
+\r
+       if (error && *error)\r
+       {\r
+               vprintf(error,ap);\r
+               exit_code = 1;\r
+       }\r
+#ifndef CATALOG\r
+       else\r
+       if (!NoWait)\r
+       {\r
+               movedata (finscreen,0,0xb800,0,4000);\r
+               bioskey (0);\r
+       }\r
+#endif\r
+\r
+       va_end(ap);\r
+\r
+#ifndef CATALOG\r
+       if (!error)\r
+       {\r
+               _argc = 2;\r
+               _argv[1] = "LAST.SHL";\r
+               _argv[2] = "ENDSCN.SCN";\r
+               _argv[3] = NULL;\r
+               if (execv("LOADSCN.EXE", _argv) == -1)\r
+               {\r
+                       clrscr();\r
+                       puts("Couldn't find executable LOADSCN.EXE.\n");\r
+                       exit(1);\r
+               }\r
+       }\r
+#endif\r
+\r
+       exit(exit_code);\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
+= DisplayDepartment\r
+=\r
+====================\r
+*/\r
+void DisplayDepartment(char *text)\r
+{\r
+       short temp;\r
+\r
+//     bufferofs = 0;\r
+       PrintY = 5;\r
+       WindowX = 17;\r
+       WindowW = 168;\r
+\r
+       VW_Bar(WindowX,PrintY+1,WindowW,7,0);\r
+       temp = fontcolor;\r
+       fontcolor = 10;\r
+       US_CPrintLine (text);\r
+       fontcolor = temp;\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
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// main game cycle\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+       displayofs = bufferofs = 0;\r
+       VW_Bar (0,0,320,200,0);\r
+       VW_SetScreen(0,0);\r
+\r
+//\r
+// Read in all the graphic images needed for the title sequence\r
+//\r
+               VW_WaitVBL(1);\r
+               IN_ReadControl(0,&control);\r
+\r
+//     set EASYMODE\r
+//\r
+       if (stricmp(_argv[2], "1") == 0)\r
+               EASYMODEON = true;\r
+       else\r
+               EASYMODEON = false;\r
+\r
+// restore game\r
+//\r
+       if (stricmp(_argv[3], "1") == 0)\r
+       {\r
+               VW_FadeOut();\r
+               bufferofs = displayofs = 0;\r
+               VW_Bar(0,0,320,200,0);\r
+               if (GE_LoadGame())\r
+               {\r
+                       loadedgame = true;\r
+                       playstate = ex_loadedgame;\r
+                       Keyboard[sc_Enter] = true;\r
+                       VW_Bar(0,0,320,200,0);\r
+                       ColoredPalette();\r
+               }\r
+               VW_Bar(0,0,320,200,0);\r
+               VW_FadeIn();\r
+       }\r
+\r
+       // Play a game\r
+       //\r
+               restartgame = gd_Normal;\r
+               NewGame();\r
+               GameLoop();\r
+}\r
+\r
+//-------------------------------------------------------------------------\r
+// DisplayIntroText()\r
+//-------------------------------------------------------------------------\r
+void DisplayIntroText()\r
+{\r
+       PresenterInfo pi;\r
+\r
+#ifdef TEXT_PRESENTER\r
+       char *toptext = "You stand before the gate leading into the Towne "\r
+                                                "of Morbidity.... "\r
+                                                "^XX";\r
+\r
+       char *bottomtext = "Enter now boldly to defeat the evil Nemesis "\r
+                                                        "deep inside the catacombs."\r
+                                                        "\r
+                                                        "^XX";\r
+#endif\r
+\r
+       char oldfontcolor=fontcolor;\r
+\r
+       fontcolor = 14;\r
+\r
+\r
+#ifdef TEXT_PRESENTER\r
+       pi.xl = 0;\r
+       pi.yl = 0;\r
+       pi.xh = 319;\r
+       pi.yh = 1;\r
+       pi.bgcolor = 0;\r
+       pi.script[0] = (char far *)toptext;\r
+       Presenter(&pi);\r
+\r
+       pi.yl = 160;\r
+       pi.yh = 161;\r
+       pi.script[0] = (char far *)bottomtext;\r
+       Presenter(&pi);\r
+\r
+#else\r
+       PrintY = 1;\r
+       PrintX = 0;\r
+       WindowX = 0;\r
+       WindowW = 320;\r
+\r
+\r
+       US_Print ("      A chilling wind greets you at the entrance\n");\r
+       US_Print ("            to the Sanctuary of the Dead.\n");\r
+\r
+       PrintY = 180;\r
+\r
+       fontcolor = 9;\r
+       US_Print ("                   Shall you proceed as\n");\r
+       fontcolor = 14;\r
+       US_Print ("                  N");\r
+       fontcolor = 9;\r
+       US_Print ("ovice   or");\r
+       fontcolor = 14;\r
+       US_Print ("   W");\r
+       fontcolor = 9;\r
+       US_Print ("arrior ?");\r
+\r
+#endif\r
+\r
+       fontcolor = oldfontcolor;\r
+}\r
+\r
+#if 0\r
+boolean ChooseGameLevel()\r
+{\r
+       char choices[] = {sc_Escape,sc_E,sc_N,sc_H,0},ch;\r
+\r
+       CenterWindow(20,10);\r
+\r
+       US_Print("\n   Choose difficulty level:\n");\r
+       US_Print("       (E)asy\n");\r
+       US_Print("       (N)ormal\n");\r
+       US_Print("       (H)ard\n");\r
+       US_Print("\n      (ESC)ape aborts\n");\r
+\r
+//     VW_UpdateScreen();\r
+       if ((ch=GetKeyChoice(choices)) == sc_Escape)\r
+       {\r
+               while (Keyboard[sc_Escape]);\r
+               LastScan = 0;\r
+               return(false);\r
+       }\r
+\r
+       if (ch == sc_E)\r
+               restartgame = gd_Easy;\r
+       else\r
+       if (ch == sc_N)\r
+               restartgame = gd_Normal;\r
+       else\r
+               restartgame = gd_Hard;\r
+\r
+       return(true);\r
+}\r
+#endif\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+==========================\r
+=\r
+= SetupScalePic\r
+=\r
+==========================\r
+*/\r
+\r
+void SetupScalePic (unsigned picnum)\r
+{\r
+       unsigned        scnum;\r
+\r
+       if (picnum == 1)\r
+               return;\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
+       if (picnum == 1)\r
+               return;\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
+#if 0\r
+/*\r
+==================\r
+=\r
+= CheckMemory\r
+=\r
+==================\r
+*/\r
+\r
+#define MINMEMORY      400000l\r
+\r
+void   CheckMemory(void)\r
+{\r
+       unsigned        finscreen;\r
+\r
+       if (Flags & FL_NOMEMCHECK)\r
+               return;\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
+#endif\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+==========================\r
+=\r
+= main\r
+=\r
+==========================\r
+*/\r
+\r
+char                   *MainParmStrings[] = {"q","l","ver","nomemcheck","helptest",nil};\r
+\r
+void main (void)\r
+{\r
+       short i;\r
+\r
+       starting_level = 0;\r
+\r
+       for (i = 1;i < _argc;i++)\r
+       {\r
+               switch (US_CheckParm(_argv[i],MainParmStrings))\r
+               {\r
+                       case 0:\r
+                               Flags |= FL_QUICK;\r
+                       break;\r
+\r
+                       case 1:\r
+                               starting_level = atoi(_argv[i]+1);\r
+                               if ((starting_level < 0) || (starting_level > LASTMAP-1))\r
+                                       starting_level = 0;\r
+                       break;\r
+\r
+                       case 2:\r
+                               printf("%s\n", GAMENAME);\r
+                               printf("Copyright 1992-93 Softdisk Publishing\n");\r
+                               printf("%s %s\n",VERSION,REVISION);\r
+                               printf("\n");\r
+                               exit(0);\r
+                       break;\r
+\r
+                       case 3:\r
+                               Flags |= FL_NOMEMCHECK;\r
+                       break;\r
+\r
+                       case 4:\r
+                               Flags |= (FL_HELPTEST|FL_QUICK);\r
+                       break;\r
+\r
+               }\r
+       }\r
+\r
+       if (stricmp(_argv[1], "^(a@&r`"))\r
+               Quit("You must type CATAPOC to run CATACOMB APOCALYPSE\n");\r
+\r
+\r
+#if 0\r
+       MainHelpText.xl = 0;\r
+       MainHelpText.yl = 0;\r
+       MainHelpText.xh = 639;\r
+       MainHelpText.yh = 199;\r
+       MainHelpText.bgcolor = 7;\r
+       MainHelpText.ltcolor = 15;\r
+       MainHelpText.dkcolor = 8;\r
+#endif\r
+\r
+//     jabhack();\r
+\r
+       randomize();\r
+\r
+       InitGame ();\r
+//     CheckMemory ();\r
+       LoadLatchMem ();\r
+\r
+//     if (!LoadTextFile("MAINHELP."EXT,&MainHelpText))\r
+//             Quit("Can't load MAINHELP."EXT);\r
+\r
+#ifdef PROFILE\r
+       NewGame ();\r
+       GameLoop ();\r
+#endif\r
+\r
+       DemoLoop();\r
+       Quit(NULL);\r
+}\r
+\r
+//-------------------------------------------------------------------------\r
+// Display640()\r
+//-------------------------------------------------------------------------\r
+void Display640(void)\r
+{\r
+// Can you believe it takes all this just to change to 640 mode!!???!\r
+//\r
+       VW_ScreenToScreen(0,FREESTART-STATUSLEN,40,80);\r
+       VW_SetLineWidth(80);\r
+       MoveScreen(0,0);\r
+       VW_Bar (0,0,640,200,0);\r
+       VW_SetScreenMode(EGA640GR);\r
+       VW_SetLineWidth(80);\r
+       BlackPalette();\r
+}\r
+\r
+//-------------------------------------------------------------------------\r
+// Display320()\r
+//-------------------------------------------------------------------------\r
+void Display320(void)\r
+{\r
+// Can you believe it takes all this just to change to 320 mode!!???!\r
+//\r
+       VW_ColorBorder(0);\r
+       VW_FadeOut();\r
+       VW_SetLineWidth(40);\r
+       MoveScreen(0,0);\r
+       VW_Bar (0,0,320,200,0);\r
+       VW_SetScreenMode(EGA320GR);\r
+       VW_SetLineWidth(40);\r
+       BlackPalette();\r
+       VW_ScreenToScreen(FREESTART-STATUSLEN,0,40,80);\r
+}\r
+\r
+void PrintHelp(void)\r
+{\r
+       char oldfontcolor = fontcolor;\r
+       PrintY = 1;\r
+       WindowX = 135;\r
+       WindowW = 640;\r
+\r
+       VW_FadeOut();\r
+       bufferofs = displayofs = screenloc[0];\r
+       VW_Bar(0,0,320,200,0);\r
+\r
+       Display640();\r
+\r
+       VW_Bar(0, 0, 640, 200, 7);\r
+\r
+       fontcolor = (7 ^ 1);\r
+       US_Print ("\n\n                    SUMMARY OF GAME CONTROLS\n\n");\r
+\r
+       fontcolor = (7 ^ 4);\r
+       US_Print ("         ACTION\n\n");\r
+\r
+       US_Print ("Arrow keys, joystick, or mouse\n");\r
+       US_Print ("TAB or V while turning\n");\r
+       US_Print ("ALT or Button 2 while turning\n");\r
+       US_Print ("CTRL or Button 1\n");\r
+       US_Print ("Z\n");\r
+       US_Print ("X or Enter\n");\r
+       US_Print ("F1\n");\r
+       US_Print ("F2\n");\r
+       US_Print ("F3\n");\r
+       US_Print ("F4\n");\r
+       US_Print ("F5\n");\r
+       US_Print ("ESC\n\n");\r
+       fontcolor = (7 ^ 0);\r
+#ifndef CATALOG\r
+       US_Print ("          (See complete Instructions for more info)\n");\r
+#endif\r
+       US_Print ("\n           copyright (c) 1992-93 Softdisk Publishing\n");\r
+\r
+       fontcolor = (7 ^ 8);\r
+       PrintX = 400;\r
+       PrintY = 37;\r
+       WindowX = 400;\r
+       US_Print ("   REACTION\n\n");\r
+       US_Print ("Move and turn\n");\r
+       US_Print ("Turn quickly (Quick Turn)\n");\r
+       US_Print ("Move sideways\n");\r
+       US_Print ("Shoot a Missile\n");\r
+       US_Print ("Shoot a Zapper\n");\r
+       US_Print ("Shoot an Xterminator\n");\r
+       US_Print ("Help (this screen)\n");\r
+       US_Print ("Sound control\n");\r
+       US_Print ("Save game position\n");\r
+       US_Print ("Restore a saved game\n");\r
+       US_Print ("Joystick control\n");\r
+       US_Print ("System options\n\n\n");\r
+\r
+       VW_UpdateScreen();\r
+       VW_FadeIn();\r
+       VW_ColorBorder(8 | 56);\r
+       IN_Ack();\r
+       Display320();\r
+       fontcolor = oldfontcolor;\r
+}
\ No newline at end of file
diff --git a/src/lib/hb/c6_play.c b/src/lib/hb/c6_play.c
new file mode 100755 (executable)
index 0000000..995e6c7
--- /dev/null
@@ -0,0 +1,1429 @@
+/* Catacomb Apocalypse Source Code\r
+ * Copyright (C) 1993-2014 Flat Rock Software\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License along\r
+ * with this program; if not, write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+ */\r
+\r
+// C3_PLAY.C\r
+\r
+#include "DEF.H"\r
+#include "gelib.h"\r
+#pragma hdrstop\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+#define POINTTICS      6\r
+#define PAUSE 300\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                GLOBAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+byte bcolor;\r
+short skytimer=-1,skytimer_reset;\r
+short groundtimer=-1,groundtimer_reset;\r
+\r
+unsigned scolor,gcolor;\r
+unsigned *skycolor,*groundcolor,debug_sky,debug_gnd;\r
+\r
+unsigned nocolorchange=0xFFFF;\r
+byte BGFLAGS,                          // global that holds all current flags\r
+         bgflag;                               // used by BG changer, this flag is set when done\r
+\r
+\r
+unsigned sky_daytonight[]={0x0909,0x0101,0x0808,0x0000,0xFFFF};\r
+//unsigned gnd_daytonight[]={0x0202,0xFFFF};\r
+\r
+unsigned sky_lightning[]={0x0101,0x0909,0x0f0f,0x0808,0x0000,0xFFFF};\r
+\r
+unsigned sky_colors[NUMLEVELS]={0x0000,0x0000,0x0000,0x0000,0x0808,\r
+                                                                                 0x0404,0x0000,0x0000,0x0000,0x0000,\r
+                                                                                 0x0000,0x0000,0x0000,0x0000,0x0606,\r
+                                                                                 0x0000,0x0000,0x0000,0x0000,0x0000,\r
+                                                                                 0x0000};\r
+unsigned gnd_colors[NUMLEVELS]={0x0202,0x0202,0x0606,0x0202,0x0707,\r
+                                                                                 0x0505,0x0808,0x0606,0x0101,0x0808,\r
+                                                                                 0x0606,0x0404,0x0808,0x0c0c,0x0e0e,\r
+                                                                                 0x0808,0x0808,0x0c0c,0x0000,0x0707,\r
+                                                                                 0x0808};\r
+\r
+\r
+ControlInfo    control;\r
+boolean                running=false; //,slowturn;\r
+\r
+int                    bordertime;\r
+objtype objlist[MAXACTORS],*new,*obj,*player,*lastobj,*objfreelist;\r
+\r
+#if USE_INERT_LIST\r
+inertobjtype inertobjlist[MAXINERTOBJ],*inert;\r
+#endif\r
+\r
+unsigned       farmapylookup[MAPSIZE];\r
+byte           *nearmapylookup[MAPSIZE];\r
+\r
+boolean                singlestep,godmode;\r
+int                    extravbls;\r
+status_flags    status_flag;\r
+int             status_delay;\r
+\r
+//\r
+// replacing refresh manager\r
+//\r
+unsigned       mapwidth,mapheight,tics,realtics;\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
+short BeepTime = 0;\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+void CalcBounds (objtype *ob);\r
+void DrawPlayScreen (void);\r
+void PreFullDisplay(void);\r
+void PostFullDisplay(boolean draw_view);\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
+void CalibrateJoystick(short joynum);\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   320\r
+#define MAXY   120\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
+       extern boolean autofire;\r
+\r
+       if (screenfaded)                        // don't do anything with a faded screen\r
+               return;\r
+\r
+#if 0\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
+       else\r
+       if (Keyboard[sc_Enter])                 // P = pause with no screen disruptioon\r
+       {\r
+//             SD_MusicOff();\r
+               DisplaySMsg("PAUSED",NULL);\r
+               IN_Ack();\r
+//             SD_MusicOn();\r
+               if (MousePresent) Mouse(MDelta);        // Clear accumulated mouse movement\r
+       }\r
+       else\r
+       if (Keyboard[sc_S])\r
+       {\r
+               char *Text[] = {{"Slow Mode ON"},{"Slow Mode OFF"}};\r
+\r
+               SlowMode ^= 1;\r
+               extravbls = SlowMode << 3;\r
+               CenterWindow (8,3);\r
+               US_PrintCentered (Text[SlowMode]);\r
+               VW_UpdateScreen ();\r
+//             SD_MusicOff();\r
+               IN_Ack();\r
+//             SD_MusicOn();\r
+               if (MousePresent) Mouse(MDelta);        // Clear accumulated mouse movement\r
+       }\r
+#endif\r
+\r
+\r
+// F2 - SOUND OPTIONS\r
+//\r
+       if (Keyboard[sc_F2])\r
+       {\r
+               int height=7;\r
+               boolean ChoiceMade = false;\r
+\r
+               if (AdLibPresent)\r
+                       height++;\r
+\r
+               VW_FixRefreshBuffer();\r
+               CenterWindow(22,height);\r
+               US_Print( "\n        1 )  NO SOUND \n");\r
+               US_Print(   "        2 )  PC  AUDIO \n");\r
+\r
+               if (AdLibPresent)\r
+                       US_Print("        3 ) ADLIB AUDIO\n");\r
+\r
+               US_Print( "\n       ESC)    EXIT    ");\r
+               VW_UpdateScreen();\r
+\r
+               // Switch audio device ON/OFF & load sounds if there\r
+               // was a change in the device.\r
+\r
+               do {\r
+\r
+                       if (Keyboard[1])                                                                // ESC - Exit\r
+                               ChoiceMade = true;\r
+                       else\r
+                       if (Keyboard[2])                                                                // 1 - No Sound\r
+                       {\r
+                               SD_SetSoundMode(sdm_Off);\r
+                               ChoiceMade = true;\r
+                       }\r
+                       else\r
+                       if (Keyboard[3])                                                        // 2 - PC Audio\r
+                       {\r
+                               SD_SetSoundMode(sdm_PC);\r
+//                             if (oldsoundmode != sdm_PC)\r
+                                       CA_LoadAllSounds();\r
+                               ChoiceMade = true;\r
+                       }\r
+                       else\r
+                       if ((Keyboard[4]) &&    AdLibPresent)           // 3 - AdLib Audio\r
+                       {\r
+                               SD_SetSoundMode(sdm_AdLib);\r
+//                             if (oldsoundmode != sdm_AdLib)\r
+                                       CA_LoadAllSounds();\r
+                               ChoiceMade = true;\r
+                       }\r
+\r
+               } while (!ChoiceMade);\r
+               tics = realtics = 1;\r
+               IN_ClearKeysDown();\r
+       }\r
+\r
+// F5 - CALIBRATE JOYSTICK\r
+//\r
+       if (Keyboard[sc_F5])\r
+       {\r
+               CalibrateJoystick(0);\r
+               tics = realtics = 1;\r
+               IN_ClearKeysDown();\r
+       }\r
+\r
+deadloop:;\r
+// ESCAPE - quits game\r
+//\r
+       if ((Keyboard[sc_Escape]) || (Flags & FL_DEAD))\r
+       {\r
+               char ch;\r
+\r
+               DisplaySMsg("Options", NULL);\r
+               status_flag = S_NONE;\r
+\r
+\r
+               if (Flags & FL_DEAD)\r
+               {\r
+                       char choices[] = {sc_Escape,sc_R,sc_N,sc_Q,0};\r
+                       ch = DisplayMsg("Restore          New          Quit",choices);\r
+                       DisplayMsg("                                      ", NULL);\r
+               }\r
+               else\r
+               {\r
+                       char choices[] = {sc_Escape,sc_S,sc_R,sc_N,sc_Q,0};\r
+                       ch = DisplayMsg("Save       Restore       New       Quit",choices);\r
+               }\r
+               DrawText(true);\r
+\r
+               switch (ch)\r
+               {\r
+                       case sc_S:\r
+                               if (!(Flags & FL_DEAD))\r
+                                       Keyboard[sc_F3] = true;\r
+                       break;\r
+\r
+                       case sc_R:\r
+                               Keyboard[sc_F4] = true;\r
+                       break;\r
+\r
+                       case sc_N:\r
+                               DisplaySMsg("Starting anew", NULL);\r
+                               VW_WaitVBL(60);\r
+                               playstate = ex_resetgame;\r
+                               Flags &= ~FL_DEAD;\r
+                       break;\r
+\r
+                       case sc_Q:\r
+                               DisplaySMsg("FARE THEE WELL!", NULL);\r
+                               VW_WaitVBL(120);\r
+                               if (!Flags & FL_QUICK)\r
+                                       VW_FadeOut();\r
+                               NormalScreen();\r
+                               FreeUpMemory();\r
+                               Quit(NULL);\r
+                       break;\r
+               }\r
+               tics = realtics = 1;\r
+       }\r
+\r
+// F1 - DISPLAY HELP\r
+//\r
+       if (Keyboard[sc_F1])\r
+       {\r
+               PrintHelp();\r
+\r
+#ifdef TEXT_PRESENTER\r
+\r
+               extern PresenterInfo MainHelpText;\r
+\r
+               VW_FadeOut();\r
+\r
+               FreeUpMemory();\r
+               if (!LoadPresenterScript("HELP.TXT",&MainHelpText))\r
+               {\r
+                       VW_FadeIn();\r
+                       CenterWindow(30,5);\r
+                       US_CPrint("\nError loading HELP file.\n");\r
+                       US_CPrint("Press any key.");\r
+                       IN_Ack();\r
+                       VW_FadeOut();\r
+               }\r
+               else\r
+               {\r
+                       VW_SetSplitScreen(200);\r
+                       bufferofs = displayofs = screenloc[0];\r
+                       VW_Bar(0,0,320,200,0);\r
+\r
+                       Display640();\r
+                       Presenter(&MainHelpText);\r
+                       Display320();\r
+               }\r
+               FreePresenterScript(&MainHelpText);\r
+#endif\r
+               VW_SetSplitScreen(120);\r
+               VW_SetScreen(screenloc[0],0);\r
+               screenpage = 0;\r
+               CacheScaleds();\r
+\r
+               bufferofs = 0;\r
+               RedrawStatusWindow();\r
+               ThreeDRefresh();\r
+               VW_FadeIn();\r
+               Keyboard[sc_F1] = false;\r
+               tics = realtics = 1;\r
+               IN_ClearKeysDown();\r
+       }\r
+\r
+// F3 - SAVE GAME\r
+//\r
+       if ((Keyboard[sc_F3]) && (!(Flags & FL_DEAD)))\r
+       {\r
+               PreFullDisplay();\r
+               GE_SaveGame();\r
+               PostFullDisplay(true);\r
+               tics = realtics = 1;\r
+               IN_ClearKeysDown();\r
+       }\r
+\r
+// F4 - LOAD GAME\r
+//\r
+       if (Keyboard[sc_F4])\r
+       {\r
+               PreFullDisplay();\r
+               if (GE_LoadGame())\r
+               {\r
+                       loadedgame = true;\r
+                       playstate = ex_loadedgame;\r
+                       Flags &= ~FL_DEAD;\r
+                       lasttext = -1;\r
+                       PostFullDisplay(false);\r
+               }\r
+               else\r
+               if (playstate == ex_victorious)\r
+               {\r
+                       PostFullDisplay(false);\r
+                       Victory(false);\r
+                       IN_Ack();\r
+                       Quit(NULL);\r
+               }\r
+               else\r
+                       PostFullDisplay(true);\r
+               Keyboard[sc_F5] = false;\r
+               tics = realtics = 1;\r
+               IN_ClearKeysDown();\r
+       }\r
+\r
+       if (Flags & FL_DEAD)\r
+               goto deadloop;\r
+\r
+//\r
+// F10-? debug keys\r
+//\r
+       if (Keyboard[sc_BackSpace])\r
+       {\r
+               DebugKeys();\r
+               if (MousePresent) Mouse(MDelta);        // Clear accumulated mouse movement\r
+               lasttimecount = TimeCount;\r
+       }\r
+}\r
+\r
+//-------------------------------------------------------------------------\r
+// PreFullDisplay()\r
+//-------------------------------------------------------------------------\r
+void PreFullDisplay()\r
+{\r
+       VW_FadeOut();\r
+       VW_SetSplitScreen(200);\r
+       bufferofs = displayofs = screenloc[0];\r
+       VW_Bar(0,0,320,200,0);\r
+}\r
+\r
+//-------------------------------------------------------------------------\r
+// PostFullDisplay()\r
+//-------------------------------------------------------------------------\r
+void PostFullDisplay(boolean draw_view)\r
+{\r
+       VW_SetSplitScreen(120);\r
+       bufferofs = 0;\r
+       RedrawStatusWindow();\r
+       if (draw_view)\r
+       {\r
+               ThreeDRefresh();\r
+               VW_FadeIn();\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
+#if USE_INERT_LIST\r
+       inert = inertobjlist;\r
+#endif\r
+\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
+       objectcount--;\r
+}\r
+\r
+#if USE_INERT_LIST\r
+\r
+//--------------------------------------------------------------------------\r
+// MoveObjToInert()\r
+//--------------------------------------------------------------------------\r
+void MoveObjToInert(objtype *obj)\r
+{\r
+\r
+       if (inert == &inertobjlist[MAXINERTOBJ])\r
+               return;\r
+\r
+// Transfer info needed by inert objtype\r
+//\r
+       inert->x = obj->x;\r
+       inert->y = obj->y;\r
+       inert->size = obj->size;\r
+       inert->viewx = obj->viewx;\r
+       inert->tilex = obj->tilex;\r
+       inert->tiley = obj->tiley;\r
+       inert->state = obj->state;\r
+       inert->ticcount = obj->ticcount;\r
+\r
+// Setup links between inert objects\r
+//\r
+       if (inert != inertobjlist)\r
+               (inert-1)->next = inert;\r
+       inert->next = NULL;\r
+       inert++;\r
+\r
+// Free 'real' object from list.\r
+//\r
+       RemoveObj(obj);\r
+}\r
+\r
+#endif\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,&control);\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
+                       control.button0 = 1;\r
+               if (buttons&2)\r
+                       control.button1 = 1;\r
+\r
+       }\r
+\r
+       if (Keyboard[sc_V] || Keyboard[sc_Tab])\r
+               running = true;\r
+       else\r
+               running = false;\r
+}\r
+\r
+//==========================================================================\r
+\r
+#if 0\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
+#endif\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= PlayLoop\r
+=\r
+===================\r
+*/\r
+\r
+void PlayLoop (void)\r
+{\r
+       char shot_color[3] = {4,9,14};\r
+\r
+       int allgems[5]={GEM_DELAY_TIME,         // used for Q & D comparison\r
+                                                GEM_DELAY_TIME,                // for having all gems...\r
+                                                GEM_DELAY_TIME,                // the "allgems" declaration MUST\r
+                                                GEM_DELAY_TIME,                // match the "gems" declaration in\r
+                                                GEM_DELAY_TIME         // the gametype structure!\r
+                                               };\r
+\r
+//     int originx=0;\r
+//     int i=100;\r
+       signed long dx,dy,radius,psin,pcos,newx,newy;\r
+       int             give;\r
+       short objnum;\r
+       signed long ox,oy,xl,xh,yl,yh,px,py,norm_dx,norm_dy;\r
+       short o_radius;\r
+\r
+       void (*think)();\r
+\r
+       ingame = true;\r
+       playstate = TimeCount = 0;\r
+       gamestate.shotpower = handheight = 0;\r
+       pointcount = pointsleft = 0;\r
+\r
+       status_flag = S_NONE;\r
+\r
+#if 0\r
+       // setup sky/ground colors and effects (based on level)\r
+       //\r
+       switch (gamestate.mapon)\r
+       {\r
+               case 255:\r
+                       if (!(BGFLAGS & BGF_NIGHT))\r
+                       {\r
+                               InitBgChange(3*60,sky_daytonight,-1,NULL,BGF_NIGHT);\r
+                               groundcolor = &gnd_colors[0];\r
+                       }\r
+                       else\r
+                       {\r
+                               skycolor = &sky_colors[0];\r
+                               groundcolor = &gnd_colors[0];\r
+                       }\r
+               break;\r
+\r
+               default:\r
+                       skycolor = &sky_colors[gamestate.mapon];\r
+                       groundcolor = &gnd_colors[gamestate.mapon];\r
+                       skytimer = groundtimer = -1;\r
+               break;\r
+       }\r
+#endif\r
+\r
+       BGFLAGS |= BGF_NOT_LIGHTNING;\r
+       skytimer = groundtimer = -1;\r
+\r
+       debug_gnd = *groundcolor;\r
+       debug_sky = *skycolor;\r
+       RedrawStatusWindow();\r
+       ThreeDRefresh();\r
+       if (screenfaded)\r
+               VW_FadeIn();\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
+               control.xaxis = 1;\r
+               if (++TimeCount == 300)\r
+                       return;\r
+#endif\r
+               DisplayStatus(&status_flag);\r
+\r
+               objnum=0;\r
+               for (obj = player;obj;obj = obj->next)\r
+               {\r
+                       if ((obj->active >= yes) && (!(FreezeTime && (obj!=player))))\r
+                       {\r
+                               if (obj->ticcount)\r
+                               {\r
+                                       obj->ticcount-=realtics;\r
+                                       while ( obj->ticcount <= 0)\r
+                                       {\r
+                                               think = obj->state->think;\r
+                                               if (think)\r
+                                               {\r
+                                                       statetype *oldstate=obj->state;\r
+\r
+                                                       think (obj);\r
+                                                       if (!obj->state)\r
+                                                       {\r
+                                                               RemoveObj (obj);\r
+                                                               goto nextactor;\r
+                                                       }\r
+                                                       if (obj->state != oldstate)\r
+                                                               break;\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
+\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
+                       // keep a list of objects around the player for radar updates\r
+                       //\r
+                               if (obj == player)\r
+                               {\r
+                                       px = player->x;\r
+                                       py = player->y;\r
+                                       psin = sintable[player->angle];\r
+                                       pcos = costable[player->angle];\r
+                                       xl = px-((long)RADAR_WIDTH<<TILESHIFT)/2;\r
+                                       xh = px+((long)RADAR_WIDTH<<TILESHIFT)/2-1;\r
+                                       yl = py-((long)RADAR_HEIGHT<<TILESHIFT)/2;\r
+                                       yh = py+((long)RADAR_HEIGHT<<TILESHIFT)/2;\r
+                               }\r
+\r
+                               if (objnum > MAX_RADAR_BLIPS-2)\r
+                                       objnum = MAX_RADAR_BLIPS-2;\r
+\r
+                               ox = obj->x;\r
+                               oy = obj->y;\r
+\r
+\r
+                               if ((ox >= xl) && (ox <= xh) && (oy >= yl) && (oy <= yh))\r
+                               {\r
+                                       norm_dx = (dx = px-ox)>>TILESHIFT;\r
+                                       norm_dy = (dy = oy-py)>>TILESHIFT;\r
+\r
+                                       o_radius = IntSqrt((norm_dx * norm_dx) + (norm_dy * norm_dy));\r
+\r
+                                       if (o_radius < RADAR_RADIUS)\r
+                                       {\r
+                                               newx = FixedByFrac(dy,pcos)-FixedByFrac(dx,psin);\r
+                                               newy = FixedByFrac(dy,psin)+FixedByFrac(dx,pcos);\r
+\r
+                                               RadarXY[objnum][0]=newx>>TILESHIFT;\r
+                                               RadarXY[objnum][1]=newy>>TILESHIFT;\r
+\r
+                                               // Define color to use for this object...\r
+                                               //\r
+\r
+                                               switch (obj->obclass)\r
+                                               {\r
+                       // NO GEM NEEDED\r
+                       //\r
+                                       // THE WIZARD! (YOU)\r
+                                       //\r
+                                                       case playerobj:\r
+                                                               RadarXY[objnum++][2]=15;\r
+                                                       break;\r
+\r
+                                       // WIZARD'S SHOTS\r
+                                       //\r
+                                                       case bounceobj:\r
+                                                       case pshotobj:\r
+                                                       case bigpshotobj:\r
+                                                               RadarXY[objnum++][2]=shot_color[screenpage];\r
+                                                       break;\r
+\r
+                       // RED GEM\r
+                       //\r
+                                       // STOMPY                                                                               (DK RED)\r
+                                       //\r
+                                                       case invisdudeobj:\r
+                                                       case stompyobj:\r
+                                                               if (gamestate.gems[B_RGEM-B_RGEM])\r
+                                                                       if (obj->active == always)\r
+                                                                               RadarXY[objnum++][2]=4;\r
+                                                       break;\r
+\r
+                                       // BLOB                                                                                 (LT RED)\r
+                                       //\r
+                                                       case blobobj:\r
+                                                               if (gamestate.gems[B_RGEM-B_RGEM])\r
+                                                                       if (obj->active == always)\r
+                                                                               RadarXY[objnum++][2]=12;\r
+                                                       break;\r
+\r
+                       // BLUE GEM\r
+                       //\r
+                                       // ROBOTANK                                                                             (LT BLUE)\r
+                                       //\r
+                                                       case robotankobj:\r
+                                                       case fmageobj:\r
+                                                               if (gamestate.gems[B_BGEM-B_RGEM])\r
+                                                                       if (obj->active == always)\r
+                                                                               RadarXY[objnum++][2]=9;\r
+                                                       break;\r
+\r
+#if 1\r
+                                       // BLUE DEMON                                                                   (DK BLUE)\r
+                                       //\r
+                                                       case demonobj:\r
+                                                               if (gamestate.gems[B_GGEM-B_RGEM])\r
+                                                                       if (obj->active == always)\r
+                                                                               RadarXY[objnum++][2]=1;\r
+                                                       break;\r
+#endif\r
+\r
+                       // GREEN GEM\r
+                       //\r
+                                       // WIZARD                                                                               (LT GREEN)\r
+                                       //\r
+                                                       case wizardobj:\r
+                                                               if (gamestate.gems[B_GGEM-B_RGEM])\r
+                                                                       if (obj->active == always)\r
+                                                                               RadarXY[objnum++][2]=10;\r
+                                                       break;\r
+\r
+                                       // AQUA MAN                                                                             (DK GREEN)\r
+                                       //\r
+                                                       case aquamanobj:\r
+                                                               if (gamestate.gems[B_GGEM-B_RGEM])\r
+                                                                       if (obj->active == always)\r
+                                                                               RadarXY[objnum++][2]=2;\r
+                                                       break;\r
+\r
+                       // YELLOW GEM\r
+                       //\r
+                                       // EQYPTIAN HEAD                                                                (BROWN)\r
+                                       //\r
+                                                       case headobj:\r
+                                                               if (gamestate.gems[B_YGEM-B_RGEM])\r
+                                                                       if (obj->active == always)\r
+                                                                               RadarXY[objnum++][2]=6;\r
+                                                       break;\r
+\r
+                                       //      RAMBONE                                                                         (YELLOW)\r
+                                       //      TROLL\r
+                                                       case ramboneobj:\r
+                                                       case trollobj:\r
+                                                               if (gamestate.gems[B_YGEM-B_RGEM])\r
+                                                                       if (obj->active == always)\r
+                                                                               RadarXY[objnum++][2]=14;\r
+                                                       break;\r
+\r
+                                       //      BUG                                                                                     (LIGHT GRAY)\r
+                                                       case bugobj:\r
+                                                               if (gamestate.gems[B_YGEM-B_RGEM])\r
+                                                                       if (obj->active == always)\r
+                                                                               RadarXY[objnum++][2]=7;\r
+                                                       break;\r
+\r
+                                       //      RAY                                                                                     (DARK GRAY)\r
+                                                       case rayobj:\r
+                                                               if (gamestate.gems[B_YGEM-B_RGEM])\r
+                                                                       if (obj->active == always)\r
+                                                                               RadarXY[objnum++][2]=8;\r
+                                                       break;\r
+\r
+                       // PURPLE GEM\r
+                       //\r
+                                       // MEC DEMON                                                                    (PURPLE)\r
+                                       //\r
+                                                       case cyborgdemonobj:\r
+                                                               if (gamestate.gems[B_PGEM-B_RGEM])\r
+                                                                       if (obj->active == always)\r
+                                                                               RadarXY[objnum++][2]=5;\r
+                                                       break;\r
+\r
+                                       // EYE                                                                                  (LT PURPLE)\r
+                                       //\r
+                                                       case eyeobj:\r
+                                                       case reyeobj:\r
+                                                               if (gamestate.gems[B_PGEM-B_RGEM])\r
+                                                                       if (obj->active == always)\r
+                                                                               RadarXY[objnum++][2]=13;\r
+                                                       break;\r
+\r
+                       // ALL GEMS NEEDED\r
+                       //\r
+                                       // NEMESIS\r
+                                       //\r
+                                                       case grelmobj:\r
+                                                               if (!memcmp(gamestate.gems,allgems,sizeof(gamestate.gems)))\r
+                                                                       if (obj->active == always)\r
+                                                                               RadarXY[objnum++][2]=15;\r
+                                                       break;\r
+                                               }\r
+                                       }\r
+                               }\r
+               }\r
+               RadarXY[objnum][2]=-1;          // Signals end of RadarXY list...\r
+\r
+#if USE_INERT_LIST\r
+               if (inert != inertobjlist)\r
+                       for (obj=(objtype *)inertobjlist;obj;obj=obj->next)\r
+                               if (obj->ticcount)\r
+                               {\r
+                                       obj->ticcount-=realtics;\r
+                                       while ( obj->ticcount <= 0)\r
+                                       {\r
+                                               obj->state = obj->state->next;\r
+                                               if (!obj->state)\r
+                                                       Quit("Removable object in INERT list.");\r
+\r
+                                               if (!obj->state->tictime)\r
+                                               {\r
+                                                       obj->ticcount = 0;\r
+                                                       goto nextactor;\r
+                                               }\r
+\r
+                                               if (obj->state->tictime>0)\r
+                                                       obj->ticcount += obj->state->tictime;\r
+                                       }\r
+                               }\r
+#endif\r
+\r
+               if (bordertime)\r
+               {\r
+                       bordertime -= realtics;\r
+                       if (bordertime<=0)\r
+                       {\r
+                               bordertime = 0;\r
+                               VW_ColorBorder(0);\r
+                       }\r
+               }\r
+\r
+#if 1\r
+// random lightning?\r
+//\r
+       if (BGFLAGS & (BGF_NOT_LIGHTNING))\r
+       {\r
+               if ((scolor & 0xe0) && (!(random(20-realtics))))\r
+               {\r
+                       BGFLAGS &= ~BGF_NOT_LIGHTNING;\r
+                       InitBgChange(1,sky_lightning,-1,NULL,BGF_NOT_LIGHTNING);\r
+               }\r
+       }\r
+\r
+// handle sky/ground color changes\r
+//\r
+               if (skytimer != -1)\r
+               {\r
+                       skytimer -= realtics;\r
+                       if (skytimer < 0)\r
+                       {\r
+                               skycolor++;\r
+                               if (*skycolor == 0xffff)\r
+                               {\r
+                                       skytimer = -1;\r
+//                                     skycolor--;\r
+                                       skycolor = &scolor;\r
+                                       if (groundtimer == -1)\r
+                                               BGFLAGS |= bgflag;\r
+                               }\r
+                               else\r
+                                       skytimer = skytimer_reset;\r
+                       }\r
+               }\r
+\r
+               if (groundtimer != -1)\r
+               {\r
+                       groundtimer -= realtics;\r
+                       if (groundtimer < 0)\r
+                       {\r
+                               groundcolor++;\r
+                               if (*groundcolor == 0xffff)\r
+                               {\r
+                                       groundtimer = -1;\r
+//                                     groundcolor--;\r
+                                       groundcolor = &gcolor;\r
+                                       if (skytimer == -1)\r
+                                               BGFLAGS |= bgflag;\r
+                               }\r
+                               else\r
+                                       groundtimer = groundtimer_reset;\r
+                       }\r
+               }\r
+#endif\r
+\r
+\r
+//\r
+//             Handle FreezeTime counter..\r
+//\r
+               if (FreezeTime)\r
+               {\r
+                       if (FreezeTime<20*30)\r
+                               if ((BeepTime+=realtics)>=60)\r
+                               {\r
+                                       BeepTime -= 60;\r
+                                       SD_PlaySound(TICKSND);\r
+                               }\r
+\r
+                       if ((FreezeTime-=realtics)<=0)\r
+                       {\r
+                               FreezeTime=0;\r
+                               SD_PlaySound(TIMERETURNSND);\r
+                               DisplaySMsg(NULL,NULL);\r
+                               status_flag = S_NONE;\r
+                       }\r
+               }\r
+\r
+\r
+// refresh all\r
+//\r
+               ThreeDRefresh ();\r
+\r
+               if (Flags & FL_DEAD)\r
+               {\r
+                       SD_PlaySound (GAMEOVERSND);\r
+                       DisplaySMsg("DEAD",NULL);\r
+                       DrawHealth();\r
+               }\r
+\r
+// check for win\r
+//\r
+               if (playstate == ex_victorious)\r
+               {\r
+                       Victory(true);\r
+                       IN_Ack();\r
+                       Quit(NULL);\r
+               }\r
+\r
+               CheckKeys();\r
+\r
+       }while (!playstate);\r
+//     StopMusic ();\r
+\r
+       ingame = false;\r
+       if (bordertime)\r
+       {\r
+               bordertime = 0;\r
+               VW_ColorBorder(0);\r
+       }\r
+\r
+       if (abortgame)\r
+               abortgame = false;\r
+}\r
+\r
+//--------------------------------------------------------------------------\r
+// IntSqrt() - by Master Programmer, George Leritte!\r
+//--------------------------------------------------------------------------\r
+int IntSqrt(long va)\r
+{\r
+asm     mov     AX, word ptr va\r
+asm     mov     DX, word ptr va+2\r
+asm     mov     bx,dx           // {bx = integer square root of dx:ax}\r
+asm     or      bx,ax           // {if dx:ax=0 then return}\r
+asm     jz      isq01\r
+asm     mov     bx,dx\r
+asm     shl     bx,1\r
+asm     or      bl,ah\r
+asm     or      bl,al\r
+asm     dec     bx\r
+asm     add     bx,dx           // { initial guess}\r
+asm     jg      isq10\r
+asm     inc     bx              // { don't return zero}\r
+asm     jg      isq10\r
+asm     mov     bx,7fffh\r
+isq01:;\r
+                 goto    exitrout;\r
+\r
+isq10:;\r
+asm     push    ax\r
+asm     push    dx\r
+asm     div     bx\r
+asm     sub     ax,bx\r
+asm     cmp     ax,1\r
+asm     jbe     isq90\r
+asm     cmp     ax,-1\r
+asm     jae     isq90\r
+asm     sar     ax,1\r
+asm     add     bx,ax\r
+asm     pop     dx\r
+asm     pop     ax\r
+asm     jmp     isq10\r
+isq90:;\r
+asm     pop     dx\r
+asm     pop     ax\r
+exitrout:;\r
+asm     mov     ax,bx\r
+}\r
+\r
+//-------------------------------------------------------------------------\r
+// InitBgChange()\r
+//-------------------------------------------------------------------------\r
+void InitBgChange(short stimer, unsigned *scolors, short gtimer, unsigned *gcolors, byte flag)\r
+{\r
+       skytimer_reset = skytimer = stimer;\r
+       if (scolors)\r
+               skycolor = scolors;\r
+\r
+       groundtimer_reset = groundtimer = gtimer;\r
+       if (gcolors)\r
+               groundcolor = gcolors;\r
+\r
+       bgflag = flag;\r
+}\r
+\r
+////////////////////////////////////////////////////////\r
+//\r
+// DisplayStatus\r
+//\r
+//  Stat_Flag -  contains the type of status displayed\r
+//  -- also uses status_delay (global variable) will not\r
+//     change display until this variable is zero.\r
+//  -- heirarchy is determined by the series of if statements,\r
+//        to change it, rearrange th if statements.\r
+//\r
+////////////////////////////////////////////////////////\r
+\r
+#define MESSAGEDELAY  25\r
+void DisplayStatus (status_flags *stat_flag)\r
+{\r
+       status_flags temp_status;\r
+\r
+\r
+       if (*stat_flag == S_TIMESTOP)\r
+         return;\r
+\r
+       if (status_delay > 0)\r
+       {\r
+               status_delay -= realtics;\r
+               return;\r
+       }\r
+       else\r
+               status_delay = 0;\r
+\r
+       // check for a change in status from previous call\r
+\r
+       temp_status = S_VIEWING;                             //precaution\r
+\r
+       if (Keyboard[sc_Control] || control.button0)\r
+               temp_status = S_MISSLE;\r
+\r
+       if (Keyboard[sc_Z] && !Keyboard[sc_F10])\r
+               temp_status = S_ZAPPER;\r
+\r
+       if ((Keyboard[sc_X] && !Keyboard[sc_F10]) || Keyboard[sc_Enter])\r
+               temp_status = S_XTER;\r
+\r
+       if (control.x)\r
+               temp_status = S_TURN;\r
+\r
+       if ((Keyboard[sc_V] || Keyboard[sc_Tab]) && control.x)\r
+               temp_status = S_QTURN;\r
+\r
+       if (Keyboard[sc_Alt] && control.x)\r
+               temp_status = S_SIDESTEP;\r
+\r
+       if (control.y < 0)\r
+               temp_status = S_ADVANCE;\r
+\r
+       if (control.y > 0)\r
+               temp_status = S_RETREAT;\r
+\r
+       if (Keyboard[sc_F5])\r
+               temp_status = S_JOYSTICK;\r
+\r
+       if (Keyboard[sc_F4])\r
+               temp_status = S_RESTORING;\r
+\r
+       if (Keyboard[sc_F3])\r
+               temp_status = S_SAVING;\r
+\r
+       if (Keyboard[sc_F2])\r
+               temp_status = S_SND;\r
+\r
+       if (Keyboard[sc_F1])\r
+               temp_status = S_HELP;\r
+\r
+       if (temp_status != *stat_flag)\r
+       {\r
+               *stat_flag = temp_status;\r
+\r
+\r
+               switch (*stat_flag)\r
+               {\r
+                       case S_MISSLE:\r
+                               DisplaySMsg("Magick Missile", NULL);\r
+                               status_delay = MESSAGEDELAY;\r
+                       break;\r
+\r
+                       case S_ZAPPER:\r
+                               if (gamestate.bolts)\r
+                               {\r
+                                       DisplaySMsg("Zapper", NULL);\r
+                                       status_delay = MESSAGEDELAY+10;\r
+                               }\r
+                       break;\r
+\r
+                       case S_XTER:\r
+                               if (gamestate.nukes)\r
+                               {\r
+                                       DisplaySMsg("Xterminator", NULL);\r
+                                       status_delay = MESSAGEDELAY+5;\r
+                               }\r
+                       break;\r
+\r
+                       case S_TURN:\r
+                               DisplaySMsg("Turning", NULL);\r
+                               status_delay = MESSAGEDELAY;\r
+                       break;\r
+\r
+                       case S_QTURN:\r
+                               DisplaySMsg("Quick Turning", NULL);\r
+                               status_delay = MESSAGEDELAY;\r
+                       break;\r
+\r
+                       case S_SIDESTEP:\r
+                               DisplaySMsg("Sidestepping", NULL);\r
+                               status_delay = MESSAGEDELAY;\r
+                       break;\r
+\r
+                       case S_ADVANCE:\r
+                               DisplaySMsg("Advancing", NULL);\r
+                               status_delay = MESSAGEDELAY;\r
+                       break;\r
+\r
+                       case S_RETREAT:\r
+                               DisplaySMsg("Retreating", NULL);\r
+                               status_delay = MESSAGEDELAY;\r
+                       break;\r
+\r
+                       case S_JOYSTICK:\r
+                               DisplaySMsg("Adjusting Joystick", NULL);\r
+                       break;\r
+\r
+                       case S_RESTORING:\r
+                               DisplaySMsg("Restoring", NULL);\r
+                       break;\r
+\r
+                       case S_SAVING:\r
+                               DisplaySMsg("Saving", NULL);\r
+                       break;\r
+\r
+                       case S_SND:\r
+                               DisplaySMsg("Select Sound", NULL);\r
+                       break;\r
+\r
+                       case S_HELP:\r
+                               DisplaySMsg("Getting Help", NULL);\r
+                       break;\r
+\r
+                       case S_VIEWING:\r
+                               DisplaySMsg("Viewing", NULL);\r
+                       break;\r
+               }\r
+               bufferofs = displayofs = screenloc[screenpage];\r
+\r
+       }\r
+}\r
diff --git a/src/lib/hb/c6_sca_a.asm b/src/lib/hb/c6_sca_a.asm
new file mode 100755 (executable)
index 0000000..74160c3
--- /dev/null
@@ -0,0 +1,153 @@
+; Catacomb Apocalypse Source Code\r
+; Copyright (C) 1993-2014 Flat Rock Software\r
+;\r
+; This program is free software; you can redistribute it and/or modify\r
+; it under the terms of the GNU General Public License as published by\r
+; the Free Software Foundation; either version 2 of the License, or\r
+; (at your option) any later version.\r
+;\r
+; This program is distributed in the hope that it will be useful,\r
+; but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+; GNU General Public License for more details.\r
+;\r
+; You should have received a copy of the GNU General Public License along\r
+; with this program; if not, write to the Free Software Foundation, Inc.,\r
+; 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+\r
+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/src/lib/hb/c6_scale.c b/src/lib/hb/c6_scale.c
new file mode 100755 (executable)
index 0000000..bb824ac
--- /dev/null
@@ -0,0 +1,697 @@
+/* Catacomb Apocalypse Source Code\r
+ * Copyright (C) 1993-2014 Flat Rock Software\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License along\r
+ * with this program; if not, write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+ */\r
+\r
+// C3_SCALE.C\r
+\r
+#include "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[NUMSCALEPICS];\r
+t_compscale _seg *scaledirectory[NUMSCALEPICS];\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>8 || 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
+\r
+       if (totalsize >= (PAGELEN*2))\r
+               Quit("BuildCompShape(): Shape is too complex!");\r
+\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
+       #define MAX_OBJ_SCALE (MAXSCALE)\r
+\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>MAX_OBJ_SCALE)\r
+               scale = MAX_OBJ_SCALE;\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/src/lib/hb/c6_state.c b/src/lib/hb/c6_state.c
new file mode 100755 (executable)
index 0000000..e17b77f
--- /dev/null
@@ -0,0 +1,736 @@
+/* Catacomb Apocalypse Source Code\r
+ * Copyright (C) 1993-2014 Flat Rock Software\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License along\r
+ * with this program; if not, write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+ */\r
+\r
+// C3_STATE.C\r
+\r
+#include "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 opposite[9] =\r
+       {south,west,north,east,southwest,northwest,northeast,southeast,nodir};\r
+\r
+\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= Internal_SpawnNewObj\r
+=\r
+===================\r
+*/\r
+void Internal_SpawnNewObj (unsigned x, unsigned y, statetype *state, unsigned size, boolean UseDummy, boolean PutInActorat)\r
+{\r
+       extern objtype dummyobj;\r
+\r
+       GetNewObj(UseDummy);\r
+       new->size = size;\r
+       new->state = state;\r
+       new->ticcount = random (state->tictime)+1;\r
+\r
+       new->tilex = x;\r
+       new->tiley = y;\r
+       new->x = ((long)x<<TILESHIFT)+TILEGLOBAL/2;\r
+       new->y = ((long)y<<TILESHIFT)+TILEGLOBAL/2;\r
+       CalcBounds(new);\r
+       new->dir = nodir;\r
+       new->active = noalways;\r
+\r
+       if (new != &dummyobj && PutInActorat)\r
+               actorat[new->tilex][new->tiley] = new;\r
+}\r
+\r
+void Internal_SpawnNewObjFrac (long x, long y, statetype *state, unsigned size,boolean UseDummy)\r
+{\r
+       GetNewObj(UseDummy);\r
+       new->size = size;\r
+       new->state = state;\r
+       new->ticcount = random (state->tictime)+1;\r
+       new->active = noalways;\r
+\r
+       new->x = x;\r
+       new->y = y;\r
+       new->tilex = x>>TILESHIFT;\r
+       new->tiley = y>>TILESHIFT;\r
+       CalcBounds(new);\r
+       new->distance = 100;\r
+       new->dir = nodir;\r
+}\r
+\r
+\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= CheckHandAttack\r
+=\r
+= If the object can move next to the player, it will return true\r
+=\r
+===================\r
+*/\r
+\r
+boolean CheckHandAttack (objtype *ob)\r
+{\r
+       long deltax,deltay,size;\r
+\r
+       size = (long)ob->size + player->size + ob->speed*tics + SIZE_TEST;\r
+       deltax = ob->x - player->x;\r
+       deltay = ob->y - player->y;\r
+\r
+       if (deltax > size || deltax < -size || deltay > size || deltay < -size)\r
+               return false;\r
+\r
+       return true;\r
+}\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= T_DoDamage\r
+=\r
+= Attacks the player if still nearby, then immediately changes to next state\r
+=\r
+===================\r
+*/\r
+\r
+void T_DoDamage (objtype *ob)\r
+{\r
+       int     points;\r
+\r
+\r
+       if (CheckHandAttack(ob) && (!(ob->flags & of_damagedone)))\r
+       {\r
+               points = 0;\r
+\r
+               switch (ob->obclass)\r
+               {\r
+               case aquamanobj:\r
+                       points = 7;\r
+               break;\r
+\r
+               case wizardobj:\r
+                       points = 7;\r
+               break;\r
+\r
+               case trollobj:\r
+                       points = 10;\r
+               break;\r
+\r
+               case invisdudeobj:\r
+                       points = 10;\r
+               break;\r
+\r
+               case demonobj:\r
+               case cyborgdemonobj:\r
+                       points = 15;\r
+               break;\r
+\r
+               }\r
+               points = EasyDoDamage(points);\r
+               TakeDamage (points);\r
+               ob->flags |= of_damagedone;\r
+       }\r
+}\r
+\r
+\r
+//==========================================================================\r
+\r
+/*\r
+==================================\r
+=\r
+= Walk\r
+=\r
+==================================\r
+*/\r
+\r
+boolean Walk (objtype *ob)\r
+{\r
+       switch (ob->dir)\r
+       {\r
+       case north:\r
+               if (actorat[ob->tilex][ob->tiley-1])\r
+                       return false;\r
+               ob->tiley--;\r
+               ob->distance = TILEGLOBAL;\r
+               return true;\r
+\r
+       case northeast:\r
+               if (actorat[ob->tilex+1][ob->tiley-1])\r
+                       return false;\r
+               ob->tilex++;\r
+               ob->tiley--;\r
+               ob->distance = TILEGLOBAL;\r
+               return true;\r
+\r
+       case east:\r
+               if (actorat[ob->tilex+1][ob->tiley])\r
+                       return false;\r
+               ob->tilex++;\r
+               ob->distance = TILEGLOBAL;\r
+               return true;\r
+\r
+       case southeast:\r
+               if (actorat[ob->tilex+1][ob->tiley+1])\r
+                       return false;\r
+               ob->tilex++;\r
+               ob->tiley++;\r
+               ob->distance = TILEGLOBAL;\r
+               return true;\r
+\r
+       case south:\r
+               if (actorat[ob->tilex][ob->tiley+1])\r
+                       return false;\r
+               ob->tiley++;\r
+               ob->distance = TILEGLOBAL;\r
+               return true;\r
+\r
+       case southwest:\r
+               if (actorat[ob->tilex-1][ob->tiley+1])\r
+                       return false;\r
+               ob->tilex--;\r
+               ob->tiley++;\r
+               ob->distance = TILEGLOBAL;\r
+               return true;\r
+\r
+       case west:\r
+               if (actorat[ob->tilex-1][ob->tiley])\r
+                       return false;\r
+               ob->tilex--;\r
+               ob->distance = TILEGLOBAL;\r
+               return true;\r
+\r
+       case northwest:\r
+               if (actorat[ob->tilex-1][ob->tiley-1])\r
+                       return false;\r
+               ob->tilex--;\r
+               ob->tiley--;\r
+               ob->distance = TILEGLOBAL;\r
+               return true;\r
+\r
+       case nodir:\r
+               return false;\r
+       }\r
+\r
+       Quit ("Walk: Bad dir");\r
+       return false;\r
+}\r
+\r
+\r
+\r
+/*\r
+==================================\r
+=\r
+= ChaseThink\r
+= have the current monster go after the player,\r
+= either diagonally or straight on\r
+=\r
+==================================\r
+*/\r
+\r
+void ChaseThink (objtype *obj, boolean diagonal)\r
+{\r
+       int deltax,deltay,i;\r
+       dirtype d[3];\r
+       dirtype tdir, olddir, turnaround;\r
+\r
+\r
+       olddir=obj->dir;\r
+       turnaround=opposite[olddir];\r
+\r
+       deltax=player->tilex - obj->tilex;\r
+       deltay=player->tiley - obj->tiley;\r
+\r
+       d[1]=nodir;\r
+       d[2]=nodir;\r
+\r
+       if (deltax>0)\r
+               d[1]= east;\r
+       if (deltax<0)\r
+               d[1]= west;\r
+       if (deltay>0)\r
+               d[2]=south;\r
+       if (deltay<0)\r
+               d[2]=north;\r
+\r
+       if (abs(deltay)>abs(deltax))\r
+       {\r
+               tdir=d[1];\r
+               d[1]=d[2];\r
+               d[2]=tdir;\r
+       }\r
+\r
+       if (d[1]==turnaround)\r
+               d[1]=nodir;\r
+       if (d[2]==turnaround)\r
+               d[2]=nodir;\r
+\r
+\r
+       if (diagonal)\r
+       {                           /*ramdiagonals try the best dir first*/\r
+               if (d[1]!=nodir)\r
+               {\r
+                       obj->dir=d[1];\r
+                       if (Walk(obj))\r
+                               return;     /*either moved forward or attacked*/\r
+               }\r
+\r
+               if (d[2]!=nodir)\r
+               {\r
+                       obj->dir=d[2];\r
+                       if (Walk(obj))\r
+                               return;\r
+               }\r
+       }\r
+       else\r
+       {                  /*ramstraights try the second best dir first*/\r
+\r
+               if (d[2]!=nodir)\r
+               {\r
+                       obj->dir=d[2];\r
+                       if (Walk(obj))\r
+                               return;\r
+               }\r
+\r
+               if (d[1]!=nodir)\r
+               {\r
+                       obj->dir=d[1];\r
+                       if (Walk(obj))\r
+                               return;\r
+               }\r
+       }\r
+\r
+       // Kluge to make the running eye stay in place if blocked, ie, not divert\r
+       // from path\r
+       if (obj->obclass == reyeobj)\r
+               return;\r
+\r
+\r
+/* there is no direct path to the player, so pick another direction */\r
+\r
+       obj->dir=olddir;\r
+       if (Walk(obj))\r
+               return;\r
+\r
+       if (US_RndT()>128)      /*randomly determine direction of search*/\r
+       {\r
+               for (tdir=north;tdir<=west;tdir++)\r
+               {\r
+                       if (tdir!=turnaround)\r
+                       {\r
+                               obj->dir=tdir;\r
+                               if (Walk(obj))\r
+                                       return;\r
+                       }\r
+               }\r
+       }\r
+       else\r
+       {\r
+               for (tdir=west;tdir>=north;tdir--)\r
+               {\r
+                       if (tdir!=turnaround)\r
+                       {\r
+                         obj->dir=tdir;\r
+                         if (Walk(obj))\r
+                               return;\r
+                       }\r
+               }\r
+       }\r
+\r
+       obj->dir=turnaround;\r
+       Walk(obj);              /*last chance, don't worry about returned value*/\r
+}\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= MoveObj\r
+=\r
+=================\r
+*/\r
+\r
+void MoveObj (objtype *ob, long move)\r
+{\r
+       ob->distance -=move;\r
+\r
+       switch (ob->dir)\r
+       {\r
+       case north:\r
+               ob->y -= move;\r
+               return;\r
+       case northeast:\r
+               ob->x += move;\r
+               ob->y -= move;\r
+               return;\r
+       case east:\r
+               ob->x += move;\r
+               return;\r
+       case southeast:\r
+               ob->x += move;\r
+               ob->y += move;\r
+               return;\r
+       case south:\r
+               ob->y += move;\r
+               return;\r
+       case southwest:\r
+               ob->x -= move;\r
+               ob->y += move;\r
+               return;\r
+       case west:\r
+               ob->x -= move;\r
+               return;\r
+       case northwest:\r
+               ob->x -= move;\r
+               ob->y -= move;\r
+               return;\r
+\r
+       case nodir:\r
+               return;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= Chase\r
+=\r
+= returns true if hand attack range\r
+=\r
+=================\r
+*/\r
+\r
+boolean Chase (objtype *ob, boolean diagonal)\r
+{\r
+       long move;\r
+       long deltax,deltay,size;\r
+\r
+       ob->flags &= ~of_damagedone;\r
+\r
+       move = ob->speed*tics;\r
+       size = (long)ob->size + player->size + move + SIZE_TEST;\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)\r
+               {\r
+                       CalcBounds (ob);\r
+                       return true;\r
+               }\r
+\r
+               if (move < ob->distance)                //ob->distance - distance before you move\r
+               {                             //               over into next tile\r
+                       MoveObj (ob,move);\r
+                       break;\r
+               }\r
+               else\r
+                       if (ob->obclass == reyeobj)     // Kludge for the "running eye"\r
+                       {\r
+                               if (ob->temp1 < 2)\r
+                               {\r
+                                       MoveObj(ob, ob->distance/2);\r
+                                       ob->temp1 = 0;\r
+                               }\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
+               ChaseThink (ob, diagonal);\r
+               if (!ob->distance)\r
+                       break;                  // no possible move\r
+               actorat[ob->tilex][ob->tiley] = ob;     // set down a new goal marker\r
+       }\r
+       CalcBounds (ob);\r
+       return false;\r
+}\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= ShootActor\r
+=\r
+===================\r
+*/\r
+\r
+void ShootActor (objtype *ob, unsigned damage)\r
+{\r
+\r
+       ob->hitpoints -= damage;\r
+\r
+       if (ob->hitpoints<=0)\r
+       {\r
+               switch (ob->obclass)\r
+               {\r
+\r
+               case headobj:\r
+                       ob->state = &s_pshot_exp1;\r
+                       ob->obclass = expobj;\r
+                       ob->ticcount = ob->state->tictime;\r
+                       SpawnBigExplosion(ob->x,ob->y,12,(16l<<16L));\r
+               break;\r
+\r
+               case aquamanobj:\r
+                       ob->state = &s_aqua_die1;\r
+                       ob->temp1 = 10;\r
+               break;\r
+\r
+               case wizardobj:\r
+                       ob->state = &s_wizard_die1;\r
+               break;\r
+\r
+               case trollobj:\r
+                       ob->state = &s_trolldie1;\r
+               break;\r
+\r
+               case blobobj:\r
+                       ob->state = &s_blob_die1;\r
+               break;\r
+\r
+               case rayobj:\r
+                       ob->state = &s_ray_die1;\r
+               break;\r
+\r
+               case ramboneobj:\r
+                       ob->state = &s_skel_die1;\r
+               break;\r
+\r
+               case fmageobj:\r
+                       ob->state = &s_fmagedie1;\r
+               break;\r
+\r
+               case robotankobj:\r
+                       ob->state = &s_robotank_death1;\r
+                       ob->temp1 = 10;\r
+               break;\r
+\r
+               case stompyobj:\r
+                       ob->state = &s_stompy_death1;\r
+               break;\r
+\r
+               case bugobj:\r
+                       ob->state = &s_bug_death1;\r
+               break;\r
+\r
+               case demonobj:\r
+                       ob->state = &s_demondie1;\r
+               break;\r
+\r
+               case cyborgdemonobj:\r
+                       ob->state = &s_cyborg_demondie1;\r
+               break;\r
+\r
+               case invisdudeobj:\r
+                       ob->state = &s_invis_death1;\r
+               break;\r
+\r
+               case grelmobj:\r
+                       ob->state = &s_greldie1;\r
+               break;\r
+\r
+               case eyeobj:\r
+                       ob->state = &s_eye_die1;\r
+               break;\r
+\r
+               case reyeobj:\r
+                       ob->state = &s_reye_die1;\r
+               break;\r
+\r
+               case bounceobj:\r
+                       ob->state = &s_pshot_exp1;\r
+                       ob->obclass = expobj;\r
+                       ob->ticcount = ob->state->tictime;\r
+                       SpawnBigExplosion(ob->x,ob->y,12,(16l<<16L));\r
+               break;\r
+\r
+               case rshotobj:\r
+               case eshotobj:\r
+               case wshotobj:\r
+               case hshotobj:\r
+               case bshotobj:\r
+               case rbshotobj:\r
+               case fmshotobj:\r
+               case rtshotobj:\r
+               case syshotobj:\r
+               case bgshotobj:\r
+                       ob->state = &s_bonus_die;\r
+#if USE_INERT_LIST\r
+                       ob->obclass = solidobj;         // don't add these objs to inert list\r
+#endif\r
+               break;\r
+\r
+               case bonusobj:\r
+               case freezeobj:\r
+                       switch (ob->temp1)\r
+                       {\r
+                               case B_POTION:\r
+                               case B_OLDCHEST:\r
+                               case B_CHEST:\r
+                               case B_NUKE:\r
+                               case B_BOLT:\r
+                                       ob->state = &s_pshot_exp1;\r
+                                       ob->obclass = expobj;\r
+                                       ob->ticcount = ob->state->tictime;\r
+                                       SpawnBigExplosion(ob->x,ob->y,12,(16l<<16L));\r
+                                       bordertime = FLASHTICS<<2;\r
+                                       bcolor = 14;\r
+                                       VW_ColorBorder(14 | 56);\r
+                                       DisplaySMsg("Item destroyed", NULL);\r
+                                       status_flag  = S_NONE;\r
+                                       status_delay = 80;\r
+                               break;\r
+                       }\r
+#if USE_INERT_LIST\r
+                       ob->obclass = solidobj;         // don't add this obj to inert list\r
+#endif\r
+               break;\r
+               }\r
+\r
+               if (ob->obclass != solidobj && ob->obclass != realsolidobj)\r
+               {\r
+                       ob->obclass = inertobj;\r
+                       ob->flags &= ~of_shootable;\r
+                       actorat[ob->tilex][ob->tiley] = NULL;\r
+#if USE_INERT_LIST\r
+                       MoveObjToInert(ob);\r
+#endif\r
+               }\r
+               else\r
+               {\r
+                       if (ob->flags & of_forcefield)\r
+                       {\r
+                               ob->state = &s_force_field_die;\r
+                               ob->flags &= ~of_shootable;\r
+                       }\r
+               }\r
+       }\r
+       else\r
+       {\r
+               switch (ob->obclass)\r
+               {\r
+               case wizardobj:\r
+                       ob->state = &s_wizard_ouch;\r
+               break;\r
+\r
+               case trollobj:\r
+                       if (!random(5))\r
+                               ob->state = &s_trollouch;\r
+                       else\r
+                               return;\r
+               break;\r
+\r
+               case blobobj:\r
+                       ob->state = &s_blob_ouch;\r
+               break;\r
+\r
+               case ramboneobj:\r
+                       ob->state = &s_skel_ouch;\r
+               break;\r
+\r
+               case fmageobj:\r
+                       ob->state = &s_fmageouch;\r
+               break;\r
+\r
+               case stompyobj:\r
+                       ob->state = &s_stompy_ouch;\r
+               break;\r
+\r
+               case bugobj:\r
+                       ob->state = &s_bug_ouch;\r
+               break;\r
+\r
+               case cyborgdemonobj:\r
+                       if (!(random(8)))\r
+                               ob->state = &s_cyborg_demonouch;\r
+                       else\r
+                               return;\r
+               break;\r
+\r
+               case demonobj:\r
+                       if (!(random(8)))\r
+                               ob->state = &s_demonouch;\r
+                       else\r
+                               return;\r
+               break;\r
+\r
+               case invisdudeobj:\r
+                       ob->state = &s_invis_fizz1;\r
+               break;\r
+\r
+               case grelmobj:\r
+                       ob->state = &s_grelouch;\r
+               break;\r
+\r
+               case eyeobj:\r
+                       ob->state = &s_eye_ouch;\r
+               break;\r
+\r
+               case reyeobj:\r
+                       ob->state = &s_reye_ouch;\r
+               break;\r
+               }\r
+       }\r
+\r
+       ob->ticcount = ob->state->tictime;\r
+}\r
+\r
+\r
diff --git a/src/lib/hb/c6_trace.c b/src/lib/hb/c6_trace.c
new file mode 100755 (executable)
index 0000000..82ace1c
--- /dev/null
@@ -0,0 +1,872 @@
+/* Catacomb Apocalypse Source Code\r
+ * Copyright (C) 1993-2014 Flat Rock Software\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License along\r
+ * with this program; if not, write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+ */\r
+\r
+// C3_TRACE.C\r
+\r
+#include "DEF.H"\r
+#pragma hdrstop\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+//\r
+// TESTWALLVISABLE will set the global variable wallvisable to 1 or 0\r
+// depending on if tile.x,tile.y,wallon is visable from focal point\r
+//\r
+#define TESTWALLVISABLE {                                              \\r
+       if (tile.y<focal.y)                         \\r
+               voffset = 0;                            \\r
+       else if (tile.y==focal.y)                   \\r
+               voffset = 3;                            \\r
+       else                                        \\r
+               voffset = 6;                            \\r
+       if (tile.x==focal.x)                        \\r
+               voffset ++;                             \\r
+       else if (tile.x>focal.x)                    \\r
+               voffset += 2;                           \\r
+       wallvisable = visable[voffset][wallon]; }\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                GLOBAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+boolean        aborttrace;\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+unsigned       wallvisable,voffset;\r
+\r
+\r
+fixed edgex,edgey;\r
+\r
+int wallon;\r
+int basecolor;\r
+\r
+walltype *oldwall;\r
+\r
+//\r
+// offsets from upper left corner of a tile to the left and right edges of\r
+// a given wall (NORTH-WEST)\r
+//\r
+fixed point1x[4] = {GLOBAL1,GLOBAL1,0      ,0       };\r
+fixed point1y[4] = {0      ,GLOBAL1,GLOBAL1,0       };\r
+\r
+fixed point2x[4] = {0      ,GLOBAL1,GLOBAL1,0       };\r
+fixed point2y[4] = {0     ,0      ,GLOBAL1 ,GLOBAL1};\r
+\r
+\r
+//\r
+// offset from tile.x,tile.y of the tile that shares wallon side\r
+// (side is not visable if it is shared)\r
+//\r
+int sharex[4] = { 0, 1, 0,-1};\r
+int sharey[4] = {-1, 0, 1, 0};\r
+\r
+//\r
+// amount to move tile.x,tile.y to follow wallon to another tile\r
+//\r
+int followx[4] = {-1, 0, 1, 0};\r
+int followy[4] = { 0,-1, 0, 1};\r
+\r
+//\r
+// cornerwall gives the wall on the same tile to start following when the\r
+// wall ends at an empty tile (go around an edge on same tile)\r
+// turnwall gives the wall on tile.x+sharex,tile.y+sharey to start following\r
+// when the wall hits another tile (right angle corner)\r
+//\r
+int cornerwall[4] = {WEST,NORTH,EAST,SOUTH};\r
+int turnwall[4] = {EAST,SOUTH,WEST,NORTH};\r
+\r
+//\r
+// wall visabilities in reletive locations\r
+// -,- 0,- +,-\r
+// -,0 0,0 +,0\r
+// -,+ 0,+ +,+\r
+//\r
+int visable[9][4] =\r
+{\r
+ {0,1,1,0}, {0,0,1,0}, {0,0,1,1},\r
+ {0,1,0,0}, {0,0,0,0}, {0,0,0,1},\r
+ {1,1,0,0}, {1,0,0,0}, {1,0,0,1}\r
+};\r
+\r
+int startwall[9] =  {2,2,3, 1,0,3, 1,0,0};\r
+int backupwall[9] = {3,3,0, 2,0,0, 2,1,1};\r
+\r
+\r
+int    walllength;\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                        FUNCTIONS\r
+\r
+=============================================================================\r
+*/\r
+\r
+/*\r
+========================\r
+=\r
+= FollowTrace\r
+=\r
+========================\r
+*/\r
+\r
+int FollowTrace (fixed tracex, fixed tracey, long deltax, long deltay, int max)\r
+{\r
+       int tx,ty,otx,oty;\r
+       long absdx,absdy,xstep,ystep;\r
+\r
+       tx = tracex>>TILESHIFT;\r
+       ty = tracey>>TILESHIFT;\r
+\r
+       spotvis[tx][ty] = true;\r
+\r
+       absdx=LABS(deltax);\r
+       absdy=LABS(deltay);\r
+\r
+       if (absdx>absdy)\r
+       {\r
+               ystep = (deltay<<8)/(absdx>>8);\r
+\r
+               if (!ystep)\r
+                       ystep = deltay>0 ? 1 : -1;\r
+\r
+               oty = (tracey+ystep)>>TILESHIFT;\r
+               if (deltax>0)\r
+               {\r
+//###############\r
+//\r
+// step x by +1\r
+//\r
+//###############\r
+                       do\r
+                       {\r
+                               tx++;\r
+                               spotvis[tx][ty] = true;\r
+                               tracey+=ystep;\r
+                               ty = tracey>>TILESHIFT;\r
+\r
+                               if (ty!=oty)\r
+                               {\r
+                                       if (tilemap[tx-1][ty])\r
+                                       {\r
+                                               tile.x = tx-1;\r
+                                               tile.y = ty;\r
+                                               return 1;\r
+                                       }\r
+                                       oty = ty;\r
+                               }\r
+                               if (tilemap[tx][ty])\r
+                               {\r
+                                       tile.x = tx;\r
+                                       tile.y = ty;\r
+                                       return 1;\r
+                               }\r
+                       } while (--max);\r
+                       return 0;\r
+               }\r
+               else\r
+               {\r
+//###############\r
+//\r
+// step x by -1\r
+//\r
+//###############\r
+                       do\r
+                       {\r
+                               tx--;\r
+                               spotvis[tx][ty] = true;\r
+                               tracey+=ystep;\r
+                               ty = tracey>>TILESHIFT;\r
+\r
+                               if (ty!=oty)\r
+                               {\r
+                                       if (tilemap[tx][oty])\r
+                                       {\r
+                                               tile.x = tx;\r
+                                               tile.y = oty;\r
+                                               return 1;\r
+                                       }\r
+                                       oty = ty;\r
+                               }\r
+                               if (tilemap[tx][ty])\r
+                               {\r
+                                       tile.x = tx;\r
+                                       tile.y = ty;\r
+                                       return 1;\r
+                               }\r
+                       } while (--max);\r
+                       return 0;\r
+\r
+               }\r
+       }\r
+       else\r
+       {\r
+               xstep = (deltax<<8)/(absdy>>8);\r
+               if (!xstep)\r
+                       xstep = deltax>0 ? 1 : -1;\r
+\r
+\r
+               otx = (tracex+xstep)>>TILESHIFT;\r
+               if (deltay>0)\r
+               {\r
+//###############\r
+//\r
+// step y by +1\r
+//\r
+//###############\r
+                       do\r
+                       {\r
+                               ty++;\r
+                               spotvis[tx][ty] = true;\r
+                               tracex+=xstep;\r
+                               tx = tracex>>TILESHIFT;\r
+\r
+                               if (tx!=otx)\r
+                               {\r
+                                       if (tilemap[tx][ty-1])\r
+                                       {\r
+                                               tile.x = tx;\r
+                                               tile.y = ty-1;\r
+                                               return 1;\r
+                                       }\r
+                                       otx = tx;\r
+                               }\r
+                               if (tilemap[tx][ty])\r
+                               {\r
+                                       tile.x = tx;\r
+                                       tile.y = ty;\r
+                                       return 1;\r
+                               }\r
+                       } while (--max);\r
+                       return 0;\r
+               }\r
+               else\r
+               {\r
+//###############\r
+//\r
+// step y by -1\r
+//\r
+//###############\r
+                       do\r
+                       {\r
+                               ty--;\r
+                               spotvis[tx][ty] = true;\r
+                               tracex+=xstep;\r
+                               tx = tracex>>TILESHIFT;\r
+\r
+                               if (tx!=otx)\r
+                               {\r
+                                       if (tilemap[otx][ty])\r
+                                       {\r
+                                               tile.x = otx;\r
+                                               tile.y = ty;\r
+                                               return 1;\r
+                                       }\r
+                                       otx = tx;\r
+                               }\r
+                               if (tilemap[tx][ty])\r
+                               {\r
+                                       tile.x = tx;\r
+                                       tile.y = ty;\r
+                                       return 1;\r
+                               }\r
+                       } while (--max);\r
+                       return 0;\r
+               }\r
+\r
+       }\r
+\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= BackTrace\r
+=\r
+= Traces backwards from edgex,edgey to viewx,viewy to see if a closer\r
+= tile obscures the given point.  If it does, it finishes the wall and\r
+= starts a new one.\r
+= Returns true if a tile is hit.\r
+= Call with a 1 to have it automatically finish the current wall\r
+=\r
+=================\r
+*/\r
+\r
+int BackTrace (int finish)\r
+{\r
+  fixed tracex,tracey;\r
+  long deltax,deltay,absdx,absdy;\r
+  int steps,otx,oty,testx,testheight,offset,wall;\r
+\r
+  deltax = viewx-edgex;\r
+  deltay = viewy-edgey;\r
+\r
+  absdx = LABS(deltax);\r
+  absdy = LABS(deltay);\r
+\r
+  if (absdx>absdy)\r
+    steps = ABS(focal.x-(edgex>>TILESHIFT))-1;\r
+  else\r
+    steps = ABS(focal.y-(edgey>>TILESHIFT))-1;\r
+\r
+  if (steps<=0)\r
+    return 0;\r
+\r
+  otx = tile.x;\r
+  oty = tile.y;\r
+  if (!FollowTrace(edgex,edgey,deltax,deltay,steps))\r
+    return 0;\r
+\r
+//\r
+// if the start wall is behind the focal point, the trace went too far back\r
+//\r
+  if (ABS(tile.x-focal.x)<2 && ABS(tile.y-focal.y)<2)  // too close\r
+  {\r
+    if (tile.x == focal.x && tile.y == focal.y)\r
+    {\r
+      tile.x = otx;\r
+      tile.y = oty;\r
+      return 0;\r
+    }\r
+\r
+    if (tile.x<focal.x)\r
+    {\r
+      if (tile.y<focal.y)\r
+       wall = SOUTH;\r
+      else\r
+       wall = EAST;\r
+    }\r
+    else if (tile.x==focal.x)\r
+    {\r
+         if (tile.y<focal.y)\r
+       wall = SOUTH;\r
+      else\r
+       wall = NORTH;\r
+    }\r
+    else\r
+       {\r
+      if (tile.y<=focal.y)\r
+       wall = WEST;\r
+      else\r
+       wall = NORTH;\r
+    }\r
+\r
+    //\r
+    // rotate the X value to see if it is behind the view plane\r
+    //\r
+    if (TransformX (((long)tile.x<<16)+point1x[wall],\r
+                   ((long)tile.y<<16)+point1y[wall]) < FOCALLENGTH)\r
+    {\r
+      tile.x = otx;\r
+      tile.y = oty;\r
+      return 0;\r
+    }\r
+  }\r
+\r
+//\r
+// if the old wall is still behind a closer wall, ignore the back trace\r
+// and continue on (dealing with limited precision...)\r
+//\r
+  if (finish && !FinishWall ())        // the wall is still behind a forward wall\r
+  {\r
+    tile.x = otx;\r
+    tile.y = oty;\r
+    rightwall->x1 = oldwall->x2;               // common edge with last wall\r
+    rightwall->height1 = oldwall->height2;\r
+    return 0;\r
+  }\r
+\r
+\r
+//\r
+// back up along the intersecting face to find the rightmost wall\r
+//\r
+\r
+  if (tile.y<focal.y)\r
+    offset = 0;\r
+  else if (tile.y==focal.y)\r
+    offset = 3;\r
+  else\r
+    offset = 6;\r
+  if (tile.x==focal.x)\r
+    offset ++;\r
+  else if (tile.x>focal.x)\r
+    offset += 2;\r
+\r
+  wallon = backupwall[offset];\r
+\r
+  while (tilemap[tile.x][tile.y])\r
+  {\r
+    tile.x += followx[wallon];\r
+    tile.y += followy[wallon];\r
+  };\r
+\r
+  tile.x -= followx[wallon];\r
+  tile.y -= followy[wallon];\r
+\r
+  wallon = cornerwall[wallon]; // turn to first visable face\r
+\r
+  edgex = ((long)tile.x<<16);\r
+  edgey = ((long)tile.y<<16);\r
+\r
+  TransformPoint (edgex+point1x[wallon],edgey+point1y[wallon],\r
+    &rightwall->x1,&rightwall->height1);\r
+\r
+  basecolor = tilemap[tile.x][tile.y];\r
+\r
+  return 1;\r
+}\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= ForwardTrace\r
+=\r
+= Traces forwards from edgex,edgey along the line from viewx,viewy until\r
+= a solid tile is hit.  Sets tile.x,tile.y\r
+=\r
+=================\r
+*/\r
+\r
+void ForwardTrace (void)\r
+{\r
+  int offset;\r
+  fixed tracex,tracey;\r
+  long deltax,deltay;\r
+\r
+  deltax = edgex-viewx;\r
+  deltay = edgey-viewy;\r
+\r
+  FollowTrace(edgex,edgey,deltax,deltay,0);\r
+\r
+  if (tile.y<focal.y)\r
+    offset = 0;\r
+  else if (tile.y==focal.y)\r
+    offset = 3;\r
+  else\r
+    offset = 6;\r
+  if (tile.x==focal.x)\r
+    offset ++;\r
+  else if (tile.x>focal.x)\r
+    offset += 2;\r
+\r
+  wallon = startwall[offset];\r
+\r
+//\r
+// start the new wall\r
+//\r
+  edgex = ((long)tile.x<<16);\r
+  edgey = ((long)tile.y<<16);\r
+\r
+//\r
+// if entire first wall is invisable, corner\r
+//\r
+  TransformPoint (edgex+point2x[wallon],edgey+point2y[wallon],\r
+    &rightwall->x2,&rightwall->height2);\r
+\r
+  if (tilemap [tile.x+sharex[wallon]] [tile.y+sharey[wallon]]\r
+  || rightwall->x2 < (rightwall-1)->x2 )\r
+    wallon = cornerwall [wallon];\r
+\r
+//\r
+// transform first point\r
+//\r
+\r
+  TransformPoint (edgex+point1x[wallon],edgey+point1y[wallon],\r
+    &rightwall->x1,&rightwall->height1);\r
+\r
+  basecolor = tilemap[tile.x][tile.y];\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= FinishWall\r
+=\r
+= Transforms edgex,edgey as the next point of the current wall\r
+= and sticks it in the wall list\r
+=\r
+=================\r
+*/\r
+\r
+int FinishWall (void)\r
+{\r
+  char num[20];\r
+\r
+  oldwall = rightwall;\r
+\r
+       rightwall->color  = basecolor;\r
+\r
+  TransformPoint (edgex,edgey,&rightwall->x2,&rightwall->height2);\r
+\r
+  if (rightwall->x2 <= (rightwall-1)->x2+2\r
+  && rightwall->height2 < (rightwall-1)->height2 )\r
+       return 0;\r
+\r
+  rightwall->walllength = walllength;\r
+\r
+  switch (wallon)\r
+  {\r
+  case north:\r
+  case south:\r
+         rightwall->side = 0;\r
+         rightwall->planecoord = edgey;\r
+         break;\r
+\r
+  case west:\r
+  case east:\r
+         rightwall->side = 1;\r
+         rightwall->planecoord = edgex;\r
+         break;\r
+  }\r
+\r
+  walllength = 1;\r
+\r
+  rightwall++;\r
+\r
+  return 1;\r
+}\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= InsideCorner\r
+=\r
+=================\r
+*/\r
+\r
+void InsideCorner (void)\r
+{\r
+  int offset;\r
+\r
+  //\r
+  // the wall turned -90 degrees, so draw what we have, move to the new tile,\r
+  // change wallon, change color, and continue following.\r
+  //\r
+  FinishWall ();\r
+\r
+  tile.x += sharex[wallon];\r
+  tile.y += sharey[wallon];\r
+\r
+  wallon = turnwall[wallon];\r
+\r
+  //\r
+  // if the new wall is visable, continue following it.  Otherwise\r
+  // follow it backwards until it turns\r
+  //\r
+  TESTWALLVISABLE;\r
+\r
+  if (wallvisable)\r
+  {\r
+  //\r
+  // just turn to the next wall and continue\r
+  //\r
+    rightwall->x1 = oldwall->x2;               // common edge with last wall\r
+    rightwall->height1 = oldwall->height2;\r
+    basecolor = tilemap[tile.x][tile.y];\r
+    return;                    // continue from here\r
+  }\r
+\r
+  //\r
+  // back follow the invisable wall until it turns, then follow that\r
+  //\r
+  do\r
+  {\r
+       tile.x += followx[wallon];\r
+    tile.y += followy[wallon];\r
+  } while (tilemap[tile.x][tile.y]);\r
+\r
+  tile.x -= followx[wallon];\r
+  tile.y -= followy[wallon];\r
+\r
+  wallon = cornerwall[wallon]; // turn to first visable face\r
+\r
+  edgex = ((long)tile.x<<16)+point1x[wallon];\r
+  edgey = ((long)tile.y<<16)+point1y[wallon];\r
+\r
+  if (!BackTrace(0))           // backtrace without finishing a wall\r
+  {\r
+    TransformPoint (edgex,edgey,&rightwall->x1,&rightwall->height1);\r
+    basecolor = tilemap[tile.x][tile.y];\r
+  }\r
+}\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= OutsideCorner\r
+=\r
+=================\r
+*/\r
+\r
+void OutsideCorner (void)\r
+{\r
+  int offset;\r
+\r
+  //\r
+  // edge is the outside edge of a corner, so draw the current wall and\r
+  // turn the corner (+90 degrees)\r
+  //\r
+  FinishWall ();\r
+\r
+  tile.x -= followx[wallon];   // backup to the real tile\r
+  tile.y -= followy[wallon];\r
+  wallon = cornerwall[wallon];\r
+\r
+  //\r
+  // if the new wall is visable, continue following it.  Otherwise\r
+  // trace a ray from the corner to find a wall in the distance to\r
+  // follow\r
+  //\r
+  TESTWALLVISABLE;\r
+\r
+  if (wallvisable)\r
+  {\r
+  //\r
+  // the new wall is visable, so just continue on\r
+  //\r
+    rightwall->x1 = oldwall->x2;               // common edge with last wall\r
+    rightwall->height1 = oldwall->height2;\r
+    return;                    // still on same tile, so color is ok\r
+  }\r
+\r
+//\r
+// start from a new tile further away\r
+//\r
+  ForwardTrace();              // find the next wall further back\r
+\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= FollowWalls\r
+=\r
+= Starts a wall edge at the leftmost edge of tile.x,tile.y and follows it\r
+= until something else is seen or the entire view area is covered\r
+=\r
+=================\r
+*/\r
+\r
+void FollowWalls (void)\r
+{\r
+  int height,newcolor,offset,wall;\r
+\r
+//####################\r
+//\r
+// figure leftmost wall of new tile\r
+//\r
+//####################\r
+\r
+restart:\r
+\r
+  walllength = 1;\r
+\r
+  if (tile.y<focal.y)\r
+       offset = 0;\r
+  else if (tile.y==focal.y)\r
+       offset = 3;\r
+  else\r
+       offset = 6;\r
+  if (tile.x==focal.x)\r
+       offset ++;\r
+  else if (tile.x>focal.x)\r
+       offset += 2;\r
+\r
+  wallon = startwall[offset];\r
+\r
+//\r
+// if the start wall is inside a block, skip it by cornering to the second wall\r
+//\r
+  if ( tilemap [tile.x+sharex[wallon]] [tile.y+sharey[wallon]])\r
+       wallon = cornerwall [wallon];\r
+\r
+//\r
+// transform first edge to screen coordinates\r
+//\r
+  edgex = ((long)tile.x<<16);\r
+  edgey = ((long)tile.y<<16);\r
+\r
+  TransformPoint (edgex+point1x[wallon],edgey+point1y[wallon],\r
+       &rightwall->x1,&rightwall->height1);\r
+\r
+  basecolor = tilemap[tile.x][tile.y];\r
+\r
+//##################\r
+//\r
+// follow the wall as long as possible\r
+//\r
+//##################\r
+\r
+advance:\r
+\r
+  do   // while ( tile.x != right.x || tile.y != right.y)\r
+  {\r
+//\r
+// check for conditions that shouldn't happed...\r
+//\r
+       if (rightwall->x1 > VIEWXH)     // somehow missed right tile...\r
+         return;\r
+\r
+       if (rightwall == &walls[DANGERHIGH])\r
+       {\r
+  //\r
+  // somethiing got messed up!  Correct by thrusting ahead...\r
+  //\r
+//             VW_ColorBorder(6);\r
+               bordertime = 60;\r
+               Thrust(player->angle,TILEGLOBAL/4);\r
+               player->angle+=5;\r
+               if (player->angle>ANGLES)\r
+                       player->angle-=ANGLES;\r
+               aborttrace = true;\r
+               return;\r
+\r
+#if 0\r
+         strcpy (str,"Wall list overflow at LE:");\r
+         itoa(mapon+1,str2,10);\r
+         strcat (str,str2);\r
+         strcat (str," X:");\r
+         ltoa(objlist[0].x,str2,10);\r
+         strcat (str,str2);\r
+         strcat (str," Y:");\r
+         ltoa(objlist[0].y,str2,10);\r
+         strcat (str,str2);\r
+         strcat (str," AN:");\r
+         itoa(objlist[0].angle,str2,10);\r
+         strcat (str,str2);\r
+\r
+         Quit (str);\r
+#endif\r
+       }\r
+\r
+//\r
+// proceed along wall\r
+//\r
+\r
+       edgex = ((long)tile.x<<16)+point2x[wallon];\r
+       edgey = ((long)tile.y<<16)+point2y[wallon];\r
+\r
+       if (BackTrace(1))               // went behind a closer wall\r
+         continue;\r
+\r
+       //\r
+       // advance to next tile along wall\r
+       //\r
+       tile.x += followx[wallon];\r
+       tile.y += followy[wallon];\r
+\r
+       if (tilemap [tile.x+sharex[wallon]] [tile.y+sharey[wallon]])\r
+       {\r
+         InsideCorner ();              // turn at a corner\r
+         continue;\r
+       }\r
+\r
+       newcolor = tilemap[tile.x][tile.y];\r
+\r
+       if (!newcolor)          // turn around an edge\r
+       {\r
+         OutsideCorner ();\r
+         continue;\r
+       }\r
+\r
+       if (newcolor != basecolor)\r
+       {\r
+         //\r
+         // wall changed color, so draw what we have and continue following\r
+         //\r
+         FinishWall ();\r
+         rightwall->x1 = oldwall->x2;  // new wall shares this edge\r
+         rightwall->height1 = oldwall->height2;\r
+         basecolor = newcolor;\r
+\r
+         continue;\r
+       }\r
+       walllength++;\r
+  } while (tile.x != right.x || tile.y != right.y);\r
+\r
+\r
+\r
+//######################\r
+//\r
+// draw the last tile\r
+//\r
+//######################\r
+\r
+  edgex = ((long)tile.x<<16)+point2x[wallon];\r
+  edgey = ((long)tile.y<<16)+point2y[wallon];\r
+  FinishWall();\r
+\r
+  wallon = cornerwall[wallon];\r
+\r
+  //\r
+  // if the corner wall is visable, draw it\r
+  //\r
+  TESTWALLVISABLE;\r
+\r
+  if (wallvisable)\r
+  {\r
+    rightwall->x1 = oldwall->x2;               // common edge with last wall\r
+    rightwall->height1 = oldwall->height2;\r
+    edgex = ((long)tile.x<<16)+point2x[wallon];\r
+    edgey = ((long)tile.y<<16)+point2y[wallon];\r
+    FinishWall();\r
+  }\r
+\r
+}\r
+\r
+//===========================================================================\r
diff --git a/src/lib/hb/c6_wiz.c b/src/lib/hb/c6_wiz.c
new file mode 100755 (executable)
index 0000000..571ae3f
--- /dev/null
@@ -0,0 +1,3349 @@
+/* Catacomb Apocalypse Source Code\r
+ * Copyright (C) 1993-2014 Flat Rock Software\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License along\r
+ * with this program; if not, write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+ */\r
+\r
+// C3_WIZ.C\r
+\r
+#include "DEF.H"\r
+#include "gelib.h"\r
+#pragma hdrstop\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+////////#define NUMSCROLLS     8\r
+\r
+#define        SHOWITEMS               9\r
+\r
+#define NUKETIME                       40\r
+#define NUMBOLTS                       10\r
+#define BOLTTICS                       6\r
+\r
+#define STATUSCOLOR            1\r
+#define TEXTCOLOR                      14\r
+\r
+#define SIDEBARWIDTH           5\r
+\r
+#define BODYLINE                       8\r
+#define POWERLINE                      80\r
+\r
+#define SPECTILESTART  0                       // 18\r
+\r
+\r
+#define SHOTDAMAGE             1\r
+#define BIGSHOTDAMAGE  3\r
+\r
+\r
+#define PLAYERSPEED            5120\r
+#define RUNSPEED                       (8192<<1)\r
+\r
+#define SHOTSPEED                      10000\r
+\r
+//#define LASTWALLTILE         47\r
+//#define LASTSPECIALTILE      37\r
+\r
+#define LASTTILE               (LASTWALLPIC-FIRSTWALLPIC)                                                      // 47\r
+\r
+#define FIRETIME               2\r
+\r
+#define HANDPAUSE              30\r
+\r
+#define        RIGHTEDGE       205;\r
+#define        LEFTEDGE        95;\r
+#define        PRNY                    32;\r
+#define        WINX                    10;\r
+#define        WINY            32;\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                GLOBAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+long           lastnuke,lasthand;\r
+int                    lasttext;\r
+int                    handheight;\r
+int                    boltsleft,bolttimer;\r
+short RadarXY[MAX_RADAR_BLIPS][3]={-1,-1,-1};\r
+short radarx=RADARX,radary=RADARY,radar_xcenter=RADAR_XCENTER,radar_ycenter=RADAR_YCENTER;\r
+int key_x[4]={24,27,27,24},key_y[4]={30,57,30,57};\r
+\r
+boolean redraw_gems,button0down;\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+int                    lastradar;\r
+unsigned       lastfiretime;\r
+\r
+int    strafeangle[9] = {0,90,180,270,45,135,225,315,0};\r
+\r
+short RotateAngle = -1;                                // -1 == No Angle to turn to...\r
+short FreezeTime = 0;                          // Stops all think (except player)\r
+short RotateSpeed;                                     // Speed (and dir) to rotate..\r
+\r
+\r
+//===========================================================================\r
+\r
+void CalcBounds(objtype *ob);\r
+boolean VerifyGateExit(void);\r
+void DrawNSEWIcons(void);\r
+void DrawGems(void);\r
+void DrawRadar (void);\r
+void DrawChar (unsigned x, unsigned y, unsigned tile);\r
+void RedrawStatusWindow (void);\r
+void GiveBolt (void);\r
+void TakeBolt (void);\r
+void GiveNuke (void);\r
+void TakeNuke (void);\r
+void GivePotion (void);\r
+void TakePotion (void);\r
+void GiveKey (int keytype);\r
+void TakeKey (int keytype);\r
+////////////void GiveScroll (int scrolltype,boolean show);\r
+////////////void ReadScroll (int scroll);\r
+////////////void DrawScrolls(void);\r
+\r
+void DrawNum(short x,short y,short value,short maxdigits);\r
+\r
+//----------\r
+\r
+void Shoot (void);\r
+void BigShoot (void);\r
+void CastBolt (void);\r
+void CastNuke (void);\r
+void DrinkPotion (void);\r
+\r
+//----------\r
+void DrawHealth(void);\r
+\r
+void SpawnPlayer (int tilex, int tiley, int dir);\r
+void Thrust (int angle, unsigned speed);\r
+void T_Player (objtype *ob);\r
+\r
+//void AddPoints (int points);\r
+\r
+void ClipMove (objtype *ob, long xmove, long ymove);\r
+boolean ShotClipMove (objtype *ob, long xmove, long ymove);\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= DrawChar\r
+=\r
+===============\r
+*/\r
+\r
+void DrawChar (unsigned x, unsigned y, unsigned tile)\r
+{\r
+       unsigned junk = latchpics[0];\r
+\r
+       EGAWRITEMODE(1);\r
+asm    mov     bx,[y]\r
+asm    shl     bx,1\r
+asm    mov     di,[WORD PTR ylookup+bx]\r
+asm    add     di,[x]\r
+asm    mov     si,[tile]\r
+asm    shl     si,1\r
+asm    shl     si,1\r
+asm    shl     si,1\r
+asm    add     si,[junk]               // the damn inline assembler won't reference latchpics\r
+asm    mov     ax,[screenseg]\r
+asm    mov     es,ax\r
+asm    mov     ds,ax\r
+asm    mov     dx,SCREENWIDTH-1\r
+asm    movsb\r
+asm    add     di,dx\r
+asm    movsb\r
+asm    add     di,dx\r
+asm    movsb\r
+asm    add     di,dx\r
+asm    movsb\r
+asm    add     di,dx\r
+asm    movsb\r
+asm    add     di,dx\r
+asm    movsb\r
+asm    add     di,dx\r
+asm    movsb\r
+asm    add     di,dx\r
+asm    movsb\r
+\r
+asm    mov     ax,ss\r
+asm    mov     ds,ax\r
+       EGAWRITEMODE(0);\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= RedrawStatusWindow\r
+=\r
+===============\r
+*/\r
+\r
+void RedrawStatusWindow (void)\r
+{\r
+       short keytype;\r
+\r
+       EGABITMASK(0xff);\r
+       for (keytype=0; keytype<4; keytype++)\r
+               DrawNum(key_x[keytype],key_y[keytype],gamestate.keys[keytype],2);\r
+       DrawNum(20,54,gamestate.potions,2);\r
+       DrawNum(20,36,gamestate.nukes,2);\r
+       DrawNum(20,18,gamestate.bolts,2);\r
+\r
+       DrawHealth();\r
+       DrawRadar();\r
+       EGAWRITEMODE(0);\r
+       DrawGems();\r
+////////       DrawScrolls();\r
+       redraw_gems = false;\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= GiveBolt\r
+=\r
+===============\r
+*/\r
+\r
+void GiveBolt (void)\r
+{\r
+       if (gamestate.bolts == 99)\r
+               return;\r
+\r
+       SD_PlaySound (GETBOLTSND);\r
+       DrawNum(20,18,++gamestate.bolts,2);\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= TakeBolt\r
+=\r
+===============\r
+*/\r
+\r
+void TakeBolt (void)\r
+{\r
+       SD_PlaySound (USEBOLTSND);\r
+       DrawNum(20,18,--gamestate.bolts,2);\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= GiveNuke\r
+=\r
+===============\r
+*/\r
+\r
+void GiveNuke (void)\r
+{\r
+       if (gamestate.nukes == 99)\r
+               return;\r
+\r
+       SD_PlaySound (GETNUKESND);\r
+       DrawNum(20,36,++gamestate.nukes,2);\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= TakeNuke\r
+=\r
+===============\r
+*/\r
+\r
+void TakeNuke (void)\r
+{\r
+       SD_PlaySound (USENUKESND);\r
+       DrawNum(20,36,--gamestate.nukes,2);\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= GivePotion\r
+=\r
+===============\r
+*/\r
+\r
+void GivePotion (void)\r
+{\r
+       if (gamestate.potions == 99)\r
+               return;\r
+\r
+       SD_PlaySound (GETPOTIONSND);\r
+       DrawNum(20,54,++gamestate.potions,2);\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= TakePotion\r
+=\r
+===============\r
+*/\r
+\r
+void TakePotion (void)\r
+{\r
+       SD_PlaySound (USEPOTIONSND);\r
+       DrawNum(20,54,--gamestate.potions,2);\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= GiveKey\r
+=\r
+===============\r
+*/\r
+\r
+void GiveKey (int keytype)\r
+{\r
+       int     i,j,x;\r
+\r
+       if (gamestate.keys[keytype] == 99)\r
+               return;\r
+\r
+       SD_PlaySound (GETKEYSND);\r
+       DrawNum(key_x[keytype],key_y[keytype],++gamestate.keys[keytype],2);\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= TakeKey\r
+=\r
+===============\r
+*/\r
+\r
+void TakeKey (int keytype)\r
+{\r
+       int     i,j,x;\r
+       char *key_colors[] = {"a RED key",\r
+                                                                "a YELLOW key",\r
+                                                                "a GREEN key",\r
+                                                                "a BLUE key"};\r
+\r
+\r
+       SD_PlaySound (USEKEYSND);\r
+       DrawNum(key_x[keytype],key_y[keytype],--gamestate.keys[keytype],2);\r
+       displayofs = bufferofs = screenloc[screenpage];\r
+       CenterWindow(20,5);\r
+       US_CPrint("\nYou use\n");\r
+       US_CPrint(key_colors[keytype]);\r
+       VW_UpdateScreen();\r
+       VW_WaitVBL(120);\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= GiveGem\r
+=\r
+===============\r
+*/\r
+\r
+void GiveGem (int gemtype)\r
+{\r
+#if 0\r
+       int     i,j,x;\r
+\r
+       SD_PlaySound (GETKEYSND);\r
+       DrawNum(key_x[keytype],key_y[keytype],++gamestate.keys[keytype],2);\r
+#endif\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= TakeGem\r
+=\r
+===============\r
+*/\r
+\r
+void TakeGem (int gemtype)\r
+{\r
+#if 0\r
+       int     i,j,x;\r
+\r
+       SD_PlaySound (USEKEYSND);\r
+       DrawNum(key_x[keytype],key_y[keytype],--gamestate.keys[keytype],2);\r
+#endif\r
+}\r
+\r
+/*\r
+===============\r
+=\r
+= DrawGem\r
+=\r
+===============\r
+*/\r
+\r
+void DrawGems()\r
+{\r
+       short loop;\r
+\r
+       redraw_gems = false;\r
+\r
+       bufferofs = 0;\r
+       LatchDrawPic (31,51,RADAR_BOTTOMPIC);\r
+       for (loop=0; loop<5; loop++)\r
+               if (gamestate.gems[loop])\r
+                       LatchDrawPic (32+loop,53,RADAR_RGEMPIC+loop);\r
+}\r
+\r
+//===========================================================================\r
+\r
+#if 0\r
+\r
+/*\r
+===============\r
+=\r
+= GiveScroll\r
+=\r
+===============\r
+*/\r
+\r
+void GiveScroll (int scrolltype,boolean show)\r
+{\r
+       int     i,j,x,y,scrollnum;\r
+\r
+       SD_PlaySound (GETSCROLLSND);\r
+       gamestate.scrolls[scrolltype] = true;\r
+\r
+       y = 30 + ((scrolltype > 3) * 10);\r
+       x = 26 + (scrolltype % 4);\r
+       DrawChar(x,y,SCROLLCHARS+scrolltype);\r
+\r
+       if (show)\r
+               ReadScroll(scrolltype);\r
+}\r
+\r
+/*\r
+===============\r
+=\r
+= DrawScrolls\r
+=\r
+= Force draw of all scrolls\r
+=\r
+===============\r
+*/\r
+void DrawScrolls()\r
+{\r
+       int loop,x,y;\r
+\r
+       VW_Bar(210,30,30,18,0xf);\r
+\r
+       for (loop=0;loop<8;loop++)\r
+               if (gamestate.scrolls[loop])\r
+               {\r
+                       y = 30 + ((loop > 3) * 10);\r
+                       x = 26 + (loop % 4);\r
+                       DrawChar(x,y,SCROLLCHARS+loop);\r
+               }\r
+}\r
+#endif\r
+\r
+\r
+//===========================================================================\r
+\r
+#if 0\r
+/*\r
+===============\r
+=\r
+= GivePoints\r
+=\r
+===============\r
+*/\r
+\r
+void GivePoints (int points)\r
+{\r
+       pointcount = 1;\r
+       pointsleft += points;\r
+}\r
+#endif\r
+\r
+\r
+//===========================================================================\r
+\r
+#if 0\r
+/*\r
+===============\r
+=\r
+= AddPoints\r
+=\r
+===============\r
+*/\r
+\r
+void AddPoints (int points)\r
+{\r
+       char    str[10];\r
+       int             len,x,i;\r
+\r
+       gamestate.score += points;\r
+\r
+       ltoa (gamestate.score,str,10);\r
+       len = strlen (str);\r
+\r
+       x=24+(8-len);\r
+       for (i=0;i<len;i++)\r
+               DrawChar(x++,40,NUMBERCHARS+str[i]-'0');\r
+}\r
+#endif\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= DrawHealth\r
+=\r
+===============\r
+*/\r
+void DrawHealth()\r
+{\r
+       char picnum;\r
+       int percentage;\r
+\r
+       percentage = PERCENTAGE(100,MAXBODY,gamestate.body,9);\r
+\r
+       DrawNum(11,57,percentage,3);\r
+\r
+       if (percentage > 75)\r
+               picnum = FACE1PIC;\r
+       else\r
+       if (percentage > 50)\r
+               picnum = FACE2PIC;\r
+       else\r
+       if (percentage > 25)\r
+               picnum = FACE3PIC;\r
+       else\r
+       if (percentage)\r
+               picnum = FACE4PIC;\r
+       else\r
+       {\r
+               picnum = FACE5PIC;\r
+               CA_CacheGrChunk (picnum);\r
+       }\r
+\r
+       bufferofs = 0;\r
+       if (!percentage)\r
+       {\r
+               UNMARKGRCHUNK(picnum);\r
+//             VW_DrawPic(8,14,picnum);\r
+               VW_DrawPic(10,14,picnum);\r
+       }\r
+       else\r
+               LatchDrawPic(10,14,picnum);\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= DrawFreezeTime\r
+=\r
+===============\r
+*/\r
+void DrawFreezeTime()\r
+{\r
+       short temp =  fontcolor;\r
+       long percentage;\r
+       percentage = PERCENTAGE(100,MAXFREEZETIME,(long)FreezeTime,7);\r
+       fontcolor = 1 ^ 14;\r
+       DrawNum(23,70,percentage,3);\r
+       fontcolor = temp;\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= DrawNum\r
+=\r
+===============\r
+*/\r
+void DrawNum(short x,short y,short value,short maxdigits)\r
+{\r
+       char str[10],len,i;\r
+\r
+       itoa(value,str,10);\r
+       len=strlen(str);\r
+\r
+       for (i=len; i<maxdigits; i++)\r
+               DrawChar(x++,y,BLANKCHAR);\r
+\r
+       for (i=0;i<len;i++)\r
+               DrawChar(x++,y,NUMBERCHARS+str[i]-'0');\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= GiveChest\r
+=\r
+===============\r
+*/\r
+\r
+void GiveChest(void)\r
+{\r
+       char i;\r
+\r
+       for (i=0;i<random(4);i++)\r
+       {\r
+               GiveBolt();\r
+               SD_WaitSoundDone();\r
+       }\r
+\r
+       for (i=0;i<random(3);i++)\r
+       {\r
+               GiveNuke();\r
+               SD_WaitSoundDone();\r
+       }\r
+\r
+       for (i=0;i<random(2);i++)\r
+       {\r
+               GivePotion();\r
+               SD_WaitSoundDone();\r
+       }\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= GiveGoal\r
+=\r
+===============\r
+*/\r
+\r
+void GiveGoal (void)\r
+{\r
+       SD_PlaySound (GETPOINTSSND);\r
+       playstate = ex_victorious;\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+#if 0\r
+/*\r
+===============\r
+=\r
+= DrawLevelNumber\r
+=\r
+===============\r
+*/\r
+\r
+void DrawLevelNumber (int number)\r
+{\r
+       char    str[10];\r
+       int             len;\r
+       unsigned        temp;\r
+\r
+       bufferofs = 0;\r
+       if (number<9)\r
+               PrintX=13;\r
+       else\r
+               PrintX = 5;\r
+       PrintY = 4;\r
+       VW_Bar (5,4,16,9,STATUSCOLOR);\r
+       temp = fontcolor;\r
+       fontcolor = TEXTCOLOR^STATUSCOLOR;\r
+       US_PrintUnsigned (number+1);\r
+       fontcolor = temp;\r
+}\r
+#endif\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= DrawText\r
+=\r
+===============\r
+*/\r
+\r
+void DrawText (boolean draw_text_whether_it_needs_it_or_not)\r
+{\r
+       unsigned        number;\r
+       char            str[80];\r
+       char            far *text;\r
+       unsigned        temp;\r
+\r
+       //\r
+       // draw a new text description if needed\r
+       //\r
+       number = *(mapsegs[0]+farmapylookup[player->tiley]+player->tilex)-NAMESTART;\r
+\r
+       if ( number>26 )\r
+               number = 0;\r
+\r
+       if ((number == lasttext) && (!draw_text_whether_it_needs_it_or_not))\r
+               return;\r
+\r
+       lasttext = number;\r
+\r
+       text = (char _seg *)grsegs[LEVEL1TEXT+mapon]+textstarts[number];\r
+\r
+       if (text[0] == '@')\r
+       {\r
+               bordertime = 20;//FLASHTICS;\r
+               bcolor = 15;\r
+               VW_ColorBorder (15 | 56);\r
+               text++;\r
+       }\r
+\r
+       _fmemcpy (str,text,80);\r
+       DisplayMsg(str,NULL);\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= DisplayMsg\r
+=\r
+===============\r
+*/\r
+\r
+char DisplayMsg(char *text,char *choices)\r
+{\r
+       char ch=true;\r
+       short temp;\r
+\r
+       bufferofs = 0;\r
+       PrintY = 1;\r
+       WindowX = 20;\r
+       WindowW = 270;\r
+\r
+       VW_Bar (WindowX,2,WindowW,8,STATUSCOLOR);\r
+       temp = fontcolor;\r
+       fontcolor = TEXTCOLOR^STATUSCOLOR;\r
+       US_CPrintLine (text);\r
+       fontcolor = temp;\r
+\r
+       if (choices)\r
+       {\r
+               ch=GetKeyChoice(choices,true);\r
+               LastScan = 0;\r
+       }\r
+\r
+       return(ch);\r
+}\r
+\r
+/*\r
+===============\r
+=\r
+= DisplaySMsg\r
+=\r
+===============\r
+*/\r
+char DisplaySMsg(char *text,char *choices)\r
+{\r
+       char ch=true;\r
+       short temp;\r
+\r
+       bufferofs = 0;\r
+       PrintY = 69;\r
+       WindowX = 98;\r
+       WindowW = 115;\r
+\r
+       VW_Bar(WindowX,PrintY+1,WindowW,8,STATUSCOLOR);\r
+       temp = fontcolor;\r
+       fontcolor = TEXTCOLOR^STATUSCOLOR;\r
+       US_CPrintLine (text);\r
+       fontcolor = temp;\r
+\r
+       if (choices)\r
+       {\r
+               ch=GetKeyChoice(choices,true);\r
+               LastScan = 0;\r
+       }\r
+\r
+       return(ch);\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= DrawRadar\r
+=\r
+===============\r
+*/\r
+\r
+void DrawRadar (void)\r
+{\r
+       int             angle,number;\r
+       short objnum;\r
+\r
+       bufferofs = 0;\r
+       LatchDrawPic (radarx,radary,RADAR_TOPPIC);\r
+\r
+       asm     cli\r
+       asm     mov     dx,GC_INDEX\r
+       asm     mov     ax,2*256+GC_MODE\r
+       asm     out     dx,ax                                           // write mode 2\r
+\r
+       asm     mov     ax,GC_DATAROTATE\r
+       asm     out     dx,ax                // no rotation / logical operation\r
+\r
+       asm     mov     dx,SC_INDEX\r
+       asm     mov     al,SC_MAPMASK\r
+       asm     mov     ah,15\r
+       asm     out     dx,ax                                           // write to all four planes\r
+       asm     sti\r
+\r
+       objnum = 0;\r
+       while (RadarXY[objnum][2] != -1)\r
+       {\r
+               RadarBlip(radar_xcenter+RadarXY[objnum][0],radar_ycenter+RadarXY[objnum][1],RadarXY[objnum][2]);\r
+               objnum++;\r
+       }\r
+\r
+       asm     cli\r
+       asm     mov     dx,GC_INDEX\r
+       asm     mov     ax,255*256+GC_BITMASK\r
+       asm     out     dx,ax                                           // reset bitmask to %11111111\r
+       asm     sti\r
+}\r
+\r
+//===========================================================================\r
+\r
+\r
+//--------------------------------------------------------------------------\r
+// DrawNSEWIcons(void)\r
+//--------------------------------------------------------------------------\r
+\r
+void DrawRadarObj(short dx, short dy, unsigned sprnum,signed long psin,signed long pcos);\r
+\r
+void DrawNSEWIcons()\r
+{\r
+       signed x,y;\r
+\r
+       x = -FixedByFrac(RADAR_X_IRADIUS,costable[player->angle]);\r
+       y = -FixedByFrac(RADAR_Y_IRADIUS,sintable[player->angle]);\r
+\r
+       VWB_DrawSprite(radar_xcenter+x-3,radar_ycenter+y-3,NORTHICONSPR);\r
+\r
+}\r
+\r
+#if 0\r
+/*\r
+===============\r
+=\r
+= DrawBars\r
+=\r
+===============\r
+*/\r
+\r
+void DrawBars (void)\r
+{\r
+       int                     i;\r
+       unsigned        source,dest,topline;\r
+\r
+       for (i=0;i<3;i++)\r
+       {\r
+               bufferofs = screenloc[i];\r
+               VW_Bar (34*8,POWERLINE,40,MAXSHOTPOWER,1);\r
+       }\r
+       EGAWRITEMODE(1);\r
+       asm     mov     es,[screenseg]\r
+\r
+//\r
+// shot power\r
+//\r
+       if (gamestate.shotpower)\r
+       {\r
+               topline = MAXSHOTPOWER - gamestate.shotpower;\r
+\r
+               source = latchpics[SHOTPOWERPIC-FIRSTLATCHPIC]+topline*SIDEBARWIDTH;\r
+               dest = (POWERLINE+topline)*SCREENWIDTH+34;\r
+\r
+               asm     mov     si,[source]\r
+               asm     mov     di,[dest]\r
+\r
+               asm     mov     cx,[WORD PTR gamestate.shotpower]\r
+newline:\r
+       asm     mov     al,[es:si]\r
+       asm     mov     [es:di+PAGE1START],al\r
+       asm     mov     [es:di+PAGE2START],al\r
+       asm     mov     [es:di+PAGE3START],al\r
+       asm     mov     al,[es:si+1]\r
+       asm     mov     [es:di+1+PAGE1START],al\r
+       asm     mov     [es:di+1+PAGE2START],al\r
+       asm     mov     [es:di+1+PAGE3START],al\r
+       asm     mov     al,[es:si+2]\r
+       asm     mov     [es:di+2+PAGE1START],al\r
+       asm     mov     [es:di+2+PAGE2START],al\r
+       asm     mov     [es:di+2+PAGE3START],al\r
+       asm     mov     al,[es:si+3]\r
+       asm     mov     [es:di+3+PAGE1START],al\r
+       asm     mov     [es:di+3+PAGE2START],al\r
+       asm     mov     [es:di+3+PAGE3START],al\r
+       asm     mov     al,[es:si+4]\r
+       asm     mov     [es:di+4+PAGE1START],al\r
+       asm     mov     [es:di+4+PAGE2START],al\r
+       asm     mov     [es:di+4+PAGE3START],al\r
+\r
+       asm     add     di,SCREENWIDTH\r
+       asm     add     si,5\r
+\r
+               asm     loop    newline\r
+       }\r
+\r
+//\r
+// body\r
+//\r
+       if (gamestate.body)\r
+       {\r
+               source = latchpics[BODYPIC-FIRSTLATCHPIC];\r
+               dest = BODYLINE*SCREENWIDTH+34;\r
+\r
+               asm     mov     si,[source]\r
+               asm     mov     di,[dest]\r
+\r
+               asm     mov     cx,[WORD PTR gamestate.body]\r
+newline2:\r
+       asm     mov     al,[es:si]\r
+       asm     mov     [es:di+PAGE1START],al\r
+       asm     mov     [es:di+PAGE2START],al\r
+       asm     mov     [es:di+PAGE3START],al\r
+       asm     mov     al,[es:si+1]\r
+       asm     mov     [es:di+1+PAGE1START],al\r
+       asm     mov     [es:di+1+PAGE2START],al\r
+       asm     mov     [es:di+1+PAGE3START],al\r
+       asm     mov     al,[es:si+2]\r
+       asm     mov     [es:di+2+PAGE1START],al\r
+       asm     mov     [es:di+2+PAGE2START],al\r
+       asm     mov     [es:di+2+PAGE3START],al\r
+       asm     mov     al,[es:si+3]\r
+       asm     mov     [es:di+3+PAGE1START],al\r
+       asm     mov     [es:di+3+PAGE2START],al\r
+       asm     mov     [es:di+3+PAGE3START],al\r
+       asm     mov     al,[es:si+4]\r
+       asm     mov     [es:di+4+PAGE1START],al\r
+       asm     mov     [es:di+4+PAGE2START],al\r
+       asm     mov     [es:di+4+PAGE3START],al\r
+\r
+       asm     add     di,SCREENWIDTH\r
+       asm     add     si,5\r
+\r
+               asm     loop    newline2\r
+       }\r
+\r
+       if (gamestate.body != MAXBODY)\r
+       {\r
+               source = latchpics[NOBODYPIC-FIRSTLATCHPIC]+gamestate.body*SIDEBARWIDTH;\r
+               dest = (BODYLINE+gamestate.body)*SCREENWIDTH+34;\r
+               topline = MAXBODY-gamestate.body;\r
+\r
+               asm     mov     si,[source]\r
+               asm     mov     di,[dest]\r
+\r
+               asm     mov     cx,[WORD PTR topline]\r
+newline3:\r
+       asm     mov     al,[es:si]\r
+       asm     mov     [es:di+PAGE1START],al\r
+       asm     mov     [es:di+PAGE2START],al\r
+       asm     mov     [es:di+PAGE3START],al\r
+       asm     mov     al,[es:si+1]\r
+       asm     mov     [es:di+1+PAGE1START],al\r
+       asm     mov     [es:di+1+PAGE2START],al\r
+       asm     mov     [es:di+1+PAGE3START],al\r
+       asm     mov     al,[es:si+2]\r
+       asm     mov     [es:di+2+PAGE1START],al\r
+       asm     mov     [es:di+2+PAGE2START],al\r
+       asm     mov     [es:di+2+PAGE3START],al\r
+       asm     mov     al,[es:si+3]\r
+       asm     mov     [es:di+3+PAGE1START],al\r
+       asm     mov     [es:di+3+PAGE2START],al\r
+       asm     mov     [es:di+3+PAGE3START],al\r
+       asm     mov     al,[es:si+4]\r
+       asm     mov     [es:di+4+PAGE1START],al\r
+       asm     mov     [es:di+4+PAGE2START],al\r
+       asm     mov     [es:di+4+PAGE3START],al\r
+\r
+       asm     add     di,SCREENWIDTH\r
+       asm     add     si,5\r
+\r
+               asm     loop    newline3\r
+       }\r
+\r
+       EGAWRITEMODE(0);\r
+}\r
+#endif\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+//  Check the object and make sure it is a monster.  Used in making the sound\r
+//  of a monster being shot.\r
+//\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+boolean PlayMonsterSound(classtype objclass)\r
+{\r
+       switch (objclass)\r
+       {\r
+               case solidobj:\r
+               case realsolidobj:\r
+                       return false;\r
+               default:\r
+                       return true;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                       SHOTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+void T_Pshot (objtype *ob);\r
+\r
+\r
+extern statetype s_pshot1;\r
+extern statetype s_pshot2;\r
+\r
+//extern       statetype s_bigpshot1;\r
+//extern       statetype s_bigpshot2;\r
+\r
+\r
+statetype s_pshot1 = {PSHOT1PIC,8,&T_Pshot,&s_pshot2};\r
+statetype s_pshot2 = {PSHOT2PIC,8,&T_Pshot,&s_pshot1};\r
+\r
+\r
+statetype s_pshot_exp1 = {PSHOT_EXP1PIC,7,NULL,&s_pshot_exp2};\r
+statetype s_pshot_exp2 = {PSHOT_EXP2PIC,7,NULL,&s_pshot_exp3};\r
+statetype s_pshot_exp3 = {PSHOT_EXP3PIC,7,NULL,NULL};\r
+\r
+\r
+//statetype s_shotexplode = {PSHOT2PIC,8,NULL,NULL};\r
+\r
+//statetype s_bigpshot1 = {BIGPSHOT1PIC,8,&T_Pshot,&s_bigpshot2};\r
+//statetype s_bigpshot2 = {BIGPSHOT2PIC,8,&T_Pshot,&s_bigpshot1};\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= SpawnPShot\r
+=\r
+===================\r
+*/\r
+\r
+void SpawnPShot (void)\r
+{\r
+       DSpawnNewObjFrac (player->x,player->y,&s_pshot1,PIXRADIUS*2);\r
+       new->obclass = pshotobj;\r
+       new->speed = SHOTSPEED;\r
+       new->angle = player->angle;\r
+       new->active = always;\r
+}\r
+\r
+#if 0\r
+void SpawnBigPShot (void)\r
+{\r
+       SpawnNewObjFrac (player->x,player->y,&s_bigpshot1,24*PIXRADIUS);\r
+       new->obclass = bigpshotobj;\r
+       new->speed = SHOTSPEED;\r
+       new->angle = player->angle;\r
+}\r
+#endif\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= JimsShotClipMove\r
+=\r
+= Only checks corners, so the object better be less than one tile wide!\r
+=\r
+===================\r
+*/\r
+boolean JimsShotClipMove (objtype *ob, long xmove, long ymove)\r
+{\r
+       int                     xl,yl,xh,yh,tx,ty,nt1,nt2,x,y;\r
+       long            intersect,basex,basey,pointx,pointy;\r
+       unsigned        inside,total,tile;\r
+       objtype         *check;\r
+       boolean         moveok;\r
+\r
+//\r
+// move player and check to see if any corners are in solid tiles\r
+//\r
+//     basex = ob->x;\r
+//     basey = ob->y;\r
+\r
+//     ob->x += xmove;\r
+//     ob->y += ymove;\r
+\r
+//     CalcBounds (ob);\r
+\r
+       xl = ob->xl>>TILESHIFT;\r
+       yl = ob->yl>>TILESHIFT;\r
+\r
+       xh = ob->xh>>TILESHIFT;\r
+       yh = ob->yh>>TILESHIFT;\r
+\r
+       for (y=yl;y<=yh;y++)\r
+               for (x=xl;x<=xh;x++)\r
+               {\r
+                       check = actorat[x][y];\r
+\r
+                       if ((!check) || (check == player) || (!(check->flags & of_shootable)))\r
+                               continue;\r
+\r
+                       ob->x -= xmove;\r
+                       ob->y -= ymove;\r
+\r
+                       if (check->obclass != solidobj)\r
+                       {\r
+                               if (PlayMonsterSound(check->obclass))\r
+                                       SD_PlaySound (SHOOTMONSTERSND);\r
+                               if (ob->obclass == bigpshotobj)\r
+                                       ShootActor (check,BIGSHOTDAMAGE);\r
+                               else\r
+                                       ShootActor (check,SHOTDAMAGE);\r
+                       }\r
+                       else\r
+                               if (check->obclass == solidobj && (check->flags & of_forcefield))\r
+                               {\r
+                                       if (PlayMonsterSound(check->obclass))\r
+                                               SD_PlaySound (SHOOTMONSTERSND);\r
+                                       if (ob->obclass == bigpshotobj)\r
+                                               ShootActor (check,BIGSHOTDAMAGE);\r
+                                       else\r
+                                               ShootActor (check,SHOTDAMAGE);\r
+                               }\r
+                       ob->state = &s_pshot_exp1;\r
+                       ob->ticcount = ob->state->tictime;\r
+                       return(true);\r
+               }\r
+\r
+       return(false);          // move is OK!\r
+\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= T_Pshot\r
+=\r
+===============\r
+*/\r
+#if 0\r
+void T_Pshot (objtype *ob)\r
+{\r
+       objtype *check;\r
+       long    xmove,ymove,speed;\r
+\r
+//\r
+// check current position for monsters having moved into it\r
+//\r
+       for (check = player->next; check; check=check->next)\r
+               if ((check->flags & of_shootable)\r
+               && ob->xl <= check->xh\r
+               && ob->xh >= check->xl\r
+               && ob->yl <= check->yh\r
+               && ob->yh >= check->yl)\r
+               {\r
+\r
+                       if (check->obclass != solidobj)\r
+                       {\r
+                               if (PlayMonsterSound(check->obclass))\r
+                                       SD_PlaySound (SHOOTMONSTERSND);\r
+                               if (ob->obclass == bigpshotobj)\r
+                                       ShootActor (check,BIGSHOTDAMAGE);\r
+                               else\r
+                                       ShootActor (check,SHOTDAMAGE);\r
+                       }\r
+\r
+                       ob->state = &s_pshot_exp1;\r
+                       ob->ticcount = ob->state->tictime;\r
+                       return;\r
+               }\r
+\r
+\r
+//\r
+// move ahead, possibly hitting a wall\r
+//\r
+       speed = ob->speed*tics;\r
+\r
+       xmove = FixedByFrac(speed,costable[ob->angle]);\r
+       ymove = -FixedByFrac(speed,sintable[ob->angle]);\r
+\r
+       if (ShotClipMove(ob,xmove,ymove))\r
+       {\r
+               ob->state = &s_pshot_exp1;\r
+               ob->ticcount = ob->state->tictime;\r
+               return;\r
+       }\r
+\r
+       ob->tilex = ob->x >> TILESHIFT;\r
+       ob->tiley = ob->y >> TILESHIFT;\r
+\r
+//\r
+// check final position for monsters hit\r
+//\r
+       for (check = player->next; check; check=check->next)\r
+               if ((ob->flags & of_shootable)\r
+               && ob->xl <= check->xh\r
+               && ob->xh >= check->xl\r
+               && ob->yl <= check->yh\r
+               && ob->yh >= check->yl)\r
+               {\r
+                       ShootActor (check,SHOTDAMAGE);\r
+                       ob->state = &s_pshot_exp1;\r
+                       ob->ticcount = ob->state->tictime;\r
+                       return;\r
+               }\r
+}\r
+#endif\r
+\r
+\r
+\r
+void T_Pshot (objtype *ob)\r
+{\r
+       objtype *check;\r
+       long    xmove,ymove,speed;\r
+       int                     xl,yl,xh,yh,tx,ty,nt1,nt2,x,y;\r
+       long            intersect,basex,basey,pointx,pointy;\r
+       unsigned        inside,total,tile;\r
+       boolean         moveok;\r
+\r
+//\r
+// check current position for monsters having moved into it\r
+//\r
+       for (check = player->next; check; check=check->next)\r
+               if ((check->flags & of_shootable)\r
+               && ob->xl <= check->xh\r
+               && ob->xh >= check->xl\r
+               && ob->yl <= check->yh\r
+               && ob->yh >= check->yl)\r
+               {\r
+\r
+                       if (check->obclass != solidobj)\r
+                       {\r
+                               if (PlayMonsterSound(check->obclass))\r
+                                       SD_PlaySound (SHOOTMONSTERSND);\r
+                               if (ob->obclass == bigpshotobj)\r
+                                       ShootActor (check,BIGSHOTDAMAGE);\r
+                               else\r
+                                       ShootActor (check,SHOTDAMAGE);\r
+                       }\r
+\r
+                       ob->state = &s_pshot_exp1;\r
+                       ob->obclass = expobj;\r
+                       ob->ticcount = ob->state->tictime;\r
+                       return;\r
+               }\r
+\r
+\r
+//\r
+// move ahead, possibly hitting a wall\r
+//\r
+       speed = ob->speed*tics;\r
+\r
+       xmove = FixedByFrac(speed,costable[ob->angle]);\r
+       ymove = -FixedByFrac(speed,sintable[ob->angle]);\r
+\r
+       if (ShotClipMove(ob,xmove,ymove))\r
+       {\r
+               ob->state = &s_pshot_exp1;\r
+               ob->obclass = expobj;\r
+               ob->ticcount = ob->state->tictime;\r
+               return;\r
+       }\r
+\r
+       ob->tilex = ob->x >> TILESHIFT;\r
+       ob->tiley = ob->y >> TILESHIFT;\r
+\r
+//\r
+// check final position for monsters hit\r
+//\r
+\r
+       JimsShotClipMove(obj,xmove,ymove);\r
+\r
+}\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                       PLAYER ACTIONS\r
+\r
+=============================================================================\r
+*/\r
+\r
+/*\r
+===============\r
+=\r
+= BuildShotPower\r
+=\r
+===============\r
+*/\r
+\r
+void BuildShotPower (void)\r
+{\r
+       int             newlines,topline;\r
+       long    i;\r
+       unsigned        source,dest;\r
+\r
+       if (gamestate.shotpower == MAXSHOTPOWER)\r
+               return;\r
+\r
+       newlines = 0;\r
+       for (i=lasttimecount-realtics;i<lasttimecount;i++)\r
+               newlines += (i&1);\r
+\r
+       gamestate.shotpower += newlines;\r
+\r
+       if (gamestate.shotpower > MAXSHOTPOWER)\r
+       {\r
+               newlines -= (gamestate.shotpower - MAXSHOTPOWER);\r
+               gamestate.shotpower = MAXSHOTPOWER;\r
+       }\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= ClearShotPower\r
+=\r
+===============\r
+*/\r
+\r
+void ClearShotPower (void)\r
+{\r
+       unsigned        source,dest,topline;\r
+\r
+#if 0\r
+       topline = MAXSHOTPOWER - gamestate.shotpower;\r
+\r
+       source = latchpics[L_NOSHOT]+topline*SIDEBARWIDTH;\r
+       dest = (POWERLINE+topline)*SCREENWIDTH+34;\r
+\r
+       asm     mov     es,[screenseg]\r
+       asm     mov     si,[source]\r
+       asm     mov     di,[dest]\r
+\r
+       if (!gamestate.shotpower)\r
+               return;\r
+\r
+       EGAWRITEMODE(1);\r
+\r
+       asm     mov     cx,[WORD PTR gamestate.shotpower]\r
+newline:\r
+       asm     mov     al,[es:si]\r
+       asm     mov     [es:di+PAGE1START],al\r
+       asm     mov     [es:di+PAGE2START],al\r
+       asm     mov     [es:di+PAGE3START],al\r
+       asm     mov     al,[es:si+1]\r
+       asm     mov     [es:di+1+PAGE1START],al\r
+       asm     mov     [es:di+1+PAGE2START],al\r
+       asm     mov     [es:di+1+PAGE3START],al\r
+       asm     mov     al,[es:si+2]\r
+       asm     mov     [es:di+2+PAGE1START],al\r
+       asm     mov     [es:di+2+PAGE2START],al\r
+       asm     mov     [es:di+2+PAGE3START],al\r
+       asm     mov     al,[es:si+3]\r
+       asm     mov     [es:di+3+PAGE1START],al\r
+       asm     mov     [es:di+3+PAGE2START],al\r
+       asm     mov     [es:di+3+PAGE3START],al\r
+       asm     mov     al,[es:si+4]\r
+       asm     mov     [es:di+4+PAGE1START],al\r
+       asm     mov     [es:di+4+PAGE2START],al\r
+       asm     mov     [es:di+4+PAGE3START],al\r
+\r
+       asm     add     di,SCREENWIDTH\r
+       asm     add     si,5\r
+\r
+       asm     loop    newline\r
+\r
+       EGAWRITEMODE(0);\r
+#endif\r
+\r
+       gamestate.shotpower = 0;\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= Shoot\r
+=\r
+===============\r
+*/\r
+\r
+void Shoot (void)\r
+{\r
+       ClearShotPower ();\r
+       SD_PlaySound (SHOOTSND);\r
+       SpawnPShot ();\r
+}\r
+\r
+//===========================================================================\r
+\r
+#if 0\r
+/*\r
+===============\r
+=\r
+= BigShoot\r
+=\r
+===============\r
+*/\r
+\r
+void BigShoot (void)\r
+{\r
+       ClearShotPower ();\r
+       SD_PlaySound (BIGSHOOTSND);\r
+       SpawnBigPShot ();\r
+}\r
+#endif\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= CastBolt\r
+=\r
+===============\r
+*/\r
+\r
+void CastBolt (void)\r
+{\r
+       if (!gamestate.bolts)\r
+       {\r
+               SD_PlaySound (NOITEMSND);\r
+               return;\r
+       }\r
+\r
+       TakeBolt ();\r
+       boltsleft = NUMBOLTS;\r
+       bolttimer = BOLTTICS;\r
+       Shoot ();\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= ContinueBolt\r
+=\r
+===============\r
+*/\r
+\r
+void ContinueBolt (void)\r
+{\r
+       bolttimer-=realtics;\r
+       if (bolttimer<0)\r
+       {\r
+               boltsleft--;\r
+               bolttimer = BOLTTICS;\r
+               Shoot ();\r
+       }\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= CastNuke\r
+=\r
+===============\r
+*/\r
+\r
+void CastNuke (void)\r
+{\r
+//     extern boolean autofire;\r
+\r
+       int     angle;\r
+\r
+       if (!gamestate.nukes)\r
+       {\r
+               SD_PlaySound (NOITEMSND);\r
+               return;\r
+       }\r
+\r
+//     if (!autofire)\r
+               TakeNuke ();\r
+       lastnuke = TimeCount;\r
+\r
+       for (angle = 0; angle < ANGLES; angle+= ANGLES/16)\r
+       {\r
+               DSpawnNewObjFrac (player->x,player->y,&s_pshot1,24*PIXRADIUS);\r
+               new->obclass = bigpshotobj;\r
+               new->speed = SHOTSPEED;\r
+               new->angle = angle;\r
+               new->active = always;\r
+       }\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= DrinkPotion\r
+=\r
+===============\r
+*/\r
+\r
+void DrinkPotion (void)\r
+{\r
+       unsigned        source,dest,topline;\r
+\r
+       if (!gamestate.potions)\r
+       {\r
+               SD_PlaySound (NOITEMSND);\r
+               return;\r
+       }\r
+\r
+       DisplaySMsg("Curing", NULL);\r
+       TakePotion ();\r
+       gamestate.body = MAXBODY;\r
+       VW_WaitVBL(30);\r
+       status_flag    = S_NONE;\r
+\r
+#if 0\r
+//\r
+// draw a full up bar\r
+//\r
+       source = latchpics[L_BODYBAR];\r
+       dest = BODYLINE*SCREENWIDTH+34;\r
+\r
+       asm     mov     es,[screenseg]\r
+       asm     mov     si,[source]\r
+       asm     mov     di,[dest]\r
+\r
+       EGAWRITEMODE(1);\r
+\r
+       asm     mov     cx,MAXBODY\r
+newline:\r
+       asm     mov     al,[es:si]\r
+       asm     mov     [es:di+PAGE1START],al\r
+       asm     mov     [es:di+PAGE2START],al\r
+       asm     mov     [es:di+PAGE3START],al\r
+       asm     mov     al,[es:si+1]\r
+       asm     mov     [es:di+1+PAGE1START],al\r
+       asm     mov     [es:di+1+PAGE2START],al\r
+       asm     mov     [es:di+1+PAGE3START],al\r
+       asm     mov     al,[es:si+2]\r
+       asm     mov     [es:di+2+PAGE1START],al\r
+       asm     mov     [es:di+2+PAGE2START],al\r
+       asm     mov     [es:di+2+PAGE3START],al\r
+       asm     mov     al,[es:si+3]\r
+       asm     mov     [es:di+3+PAGE1START],al\r
+       asm     mov     [es:di+3+PAGE2START],al\r
+       asm     mov     [es:di+3+PAGE3START],al\r
+       asm     mov     al,[es:si+4]\r
+       asm     mov     [es:di+4+PAGE1START],al\r
+       asm     mov     [es:di+4+PAGE2START],al\r
+       asm     mov     [es:di+4+PAGE3START],al\r
+       asm     add     di,SCREENWIDTH\r
+       asm     add     si,5\r
+\r
+       asm     loop    newline\r
+\r
+       EGAWRITEMODE(0);\r
+#endif\r
+}\r
+\r
+\r
+\r
+//===========================================================================\r
+\r
+#if 0\r
+\r
+////////////////////////////////////////////////////////////////////////////\r
+//\r
+//   GetScrollText\r
+//\r
+//   parms   - scroll -- the number of the scroll to display\r
+//   returns - a far pointer to the scroll text\r
+//\r
+////////////////////////////////////////////////////////////////////////////\r
+\r
+char far *GetScrollText (int scroll)\r
+{\r
+       boolean found;\r
+       int     i;\r
+       char far *txt;\r
+       unsigned ofset;\r
+\r
+       CA_CacheGrChunk(SCROLLTEXT);\r
+\r
+       found = false;\r
+       i     = 0;\r
+\r
+       txt = (char _seg *)grsegs[SCROLLTEXT];\r
+\r
+       while (!found)\r
+       {\r
+               while (*txt != '\n')\r
+               {\r
+                       if (*txt == '\r')\r
+                               *txt = 0;\r
+                       txt++;\r
+               }\r
+               txt++;\r
+               if (i == scroll)\r
+               {\r
+                       found   = true;\r
+                       ofset = FP_OFF(txt);\r
+\r
+                       while (*txt != '\n')\r
+                       {\r
+                               if (*txt == '\r')\r
+                                       *txt = 0;\r
+                               txt++;\r
+                       }\r
+               }\r
+               i++;\r
+       }\r
+       txt = (char _seg *)grsegs[SCROLLTEXT]+ofset;\r
+\r
+       UNMARKGRCHUNK(SCROLLTEXT);\r
+       return(txt);\r
+}      //End of GetScrollText\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= ReadScroll\r
+=\r
+===============\r
+*/\r
+\r
+extern boolean tileneeded[NUMFLOORS];\r
+\r
+void ReadScroll (int scroll)\r
+{\r
+       PresenterInfo pi;\r
+       int     i;\r
+       unsigned *skytemp,*gndtemp,blackcolor=0;\r
+       char far *scrolltext;\r
+\r
+       DisplaySMsg("Reading Scroll", NULL);\r
+       bufferofs = displayofs = screenloc[screenpage];\r
+\r
+       if (status_flag != S_TIMESTOP)\r
+               status_flag = S_NONE;\r
+\r
+       FreeUpMemory();\r
+\r
+       CA_CacheGrChunk (SCROLLTOPPIC);\r
+       CA_CacheGrChunk (SCROLL1PIC);\r
+       CA_CacheGrChunk (SCROLLBOTTOMPIC);\r
+\r
+       skytemp = skycolor;\r
+       gndtemp = groundcolor;\r
+       skycolor = groundcolor = &blackcolor;\r
+\r
+       VW_Bar(0,0,VIEWWIDTH,VIEWHEIGHT,0);\r
+       VW_DrawPic (10,0,SCROLLTOPPIC);\r
+       VW_DrawPic (10,32,SCROLL1PIC);\r
+       VW_DrawPic (10,88,SCROLLBOTTOMPIC);\r
+\r
+       scrolltext = GetScrollText(scroll);\r
+\r
+       pi.xl = LEFTEDGE;\r
+       pi.yl = PRNY;\r
+       pi.xh = RIGHTEDGE;\r
+       pi.yh = PRNY+1;\r
+       pi.bgcolor = 7;\r
+       pi.script[0] = (char far *)scrolltext;\r
+       Presenter(&pi);\r
+\r
+       skycolor = skytemp;\r
+       groundcolor = gndtemp;\r
+\r
+       UNMARKGRCHUNK(SCROLL1PIC);\r
+       UNMARKGRCHUNK(SCROLLTOPPIC);\r
+       UNMARKGRCHUNK(SCROLLBOTTOMPIC);\r
+       MM_FreePtr (&grsegs[SCROLL1PIC]);\r
+       MM_FreePtr (&grsegs[SCROLLTOPPIC]);\r
+       MM_FreePtr (&grsegs[SCROLLBOTTOMPIC]);\r
+\r
+       CacheScaleds();\r
+\r
+       IN_ClearKeysDown ();\r
+       lasttext = -1;\r
+       DisplayMsg("Press ENTER or ESC to exit.",NULL);\r
+       while ((!Keyboard[sc_Escape]) && (!Keyboard[sc_Enter]));\r
+       IN_ClearKeysDown ();\r
+\r
+       if (status_flag == S_TIMESTOP)\r
+               DisplaySMsg("Time Stopped:     ",NULL);\r
+}\r
+\r
+#endif\r
+\r
+\r
+//===============\r
+//\r
+// StopTime()\r
+//\r
+//\r
+//===============\r
+void StopTime()\r
+{\r
+       FreezeTime = MAXFREEZETIME;\r
+       SD_PlaySound(FREEZETIMESND);\r
+       DisplaySMsg("Time Stopped:     ",NULL);\r
+       status_flag = S_TIMESTOP;\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= TakeDamage\r
+=\r
+===============\r
+*/\r
+\r
+void TakeDamage (int points)\r
+{\r
+       unsigned        source,dest,topline;\r
+\r
+       if (!gamestate.body || (bordertime && bcolor==FLASHCOLOR) || godmode)\r
+               return;\r
+\r
+       points = EasyDoDamage(points);\r
+\r
+       if (points >= gamestate.body)\r
+       {\r
+               points = gamestate.body;\r
+               Flags |= FL_DEAD;\r
+       }\r
+\r
+       bordertime = FLASHTICS<<2;\r
+       bcolor = FLASHCOLOR;\r
+       VW_ColorBorder (FLASHCOLOR);\r
+\r
+       DisplaySMsg("Damaging blows!", NULL);\r
+       status_flag  = S_NONE;\r
+       status_delay = 80;\r
+\r
+       if (gamestate.body<MAXBODY/3)\r
+               SD_PlaySound (TAKEDMGHURTSND);\r
+       else\r
+               SD_PlaySound (TAKEDAMAGESND);\r
+\r
+       gamestate.body -= points;\r
+}\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                       INTERACTION\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+#if 0\r
+/*\r
+==================\r
+=\r
+= OpenDoor\r
+=\r
+==================\r
+*/\r
+\r
+void OpenDoor (unsigned bx, unsigned by, unsigned doorbase)\r
+{\r
+       int x,y;\r
+       unsigned        far *map;\r
+\r
+       x=bx;\r
+       y=by;\r
+       map = mapsegs[0]+farmapylookup[y]+x;\r
+       while (tilemap[x][y]-doorbase<4)\r
+       {\r
+               tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;\r
+               map--;\r
+               x--;\r
+       }\r
+       x=bx+1;\r
+       map = mapsegs[0]+farmapylookup[y]+x;\r
+       while (tilemap[x][y]-doorbase<4)\r
+       {\r
+               tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;\r
+               map++;\r
+               x++;\r
+       }\r
+       x=bx;\r
+       y=by-1;\r
+       map = mapsegs[0]+farmapylookup[y]+x;\r
+       while (tilemap[x][y]-doorbase<4)\r
+       {\r
+               tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;\r
+               map-=mapwidth;\r
+               y--;\r
+       }\r
+       y=by+1;\r
+       map = mapsegs[0]+farmapylookup[y]+x;\r
+       while (tilemap[x][y]-doorbase<4)\r
+       {\r
+               tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;\r
+               map+=mapwidth;\r
+               y++;\r
+       }\r
+}\r
+#endif\r
+\r
+#if 0\r
+/*\r
+==================\r
+=\r
+= RemoveWalls - similar to OpenDoor(), but on a different plane\r
+=\r
+==================\r
+*/\r
+void RemoveWalls (unsigned bx, unsigned by, unsigned remove_code)\r
+{\r
+       int x,y;\r
+       unsigned        far *map,*p2;\r
+\r
+       x=bx;\r
+       y=by;\r
+       p2 = *(mapsegs[2]+farmapylookup[y]+x);\r
+       map = mapsegs[0]+farmapylookup[y]+x;\r
+       while (*p2 == remove_code)\r
+       {\r
+               tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;\r
+               map--;\r
+               p2--;\r
+               x--;\r
+       }\r
+       x=bx+1;\r
+       p2 = *(mapsegs[2]+farmapylookup[y]+x);\r
+       map = mapsegs[0]+farmapylookup[y]+x;\r
+       while (*p2 == remove_code)\r
+       {\r
+               tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;\r
+               map++;\r
+               p2++;\r
+               x++;\r
+       }\r
+       x=bx;\r
+       y=by-1;\r
+       p2 = *(mapsegs[2]+farmapylookup[y]+x);\r
+       map = mapsegs[0]+farmapylookup[y]+x;\r
+       while (*p2 == remove_code)\r
+       {\r
+               tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;\r
+               map-=mapwidth;\r
+               p2 -= mapwidth;\r
+               y--;\r
+       }\r
+       y=by+1;\r
+       p2 = *(mapsegs[2]+farmapylookup[y]+x);\r
+       map = mapsegs[0]+farmapylookup[y]+x;\r
+       while (*p2 == remove_code)\r
+       {\r
+               tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;\r
+               map+=mapwidth;\r
+               p2 += mapwidth;\r
+               y++;\r
+       }\r
+}\r
+#endif\r
+\r
+/*\r
+==================\r
+=\r
+= HitSpecialTile\r
+=\r
+= Returns true if the move is blocked\r
+=\r
+==================\r
+*/\r
+\r
+boolean HitSpecialTile (unsigned x, unsigned y, unsigned tile)\r
+{\r
+       objtype *check;\r
+       short keyspot;\r
+       unsigned        temp,spot,curmap=gamestate.mapon,newlevel;\r
+       char *key_colors[] = {"a RED key",\r
+                                       "a YELLOW key",\r
+                                       "a GREEN key",\r
+                                       "a BLUE key"};\r
+\r
+       switch (tile)\r
+       {\r
+               case 44:\r
+                       playstate = ex_victorious;\r
+               break;\r
+\r
+               case 17:\r
+               case 30:\r
+               case 31:\r
+               case 35:\r
+               case 46:\r
+               case 47:\r
+               case 48:\r
+               case 49:\r
+               case 57:\r
+               case 58:\r
+               case 71:\r
+               case 85:\r
+               case 94:\r
+\r
+                       if (!playstate && !FreezeTime)\r
+                       {\r
+\r
+                       // Is this an openable door? (Is "openable" a word?)\r
+                       //\r
+                               spot = (*(mapsegs[2]+farmapylookup[y]+x)) >> 8;\r
+                               if (spot == CANT_OPEN_CODE)     // CAN'T EVER OPEN (it's just for looks)\r
+                               {\r
+                                       CenterWindow(30,4);\r
+                                       US_CPrint("\nThis door is permanently blocked");\r
+                                       VW_UpdateScreen();\r
+                                       IN_ClearKeysDown();\r
+                                       IN_Ack();\r
+                                       return;\r
+                               }\r
+\r
+                               // make sure player has key to get into door\r
+                               //\r
+\r
+                               if (TILE_FLAGS(tile) & tf_EMBEDDED_KEY_COLOR)\r
+                                       keyspot = GATE_KEY_COLOR(tile);\r
+                               else\r
+                                       keyspot = (*(mapsegs[2]+farmapylookup[y+1]+x)) >> 8;\r
+\r
+                               if (keyspot--)\r
+                                       if (!gamestate.keys[keyspot])\r
+                                       {\r
+                                               SD_PlaySound(HIT_GATESND);\r
+                                               CenterWindow(20,5);\r
+                                               US_CPrint("\nYou need\n");\r
+                                               US_CPrint(key_colors[keyspot]);\r
+                                               VW_UpdateScreen();\r
+                                               IN_ClearKeysDown();\r
+                                               IN_Ack();\r
+                                               return;\r
+                                       }\r
+\r
+                       //\r
+                       // deal with this gate (warp? simply open? whatever...)\r
+                       //\r
+                               switch (spot)\r
+                               {\r
+                                       case NEXT_LEVEL_CODE:           // WARP TO NEXT LEVEL\r
+                                               newlevel = gamestate.mapon+1;\r
+                                               playstate = ex_warped;\r
+                                       break;\r
+\r
+                                       case REMOVE_DOOR_CODE:          // REMOVE DOOR\r
+                                               (unsigned)actorat[x][y] = tilemap[x][y] =       *(mapsegs[0]+farmapylookup[y]+x) = 0;\r
+                                               *(mapsegs[2]+farmapylookup[y+1]+x) = 0; // key no longer needed\r
+                                               if (keyspot>=0)\r
+                                                       TakeKey(keyspot);\r
+                                       break;\r
+\r
+                                       default:                        // WARP TO A LEVEL\r
+                                               newlevel = spot;\r
+                                               playstate = ex_warped;\r
+                                       break;\r
+                               }\r
+\r
+                               if (playstate == ex_warped)\r
+                               {\r
+                                       SD_PlaySound(HIT_GATESND);\r
+//                                     levelinfo *li=&gamestate.levels[curmap];\r
+\r
+//                                     OldAngle = FaceDoor(x,y);\r
+\r
+                                       if (!VerifyGateExit())\r
+                                       {\r
+                                               IN_ClearKeysDown ();\r
+                                               playstate = ex_stillplaying;\r
+                                               break;\r
+                                       }\r
+\r
+//                                     FaceAngle(OldAngle);\r
+\r
+                                       if (keyspot>=0)\r
+                                               TakeKey(keyspot);\r
+                                       *(mapsegs[2]+farmapylookup[y+1]+x) = 0; // key no longer needed\r
+\r
+                                       gamestate.mapon = newlevel;\r
+                                       SD_PlaySound(WARPUPSND);\r
+                                       IN_ClearKeysDown ();\r
+\r
+//                                     li->x = player->tilex;\r
+//                                     li->y = player->tiley;\r
+//                                     li->angle = player->angle+180;\r
+//                                     if (li->angle > 360)\r
+//                                             li->angle -= 360;\r
+                               }\r
+                       }\r
+               break;\r
+       }\r
+\r
+       return true;\r
+}\r
+\r
+//-------------------------------------------------------------------------\r
+// VerifyGateExit()\r
+//-------------------------------------------------------------------------\r
+boolean VerifyGateExit()\r
+{\r
+       char choices[] = {sc_Escape,sc_Y,sc_N,0},ch;\r
+\r
+       ch=DisplayMsg("Pass this way?      Y/N",choices);\r
+       DrawText(true);\r
+\r
+       return(ch == sc_Y);\r
+}\r
+\r
+\r
+/*\r
+==================\r
+=\r
+= TouchActor\r
+=\r
+= Returns true if the move is blocked\r
+=\r
+==================\r
+*/\r
+\r
+boolean TouchActor (objtype *ob, objtype *check)\r
+{\r
+       if (ob->xh < check->xl || ob->xl > check->xh ||\r
+               ob->yh < check->yl || ob->yl > check->yh)\r
+               return false;                           // not quite touching\r
+\r
+       switch (check->obclass)\r
+       {\r
+               case bonusobj:\r
+                       switch (check->temp1)\r
+                       {\r
+                               case B_BOLT:            GiveBolt ();            break;\r
+\r
+                               case B_NUKE:            GiveNuke ();            break;\r
+\r
+                               case B_POTION:          GivePotion ();          break;\r
+\r
+//                             case B_RKEY2:           GiveKey(B_RKEY-B_RKEY);                                 break;\r
+\r
+                               case B_RKEY:\r
+                               case B_YKEY:\r
+                               case B_GKEY:\r
+                               case B_BKEY:            GiveKey (check->temp1-B_RKEY);          break;\r
+\r
+#if 0\r
+                               case B_SCROLL1:\r
+                               case B_SCROLL2:\r
+                               case B_SCROLL3:\r
+                               case B_SCROLL4:\r
+                               case B_SCROLL5:\r
+                               case B_SCROLL6:\r
+                               case B_SCROLL7:\r
+                               case B_SCROLL8: GiveScroll (check->temp1-B_SCROLL1,true);       break;\r
+#endif\r
+\r
+                               case B_OLDCHEST:\r
+                               case B_CHEST:           GiveChest ();           break;\r
+\r
+                               case B_RGEM:\r
+                               case B_YGEM:\r
+                               case B_GGEM:\r
+                               case B_BGEM:\r
+                               case B_PGEM:\r
+                                       SD_PlaySound(GETGEMSND);\r
+                                       gamestate.gems[check->temp1-B_RGEM] = GEM_DELAY_TIME;\r
+                                       redraw_gems = true;\r
+                               break;\r
+\r
+                               default:\r
+                                       Quit("TouchActor(): INVALID BONUS");\r
+                               break;\r
+                       }\r
+\r
+                       (unsigned)actorat[check->tilex][check->tiley] = 0;\r
+                       RemoveObj (check);\r
+\r
+                       return false;\r
+\r
+               case freezeobj:\r
+                       StopTime();\r
+                       (unsigned)actorat[check->tilex][check->tiley] = 0;\r
+                       RemoveObj(check);\r
+                       return(false);\r
+       }\r
+\r
+       return  true;\r
+}\r
+\r
+\r
+/*\r
+==================\r
+=\r
+= CalcBounds\r
+=\r
+==================\r
+*/\r
+\r
+void CalcBounds (objtype *ob)\r
+{\r
+//\r
+// calculate hit rect\r
+//\r
+  ob->xl = ob->x - ob->size;\r
+  ob->xh = ob->x + ob->size;\r
+  ob->yl = ob->y - ob->size;\r
+  ob->yh = ob->y + ob->size;\r
+}\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= LocationInActor\r
+=\r
+===================\r
+*/\r
+\r
+boolean LocationInActor (objtype *ob)\r
+{\r
+       int     x,y,xmin,ymin,xmax,ymax;\r
+       objtype *check;\r
+\r
+       CalcBounds (ob);\r
+\r
+       xmin = (ob->x >> TILESHIFT)-2;\r
+       ymin = (ob->y >> TILESHIFT)-2;\r
+       xmax = xmin+5;\r
+       ymax = ymin+5;\r
+\r
+       for (x=xmin;x<xmax;x++)\r
+               for (y=ymin;y<ymax;y++)\r
+               {\r
+                       check = actorat[x][y];\r
+                       if (check>(objtype *)LASTTILE\r
+                               && (check->flags & of_shootable)\r
+                               &&      (check->obclass != bonusobj)\r
+                               && (check->obclass != freezeobj)\r
+                               && (check->obclass != solidobj)\r
+                               && ob->xl-SIZE_TEST <= check->xh\r
+                               && ob->xh+SIZE_TEST >= check->xl\r
+                               && ob->yl-SIZE_TEST <= check->yh\r
+                               && ob->yh+SIZE_TEST >= check->yl)\r
+                                       return true;\r
+               }\r
+\r
+       return false;\r
+}\r
+\r
+/*\r
+===================\r
+=\r
+= ClipXMove\r
+=\r
+= Only checks corners, so the object better be less than one tile wide!\r
+=\r
+===================\r
+*/\r
+void ClipXMove (objtype *ob, long xmove)\r
+{\r
+       int                     xl,yl,xh,yh,tx,ty,nt1,nt2,x,y;\r
+       long            intersect,basex,basey,pointx,pointy;\r
+       unsigned        inside,total,tile;\r
+       objtype         *check;\r
+       boolean         moveok;\r
+       boolean         invisible_present = false;\r
+\r
+//\r
+// move player and check to see if any corners are in solid tiles\r
+//\r
+       basex = ob->x;\r
+       basey = ob->y;\r
+\r
+       ob->x += xmove;\r
+\r
+       CalcBounds (ob);\r
+\r
+       xl = ob->xl>>TILESHIFT;\r
+       yl = ob->yl>>TILESHIFT;\r
+\r
+       xh = ob->xh>>TILESHIFT;\r
+       yh = ob->yh>>TILESHIFT;\r
+\r
+       for (y=yl;y<=yh;y++)\r
+               for (x=xl;x<=xh;x++)\r
+               {\r
+                       check = actorat[x][y];\r
+\r
+                       if (!check)\r
+                               continue;               // blank floor, walk ok\r
+\r
+                       if ((unsigned)check <= LASTTILE)\r
+                       {\r
+                               if (TILE_FLAGS((unsigned)check) & tf_SPECIAL)\r
+                               {\r
+                                       HitSpecialTile(x,y,(unsigned)check-SPECTILESTART);\r
+                                       goto blockmove;\r
+                               }\r
+\r
+                               if (TILE_FLAGS((unsigned)check) & tf_INVISIBLE_WALL)\r
+                               {\r
+                                       invisible_present = true;\r
+                                       goto blockmove;\r
+                               }\r
+\r
+\r
+                               if (TILE_FLAGS((unsigned)check) & tf_SOLID)\r
+                               {\r
+                                       goto blockmove;                 // solid wall\r
+                               }\r
+                       }\r
+\r
+                       TouchActor(ob,check);           // pick up items\r
+               }\r
+\r
+//\r
+// check nearby actors\r
+//\r
+       if (LocationInActor(ob))\r
+       {\r
+               ob->x -= xmove;\r
+               if (LocationInActor(ob))\r
+               {\r
+                       ob->x += xmove;\r
+                       if (LocationInActor(ob))\r
+                               ob->x -= xmove;\r
+               }\r
+       }\r
+       return;         // move is OK!\r
+\r
+\r
+blockmove:\r
+\r
+//     if (!SD_SoundPlaying())\r
+//             SD_PlaySound (HITWALLSND);\r
+\r
+       moveok = false;\r
+\r
+       do\r
+       {\r
+               xmove /= 2;\r
+               if (moveok)\r
+               {\r
+                       ob->x += xmove;\r
+               }\r
+               else\r
+               {\r
+                       ob->x -= xmove;\r
+               }\r
+               CalcBounds (ob);\r
+               xl = ob->xl>>TILESHIFT;\r
+               yl = ob->yl>>TILESHIFT;\r
+               xh = ob->xh>>TILESHIFT;\r
+               yh = ob->yh>>TILESHIFT;\r
+               if (tilemap[xl][yl] || tilemap[xh][yl]\r
+               || tilemap[xh][yh] || tilemap[xl][yh] )\r
+               {\r
+                       moveok = false;\r
+                       if (xmove>=-2048 && xmove <=2048)\r
+                       {\r
+                               ob->x = basex;\r
+                               ob->y = basey;\r
+                               return;\r
+                       }\r
+               }\r
+               else\r
+                       if (invisible_present)\r
+                       {\r
+                               moveok = false;\r
+                               if (xmove>=-2048 && xmove <=2048)\r
+                               {\r
+                                       ob->x = basex;\r
+                                       ob->y = basey;\r
+                                       return;\r
+                               }\r
+                       }\r
+                       else\r
+                               if (xmove>=-2048 && xmove <=2048)\r
+                                       return;\r
+                               moveok = true;\r
+       } while (1);\r
+}\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= ClipYMove\r
+=\r
+= Only checks corners, so the object better be less than one tile wide!\r
+=\r
+===================\r
+*/\r
+void ClipYMove (objtype *ob, long ymove)\r
+{\r
+       int                     xl,yl,xh,yh,tx,ty,nt1,nt2,x,y;\r
+       long            intersect,basex,basey,pointx,pointy;\r
+       unsigned        inside,total,tile;\r
+       objtype         *check;\r
+       boolean         moveok;\r
+       boolean         invisible_present = false;\r
+\r
+//\r
+// move player and check to see if any corners are in solid tiles\r
+//\r
+       basex = ob->x;\r
+       basey = ob->y;\r
+\r
+       ob->y += ymove;\r
+\r
+       CalcBounds (ob);\r
+\r
+       xl = ob->xl>>TILESHIFT;\r
+       yl = ob->yl>>TILESHIFT;\r
+\r
+       xh = ob->xh>>TILESHIFT;\r
+       yh = ob->yh>>TILESHIFT;\r
+\r
+       for (y=yl;y<=yh;y++)\r
+               for (x=xl;x<=xh;x++)\r
+               {\r
+                       check = actorat[x][y];\r
+                       if (!check)\r
+                               continue;               // blank floor, walk ok\r
+\r
+                       if ((unsigned)check <= LASTTILE)\r
+                       {\r
+                               if (TILE_FLAGS((unsigned)check) & tf_SPECIAL)           // <=LASTSPECIALTILE)\r
+                               {\r
+                                       HitSpecialTile (x,y,(unsigned)check-SPECTILESTART);\r
+                                       goto blockmove;\r
+                               }\r
+\r
+                               if (TILE_FLAGS((unsigned)check) & tf_INVISIBLE_WALL)\r
+                               {\r
+                                       invisible_present = true;\r
+                                       goto blockmove;\r
+                               }\r
+\r
+\r
+                               if (TILE_FLAGS((unsigned)check) & tf_SOLID)             // LASTWALLTILE)\r
+                               {\r
+                                       goto blockmove; // solid wall\r
+                               }\r
+                       }\r
+\r
+                       TouchActor(ob,check);           // pick up items\r
+               }\r
+\r
+//\r
+// check nearby actors\r
+//\r
+       if (LocationInActor(ob))\r
+       {\r
+               if (LocationInActor(ob))\r
+               {\r
+                       ob->y -= ymove;\r
+               }\r
+       }\r
+       return;         // move is OK!\r
+\r
+\r
+blockmove:\r
+\r
+//     if (!SD_SoundPlaying())\r
+//             SD_PlaySound (HITWALLSND);\r
+\r
+       moveok = false;\r
+\r
+       do\r
+       {\r
+               ymove /= 2;\r
+               if (moveok)\r
+               {\r
+                       ob->y += ymove;\r
+               }\r
+               else\r
+               {\r
+                       ob->y -= ymove;\r
+               }\r
+               CalcBounds (ob);\r
+               xl = ob->xl>>TILESHIFT;\r
+               yl = ob->yl>>TILESHIFT;\r
+               xh = ob->xh>>TILESHIFT;\r
+               yh = ob->yh>>TILESHIFT;\r
+               if (tilemap[xl][yl] || tilemap[xh][yl]\r
+               || tilemap[xh][yh] || tilemap[xl][yh] )\r
+               {\r
+                       moveok = false;\r
+                       if (ymove>=-2048 && ymove <=2048)\r
+                       {\r
+                               ob->x = basex;\r
+                               ob->y = basey;\r
+                               return;\r
+                       }\r
+               }\r
+               else\r
+                       if (invisible_present)\r
+                       {\r
+                               moveok = false;\r
+                               if (ymove>=-2048 && ymove <=2048)\r
+                               {\r
+                                       ob->x = basex;\r
+                                       ob->y = basey;\r
+                                       return;\r
+                               }\r
+                       }\r
+                       else\r
+                               if (ymove>=-2048 && ymove <=2048)\r
+                                       return;\r
+                               moveok = true;\r
+       } while (1);\r
+}\r
+\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= ShotClipMove\r
+=\r
+= Only checks corners, so the object better be less than one tile wide!\r
+=\r
+===================\r
+*/\r
+\r
+boolean ShotClipMove (objtype *ob, long xmove, long ymove)\r
+{\r
+       int                     xl,yl,xh,yh,tx,ty,nt1,nt2,x,y;\r
+       long            intersect,basex,basey,pointx,pointy;\r
+       unsigned        inside,total,spot,tile;\r
+       objtype         *check;\r
+       boolean         moveok;\r
+\r
+//\r
+// move shot and check to see if any corners are in solid tiles\r
+//\r
+       basex = ob->x;\r
+       basey = ob->y;\r
+\r
+       ob->x += xmove;\r
+       ob->y += ymove;\r
+\r
+       CalcBounds (ob);\r
+\r
+       xl = ob->xl>>TILESHIFT;\r
+       yl = ob->yl>>TILESHIFT;\r
+\r
+       xh = ob->xh>>TILESHIFT;\r
+       yh = ob->yh>>TILESHIFT;\r
+\r
+       for (y=yl;y<=yh;y++)\r
+               for (x=xl;x<=xh;x++)\r
+               {\r
+                       spot = (*(mapsegs[2]+farmapylookup[y]+x)) >> 8;\r
+                       if (spot == EXP_WALL_CODE)\r
+                               switch (ob->obclass)\r
+                               {\r
+                                       case pshotobj:\r
+                                       case bigpshotobj:\r
+                                               ExplodeWall (x,y);\r
+                                               goto blockmove;\r
+//                                     break;\r
+                               }\r
+\r
+                       tile = *(mapsegs[0]+farmapylookup[y]+x);\r
+                       if (TILE_FLAGS(tile) & tf_SOLID)\r
+                               goto blockmove;\r
+               }\r
+       return false;           // move is OK!\r
+\r
+\r
+blockmove:\r
+\r
+       if (ob->obclass == pshotobj)\r
+               SD_PlaySound (SHOOTWALLSND);\r
+\r
+       moveok = false;\r
+\r
+       do\r
+       {\r
+               xmove /= 2;\r
+               ymove /= 2;\r
+               if (moveok)\r
+               {\r
+                       ob->x += xmove;\r
+                       ob->y += ymove;\r
+               }\r
+               else\r
+               {\r
+                       ob->x -= xmove;\r
+                       ob->y -= ymove;\r
+               }\r
+               CalcBounds (ob);\r
+               xl = ob->xl>>TILESHIFT;\r
+               yl = ob->yl>>TILESHIFT;\r
+               xh = ob->xh>>TILESHIFT;\r
+               yh = ob->yh>>TILESHIFT;\r
+               if (tilemap[xl][yl] || tilemap[xh][yl]\r
+               || tilemap[xh][yh] || tilemap[xl][yh] )\r
+               {\r
+                       moveok = false;\r
+                       if (xmove>=-2048 && xmove <=2048 && ymove>=-2048 && ymove <=2048)\r
+                       {\r
+                               ob->x = basex;\r
+                               ob->y = basey;\r
+                               return true;\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       if (xmove>=-2048 && xmove <=2048 && ymove>=-2048 && ymove <=2048)\r
+                               return true;\r
+                       moveok = true;\r
+               }\r
+       } while (1);\r
+}\r
+\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                       PLAYER CONTROL\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+\r
+void   T_Player (objtype *ob);\r
+\r
+statetype s_player = {0,0,&T_Player,&s_player};\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnPlayer\r
+=\r
+===============\r
+*/\r
+\r
+void SpawnPlayer (int tilex, int tiley, int dir)\r
+{\r
+#if 0\r
+       levelinfo *li=&gamestate.levels[gamestate.mapon];\r
+\r
+       if (li->x != -1)\r
+       {\r
+               tilex = li->x;\r
+               tiley = li->y;\r
+               player->angle = li->angle;\r
+       }\r
+       else\r
+               player->angle = (1-dir)*90;\r
+#endif\r
+\r
+       player->obclass = playerobj;\r
+       player->active = always;\r
+       player->tilex = tilex;\r
+       player->tiley = tiley;\r
+       player->x = ((long)tilex<<TILESHIFT)+TILEGLOBAL/2;\r
+       player->y = ((long)tiley<<TILESHIFT)+TILEGLOBAL/2;\r
+       player->state = &s_player;\r
+       player->size = MINDIST;\r
+       CalcBounds(player);\r
+       player->angle = (1-dir)*90;\r
+       if (player->angle<0)\r
+               player->angle += ANGLES;\r
+}\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= Thrust\r
+=\r
+===================\r
+*/\r
+\r
+void Thrust (int angle, unsigned speed)\r
+{\r
+       long xmove,ymove;\r
+\r
+       if (lasttimecount>>5 != ((lasttimecount-tics)>>5) )\r
+       {\r
+       //\r
+       // walk sound\r
+       //\r
+               if (lasttimecount&32)\r
+                       SD_PlaySound (WALK1SND);\r
+               else\r
+                       SD_PlaySound (WALK2SND);\r
+       }\r
+\r
+       xmove = FixedByFrac(speed,costable[angle]);\r
+       ymove = -FixedByFrac(speed,sintable[angle]);\r
+\r
+       ClipXMove(player,xmove);\r
+       ClipYMove(player,ymove);\r
+       player->tilex = player->x >> TILESHIFT;\r
+       player->tiley = player->y >> TILESHIFT;\r
+}\r
+\r
+\r
+\r
+/*\r
+=======================\r
+=\r
+= ControlMovement\r
+=\r
+=======================\r
+*/\r
+\r
+void ControlMovement (objtype *ob)\r
+{\r
+       int     angle;\r
+       long    speed;\r
+\r
+\r
+       if (control.button1)\r
+       {\r
+       //\r
+       // strafing\r
+       //\r
+               //\r
+               // side to side move\r
+               //\r
+               if (!mousexmove)\r
+                       speed = 0;\r
+               else if (mousexmove<0)\r
+                       speed = -(long)mousexmove*300;\r
+               else\r
+                       speed = -(long)mousexmove*300;\r
+\r
+               if (control.xaxis == -1)\r
+               {\r
+                       speed += PLAYERSPEED*tics;\r
+               }\r
+               else if (control.xaxis == 1)\r
+               {\r
+                       speed -= PLAYERSPEED*tics;\r
+               }\r
+\r
+               if (speed > 0)\r
+               {\r
+                       if (speed >= TILEGLOBAL)\r
+                               speed = TILEGLOBAL-1;\r
+                       angle = ob->angle + ANGLES/4;\r
+                       if (angle >= ANGLES)\r
+                               angle -= ANGLES;\r
+                       Thrust (angle,speed);                           // move to left\r
+               }\r
+               else if (speed < 0)\r
+               {\r
+                       if (speed <= -TILEGLOBAL)\r
+                               speed = -TILEGLOBAL+1;\r
+                       angle = ob->angle - ANGLES/4;\r
+                       if (angle < 0)\r
+                               angle += ANGLES;\r
+                       Thrust (angle,-speed);                          // move to right\r
+               }\r
+       }\r
+       else\r
+       {\r
+       //\r
+       // not strafing\r
+       //\r
+\r
+               //\r
+               // turning\r
+               //\r
+               if (control.xaxis == 1)\r
+               {\r
+                       ob->angle -= tics;\r
+                       if (running)                            // fast turn\r
+                               ob->angle -= (tics<<1);\r
+               }\r
+               else if (control.xaxis == -1)\r
+               {\r
+                       ob->angle+= tics;\r
+                       if (running)                            // fast turn\r
+                               ob->angle += (tics<<1);\r
+               }\r
+\r
+               ob->angle -= (mousexmove/10);\r
+\r
+               if (ob->angle >= ANGLES)\r
+                       ob->angle -= ANGLES;\r
+               if (ob->angle < 0)\r
+                       ob->angle += ANGLES;\r
+\r
+       }\r
+\r
+       //\r
+       // forward/backwards move\r
+       //\r
+       if (!mouseymove)\r
+               speed = 0;\r
+       else if (mouseymove<0)\r
+               speed = -(long)mouseymove*500;\r
+       else\r
+               speed = -(long)mouseymove*200;\r
+\r
+       if (control.yaxis == -1)\r
+       {\r
+               speed += PLAYERSPEED*tics;\r
+       }\r
+       else if (control.yaxis == 1)\r
+       {\r
+               speed -= PLAYERSPEED*tics;\r
+       }\r
+\r
+       if (speed > 0)\r
+       {\r
+               if (speed >= TILEGLOBAL)\r
+                       speed = TILEGLOBAL-1;\r
+               Thrust (ob->angle,speed);                       // move forwards\r
+       }\r
+       else if (speed < 0)\r
+       {\r
+               if (speed <= -TILEGLOBAL)\r
+                       speed = -TILEGLOBAL+1;\r
+               angle = ob->angle + ANGLES/2;\r
+               if (angle >= ANGLES)\r
+                       angle -= ANGLES;\r
+               Thrust (angle,-speed);                          // move backwards\r
+       }\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= T_Player\r
+=\r
+===============\r
+*/\r
+\r
+void   T_Player (objtype *ob)\r
+{\r
+//     extern boolean autofire;\r
+\r
+       int     angle,speed,scroll,loop;\r
+       unsigned        text,tilex,tiley;\r
+       long    lspeed;\r
+\r
+//     boolean radar_moved=false;\r
+\r
+\r
+       ControlMovement (ob);\r
+\r
+\r
+       //\r
+       // firing\r
+       //\r
+       if (boltsleft)\r
+       {\r
+               handheight+=(realtics<<2);\r
+               if (handheight>MAXHANDHEIGHT)\r
+                       handheight = MAXHANDHEIGHT;\r
+\r
+               ContinueBolt ();\r
+               lasthand = lasttimecount;\r
+       }\r
+       else\r
+       {\r
+               if (control.button0)\r
+               {\r
+                       handheight+=(realtics<<2);\r
+                       if (handheight>MAXHANDHEIGHT)\r
+                               handheight = MAXHANDHEIGHT;\r
+                       lasthand = lasttimecount;\r
+\r
+                       if (!button0down)\r
+                               Shoot();\r
+\r
+//                     if (!autofire)\r
+                               button0down=true;\r
+               }\r
+               else\r
+               {\r
+                       if (lasttimecount > lasthand+HANDPAUSE)\r
+                       {\r
+                               handheight-=(realtics<<1);\r
+                               if (handheight<0)\r
+                                       handheight = 0;\r
+                       }\r
+\r
+                       button0down = false;\r
+               }\r
+}\r
+\r
+#if 0\r
+               if (control.button0)\r
+               {\r
+                       handheight+=(realtics<<2);\r
+                       if (handheight>MAXHANDHEIGHT)\r
+                               handheight = MAXHANDHEIGHT;\r
+\r
+                       if ((unsigned)TimeCount/FIRETIME != lastfiretime)\r
+                               BuildShotPower ();\r
+                       lasthand = lasttimecount;\r
+               }\r
+               else\r
+               {\r
+                       if (lasttimecount > lasthand+HANDPAUSE)\r
+                       {\r
+                               handheight-=(realtics<<1);\r
+                               if (handheight<0)\r
+                                       handheight = 0;\r
+                       }\r
+\r
+                       if (gamestate.shotpower)\r
+                       {\r
+                               lastfiretime = (unsigned)TimeCount/FIRETIME;\r
+                               Shoot ();\r
+                       }\r
+               }\r
+       }\r
+#endif\r
+\r
+       //\r
+       // special actions\r
+       //\r
+\r
+       if ((Keyboard[sc_Space] || Keyboard[sc_C]) && gamestate.body != MAXBODY)\r
+               DrinkPotion ();\r
+\r
+       if (Keyboard[sc_Z] && !boltsleft)\r
+               CastBolt ();\r
+\r
+       if ( (Keyboard[sc_Enter] || Keyboard[sc_X]) && ((TimeCount-lastnuke > NUKETIME))) //|| (autofire)))\r
+               CastNuke ();\r
+\r
+#if 0\r
+       scroll = LastScan-2;\r
+       if ( scroll>=0 && scroll<NUMSCROLLS && gamestate.scrolls[scroll])\r
+               ReadScroll (scroll);\r
+#endif\r
+\r
+       DrawText(false);\r
+       DrawHealth();\r
+       if (FreezeTime)\r
+               DrawFreezeTime();\r
+       DrawRadar();\r
+       EGAWRITEMODE(0);\r
+       DrawNSEWIcons();\r
+\r
+       if (redraw_gems)\r
+               DrawGems();\r
+\r
+#if 0\r
+// gems fade out over time...\r
+//\r
+       for (loop=0; loop<5; loop++)\r
+               if (gamestate.gems[loop])\r
+               {\r
+                       gamestate.gems[loop] -= realtics;\r
+                       if (gamestate.gems[loop] < 0)\r
+                       {\r
+                               gamestate.gems[loop] = 0;\r
+                               redraw_gems = true;\r
+                       }\r
+               }\r
+#endif\r
+}\r
+\r
+#if 0\r
+//------------------------------------------------------------------------\r
+// FaceDir() -\r
+//\r
+// PARAMS : x,y - pixle coords to bring in to view.\r
+//\r
+// NOTE : Params CAN NOT be shifted fracs!\r
+//------------------------------------------------------------------------\r
+void FaceDir(short x,short y,boolean StopTime)\r
+{\r
+       short diff;\r
+\r
+       RotateAngle = CalcAngle(x-(player->x>>16l),(player->y>>16l)-y);\r
+       FreezeTime = StopTime;\r
+\r
+       diff = player->angle - RotateAngle;\r
+\r
+       if (((diff>0) && (diff<180)) || ((diff<0) && (diff>-180)))\r
+               RotateSpeed = -ROTATE_SPEED;\r
+       else\r
+               RotateSpeed = ROTATE_SPEED;\r
+}\r
+#endif\r
+\r
+#if 0\r
+//------------------------------------------------------------------------\r
+// CalcAngle() -\r
+//\r
+// DESC: Calculates the angle from a given dy & dx\r
+//------------------------------------------------------------------------\r
+short CalcAngle(short dx,short dy)\r
+{\r
+       #define degtorad                                (180/PI)\r
+       float angle;\r
+       short diff;\r
+       float rad_angle;\r
+\r
+       if (dx)\r
+       {\r
+               angle = atan((float)dy/dx)* degtorad;\r
+               if (angle<=0)\r
+                       angle += 180;\r
+               if (dy>0)\r
+                       angle += 180;\r
+       }\r
+       else\r
+       {\r
+               // 90 Deg shift\r
+\r
+               if (dy < 0)\r
+                       angle = 0 + 90;                         // Above player (NORTH)\r
+               else\r
+                       angle = 180 + 90;                       // Below player (SOUTH)\r
+       }\r
+\r
+       if (!angle)                             // HACK\r
+               angle++;\r
+\r
+       return((short)abs(angle));\r
+}\r
+\r
+#endif\r
+\r
+#if 0\r
+\r
+//-------------------------------------------------------------------------\r
+// RotateView() -\r
+//\r
+// DESC : Rotates view (current view of game) to a dest angle.\r
+//-------------------------------------------------------------------------\r
+void RotateView()\r
+{\r
+       short LastPos;\r
+\r
+       // Store old angle position then change angle...\r
+       //\r
+\r
+       LastPos = player->angle;\r
+\r
+       player->angle += RotateSpeed;\r
+\r
+       // Check to see if we cranked past out dest angle...\r
+       //\r
+\r
+\r
+       if ((player->angle>ANGLES) || (!player->angle))\r
+               player->angle = 1;\r
+       else\r
+       if (player->angle<1)\r
+               player->angle = ANGLES;\r
+\r
+       // Check to see if we over shot our dest angle...\r
+       //\r
+\r
+       if (((LastPos < RotateAngle) && (player->angle > RotateAngle) && (RotateSpeed > 0)) ||\r
+               ((LastPos > RotateAngle) && (player->angle < RotateAngle) && (RotateSpeed < 0)))\r
+               player->angle = RotateAngle;\r
+\r
+       // Check for ending force turn....\r
+       //\r
+\r
+       if (player->angle == RotateAngle)\r
+               RotateAngle = -1;\r
+\r
+}\r
+\r
+\r
+//--------------------------------------------------------------------------\r
+// InitRotate()\r
+//--------------------------------------------------------------------------\r
+void InitRotate(short DestAngle)\r
+{\r
+       if (player->angle != DestAngle)\r
+       {\r
+               RotateAngle = DestAngle;\r
+\r
+               if (player->angle > DestAngle)\r
+                       RotateSpeed = -ROTATE_SPEED;\r
+               else\r
+                       RotateSpeed = ROTATE_SPEED;\r
+\r
+               if (abs(player->angle - RotateAngle) > 180)\r
+                       RotateSpeed =- RotateSpeed;\r
+       }\r
+}\r
+\r
+\r
+\r
+//------------------------------------------------------------------------\r
+// FaceAngle() -\r
+//\r
+// PARAMS : DestAngle - Destination angle to turn to\r
+//------------------------------------------------------------------------\r
+void FaceAngle(short DestAngle)\r
+{\r
+       signed long dx,dy,radius,psin,pcos,newx,newy;\r
+       int             give;\r
+       short objnum,LastPos;\r
+       signed long ox,oy,xl,xh,yl,yh,px,py,norm_dx,norm_dy;\r
+       short o_radius;\r
+       void (*think)();\r
+\r
+\r
+       // Calculate the direction we want to turn to...\r
+       //\r
+\r
+       InitRotate(DestAngle);\r
+\r
+       RedrawStatusWindow();\r
+\r
+       while (RotateAngle != -1)\r
+       {\r
+\r
+               RotateView();\r
+\r
+//             PollControls();\r
+\r
+               objnum=0;\r
+\r
+               for (obj = player;obj;obj = obj->next)\r
+               {\r
+                       if (obj->active >= yes)\r
+                       {\r
+\r
+                       // keep a list of objects around the player for radar updates\r
+                       //\r
+                               if (obj == player)\r
+                               {\r
+                                       px = player->x;\r
+                                       py = player->y;\r
+                                       psin = sintable[player->angle];\r
+                                       pcos = costable[player->angle];\r
+                                       xl = px-((long)RADAR_WIDTH<<TILESHIFT)/2;\r
+                                       xh = px+((long)RADAR_WIDTH<<TILESHIFT)/2-1;\r
+                                       yl = py-((long)RADAR_HEIGHT<<TILESHIFT)/2;\r
+                                       yh = py+((long)RADAR_HEIGHT<<TILESHIFT)/2;\r
+                               }\r
+\r
+                               if (objnum > MAX_RADAR_BLIPS-2)\r
+                                       objnum = MAX_RADAR_BLIPS-2;\r
+\r
+                               ox = obj->x;\r
+                               oy = obj->y;\r
+\r
+\r
+                               if ((ox >= xl) && (ox <= xh) && (oy >= yl) && (oy <= yh))\r
+                               {\r
+                                       norm_dx = (dx = px-ox)>>TILESHIFT;\r
+                                       norm_dy = (dy = oy-py)>>TILESHIFT;\r
+\r
+                                       o_radius = IntSqrt((norm_dx * norm_dx) + (norm_dy * norm_dy));\r
+\r
+                                       if (o_radius < RADAR_RADIUS)\r
+                                       {\r
+                                               newx = FixedByFrac(dy,pcos)-FixedByFrac(dx,psin);\r
+                                               newy = FixedByFrac(dy,psin)+FixedByFrac(dx,pcos);\r
+\r
+                                               RadarXY[objnum][0]=newx>>TILESHIFT;\r
+                                               RadarXY[objnum][1]=newy>>TILESHIFT;\r
+\r
+                                               // Define color to use for this object...\r
+                                               //\r
+\r
+                                               switch (obj->obclass)\r
+                                               {\r
+                                                       case playerobj:\r
+                                                               RadarXY[objnum++][2]=15;\r
+                                                       break;\r
+\r
+                                               // RED GEM\r
+                                               //\r
+                                                       // STOMPY                                                                               (DK RED)\r
+                                                       //\r
+                                                       case invisdudeobj:\r
+                                                       case stompyobj:\r
+                                                               RadarXY[objnum++][2]=4;\r
+                                                       break;\r
+\r
+                                                       // BLOB                                                                                 (LT RED)\r
+                                                       //\r
+                                                       case blobobj:\r
+                                                               RadarXY[objnum++][2]=12;\r
+                                                       break;\r
+\r
+                                               // BLUE GEM\r
+                                               //\r
+                                                       // ROBOTANK                                                                             (LT BLUE)\r
+                                                       //\r
+                                                       case robotankobj:\r
+                                                       case fmageobj:\r
+                                                               RadarXY[objnum++][2]=9;\r
+                                                       break;\r
+\r
+#if 1\r
+                                                       // BLUE DEMON                                                                   (DK BLUE)\r
+                                                       //\r
+                                                       case demonobj:\r
+                                                               RadarXY[objnum++][2]=1;\r
+                                                       break;\r
+#endif\r
+\r
+                                               // GREEN GEM\r
+                                               //\r
+                                                       // WIZARD                                                                               (LT GREEN)\r
+                                                       //\r
+                                                       case wizardobj:\r
+                                                               RadarXY[objnum++][2]=10;\r
+                                                       break;\r
+\r
+                                                       // AQUA MAN                                                                             (DK GREEN)\r
+                                                       //\r
+                                                       case aquamanobj:\r
+                                                               RadarXY[objnum++][2]=2;\r
+                                                       break;\r
+\r
+                                               // YELLOW GEM\r
+                                               //\r
+                                                       // EQYPTIAN HEAD                                                                (BROWN)\r
+                                                       //\r
+                                                       case headobj:\r
+                                                               RadarXY[objnum++][2]=6;\r
+                                                       break;\r
+\r
+                                                       //      RAMBONE                                                                         (YELLOW)\r
+                                                       //      TROLL\r
+                                                       case ramboneobj:\r
+                                                       case trollobj:\r
+                                                               RadarXY[objnum++][2]=14;\r
+                                                       break;\r
+\r
+                                                       //      BUG                                                                                     (LIGHT GRAY)\r
+                                                       case bugobj:\r
+                                                               RadarXY[objnum++][2]=7;\r
+                                                       break;\r
+\r
+                                                       //      RAY                                                                                     (DARK GRAY)\r
+                                                       case rayobj:\r
+                                                               RadarXY[objnum++][2]=8;\r
+                                                       break;\r
+\r
+                                               // PURPLE GEM\r
+                                               //\r
+                                                       // MEC DEMON                                                                    (PURPLE)\r
+                                                       //\r
+                                                       case cyborgdemonobj:\r
+                                                               RadarXY[objnum++][2]=5;\r
+                                                       break;\r
+\r
+                                                       // EYE                                                                                  (LT PURPLE)\r
+                                                       //\r
+                                                       case eyeobj:\r
+                                                       case reyeobj:\r
+                                                               RadarXY[objnum++][2]=13;\r
+                                                       break;\r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+\r
+               RadarXY[objnum][2]=-1;          // Signals end of RadarXY list...\r
+\r
+// refresh all\r
+//\r
+\r
+               ThreeDRefresh();\r
+               DrawRadar();\r
+               EGAWRITEMODE(0);\r
+               DrawNSEWIcons();\r
+\r
+//             CheckKeys();\r
+       }\r
+}\r
+\r
+\r
+//-------------------------------------------------------------------------\r
+// FaceDoor() - Turns the player to face a door (a tile) at a given TILE x & y\r
+//\r
+// RETURNS : Returns the orginal angle of the player.\r
+//------------------------------------------------------------------------\r
+short FaceDoor(short x, short y)\r
+{\r
+       short p_x,p_y,angle,old_angle;\r
+\r
+       old_angle = player->angle;\r
+\r
+       p_x = player->x>>16l;\r
+       p_y = player->y>>16l;\r
+\r
+       if (p_x != x)\r
+       {\r
+               if (p_x > x)\r
+                       angle = 180;            // Face Left\r
+               else\r
+                       angle = 1;                      // Face Right\r
+       }\r
+\r
+       if (p_y != y)\r
+       {\r
+               if (p_y > y)\r
+                       angle = 90;                     // Face Up\r
+               else\r
+                       angle = 270;            // Face Down\r
+       }\r
+\r
+       FaceAngle(angle);\r
+\r
+       return(old_angle);\r
+}\r
+\r
+\r
+#endif\r
+\r
+\r
+\r
+/*==========================================================================\r
+\r
+                                                               EXPLOSION SPAWNING ROUTINES\r
+\r
+===========================================================================*/\r
+\r
+statetype s_explode = {0,1,T_ExpThink,&s_explode};\r
+\r
+//-------------------------------------------------------------------------\r
+// SpawnExplosion()\r
+//------------------------------------------------------------------------\r
+void SpawnExplosion(fixed x, fixed y, short Delay)\r
+{\r
+       DSpawnNewObjFrac(x,y,&s_explode,PIXRADIUS*7);\r
+       new->obclass = expobj;\r
+       new->active = always;\r
+       new->temp1 = Delay;\r
+}\r
+\r
+\r
+//---------------------------------------------------------------------------\r
+// T_ExpThink()\r
+//---------------------------------------------------------------------------\r
+void T_ExpThink(objtype *obj)\r
+{\r
+       if (obj->temp1)\r
+       {\r
+               if ((obj->temp1-=realtics) <= 0)\r
+                       obj->temp1 = 0;\r
+       }\r
+       else\r
+       {\r
+               obj->state = &s_pshot_exp1;\r
+               obj->ticcount = obj->state->tictime;\r
+               SD_PlaySound(BOOMSND);\r
+       }\r
+}\r
+\r
+\r
+\r
+//-------------------------------------------------------------------------\r
+// SpawnBigExplosion()\r
+//------------------------------------------------------------------------\r
+void SpawnBigExplosion(fixed x, fixed y, short Delay, fixed Range)\r
+{\r
+       SpawnExplosion(x-random(Range),y+random(Range),random(Delay));\r
+       SpawnExplosion(x+random(Range),y-random(Range),random(Delay));\r
+       SpawnExplosion(x-random(Range),y-random(Range),random(Delay));\r
+       SpawnExplosion(x+random(Range),y+random(Range),random(Delay));\r
+}\r
+\r
diff --git a/src/lib/hb/demokd.c b/src/lib/hb/demokd.c
new file mode 100755 (executable)
index 0000000..1b19e36
--- /dev/null
@@ -0,0 +1,126 @@
+/*\r
+=====================\r
+=\r
+= DemoLoop\r
+=\r
+=====================\r
+*/\r
+\r
+void\r
+DemoLoop (void)\r
+{\r
+       char            *s;\r
+       word            move;\r
+       longword        lasttime;\r
+       char *FileName1;\r
+       struct Shape FileShape1;\r
+#if CREDITS\r
+       char *FileName2;\r
+       struct Shape FileShape2;\r
+#endif\r
+       struct ffblk ffblk;\r
+       WindowRec       mywin;\r
+       int bufsave     = bufferofs;\r
+       int dissave     = displayofs;\r
+\r
+\r
+#if FRILLS\r
+//\r
+// check for launch from ted\r
+//\r
+       if (tedlevel)\r
+       {\r
+               NewGame();\r
+               gamestate.mapon = tedlevelnum;\r
+               GameLoop();\r
+               TEDDeath();\r
+       }\r
+#endif\r
+\r
+//\r
+// demo loop\r
+//\r
+       US_SetLoadSaveHooks(LoadGame,SaveGame,ResetGame);\r
+       restartgame = gd_Continue;\r
+\r
+       if (findfirst("KDREAMS.CMP", &ffblk, 0) == -1)\r
+               Quit("Couldn't find KDREAMS.CMP");\r
+\r
+       while (true)\r
+       {\r
+\r
+               loadedgame = false;\r
+\r
+               FileName1 = "TITLESCR.LBM";\r
+               if (LoadLIBShape("KDREAMS.CMP", FileName1, &FileShape1))\r
+                       Quit("Can't load TITLE SCREEN");\r
+#if CREDITS\r
+               FileName2 = "CREDITS.LBM";\r
+               if (LoadLIBShape("KDREAMS.CMP", FileName2, &FileShape2))\r
+                       Quit("Can't load CREDITS SCREEN");\r
+#endif\r
+\r
+               while (!restartgame && !loadedgame)\r
+               {\r
+\r
+                       VW_InitDoubleBuffer();\r
+                       IN_ClearKeysDown();\r
+\r
+                       while (true)\r
+                       {\r
+\r
+                               VW_SetScreen(0, 0);\r
+                               MoveGfxDst(0, 200);\r
+                               UnpackEGAShapeToScreen(&FileShape1, 0, 0);\r
+                               VW_ScreenToScreen (64*200,0,40,200);\r
+\r
+#if CREDITS\r
+                               if (IN_UserInput(TickBase * 8, false))\r
+                                       break;\r
+#else\r
+                               if (IN_UserInput(TickBase * 4, false))\r
+                                       break;\r
+#endif\r
+\r
+#if CREDITS\r
+                               MoveGfxDst(0, 200);\r
+                               UnpackEGAShapeToScreen(&FileShape2, 0, 0);\r
+                               VW_ScreenToScreen (64*200,0,40,200);\r
+\r
+                               if (IN_UserInput(TickBase * 7, false))\r
+                                       break;\r
+#else\r
+                               MoveGfxDst(0, 200);\r
+                               UnpackEGAShapeToScreen(&FileShape1, 0, 0);\r
+                               VW_ScreenToScreen (64*200,0,40,200);\r
+\r
+                               if (IN_UserInput(TickBase * 3, false))\r
+                                       break;\r
+#endif\r
+\r
+                               displayofs = 0;\r
+                               VWB_Bar(0,0,320,200,FIRSTCOLOR);\r
+                               US_DisplayHighScores(-1);\r
+\r
+                               if (IN_UserInput(TickBase * 6, false))\r
+                                       break;\r
+\r
+                       }\r
+\r
+                       bufferofs = bufsave;\r
+                       displayofs = dissave;\r
+\r
+                       VW_FixRefreshBuffer();\r
+                       US_ControlPanel ();\r
+               }\r
+\r
+               if (!loadedgame)\r
+                       NewGame();\r
+\r
+               FreeShape(&FileShape1);\r
+#if CREDITS\r
+               FreeShape(&FileShape2);\r
+#endif\r
+               GameLoop();\r
+       }\r
+}\r
diff --git a/src/lib/hb/demowl.c b/src/lib/hb/demowl.c
new file mode 100755 (executable)
index 0000000..85958ef
--- /dev/null
@@ -0,0 +1,170 @@
+/*\r
+=====================\r
+=\r
+= DemoLoop\r
+=\r
+=====================\r
+*/\r
+\r
+static  char *ParmStrings[] = {"baby","easy","normal","hard",""};\r
+\r
+void    DemoLoop (void)\r
+{\r
+       static int LastDemo;\r
+       int     i,level;\r
+       long nsize;\r
+       memptr  nullblock;\r
+\r
+//\r
+// check for launch from ted\r
+//\r
+       if (tedlevel)\r
+       {\r
+               NoWait = true;\r
+               NewGame(1,0);\r
+\r
+               for (i = 1;i < _argc;i++)\r
+               {\r
+                       if ( (level = US_CheckParm(_argv[i],ParmStrings)) != -1)\r
+                       {\r
+                        gamestate.difficulty=level;\r
+                        break;\r
+                       }\r
+               }\r
+\r
+#ifndef SPEAR\r
+               gamestate.episode = tedlevelnum/10;\r
+               gamestate.mapon = tedlevelnum%10;\r
+#else\r
+               gamestate.episode = 0;\r
+               gamestate.mapon = tedlevelnum;\r
+#endif\r
+               GameLoop();\r
+               Quit (NULL);\r
+       }\r
+\r
+\r
+//\r
+// main game cycle\r
+//\r
+\r
+\r
+//     nsize = (long)40*1024;\r
+//     MM_GetPtr(&nullblock,nsize);\r
+\r
+#ifndef DEMOTEST\r
+\r
+       #ifndef UPLOAD\r
+\r
+               #ifndef GOODTIMES\r
+               #ifndef SPEAR\r
+               #ifndef JAPAN\r
+               if (!NoWait)\r
+                       NonShareware();\r
+               #endif\r
+               #else\r
+\r
+                       #ifndef GOODTIMES\r
+                       #ifndef SPEARDEMO\r
+                       CopyProtection();\r
+                       #endif\r
+                       #endif\r
+\r
+               #endif\r
+               #endif\r
+       #endif\r
+\r
+       StartCPMusic(INTROSONG);\r
+\r
+#ifndef JAPAN\r
+       if (!NoWait)\r
+               PG13 ();\r
+#endif\r
+\r
+#endif\r
+\r
+       while (1)\r
+       {\r
+               while (!NoWait)\r
+               {\r
+//\r
+// title page\r
+//\r
+                       MM_SortMem ();\r
+#ifndef DEMOTEST\r
+\r
+#ifdef SPEAR\r
+                       CA_CacheGrChunk (TITLEPALETTE);\r
+\r
+                       CA_CacheGrChunk (TITLE1PIC);\r
+                       VWB_DrawPic (0,0,TITLE1PIC);\r
+                       UNCACHEGRCHUNK (TITLE1PIC);\r
+\r
+                       CA_CacheGrChunk (TITLE2PIC);\r
+                       VWB_DrawPic (0,80,TITLE2PIC);\r
+                       UNCACHEGRCHUNK (TITLE2PIC);\r
+                       VW_UpdateScreen ();\r
+                       VL_FadeIn(0,255,grsegs[TITLEPALETTE],30);\r
+\r
+                       UNCACHEGRCHUNK (TITLEPALETTE);\r
+#else\r
+                       CA_CacheScreen (TITLEPIC);\r
+                       VW_UpdateScreen ();\r
+                       VW_FadeIn();\r
+#endif\r
+                       if (IN_UserInput(TickBase*15))\r
+                               break;\r
+                       VW_FadeOut();\r
+//\r
+// credits page\r
+//\r
+                       CA_CacheScreen (CREDITSPIC);\r
+                       VW_UpdateScreen();\r
+                       VW_FadeIn ();\r
+                       if (IN_UserInput(TickBase*10))\r
+                               break;\r
+                       VW_FadeOut ();\r
+//\r
+// high scores\r
+//\r
+                       DrawHighScores ();\r
+                       VW_UpdateScreen ();\r
+                       VW_FadeIn ();\r
+\r
+                       if (IN_UserInput(TickBase*10))\r
+                               break;\r
+#endif\r
+//\r
+// demo\r
+//\r
+\r
+                       #ifndef SPEARDEMO\r
+                       PlayDemo (LastDemo++%4);\r
+                       #else\r
+                       PlayDemo (0);\r
+                       #endif\r
+\r
+                       if (playstate == ex_abort)\r
+                               break;\r
+                       StartCPMusic(INTROSONG);\r
+               }\r
+\r
+               VW_FadeOut ();\r
+\r
+#ifndef SPEAR\r
+               if (Keyboard[sc_Tab] && MS_CheckParm("goobers"))\r
+#else\r
+               if (Keyboard[sc_Tab] && MS_CheckParm("debugmode"))\r
+#endif\r
+                       RecordDemo ();\r
+               else\r
+                       US_ControlPanel (0);\r
+\r
+               if (startgame || loadedgame)\r
+               {\r
+                       GameLoop ();\r
+                       VW_FadeOut();\r
+                       StartCPMusic(INTROSONG);\r
+               }\r
+       }\r
+}\r
diff --git a/src/lib/hb/kd_act1.c b/src/lib/hb/kd_act1.c
new file mode 100755 (executable)
index 0000000..d2cf917
--- /dev/null
@@ -0,0 +1,1130 @@
+/* Keen Dreams Source Code\r
+ * Copyright (C) 2014 Javier M. Chavez\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License along\r
+ * with this program; if not, write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+ */\r
+\r
+// KD_ACT1.C\r
+#include "KD_DEF.H"\r
+#pragma hdrstop\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+#define PLACESPRITE RF_PlaceSprite (&ob->sprite,ob->x,ob->y,ob->shapenum, \\r
+       spritedraw,0);\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                GLOBAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+int    flowertime[4] = {700,700,350,175};\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                               MISC ACTOR STUFF\r
+\r
+=============================================================================\r
+*/\r
+\r
+/*\r
+==================\r
+=\r
+= DoGravity\r
+=\r
+= Changes speed and location\r
+=\r
+==================\r
+*/\r
+\r
+\r
+void DoGravity (objtype *ob)\r
+{\r
+       long    i;\r
+//\r
+// only accelerate on odd tics, because of limited precision\r
+//\r
+       for (i=lasttimecount-tics;i<lasttimecount;i++)\r
+       {\r
+               if (i&1)\r
+               {\r
+                       if (ob->yspeed < 0 && ob->yspeed >= -ACCGRAVITY)\r
+                       {\r
+                       // stop at apex of jump\r
+                               ob->ymove += ob->yspeed;\r
+                               ob->yspeed = 0;\r
+                               return;\r
+                       }\r
+                       ob->yspeed+=ACCGRAVITY;\r
+                       if (ob->yspeed>SPDMAXY)\r
+                         ob->yspeed=SPDMAXY;\r
+               }\r
+               ob->ymove+=ob->yspeed;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= AccelerateX\r
+=\r
+===============\r
+*/\r
+\r
+void AccelerateX (objtype *ob,int dir,int max)\r
+{\r
+       long    i;\r
+       unsigned        olddir;\r
+\r
+       olddir = ob->xspeed & 0x8000;\r
+//\r
+// only accelerate on odd tics, because of limited precision\r
+//\r
+       for (i=lasttimecount-tics;i<lasttimecount;i++)\r
+       {\r
+               if (i&1)\r
+               {\r
+                       ob->xspeed+=dir;\r
+                       if ( (ob->xspeed & 0x8000) != olddir)\r
+                       {\r
+                               olddir = ob->xspeed & 0x8000;\r
+                               ob->xdir = olddir ? -1 : 1;\r
+                       }\r
+                       if (ob->xspeed>max)\r
+                         ob->xspeed=max;\r
+                       else if (ob->xspeed<-max)\r
+                         ob->xspeed=-max;\r
+               }\r
+               ob->xmove+=ob->xspeed;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= FrictionX\r
+=\r
+===============\r
+*/\r
+\r
+void FrictionX (objtype *ob)\r
+{\r
+       long    i;\r
+       int             dir;\r
+       unsigned        olddir;\r
+\r
+       olddir = ob->xspeed & 0x8000;\r
+\r
+       if (ob->xspeed > 0)\r
+               dir = -1;\r
+       else if (ob->xspeed < 0)\r
+               dir = 1;\r
+       else\r
+               dir = 0;\r
+//\r
+// only accelerate on odd tics, because of limited precision\r
+//\r
+       for (i=lasttimecount-tics;i<lasttimecount;i++)\r
+       {\r
+               if (i&1)\r
+               {\r
+                       ob->xspeed+=dir;\r
+                       if ( (ob->xspeed & 0x8000) != olddir)\r
+                               ob->xspeed = 0;\r
+               }\r
+               ob->xmove+=ob->xspeed;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= ProjectileThink\r
+=\r
+===============\r
+*/\r
+\r
+void ProjectileThink (objtype *ob)\r
+{\r
+       DoGravity (ob);\r
+       ob->xmove = tics*ob->xspeed;\r
+}\r
+\r
+/*\r
+===============\r
+=\r
+= VelocityThink\r
+=\r
+===============\r
+*/\r
+\r
+void VelocityThink (objtype *ob)\r
+{\r
+       ob->xmove = tics*ob->xspeed;\r
+       ob->ymove = tics*ob->yspeed;\r
+}\r
+\r
+/*\r
+===============\r
+=\r
+= DrawReact\r
+=\r
+===============\r
+*/\r
+\r
+void DrawReact (objtype *ob)\r
+{\r
+       RF_PlaceSprite (&ob->sprite,ob->x,ob->y,ob->shapenum,spritedraw,1);\r
+}\r
+\r
+void DrawReact2 (objtype *ob)\r
+{\r
+       RF_PlaceSprite (&ob->sprite,ob->x,ob->y,ob->shapenum,spritedraw,2);\r
+}\r
+\r
+void DrawReact3 (objtype *ob)\r
+{\r
+       RF_PlaceSprite (&ob->sprite,ob->x,ob->y,ob->shapenum,spritedraw,3);\r
+}\r
+\r
+/*\r
+==================\r
+=\r
+= ChangeState\r
+=\r
+==================\r
+*/\r
+\r
+void ChangeState (objtype *ob, statetype *state)\r
+{\r
+       ob->state = state;\r
+       ob->ticcount = 0;\r
+       if (state->rightshapenum)\r
+       {\r
+               if (ob->xdir>0)\r
+                       ob->shapenum = state->rightshapenum;\r
+               else\r
+                       ob->shapenum = state->leftshapenum;\r
+       }\r
+\r
+       ob->xmove = 0;\r
+       ob->ymove = 0;\r
+\r
+       ob->needtoreact = true;                 // it will need to be redrawn this frame\r
+       ClipToWalls (ob);\r
+}\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= WalkReact\r
+=\r
+====================\r
+*/\r
+\r
+void WalkReact (objtype *ob)\r
+{\r
+       if (ob->xdir == 1 && ob->hitwest)\r
+       {\r
+               ob->x -= ob->xmove;\r
+               ob->xdir = -1;\r
+               ob->nothink = US_RndT()>>5;\r
+               ChangeState (ob,ob->state);\r
+       }\r
+       else if (ob->xdir == -1 && ob->hiteast)\r
+       {\r
+               ob->x -= ob->xmove;\r
+               ob->xdir = 1;\r
+               ob->nothink = US_RndT()>>5;\r
+               ChangeState (ob,ob->state);\r
+       }\r
+       else if (!ob->hitnorth)\r
+       {\r
+               ob->x -= 2*ob->xmove;\r
+               ob->y -= ob->ymove;\r
+\r
+               ob->xdir = -ob->xdir;\r
+               ob->nothink = US_RndT()>>5;\r
+               ChangeState (ob,ob->state);\r
+       }\r
+\r
+       PLACESPRITE;\r
+}\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                       DOOR\r
+\r
+=============================================================================\r
+*/\r
+\r
+void   DoorContact (objtype *ob, objtype *hit);\r
+\r
+extern statetype s_door;\r
+extern statetype s_doorraise;\r
+\r
+statetype s_door        = {DOORSPR,DOORSPR,think,false,\r
+       false,0, 0,0, NULL, DoorContact, DrawReact, &s_door};\r
+statetype s_doorraise = {DOORSPR,DOORSPR,slide,false,\r
+       false,24, 0,32, NULL, DoorContact, DrawReact, NULL};\r
+\r
+/*\r
+======================\r
+=\r
+= SpawnDoor\r
+=\r
+======================\r
+*/\r
+\r
+void   SpawnDoor (int tilex, int tiley)\r
+{\r
+       GetNewObj (false);\r
+\r
+       new->obclass = doorobj;\r
+       new->x = tilex<<G_T_SHIFT;\r
+       new->y = (tiley<<G_T_SHIFT)-2*BLOCKSIZE;\r
+       new->xdir = 1;\r
+       new->ydir = -1;\r
+       new->needtoclip = false;\r
+       NewState (new,&s_door);\r
+}\r
+\r
+/*\r
+======================\r
+=\r
+= DoorContact\r
+=\r
+======================\r
+*/\r
+\r
+void   DoorContact (objtype *ob, objtype *hit)\r
+{\r
+       ClipToSpriteSide (hit,ob);\r
+}\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                       FLOWER\r
+\r
+temp1 = original class\r
+temp2 = original state\r
+temp3 = flower count\r
+\r
+=============================================================================\r
+*/\r
+\r
+void ChangeToFlower (objtype *ob);\r
+void FlowerThink (objtype *ob);\r
+void ChangeFromFlower (objtype *ob);\r
+\r
+extern statetype s_flower1;\r
+extern statetype s_flower2;\r
+extern statetype s_flower3;\r
+extern statetype s_flower4;\r
+extern statetype s_flower5;\r
+extern statetype s_flower6;\r
+\r
+extern statetype s_poofto1;\r
+extern statetype s_poofto2;\r
+extern statetype s_poofto3;\r
+extern statetype s_poofto4;\r
+\r
+extern statetype s_pooffrom1;\r
+extern statetype s_pooffrom2;\r
+extern statetype s_pooffrom3;\r
+extern statetype s_pooffrom4;\r
+extern statetype s_pooffrom5;\r
+extern statetype s_pooffrom6;\r
+extern statetype s_pooffrom7;\r
+\r
+extern statetype s_bonus1;\r
+\r
+#pragma warn -sus\r
+\r
+statetype s_flower1     = {FLOWER1SPR,FLOWER1SPR,stepthink,false,\r
+       false,20, 0,0, FlowerThink, NULL, DrawReact, &s_flower2};\r
+statetype s_flower2     = {FLOWER2SPR,FLOWER2SPR,stepthink,false,\r
+       false,20, 0,0, FlowerThink, NULL, DrawReact, &s_flower3};\r
+statetype s_flower3     = {FLOWER3SPR,FLOWER3SPR,stepthink,false,\r
+       false,20, 0,0, FlowerThink, NULL, DrawReact, &s_flower4};\r
+statetype s_flower4     = {FLOWER4SPR,FLOWER4SPR,stepthink,false,\r
+       false,20, 0,0, FlowerThink, NULL, DrawReact, &s_flower5};\r
+statetype s_flower5     = {FLOWER3SPR,FLOWER3SPR,stepthink,false,\r
+       false,20, 0,0, FlowerThink, NULL, DrawReact, &s_flower6};\r
+statetype s_flower6     = {FLOWER2SPR,FLOWER2SPR,stepthink,false,\r
+       false,20, 0,0, FlowerThink, NULL, DrawReact, &s_flower1};\r
+\r
+statetype s_poofto1             = {POOF1SPR,POOF1SPR,step,false,\r
+       false,10, 0,0, NULL, NULL, DrawReact2, &s_poofto2};\r
+statetype s_poofto2             = {POOF2SPR,POOF2SPR,step,false,\r
+       false,10, 0,0, NULL, NULL, DrawReact2, &s_poofto3};\r
+statetype s_poofto3             = {POOF3SPR,POOF3SPR,step,false,\r
+       false,10, 0,0, NULL, NULL, DrawReact2, &s_poofto4};\r
+statetype s_poofto4             = {POOF4SPR,POOF4SPR,step,false,\r
+       false,10, 0,0, NULL, NULL, DrawReact2, NULL};\r
+\r
+statetype s_pooffrom1           = {POOF4SPR,POOF4SPR,step,false,\r
+       false,10, 0,0, NULL, NULL, DrawReact2, &s_pooffrom2};\r
+statetype s_pooffrom2           = {POOF3SPR,POOF3SPR,step,false,\r
+       false,10, 0,0, NULL, NULL, DrawReact2, &s_pooffrom3};\r
+statetype s_pooffrom3           = {POOF2SPR,POOF2SPR,step,false,\r
+       false,10, 0,0, NULL, NULL, DrawReact2, &s_pooffrom4};\r
+statetype s_pooffrom4           = {POOF1SPR,POOF1SPR,step,false,\r
+       false,20, 0,0, ChangeFromFlower, NULL, DrawReact2, &s_pooffrom5};\r
+statetype s_pooffrom5           = {POOF2SPR,POOF2SPR,step,false,\r
+       false,10, 0,0, NULL, NULL, DrawReact2, &s_pooffrom6};\r
+statetype s_pooffrom6           = {POOF3SPR,POOF3SPR,step,false,\r
+       false,10, 0,0, NULL, NULL, DrawReact2, &s_pooffrom7};\r
+statetype s_pooffrom7           = {POOF4SPR,POOF4SPR,step,false,\r
+       false,10, 0,0, NULL, NULL, DrawReact2, NULL};\r
+\r
+\r
+#pragma warn +sus\r
+\r
+\r
+/*\r
+======================\r
+=\r
+= ChangeToFlower\r
+=\r
+======================\r
+*/\r
+\r
+void ChangeToFlower (objtype *ob)\r
+{\r
+       SD_PlaySound (FLOWERPOWERSND);\r
+       ob->y = ob->bottom-TILEGLOBAL*2;\r
+       ob->temp1 = (int)ob->obclass;\r
+       ob->temp2 = (int)ob->state;\r
+       ob->temp3 = 0;\r
+       ob->needtoclip = true;\r
+       ob->obclass = inertobj;\r
+       ob->xspeed = 0;\r
+       ChangeState (ob,&s_flower1);\r
+       ob->active = allways;                   // flower never deactivated\r
+       GetNewObj (true);\r
+       new->x = ob->x;\r
+       new->y = ob->y;\r
+       NewState (new,&s_poofto1);\r
+       new->active = removable;\r
+}\r
+\r
+\r
+/*\r
+======================\r
+=\r
+= FlowerThink\r
+=\r
+======================\r
+*/\r
+\r
+void FlowerThink (objtype *ob)\r
+{\r
+       ProjectileThink (ob);\r
+       if ( (ob->temp3+=tics) >= flowertime[gamestate.difficulty])\r
+       {\r
+               GetNewObj (true);\r
+               new->active = allways;\r
+               new->temp1 = (int)ob;\r
+               new->x = ob->x;\r
+               new->y = ob->y;\r
+               NewState (new,&s_pooffrom1);\r
+               ob->temp3 = 0;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+======================\r
+=\r
+= ChangeFromFlower\r
+=\r
+======================\r
+*/\r
+\r
+void ChangeFromFlower (objtype *ob)\r
+{\r
+       objtype *flower;\r
+       statetype *state;\r
+       unsigned        oldbottom;\r
+\r
+       SD_PlaySound (UNFLOWERPOWERSND);\r
+       flower = (objtype *)ob->temp1;\r
+\r
+       oldbottom = flower->bottom;\r
+       ChangeState (flower,(statetype *)flower->temp2);\r
+       flower->y += oldbottom - flower->bottom;\r
+\r
+       flower->obclass = flower->temp1;\r
+       flower->active = yes;                   // allow it to unspawn now if off screen\r
+}\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                       BONUS\r
+\r
+temp1 = bonus type\r
+temp2 = base shape number\r
+temp3 = last animated shape number +1\r
+\r
+=============================================================================\r
+*/\r
+\r
+void BonusThink (objtype *ob);\r
+\r
+extern statetype s_bonus1;\r
+\r
+#pragma warn -sus\r
+\r
+statetype s_bonus       = {NULL,NULL,step,false,\r
+       false,20, 0,0, BonusThink, NULL, DrawReact2, &s_bonus};\r
+\r
+statetype s_bonusrise           = {NULL,NULL,slide,false,\r
+       false,40, 0,8, NULL, NULL, DrawReact3, NULL};\r
+\r
+#pragma warn +sus\r
+\r
+/*\r
+====================\r
+=\r
+= SpawnBonus\r
+=\r
+====================\r
+*/\r
+\r
+int bonusshape[12] = {PEPPERMINT1SPR,COOKIE1SPR,CANDYCANE1SPR,CANDYBAR1SPR,\r
+       LOLLIPOP1SPR,COTTONCANDY1SPR,EXTRAKEEN1SPR,SUPERBONUS1SPR,FLOWERPOWER1SPR,\r
+       FLOWERPOWERUP1SPR,BOOBUSBOMB1SPR,MAGICKEY1SPR};\r
+\r
+void SpawnBonus (int tilex, int tiley, int type)\r
+{\r
+       GetNewObj (false);\r
+\r
+       new->needtoclip = false;\r
+       new->obclass = bonusobj;\r
+       new->x = tilex<<G_T_SHIFT;\r
+       new->y = tiley<<G_T_SHIFT;\r
+\r
+       if (type == 9)\r
+               new->y -= 8*PIXGLOBAL;  // flower power up one block\r
+\r
+       new->ydir = -1;                 // bonus stuff flies up when touched\r
+\r
+       new->temp1 = type;\r
+       new->temp2 = new->shapenum = bonusshape[type];\r
+       if (type != 7)\r
+               new->temp3 = new->temp2 + 2;\r
+       else\r
+               new->temp3 = new->temp2 + 4;    // super bonus is 4 stage animation\r
+\r
+       NewState (new,&s_bonus);\r
+}\r
+\r
+/*\r
+====================\r
+=\r
+= BonusThink\r
+=\r
+====================\r
+*/\r
+\r
+void BonusThink (objtype *ob)\r
+{\r
+       if (++ob->shapenum == ob->temp3)\r
+               ob->shapenum = ob->temp2;\r
+}\r
+\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                               BROCCOLASH\r
+\r
+=============================================================================\r
+*/\r
+\r
+void BroccoThink (objtype *ob);\r
+void BroccoGetUp (objtype *ob);\r
+\r
+extern statetype s_broccowalk1;\r
+extern statetype s_broccowalk2;\r
+extern statetype s_broccowalk3;\r
+extern statetype s_broccowalk4;\r
+\r
+extern statetype s_broccosmash1;\r
+extern statetype s_broccosmash2;\r
+extern statetype s_broccosmash3;\r
+extern statetype s_broccosmash4;\r
+extern statetype s_broccosmash5;\r
+extern statetype s_broccosmash6;\r
+extern statetype s_broccosmash7;\r
+extern statetype s_broccosmash8;\r
+extern statetype s_broccosmash9;\r
+\r
+#pragma warn -sus\r
+\r
+statetype s_broccowalk1         = {BROCCOLASHRUNL1SPR,BROCCOLASHRUNR1SPR,step,false,\r
+       true,7, 128,0, BroccoThink, NULL, WalkReact, &s_broccowalk2};\r
+statetype s_broccowalk2         = {BROCCOLASHRUNL2SPR,BROCCOLASHRUNR2SPR,step,false,\r
+       true,7, 128,0, BroccoThink, NULL, WalkReact, &s_broccowalk3};\r
+statetype s_broccowalk3         = {BROCCOLASHRUNL3SPR,BROCCOLASHRUNR3SPR,step,false,\r
+       true,7, 128,0, BroccoThink, NULL, WalkReact, &s_broccowalk4};\r
+statetype s_broccowalk4         = {BROCCOLASHRUNL4SPR,BROCCOLASHRUNR4SPR,step,false,\r
+       true,7, 128,0, BroccoThink, NULL, WalkReact, &s_broccowalk1};\r
+\r
+statetype s_broccosmash1 = {BROCCOLASHSMASHL1SPR,BROCCOLASHSMASHR1SPR,step,true,\r
+       false,3, 0,0, NULL, NULL, DrawReact, &s_broccosmash2};\r
+statetype s_broccosmash2 = {BROCCOLASHSMASHL2SPR,BROCCOLASHSMASHR2SPR,step,true,\r
+       false,3, 0,0, NULL, NULL, DrawReact, &s_broccosmash3};\r
+statetype s_broccosmash3 = {BROCCOLASHSMASHL3SPR,BROCCOLASHSMASHR3SPR,step,true,\r
+       false,3, 0,0, NULL, NULL, DrawReact, &s_broccosmash4};\r
+statetype s_broccosmash4 = {BROCCOLASHSMASHL4SPR,BROCCOLASHSMASHR4SPR,step,false,\r
+       false,7, 0,0, NULL, NULL, DrawReact, &s_broccosmash5};\r
+statetype s_broccosmash5 = {BROCCOLASHSMASHL3SPR,BROCCOLASHSMASHR3SPR,step,true,\r
+       false,6, 0,0, NULL, NULL, DrawReact, &s_broccosmash6};\r
+statetype s_broccosmash6 = {BROCCOLASHSMASHL2SPR,BROCCOLASHSMASHR2SPR,step,true,\r
+       false,6, 0,0, NULL, NULL, DrawReact, &s_broccosmash7};\r
+statetype s_broccosmash7 = {BROCCOLASHSMASHL1SPR,BROCCOLASHSMASHR1SPR,step,true,\r
+       false,6, 0,0, NULL, NULL, DrawReact, &s_broccosmash8};\r
+statetype s_broccosmash8 = {BROCCOLASHRUNL1SPR,BROCCOLASHRUNR1SPR,step,true,\r
+       false,6, 0,0, BroccoGetUp, NULL, DrawReact, &s_broccosmash9};\r
+statetype s_broccosmash9 = {BROCCOLASHRUNL1SPR,BROCCOLASHRUNR1SPR,step,true,\r
+       false,6, 128,0, NULL, NULL, WalkReact, &s_broccowalk1};\r
+\r
+#pragma warn +sus\r
+\r
+/*\r
+====================\r
+=\r
+= SpawnBrocco\r
+=\r
+====================\r
+*/\r
+\r
+void SpawnBrocco (int tilex, int tiley)\r
+{\r
+       GetNewObj (false);\r
+\r
+       new->obclass = broccoobj;\r
+       new->x = tilex<<G_T_SHIFT;\r
+       new->y = (tiley<<G_T_SHIFT)-2*BLOCKSIZE;\r
+       new->xdir = 1;\r
+       NewState (new,&s_broccowalk1);\r
+}\r
+\r
+/*\r
+====================\r
+=\r
+= BroccoGetUp\r
+=\r
+====================\r
+*/\r
+\r
+void BroccoGetUp (objtype *ob)\r
+{\r
+       ob->needtoclip = true;\r
+}\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= BroccoThink\r
+=\r
+====================\r
+*/\r
+\r
+void BroccoThink (objtype *ob)\r
+{\r
+       int delta;\r
+\r
+       if (ob->top > player->bottom || ob->bottom < player->top)\r
+               return;\r
+\r
+       delta = player->x - ob->x;\r
+\r
+       if ( ob->xdir == -1 )\r
+       {\r
+               if (delta < -3*TILEGLOBAL)\r
+                       return;\r
+               if (delta > TILEGLOBAL/2)\r
+               {\r
+                       ob->xdir = 1;\r
+                       return;\r
+               }\r
+               ob->state = &s_broccosmash1;\r
+               ob->needtoclip = false;\r
+               ob->xmove = 0;\r
+               return;\r
+       }\r
+       else\r
+       {\r
+               delta = player->left - ob->right;\r
+               if (delta > 3*TILEGLOBAL)\r
+                       return;\r
+               if (delta < -TILEGLOBAL/2)\r
+               {\r
+                       ob->xdir = -1;\r
+                       return;\r
+               }\r
+               ob->state = &s_broccosmash1;\r
+               ob->needtoclip = false;\r
+               ob->xmove = 0;\r
+               return;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                TOMATOOTH\r
+\r
+ob->temp1 = jumptime\r
+\r
+=============================================================================\r
+*/\r
+\r
+#define        SPDTOMATBOUNCE  30\r
+#define TICTOMATJUMP   10\r
+#define SPDTOMAT               16\r
+\r
+void TomatBounceThink (objtype *ob);\r
+void TomatReact (objtype *ob);\r
+\r
+extern statetype s_tomatbounce;\r
+extern statetype s_tomatbounce2;\r
+\r
+#pragma warn -sus\r
+\r
+statetype s_tomatbounce         = {TOMATOOTHL1SPR,TOMATOOTHR1SPR,stepthink,false,\r
+       false,20, 0,0, TomatBounceThink, NULL, TomatReact, &s_tomatbounce2};\r
+statetype s_tomatbounce2 = {TOMATOOTHL2SPR,TOMATOOTHR2SPR,stepthink,false,\r
+       false,20, 0,0, TomatBounceThink, NULL, TomatReact, &s_tomatbounce};\r
+\r
+#pragma warn +sus\r
+\r
+/*\r
+====================\r
+=\r
+= SpawnTomat\r
+=\r
+====================\r
+*/\r
+\r
+void SpawnTomat (int tilex, int tiley)\r
+{\r
+       GetNewObj (false);\r
+\r
+       new->obclass = tomatobj;\r
+       new->x = tilex<<G_T_SHIFT;\r
+       new->y = (tiley<<G_T_SHIFT)-1*BLOCKSIZE;\r
+       new->xdir = 1;\r
+       NewState (new,&s_tomatbounce);\r
+}\r
+\r
+/*\r
+====================\r
+=\r
+= TomatBounceThink\r
+=\r
+====================\r
+*/\r
+\r
+void TomatBounceThink (objtype *ob)\r
+{\r
+       AccelerateX (ob,ob->x > player->x ? -1 : 1,SPDTOMAT);\r
+       if (ob->xspeed > 0)\r
+               ob->xdir = 1;\r
+       else\r
+               ob->xdir = -1;\r
+\r
+       if (ob->temp1)\r
+       {\r
+               if (ob->temp1<tics)\r
+               {\r
+                       ob->ymove = ob->yspeed*ob->temp1;\r
+                       ob->temp1 = 0;\r
+               }\r
+               else\r
+               {\r
+                       ob->ymove = ob->yspeed*tics;\r
+                       ob->temp1-=tics;\r
+               }\r
+       }\r
+       else\r
+               DoGravity(ob);\r
+\r
+}\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= TomatReactThink\r
+=\r
+====================\r
+*/\r
+\r
+void TomatReact (objtype *ob)\r
+{\r
+       if (ob->hiteast || ob->hitwest)\r
+       {\r
+               ob->xdir = -ob->xdir;\r
+               ob->xspeed = -ob->xspeed;\r
+       }\r
+\r
+       if (ob->hitsouth)\r
+       {\r
+               if (ob->tileright >= originxtile\r
+               && ob->tileleft <= originxtilemax\r
+               && ob->tiletop >= originytile\r
+               && ob->tilebottom <= originytilemax)\r
+                       SD_PlaySound (BOUNCESND);\r
+               ob->yspeed = -ob->yspeed;\r
+       }\r
+\r
+       if (ob->hitnorth)\r
+       {\r
+               if (ob->tileright >= originxtile\r
+               && ob->tileleft <= originxtilemax\r
+               && ob->tiletop >= originytile\r
+               && ob->tilebottom <= originytilemax)\r
+                       SD_PlaySound (BOUNCESND);\r
+               ob->yspeed = -SPDTOMATBOUNCE-(US_RndT()>>4);\r
+               ob->temp1 = TICTOMATJUMP;\r
+       }\r
+\r
+       PLACESPRITE;\r
+}\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                CARROT COURIER\r
+\r
+=============================================================================\r
+*/\r
+\r
+#define        SPDCARROTLEAPX  32\r
+#define SPDCARROTLEAPY  40\r
+\r
+void CarrotThink (objtype *ob);\r
+void CarrotReact (objtype *ob);\r
+void CarrotAirReact (objtype *ob);\r
+\r
+extern statetype s_carrotwalk1;\r
+extern statetype s_carrotwalk2;\r
+extern statetype s_carrotwalk3;\r
+extern statetype s_carrotwalk4;\r
+\r
+extern statetype s_carrotleap;\r
+\r
+#pragma warn -sus\r
+\r
+statetype s_carrotwalk1         = {CARROTRUNL1SPR,CARROTRUNR1SPR,step,false,\r
+       true,5, 128,0, NULL, NULL, CarrotReact, &s_carrotwalk2};\r
+statetype s_carrotwalk2         = {CARROTRUNL2SPR,CARROTRUNR2SPR,step,false,\r
+       true,5, 128,0, NULL, NULL, CarrotReact, &s_carrotwalk3};\r
+statetype s_carrotwalk3         = {CARROTRUNL3SPR,CARROTRUNR3SPR,step,false,\r
+       true,5, 128,0, NULL, NULL, CarrotReact, &s_carrotwalk4};\r
+statetype s_carrotwalk4         = {CARROTRUNL4SPR,CARROTRUNR4SPR,step,false,\r
+       true,5, 128,0, NULL, NULL, CarrotReact, &s_carrotwalk1};\r
+\r
+statetype s_carrotleap  = {CARROTLEAPL1SPR,CARROTLEAPR1SPR,think,false,\r
+       false,0, 0,0, ProjectileThink, NULL, CarrotAirReact, NULL};\r
+\r
+#pragma warn +sus\r
+\r
+/*\r
+====================\r
+=\r
+= SpawnCarrot\r
+=\r
+====================\r
+*/\r
+\r
+void SpawnCarrot (int tilex, int tiley)\r
+{\r
+       GetNewObj (false);\r
+\r
+       new->obclass = carrotobj;\r
+       new->x = tilex<<G_T_SHIFT;\r
+       new->y = (tiley<<G_T_SHIFT)-2*BLOCKSIZE;\r
+       new->xdir = 1;\r
+       new->ydir = 1;\r
+       NewState (new,&s_carrotwalk1);\r
+       new->hitnorth = 1;\r
+}\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= CarrotReact\r
+=\r
+====================\r
+*/\r
+\r
+void CarrotReact (objtype *ob)\r
+{\r
+       unsigned x, width, bot, far *map;\r
+\r
+       if (ob->xdir == 1 && ob->hitwest)\r
+       {\r
+               ob->xdir = -1;\r
+       }\r
+       else if (ob->xdir == -1 && ob->hiteast)\r
+       {\r
+               ob->xdir = 1;\r
+       }\r
+       else if (!ob->hitnorth)\r
+       {\r
+               ob->x -= ob->xmove;\r
+               ob->y -= ob->ymove;\r
+\r
+               ob->yspeed = -SPDCARROTLEAPY;\r
+               ob->xspeed = SPDCARROTLEAPX*ob->xdir;\r
+               ChangeState (ob,&s_carrotleap);\r
+       }\r
+\r
+       PLACESPRITE;\r
+}\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= CarrotAirReact\r
+=\r
+====================\r
+*/\r
+\r
+void CarrotAirReact (objtype *ob)\r
+{\r
+       if (ob->hitsouth)\r
+               ob->yspeed = 0;\r
+\r
+       if (ob->hitnorth)\r
+               ChangeState (ob,&s_carrotwalk1);\r
+\r
+       PLACESPRITE;\r
+}\r
+\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                  ASPARAGUSTO\r
+\r
+=============================================================================\r
+*/\r
+\r
+void AsparThink (objtype *ob);\r
+\r
+extern statetype s_asparwalk1;\r
+extern statetype s_asparwalk2;\r
+extern statetype s_asparwalk3;\r
+extern statetype s_asparwalk4;\r
+\r
+#pragma warn -sus\r
+\r
+statetype s_asparwalk1  = {ASPARAGUSRUNL1SPR,ASPARAGUSRUNR1SPR,step,true,\r
+       true,3, 100,0, NULL, NULL, WalkReact, &s_asparwalk2};\r
+statetype s_asparwalk2  = {ASPARAGUSRUNL2SPR,ASPARAGUSRUNR2SPR,step,false,\r
+       true,3, 100,0, NULL, NULL, WalkReact, &s_asparwalk3};\r
+statetype s_asparwalk3  = {ASPARAGUSRUNL3SPR,ASPARAGUSRUNR3SPR,step,true,\r
+       true,3, 100,0, NULL, NULL, WalkReact, &s_asparwalk4};\r
+statetype s_asparwalk4  = {ASPARAGUSRUNL4SPR,ASPARAGUSRUNR4SPR,step,false,\r
+       true,3, 100,0, NULL, NULL, WalkReact, &s_asparwalk1};\r
+\r
+#pragma warn +sus\r
+\r
+/*\r
+====================\r
+=\r
+= SpawnAspar\r
+=\r
+====================\r
+*/\r
+\r
+void SpawnAspar (int tilex, int tiley)\r
+{\r
+       GetNewObj (false);\r
+\r
+       new->obclass = asparobj;\r
+       new->x = tilex<<G_T_SHIFT;\r
+       new->y = tiley<<G_T_SHIFT;\r
+       new->xdir = 1;\r
+       NewState (new,&s_asparwalk1);\r
+}\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                  SOUR GRAPE\r
+\r
+=============================================================================\r
+*/\r
+\r
+void GrapeThink (objtype *ob);\r
+void GrapeRiseReact (objtype *ob);\r
+void GrapeFallReact (objtype *ob);\r
+\r
+extern statetype s_grapewait;\r
+extern statetype s_grapefall;\r
+extern statetype s_grapesit;\r
+extern statetype s_graperise;\r
+\r
+#pragma warn -sus\r
+\r
+statetype s_grapewait  = {GRAPEONVINESPR,GRAPEONVINESPR,think,false,\r
+       false,0, 0,0, GrapeThink, NULL, DrawReact, NULL};\r
+\r
+statetype s_grapefall  = {GRAPEFALLINGSPR,GRAPEFALLINGSPR,think,false,\r
+       false,0, 0,0, ProjectileThink, NULL, GrapeFallReact, NULL};\r
+\r
+statetype s_grapesit   = {GRAPEONVINESPR,GRAPEONVINESPR,step,false,\r
+       false,30, 0,0, NULL, NULL, DrawReact, &s_graperise};\r
+statetype s_graperise  = {GRAPEONVINESPR,GRAPEONVINESPR,slide,false,\r
+       false,0, 0,-16, NULL, NULL, GrapeRiseReact, NULL};\r
+\r
+#pragma warn +sus\r
+\r
+/*\r
+====================\r
+=\r
+= SpawnGrape\r
+=\r
+====================\r
+*/\r
+\r
+void SpawnGrape (int tilex, int tiley)\r
+{\r
+       GetNewObj (false);\r
+\r
+       new->obclass = grapeobj;\r
+       new->x = tilex<<G_T_SHIFT;\r
+       new->y = tiley<<G_T_SHIFT;\r
+       new->xdir = 1;\r
+       new->ydir = 1;\r
+       NewState (new,&s_grapewait);\r
+}\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= GrapeThink\r
+=\r
+====================\r
+*/\r
+\r
+void GrapeThink (objtype *ob)\r
+{\r
+       unsigned y,starty,endy, far *map;\r
+\r
+       if (player->left > ob->right\r
+               || player->right < ob->left\r
+               || player->y < ob->y )\r
+               return;\r
+\r
+//\r
+// see if there are any walls between grape and player\r
+//\r
+       starty = ob->tilebottom;\r
+       endy = player->tiletop;\r
+\r
+       map = mapsegs[1] + mapbwidthtable[starty]/2 + ob->tilemidx;\r
+       for (y = starty ; y<endy ; y++,map+=mapwidth)\r
+               if (tinf[NORTHWALL+*map])\r
+                       return;\r
+\r
+       ob->state = &s_grapefall;\r
+       SD_PlaySound (GRAPESCREAMSND);\r
+\r
+}\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= GrapeRiseReact\r
+=\r
+====================\r
+*/\r
+\r
+void GrapeRiseReact (objtype *ob)\r
+{\r
+       if (ob->hitsouth)\r
+               ChangeState(ob,&s_grapewait);\r
+       PLACESPRITE;\r
+}\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= GrapeFallReact\r
+=\r
+====================\r
+*/\r
+\r
+void GrapeFallReact (objtype *ob)\r
+{\r
+       if (ob->hitnorth)\r
+       {\r
+               SD_PlaySound (BOUNCESND);\r
+               ob->yspeed = -(ob->yspeed<<1)/3;\r
+               if (ob->yspeed > -32)\r
+                       ChangeState(ob,&s_grapesit);\r
+       }\r
+       PLACESPRITE;\r
+}\r
+\r
diff --git a/src/lib/hb/kd_act2.c b/src/lib/hb/kd_act2.c
new file mode 100755 (executable)
index 0000000..e186540
--- /dev/null
@@ -0,0 +1,1509 @@
+/* Keen Dreams Source Code\r
+ * Copyright (C) 2014 Javier M. Chavez\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License along\r
+ * with this program; if not, write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+ */\r
+\r
+// KD_ACT1.C\r
+#include "KD_DEF.H"\r
+#pragma hdrstop\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+#define PLACESPRITE RF_PlaceSprite (&ob->sprite,ob->x,ob->y,ob->shapenum, \\r
+       spritedraw,0);\r
+\r
+\r
+void   ProjectileReact (objtype *ob);\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                  TATER TROOPER\r
+\r
+temp1 = chasing player\r
+temp2 = nothink time\r
+\r
+=============================================================================\r
+*/\r
+\r
+void TaterThink (objtype *ob);\r
+void BackupReact (objtype *ob);\r
+\r
+extern statetype s_taterwalk1;\r
+extern statetype s_taterwalk2;\r
+extern statetype s_taterwalk3;\r
+extern statetype s_taterwalk4;\r
+\r
+\r
+extern statetype s_taterattack1;\r
+extern statetype s_taterattack2;\r
+extern statetype s_taterattack3;\r
+\r
+#pragma warn -sus\r
+\r
+statetype s_taterwalk1 = {TATERTROOPWALKL1SPR,TATERTROOPWALKR1SPR,step,false,\r
+       true,10, 128,0, TaterThink, NULL, WalkReact, &s_taterwalk2};\r
+statetype s_taterwalk2 = {TATERTROOPWALKL2SPR,TATERTROOPWALKR2SPR,step,false,\r
+       true,10, 128,0, TaterThink, NULL, WalkReact, &s_taterwalk3};\r
+statetype s_taterwalk3 = {TATERTROOPWALKL3SPR,TATERTROOPWALKR3SPR,step,false,\r
+       true,10, 128,0, TaterThink, NULL, WalkReact, &s_taterwalk4};\r
+statetype s_taterwalk4 = {TATERTROOPWALKL4SPR,TATERTROOPWALKR4SPR,step,false,\r
+       true,10, 128,0, TaterThink, NULL, WalkReact, &s_taterwalk1};\r
+\r
+statetype s_taterattack1= {TATERTROOPLUNGEL1SPR,TATERTROOPLUNGER1SPR,step,false,\r
+       false,12, 0,0, NULL, NULL, BackupReact, &s_taterattack2};\r
+statetype s_taterattack2= {TATERTROOPLUNGEL2SPR,TATERTROOPLUNGER2SPR,step,false,\r
+       false,20, 0,0, NULL, NULL, DrawReact, &s_taterattack3};\r
+statetype s_taterattack3= {TATERTROOPLUNGEL1SPR,TATERTROOPLUNGER1SPR,step,false,\r
+       false,8, 0,0, NULL, NULL, DrawReact, &s_taterwalk1};\r
+\r
+#pragma warn +sus\r
+\r
+/*\r
+====================\r
+=\r
+= SpawnTater\r
+=\r
+====================\r
+*/\r
+\r
+void SpawnTater (int tilex, int tiley)\r
+{\r
+       GetNewObj (false);\r
+\r
+       new->obclass = taterobj;\r
+       new->x = tilex<<G_T_SHIFT;\r
+       new->y = (tiley<<G_T_SHIFT)-2*BLOCKSIZE + 15;\r
+       new->xdir = 1;\r
+       new->ydir = 1;\r
+       NewState (new,&s_taterwalk1);\r
+       new->hitnorth = 1;\r
+}\r
+\r
+/*\r
+====================\r
+=\r
+= TaterThink\r
+=\r
+====================\r
+*/\r
+\r
+void TaterThink (objtype *ob)\r
+{\r
+       int delta;\r
+\r
+       if (ob->top > player->bottom || ob->bottom < player->top)\r
+               return;\r
+\r
+       if ( ob->xdir == -1 )\r
+       {\r
+               delta = ob->left - player->right;\r
+               if (delta > TILEGLOBAL)\r
+                       return;\r
+               if (delta < -8*PIXGLOBAL)\r
+               {\r
+                       ob->xdir = 1;\r
+                       return;\r
+               }\r
+               SD_PlaySound (TATERSWINGSND);\r
+               ob->state = &s_taterattack1;\r
+               return;\r
+       }\r
+       else\r
+       {\r
+               delta = player->left - ob->right;\r
+               if (delta > TILEGLOBAL)\r
+                       return;\r
+               if (delta < -8*PIXGLOBAL)\r
+               {\r
+                       ob->xdir = -1;\r
+                       return;\r
+               }\r
+               SD_PlaySound (TATERSWINGSND);\r
+               ob->state = &s_taterattack1;\r
+               return;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= BackupReact\r
+=\r
+====================\r
+*/\r
+\r
+void BackupReact (objtype *ob)\r
+{\r
+       if (!ob->hitnorth)\r
+       {\r
+               ob->x-=ob->xmove;\r
+               ob->y-=ob->ymove;\r
+       }\r
+\r
+       PLACESPRITE;\r
+}\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                  CANTELOUPE CART\r
+\r
+=============================================================================\r
+*/\r
+\r
+extern statetype s_cartroll1;\r
+extern statetype s_cartroll2;\r
+\r
+void CartReact (objtype *ob);\r
+\r
+#pragma warn -sus\r
+\r
+statetype s_cartroll1  = {CANTCARTL1SPR,CANTCARTL1SPR,slide,true,\r
+       false,5, 32,0, NULL, NULL, CartReact, &s_cartroll2};\r
+statetype s_cartroll2  = {CANTCARTL2SPR,CANTCARTL2SPR,slide,true,\r
+       false,5, 32,0, NULL, NULL, CartReact, &s_cartroll1};\r
+\r
+#pragma warn +sus\r
+\r
+/*\r
+====================\r
+=\r
+= SpawnCart\r
+=\r
+====================\r
+*/\r
+\r
+void SpawnCart (int tilex, int tiley)\r
+{\r
+       GetNewObj (false);\r
+\r
+       new->obclass = cartobj;\r
+       new->x = tilex<<G_T_SHIFT;\r
+       new->y = (tiley<<G_T_SHIFT)-3*PIXGLOBAL;\r
+       new->xdir = 1;\r
+       new->ydir = 1;\r
+       new->active = allways;\r
+       NewState (new,&s_cartroll1);\r
+}\r
+\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= CartReact\r
+=\r
+====================\r
+*/\r
+\r
+void CartReact (objtype *ob)\r
+{\r
+       unsigned far *map;\r
+\r
+       if (ob->xdir == 1 && ob->hitwest)\r
+       {\r
+               ob->xdir = -1;\r
+       }\r
+       else if (ob->xdir == -1 && ob->hiteast)\r
+       {\r
+               ob->xdir = 1;\r
+       }\r
+\r
+       map = mapsegs[1] + mapbwidthtable[ob->tilebottom+1]/2;\r
+       if (ob->xdir == 1)\r
+               map += ob->tileright;\r
+       else\r
+               map += ob->tileleft;\r
+\r
+       if ( !tinf[NORTHWALL + *map] )\r
+               ob->xdir = -ob->xdir;\r
+\r
+       PLACESPRITE;\r
+}\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                       FRENCHY\r
+\r
+=============================================================================\r
+*/\r
+\r
+#define FRYXSPEED      40\r
+#define FRYYSPEED      -20\r
+\r
+\r
+void FrenchyThink (objtype *ob);\r
+void FrenchyRunThink (objtype *ob);\r
+void FrenchyThrow (objtype *ob);\r
+\r
+extern statetype s_frenchywalk1;\r
+extern statetype s_frenchywalk2;\r
+extern statetype s_frenchywalk3;\r
+extern statetype s_frenchywalk4;\r
+\r
+extern statetype s_frenchyrun1;\r
+extern statetype s_frenchyrun2;\r
+extern statetype s_frenchyrun3;\r
+extern statetype s_frenchyrun4;\r
+\r
+extern statetype s_frenchythrow1;\r
+extern statetype s_frenchythrow2;\r
+extern statetype s_frenchythrow3;\r
+\r
+extern statetype s_fry1;\r
+extern statetype s_fry2;\r
+\r
+#pragma warn -sus\r
+\r
+statetype s_frenchywalk1       = {FRENCHYRUNL1SPR,FRENCHYRUNR1SPR,step,false,\r
+       true,10, 128,0, FrenchyThink, NULL, WalkReact, &s_frenchywalk2};\r
+statetype s_frenchywalk2       = {FRENCHYRUNL2SPR,FRENCHYRUNR2SPR,step,false,\r
+       true,10, 128,0, FrenchyThink, NULL, WalkReact, &s_frenchywalk3};\r
+statetype s_frenchywalk3       = {FRENCHYRUNL3SPR,FRENCHYRUNR3SPR,step,false,\r
+       true,10, 128,0, FrenchyThink, NULL, WalkReact, &s_frenchywalk4};\r
+statetype s_frenchywalk4       = {FRENCHYRUNL4SPR,FRENCHYRUNR4SPR,step,false,\r
+       true,10, 128,0, FrenchyThink, NULL, WalkReact, &s_frenchywalk1};\r
+\r
+statetype s_frenchyrun1        = {FRENCHYRUNL1SPR,FRENCHYRUNR1SPR,step,true,\r
+       true,5, 128,0, FrenchyRunThink, NULL, WalkReact, &s_frenchyrun2};\r
+statetype s_frenchyrun2        = {FRENCHYRUNL2SPR,FRENCHYRUNR2SPR,step,true,\r
+       true,5, 128,0, FrenchyRunThink, NULL, WalkReact, &s_frenchyrun3};\r
+statetype s_frenchyrun3        = {FRENCHYRUNL3SPR,FRENCHYRUNR3SPR,step,true,\r
+       true,5, 128,0, FrenchyRunThink, NULL, WalkReact, &s_frenchyrun4};\r
+statetype s_frenchyrun4        = {FRENCHYRUNL4SPR,FRENCHYRUNR4SPR,step,true,\r
+       true,5, 128,0, FrenchyRunThink, NULL, WalkReact, &s_frenchyrun1};\r
+\r
+statetype s_frenchythrow1      = {FRENCHYTHROWL1SPR,FRENCHYTHROWR1SPR,step,false,\r
+       false,10, 0,0, NULL, NULL, DrawReact, &s_frenchythrow2};\r
+statetype s_frenchythrow2      = {FRENCHYTHROWL2SPR,FRENCHYTHROWR2SPR,step,false,\r
+       false,1, 0,0, FrenchyThrow, NULL, DrawReact, &s_frenchythrow3};\r
+statetype s_frenchythrow3      = {FRENCHYTHROWL2SPR,FRENCHYTHROWR2SPR,step,false,\r
+       false,10, -128,0, NULL, NULL, DrawReact, &s_frenchywalk1};\r
+\r
+statetype s_fry1               = {FRENCHFRY1SPR,FRENCHFRY1SPR,stepthink,false,\r
+       false,4, 0,0, ProjectileThink, NULL, ProjectileReact, &s_fry2};\r
+statetype s_fry2               = {FRENCHFRY2SPR,FRENCHFRY2SPR,stepthink,false,\r
+       false,4, 0,0, ProjectileThink, NULL, ProjectileReact, &s_fry1};\r
+\r
+\r
+#pragma warn +sus\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= SpawnFrenchy\r
+=\r
+====================\r
+*/\r
+\r
+void SpawnFrenchy (int tilex, int tiley)\r
+{\r
+       GetNewObj (false);\r
+\r
+       new->obclass = frenchyobj;\r
+       new->x = tilex<<G_T_SHIFT;\r
+       new->y = (tiley<<G_T_SHIFT)-2*BLOCKSIZE;\r
+       new->xdir = 1;\r
+       new->ydir = 1;\r
+       NewState (new,&s_frenchywalk1);\r
+}\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= FrenchyRunThink\r
+=\r
+====================\r
+*/\r
+\r
+void FrenchyRunThink (objtype *ob)\r
+{\r
+       ob->state = &s_frenchywalk1;\r
+}\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= FrenchyThrow\r
+=\r
+====================\r
+*/\r
+\r
+void FrenchyThrow (objtype *ob)\r
+{\r
+       GetNewObj (true);\r
+       new->obclass = shotobj;\r
+       if (ob->xdir == 1)\r
+       {\r
+               new->x = ob->x+24*16;\r
+               new->y = ob->y+8*16;\r
+       }\r
+       else\r
+       {\r
+               new->x = ob->x;\r
+               new->y = ob->y+8*16;\r
+       }\r
+       new->xdir = ob->xdir;\r
+       new->ydir = 1;\r
+       new->xspeed = ob->xdir * FRYXSPEED-(US_RndT()>>4);\r
+       new->yspeed = FRYYSPEED;\r
+       new->active = removable;\r
+       NewState (new,&s_fry1);\r
+\r
+       ob->nothink = 2;\r
+}\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= FrenchyThink\r
+=\r
+====================\r
+*/\r
+\r
+void FrenchyThink (objtype *ob)\r
+{\r
+       int delta;\r
+\r
+       if ( abs(ob->y - player->y) > 3*TILEGLOBAL )\r
+       {\r
+               if (US_RndT()<8)\r
+                       ob->xdir = -ob->xdir;           // turn randomly\r
+               return;\r
+       }\r
+\r
+       delta = player->x - ob->x;\r
+\r
+       if (delta < -8*TILEGLOBAL)\r
+       {\r
+       // walk closer\r
+               ob->xdir = -1;\r
+       }\r
+       if (delta < -4*TILEGLOBAL)\r
+       {\r
+       // throw\r
+               ob->xdir = -1;\r
+               ob->state = &s_frenchythrow1;\r
+       }\r
+       else if (delta < 0)\r
+       {\r
+       // run away\r
+               ob->xdir = 1;\r
+               ob->state = &s_frenchyrun1;\r
+               ob->nothink = 8;\r
+       }\r
+       else if (delta < 4*TILEGLOBAL)\r
+       {\r
+       // run away\r
+               ob->xdir = -1;\r
+               ob->state = &s_frenchyrun1;\r
+               ob->nothink = 8;\r
+       }\r
+       else if (delta < 8*TILEGLOBAL)\r
+       {\r
+       // throw and walk closer\r
+               ob->xdir = 1;\r
+               ob->state = &s_frenchythrow1;\r
+       }\r
+       else\r
+       {\r
+       // walk closer\r
+               ob->xdir = 1;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                 MELON LIPS\r
+\r
+ob->temp1 = direction : 0 = left, 1 = right, 2 = down\r
+\r
+=============================================================================\r
+*/\r
+\r
+#define SPITXSPEED     48\r
+#define SPITYSPEED     -20\r
+\r
+void MelonSpitThink (objtype *ob);\r
+void   ProjectileReact (objtype *ob);\r
+\r
+extern statetype s_melonside;\r
+extern statetype s_melonsidespit;\r
+extern statetype s_melonsidespit2;\r
+\r
+extern statetype s_melondown;\r
+extern statetype s_melondownspit;\r
+extern statetype s_melondownspit2;\r
+\r
+extern statetype s_melonseed1;\r
+extern statetype s_melonseed2;\r
+\r
+extern statetype s_melonseedd1;\r
+extern statetype s_melonseedd2;\r
+\r
+#pragma warn -sus\r
+\r
+statetype s_melonside  = {MELONLIPSL1SPR,MELONLIPSR1SPR,step,false,\r
+       false,200, 0,0, NULL, NULL, DrawReact, &s_melonsidespit};\r
+statetype s_melonsidespit= {MELONLIPSL2SPR,MELONLIPSR2SPR,step,false,\r
+       false,6, 0,0, MelonSpitThink, NULL, DrawReact, &s_melonsidespit2};\r
+statetype s_melonsidespit2= {MELONLIPSL2SPR,MELONLIPSR2SPR,step,false,\r
+       false,6, 0,0, NULL, NULL, DrawReact, &s_melonside};\r
+\r
+statetype s_melondown  = {MELONLIPSD1SPR,MELONLIPSD1SPR,step,false,\r
+       false,200, 0,0, NULL, NULL, DrawReact, &s_melondownspit};\r
+statetype s_melondownspit      = {MELONLIPSD2SPR,MELONLIPSD2SPR,step,false,\r
+       false,6, 0,0, MelonSpitThink, NULL, DrawReact, &s_melondownspit2};\r
+statetype s_melondownspit2     = {MELONLIPSD2SPR,MELONLIPSD2SPR,step,false,\r
+       false,6, 0,0, NULL, NULL, DrawReact, &s_melondown};\r
+\r
+statetype s_melonseed1 = {MELONSEEDL1SPR,MELONSEEDR1SPR,think,false,\r
+       false,4, 0,0, ProjectileThink, NULL, ProjectileReact, &s_melonseed2};\r
+statetype s_melonseed2 = {MELONSEEDL2SPR,MELONSEEDR2SPR,think,false,\r
+       false,4, 0,0, ProjectileThink, NULL, ProjectileReact, &s_melonseed1};\r
+\r
+statetype s_melonseedd1        = {MELONSEEDD1SPR,MELONSEEDD1SPR,stepthink,false,\r
+       false,4, 0,0, ProjectileThink, NULL, ProjectileReact, &s_melonseedd2};\r
+statetype s_melonseedd2        = {MELONSEEDD2SPR,MELONSEEDD2SPR,stepthink,false,\r
+       false,4, 0,0, ProjectileThink, NULL, ProjectileReact, &s_melonseedd1};\r
+\r
+#pragma warn +sus\r
+\r
+/*\r
+====================\r
+=\r
+= SpawnMelon\r
+=\r
+====================\r
+*/\r
+\r
+void SpawnMelon (int tilex, int tiley,int dir)\r
+{\r
+       GetNewObj (false);\r
+\r
+       new->obclass = melonobj;\r
+       new->x = tilex<<G_T_SHIFT;\r
+       new->y = tiley<<G_T_SHIFT;\r
+       if (dir)\r
+               new->xdir = 1;\r
+       else\r
+               new->xdir = -1;\r
+       if (dir <2)\r
+               NewState (new,&s_melonside);\r
+       else\r
+               NewState (new,&s_melondown);\r
+\r
+       new->ticcount = US_RndT()>>1;\r
+       new->temp1 = dir;\r
+}\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= MelonSpitThink\r
+=\r
+====================\r
+*/\r
+\r
+void MelonSpitThink (objtype *ob)\r
+{\r
+       GetNewObj (false);\r
+       new->obclass = shotobj;\r
+       switch (ob->temp1)\r
+       {\r
+       case 0:\r
+               new->x = ob->x+24*16;\r
+               new->y = ob->y+8*16;\r
+               new->xdir = ob->xdir;\r
+               new->ydir = 1;\r
+               new->xspeed = -SPITXSPEED-(US_RndT()>>4);\r
+               new->yspeed = SPITYSPEED;\r
+               NewState (new,&s_melonseed1);\r
+               break;\r
+       case 1:\r
+               new->x = ob->x;\r
+               new->y = ob->y+8*16;\r
+               new->xdir = ob->xdir;\r
+               new->ydir = 1;\r
+               new->xspeed = SPITXSPEED+(US_RndT()>>4);\r
+               new->yspeed = SPITYSPEED;\r
+               NewState (new,&s_melonseed1);\r
+               break;\r
+       case 2:\r
+               new->x = ob->x+8*16;\r
+               new->y = ob->y+24*16;\r
+               new->ydir = 1;\r
+               new->yspeed = -SPITYSPEED;\r
+               NewState (new,&s_melonseedd1);\r
+               break;\r
+       }\r
+\r
+       new->active = removable;\r
+}\r
+\r
+/*\r
+============================\r
+=\r
+= ProjectileReact\r
+=\r
+============================\r
+*/\r
+\r
+void   ProjectileReact (objtype *ob)\r
+{\r
+       unsigned wall,absx,absy,angle,newangle;\r
+       unsigned long speed;\r
+\r
+       PLACESPRITE;\r
+       if (ob->hiteast || ob->hitwest)\r
+               ob->xspeed= -ob->xspeed/2;\r
+\r
+       if (ob->hitsouth)\r
+               ob->yspeed= -ob->yspeed/2;\r
+\r
+       wall = ob->hitnorth;\r
+       if (wall)\r
+       {\r
+               if (ob->yspeed < 0)\r
+                       ob->yspeed = 0;\r
+\r
+               absx = abs(ob->xspeed);\r
+               absy = ob->yspeed;\r
+               if (absx>absy)\r
+               {\r
+                       if (absx>absy*2)        // 22 degrees\r
+                       {\r
+                               angle = 0;\r
+                               speed = absx*286;       // x*sqrt(5)/2\r
+                       }\r
+                       else                            // 45 degrees\r
+                       {\r
+                               angle = 1;\r
+                               speed = absx*362;       // x*sqrt(2)\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       if (absy>absx*2)        // 90 degrees\r
+                       {\r
+                               angle = 3;\r
+                               speed = absy*256;\r
+                       }\r
+                       else\r
+                       {\r
+                               angle = 2;              // 67 degrees\r
+                               speed = absy*286;       // y*sqrt(5)/2\r
+                       }\r
+               }\r
+               if (ob->xspeed > 0)\r
+                       angle = 7-angle;\r
+\r
+               speed >>= 1;\r
+               newangle = bounceangle[ob->hitnorth][angle];\r
+               switch (newangle)\r
+               {\r
+               case 0:\r
+                       ob->xspeed = speed / 286;\r
+                       ob->yspeed = -ob->xspeed / 2;\r
+                       break;\r
+               case 1:\r
+                       ob->xspeed = speed / 362;\r
+                       ob->yspeed = -ob->xspeed;\r
+                       break;\r
+               case 2:\r
+                       ob->yspeed = -(speed / 286);\r
+                       ob->xspeed = -ob->yspeed / 2;\r
+                       break;\r
+               case 3:\r
+\r
+               case 4:\r
+                       ob->xspeed = 0;\r
+                       ob->yspeed = -(speed / 256);\r
+                       break;\r
+               case 5:\r
+                       ob->yspeed = -(speed / 286);\r
+                       ob->xspeed = ob->yspeed / 2;\r
+                       break;\r
+               case 6:\r
+                       ob->xspeed = ob->yspeed = -(speed / 362);\r
+                       break;\r
+               case 7:\r
+                       ob->xspeed = -(speed / 286);\r
+                       ob->yspeed = ob->xspeed / 2;\r
+                       break;\r
+\r
+               case 8:\r
+                       ob->xspeed = -(speed / 286);\r
+                       ob->yspeed = -ob->xspeed / 2;\r
+                       break;\r
+               case 9:\r
+                       ob->xspeed = -(speed / 362);\r
+                       ob->yspeed = -ob->xspeed;\r
+                       break;\r
+               case 10:\r
+                       ob->yspeed = speed / 286;\r
+                       ob->xspeed = -ob->yspeed / 2;\r
+                       break;\r
+               case 11:\r
+\r
+               case 12:\r
+                       ob->xspeed = 0;\r
+                       ob->yspeed = -(speed / 256);\r
+                       break;\r
+               case 13:\r
+                       ob->yspeed = speed / 286;\r
+                       ob->xspeed = ob->yspeed / 2;\r
+                       break;\r
+               case 14:\r
+                       ob->xspeed = speed / 362;\r
+                       ob->yspeed = speed / 362;\r
+                       break;\r
+               case 15:\r
+                       ob->xspeed = speed / 286;\r
+                       ob->yspeed = ob->xspeed / 2;\r
+                       break;\r
+               }\r
+\r
+               if (speed < 256*16)\r
+                       RemoveObj (ob);\r
+       }\r
+}\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                       SQUASHER\r
+\r
+=============================================================================\r
+*/\r
+\r
+#define SPDSQUASHLEAPY  50\r
+\r
+\r
+void SquasherThink (objtype *ob);\r
+void SquasherJumpReact (objtype *ob);\r
+\r
+extern statetype s_squasherwalk1;\r
+extern statetype s_squasherwalk2;\r
+\r
+extern statetype s_squasherjump1;\r
+extern statetype s_squasherjump2;\r
+\r
+extern statetype s_squasherwait;\r
+\r
+#pragma warn -sus\r
+\r
+statetype s_squasherwalk1      = {SQUASHERWALKL1SPR,SQUASHERWALKR1SPR,step,false,\r
+       true,10, 128,0, SquasherThink, NULL, WalkReact, &s_squasherwalk2};\r
+statetype s_squasherwalk2      = {SQUASHERWALKL2SPR,SQUASHERWALKR2SPR,step,false,\r
+       true,10, 128,0, SquasherThink, NULL, WalkReact, &s_squasherwalk1};\r
+\r
+statetype s_squasherjump1      = {SQUASHERJUMPL1SPR,SQUASHERJUMPR1SPR,stepthink,false,\r
+       false,20, 0,0, ProjectileThink, NULL, SquasherJumpReact, &s_squasherjump2};\r
+statetype s_squasherjump2      = {SQUASHERJUMPL2SPR,SQUASHERJUMPR2SPR,think,false,\r
+       false,0, 0,0, ProjectileThink, NULL, SquasherJumpReact, NULL};\r
+\r
+statetype s_squasherwait       = {SQUASHERJUMPL2SPR,SQUASHERJUMPR2SPR,step,false,\r
+       false,10, 0,0, ProjectileThink, NULL, DrawReact, &s_squasherwalk1};\r
+\r
+#pragma warn +sus\r
+\r
+/*\r
+====================\r
+=\r
+= SpawnSquasher\r
+=\r
+====================\r
+*/\r
+\r
+void SpawnSquasher (int tilex, int tiley)\r
+{\r
+       GetNewObj (false);\r
+\r
+       new->obclass = squashobj;\r
+       new->x = tilex<<G_T_SHIFT;\r
+       new->y = (tiley<<G_T_SHIFT)-2*BLOCKSIZE;\r
+       new->xdir = 1;\r
+       new->ydir = 1;\r
+       NewState (new,&s_squasherwalk1);\r
+}\r
+\r
+/*\r
+====================\r
+=\r
+= SquasherThink\r
+=\r
+====================\r
+*/\r
+\r
+void SquasherThink (objtype *ob)\r
+{\r
+       int delta;\r
+\r
+       if ( abs(ob->y - player->y) > 3*TILEGLOBAL )\r
+       {\r
+               if (US_RndT()<8)\r
+                       ob->xdir = -ob->xdir;           // turn randomly\r
+               return;\r
+       }\r
+\r
+\r
+       delta = player->x - ob->x;\r
+\r
+       if ( ob->xdir == -1 )\r
+       {\r
+               if (delta < -6*TILEGLOBAL)\r
+                       return;\r
+               if (delta > 8*PIXGLOBAL)\r
+               {\r
+                       ob->xdir = 1;\r
+                       return;\r
+               }\r
+       }\r
+       else\r
+       {\r
+               if (delta > 6*TILEGLOBAL)\r
+                       return;\r
+               if (delta < -8*PIXGLOBAL)\r
+               {\r
+                       ob->xdir = 1;\r
+                       return;\r
+               }\r
+       }\r
+\r
+       ob->yspeed = -SPDSQUASHLEAPY;\r
+       ob->xspeed = delta/60;\r
+       ob->state = &s_squasherjump1;\r
+}\r
+\r
+/*\r
+====================\r
+=\r
+= SquasherJumpReact\r
+=\r
+====================\r
+*/\r
+\r
+void SquasherJumpReact (objtype *ob)\r
+{\r
+       if (ob->hitsouth)\r
+               ob->yspeed = 0;\r
+\r
+       if (ob->hitnorth)\r
+               ChangeState (ob,&s_squasherwait);\r
+\r
+       PLACESPRITE;\r
+}\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                               APEL\r
+\r
+temp4 = pole x coordinate\r
+\r
+=============================================================================\r
+*/\r
+\r
+void ApelThink (objtype *ob);\r
+void ApelClimbThink (objtype *ob);\r
+void ApelSlideThink (objtype *ob);\r
+void ApelFallThink (objtype *ob);\r
+\r
+void ApelClimbReact (objtype *ob);\r
+void ApelSlideReact (objtype *ob);\r
+void ApelFallReact (objtype *ob);\r
+\r
+extern statetype s_apelwalk1;\r
+extern statetype s_apelwalk2;\r
+extern statetype s_apelwalk3;\r
+\r
+extern statetype s_apelclimb1;\r
+extern statetype s_apelclimb2;\r
+\r
+extern statetype s_apelslide1;\r
+extern statetype s_apelslide2;\r
+extern statetype s_apelslide3;\r
+extern statetype s_apelslide4;\r
+\r
+extern statetype s_apelfall;\r
+\r
+#pragma warn -sus\r
+\r
+statetype s_apelwalk1  = {APELWALKL1SPR,APELWALKR1SPR,step,false,\r
+       true,10, 128,0, ApelThink, NULL, WalkReact, &s_apelwalk2};\r
+statetype s_apelwalk2  = {APELWALKL2SPR,APELWALKR2SPR,step,false,\r
+       true,10, 128,0, ApelThink, NULL, WalkReact, &s_apelwalk3};\r
+statetype s_apelwalk3  = {APELWALKL3SPR,APELWALKR3SPR,step,false,\r
+       true,10, 128,0, ApelThink, NULL, WalkReact, &s_apelwalk1};\r
+\r
+statetype s_apelclimb1 = {APELSHINNY1SPR,APELSHINNY1SPR,slide,false,\r
+       false,6, 0,-16, ApelClimbThink, NULL, ApelClimbReact, &s_apelclimb2};\r
+statetype s_apelclimb2 = {APELSHINNY2SPR,APELSHINNY2SPR,slide,false,\r
+       false,6, 0,-16, ApelClimbThink, NULL, ApelClimbReact, &s_apelclimb1};\r
+\r
+statetype s_apelslide1 = {APELSLIDE1SPR,APELSLIDE1SPR,slide,false,\r
+       false,6, 0,16, ApelSlideThink, NULL, ApelFallReact, &s_apelslide2};\r
+statetype s_apelslide2 = {APELSLIDE2SPR,APELSLIDE2SPR,slide,false,\r
+       false,6, 0,16, ApelSlideThink, NULL, ApelFallReact, &s_apelslide3};\r
+statetype s_apelslide3 = {APELSLIDE3SPR,APELSLIDE3SPR,slide,false,\r
+       false,6, 0,16, ApelSlideThink, NULL, ApelFallReact, &s_apelslide4};\r
+statetype s_apelslide4 = {APELSLIDE4SPR,APELSLIDE4SPR,slide,false,\r
+       false,6, 0,16, ApelSlideThink, NULL, ApelFallReact, &s_apelslide1};\r
+\r
+statetype s_apelfall = {APELWALKL1SPR,APELWALKR1SPR,think,false,\r
+       false,0, 0,0, ProjectileThink, NULL, ApelFallReact, NULL};\r
+\r
+#pragma warn +sus\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= SpawnApel\r
+=\r
+====================\r
+*/\r
+\r
+void SpawnApel (int tilex, int tiley)\r
+{\r
+       GetNewObj (false);\r
+\r
+       new->obclass = apelobj;\r
+       new->x = tilex<<G_T_SHIFT;\r
+       new->y = (tiley<<G_T_SHIFT)-2*BLOCKSIZE;\r
+       new->xdir = 1;\r
+       new->ydir = 1;\r
+       NewState (new,&s_apelwalk1);\r
+}\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= ApelThink\r
+=\r
+====================\r
+*/\r
+\r
+void ApelThink (objtype *ob)\r
+{\r
+       int     x,y;\r
+       unsigned far *map;\r
+\r
+       if (ob->top > player->bottom || ob->bottom < player->top)\r
+       {\r
+       //\r
+       // try to climb a pole to reach player\r
+       //\r
+               if (ob->y < player->y)\r
+                       y = ob->tilebottom;\r
+               else\r
+                       y = ob->tiletop;\r
+\r
+               map = (unsigned _seg *)mapsegs[1]+\r
+                       mapbwidthtable[y]/2 + ob->tilemidx;\r
+\r
+               if ((tinf[INTILE+*map]&0x7f) == 1)\r
+               {\r
+                       ob->xmove = (ob->tilemidx<<G_T_SHIFT) - ob->x;\r
+                       ob->ymove = 0;\r
+                       ob->temp4 = ob->tilemidx;       // for future reference\r
+                       ob->needtoclip = false;         // can climb through pole holes\r
+                       if (ob->y < player->y)\r
+                               ob->state = &s_apelslide1;\r
+                       else\r
+                               ob->state = &s_apelclimb1;\r
+                       return;\r
+               }\r
+       }\r
+\r
+       if (US_RndT()>32)               // don't turn around all the time\r
+               return;\r
+\r
+       if (ob->x < player->x)\r
+               ob->xdir = 1;\r
+       else\r
+               ob->xdir = -1;\r
+\r
+}\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= ApelClimbThink\r
+=\r
+====================\r
+*/\r
+\r
+void ApelClimbThink (objtype *ob)\r
+{\r
+       unsigned far *map;\r
+\r
+       map = (unsigned _seg *)mapsegs[1]+\r
+               mapbwidthtable[ob->tiletop]/2 + ob->temp4;\r
+\r
+       if ((tinf[INTILE+*map]&0x7f) != 1)\r
+       {\r
+               ob->needtoclip = true;\r
+               ob->state = &s_apelfall;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= ApelSlideThink\r
+=\r
+====================\r
+*/\r
+\r
+void ApelSlideThink (objtype *ob)\r
+{\r
+       unsigned far *map;\r
+\r
+       map = (unsigned _seg *)mapsegs[1]+\r
+               mapbwidthtable[ob->tilebottom]/2 + ob->temp4;\r
+\r
+       if ((tinf[INTILE+*map]&0x7f) != 1)\r
+       {\r
+               ob->needtoclip = true;\r
+               ob->state = &s_apelfall;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= ApelClimbReact\r
+=\r
+====================\r
+*/\r
+\r
+void ApelClimbReact (objtype *ob)\r
+{\r
+       if (ob->hitsouth)\r
+               ChangeState (ob,&s_apelfall);\r
+       PLACESPRITE;\r
+}\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= ApelFallReact\r
+=\r
+====================\r
+*/\r
+\r
+void ApelFallReact (objtype *ob)\r
+{\r
+       if (ob->hitnorth)\r
+               ChangeState (ob,&s_apelwalk1);\r
+       PLACESPRITE;\r
+}\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                               PEA BRAIN\r
+\r
+=============================================================================\r
+*/\r
+\r
+void PeaBrainThink (objtype *ob);\r
+void PeaFlyReact (objtype *ob);\r
+\r
+extern statetype s_peabrainfly;\r
+\r
+extern statetype s_peabrainwalk1;\r
+extern statetype s_peabrainwalk2;\r
+extern statetype s_peabrainwalk3;\r
+extern statetype s_peabrainwalk4;\r
+\r
+#pragma warn -sus\r
+\r
+statetype s_peabrainfly        = {PEABRAINWALKL1SPR,PEABRAINWALKR1SPR,think,false,\r
+       false,0, 0,0, ProjectileThink, NULL, PeaFlyReact, NULL};\r
+\r
+statetype s_peabrainwalk1      = {PEABRAINWALKL1SPR,PEABRAINWALKR1SPR,step,false,\r
+       true,10, 128,0, PeaBrainThink, NULL, WalkReact, &s_peabrainwalk2};\r
+statetype s_peabrainwalk2      = {PEABRAINWALKL2SPR,PEABRAINWALKR2SPR,step,false,\r
+       true,10, 128,0, PeaBrainThink, NULL, WalkReact, &s_peabrainwalk3};\r
+statetype s_peabrainwalk3      = {PEABRAINWALKL3SPR,PEABRAINWALKR3SPR,step,false,\r
+       true,10, 128,0, PeaBrainThink, NULL, WalkReact, &s_peabrainwalk4};\r
+statetype s_peabrainwalk4      = {PEABRAINWALKL4SPR,PEABRAINWALKR4SPR,step,false,\r
+       true,10, 128,0, PeaBrainThink, NULL, WalkReact, &s_peabrainwalk1};\r
+\r
+#pragma warn +sus\r
+\r
+/*\r
+====================\r
+=\r
+= SpawnPeaBrain\r
+=\r
+====================\r
+*/\r
+\r
+void SpawnPeaBrain (int tilex, int tiley)\r
+{\r
+       GetNewObj (false);\r
+\r
+       new->obclass = peabrainobj;\r
+       new->x = tilex<<G_T_SHIFT;\r
+       new->y = tiley<<G_T_SHIFT;\r
+       NewState (new,&s_peabrainwalk1);\r
+}\r
+\r
+/*\r
+====================\r
+=\r
+= PeaBrainThink\r
+=\r
+====================\r
+*/\r
+\r
+void PeaBrainThink (objtype *ob)\r
+{\r
+       ob++;\r
+}\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= PeaFlyReact\r
+=\r
+====================\r
+*/\r
+\r
+void PeaFlyReact (objtype *ob)\r
+{\r
+       if (ob->hitnorth)\r
+               ChangeState (ob,&s_peabrainwalk1);\r
+\r
+       PLACESPRITE;\r
+}\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                               PEA POD\r
+\r
+temp1 = number of peas spit\r
+\r
+=============================================================================\r
+*/\r
+\r
+#define MAXPEASPIT     4\r
+\r
+#define PEAXSPEED      48\r
+#define PEAYSPEED      -20\r
+\r
+\r
+void PeaPodThink (objtype *ob);\r
+void SpitPeaBrain (objtype *ob);\r
+\r
+extern statetype s_peapodwalk1;\r
+extern statetype s_peapodwalk2;\r
+extern statetype s_peapodwalk3;\r
+extern statetype s_peapodwalk4;\r
+\r
+extern statetype s_peapodspit1;\r
+extern statetype s_peapodspit2;\r
+\r
+#pragma warn -sus\r
+\r
+statetype s_peapodwalk1        = {PEAPODRUNL1SPR,PEAPODRUNR1SPR,step,false,\r
+       true,10, 128,0, PeaPodThink, NULL, WalkReact, &s_peapodwalk2};\r
+statetype s_peapodwalk2        = {PEAPODRUNL2SPR,PEAPODRUNR2SPR,step,false,\r
+       true,10, 128,0, PeaPodThink, NULL, WalkReact, &s_peapodwalk3};\r
+statetype s_peapodwalk3        = {PEAPODRUNL3SPR,PEAPODRUNR3SPR,step,false,\r
+       true,10, 128,0, PeaPodThink, NULL, WalkReact, &s_peapodwalk4};\r
+statetype s_peapodwalk4        = {PEAPODRUNL4SPR,PEAPODRUNR4SPR,step,false,\r
+       true,10, 128,0, PeaPodThink, NULL, WalkReact, &s_peapodwalk1};\r
+\r
+statetype s_peapodspit1        = {PEAPODSPITLSPR,PEAPODSPITRSPR,step,false,\r
+       true,30, 0,0, SpitPeaBrain, NULL, DrawReact, &s_peapodspit2};\r
+statetype s_peapodspit2        = {PEAPODSPITLSPR,PEAPODSPITRSPR,step,false,\r
+       true,30, 0,0, NULL, NULL, DrawReact, &s_peapodwalk1};\r
+\r
+#pragma warn +sus\r
+\r
+/*\r
+====================\r
+=\r
+= SpawnPeaPod\r
+=\r
+====================\r
+*/\r
+\r
+void SpawnPeaPod (int tilex, int tiley)\r
+{\r
+       GetNewObj (false);\r
+\r
+       new->obclass = peapodobj;\r
+       new->x = tilex<<G_T_SHIFT;\r
+       new->y = (tiley<<G_T_SHIFT)-2*BLOCKSIZE;\r
+       new->xdir = 1;\r
+       new->ydir = 1;\r
+       NewState (new,&s_peapodwalk1);\r
+}\r
+\r
+/*\r
+====================\r
+=\r
+= SpitPeaBrain\r
+=\r
+====================\r
+*/\r
+\r
+void SpitPeaBrain (objtype *ob)\r
+{\r
+       GetNewObj (true);\r
+       new->obclass = peabrainobj;\r
+       if (ob->xdir == 1)\r
+       {\r
+               new->x = ob->x+8*16;\r
+               new->y = ob->y+8*16;\r
+       }\r
+       else\r
+       {\r
+               new->x = ob->x;\r
+               new->y = ob->y+8*16;\r
+       }\r
+       new->xdir = ob->xdir;\r
+       new->ydir = 1;\r
+       new->xspeed = ob->xdir * PEAXSPEED-(US_RndT()>>4);\r
+       new->yspeed = PEAYSPEED;\r
+       NewState (new,&s_peabrainfly);\r
+}\r
+\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= PeaPodThink\r
+=\r
+====================\r
+*/\r
+\r
+void PeaPodThink (objtype *ob)\r
+{\r
+       int delta;\r
+\r
+       if ( abs(ob->y - player->y) > 3*TILEGLOBAL )\r
+               return;\r
+\r
+       if (player->x < ob->x && ob->xdir == 1)\r
+               return;\r
+\r
+       if (player->x > ob->x && ob->xdir == -1)\r
+               return;\r
+\r
+       if (US_RndT()<8 && ob->temp1 < MAXPEASPIT)\r
+       {\r
+               ob->temp1 ++;\r
+               ob->state = &s_peapodspit1;\r
+               ob->xmove = 0;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                       BOOBUS TUBOR\r
+\r
+temp4 = hit points\r
+\r
+=============================================================================\r
+*/\r
+\r
+#define PREFRAGTHINK   60\r
+#define POSTFRAGTHINK  60\r
+\r
+#define SPDBOOBUSJUMP  60\r
+#define SPDBOOBUSRUNJUMP 24\r
+\r
+void BoobusThink (objtype *ob);\r
+void FinishThink (objtype *ob);\r
+void FragThink (objtype *ob);\r
+void BoobusGroundReact (objtype *ob);\r
+void BoobusAirReact (objtype *ob);\r
+\r
+extern statetype s_boobuswalk1;\r
+extern statetype s_boobuswalk2;\r
+extern statetype s_boobuswalk3;\r
+extern statetype s_boobuswalk4;\r
+\r
+extern statetype s_boobusjump;\r
+\r
+extern statetype s_deathwait1;\r
+extern statetype s_deathwait2;\r
+extern statetype s_deathwait3;\r
+extern statetype s_deathboom1;\r
+extern statetype s_deathboom2;\r
+extern statetype s_deathboom3;\r
+extern statetype s_deathboom4;\r
+extern statetype s_deathboom5;\r
+extern statetype s_deathboom6;\r
+\r
+#pragma warn -sus\r
+\r
+statetype s_boobuswalk1        = {BOOBUSWALKL1SPR,BOOBUSWALKR1SPR,step,false,\r
+       true,10, 128,0, BoobusThink, NULL, BoobusGroundReact, &s_boobuswalk2};\r
+statetype s_boobuswalk2        = {BOOBUSWALKL2SPR,BOOBUSWALKR2SPR,step,false,\r
+       true,10, 128,0, BoobusThink, NULL, BoobusGroundReact, &s_boobuswalk3};\r
+statetype s_boobuswalk3        = {BOOBUSWALKL3SPR,BOOBUSWALKR3SPR,step,false,\r
+       true,10, 128,0, BoobusThink, NULL, BoobusGroundReact, &s_boobuswalk4};\r
+statetype s_boobuswalk4        = {BOOBUSWALKL4SPR,BOOBUSWALKR4SPR,step,false,\r
+       true,10, 128,0, BoobusThink, NULL, BoobusGroundReact, &s_boobuswalk1};\r
+\r
+statetype s_boobusjump = {BOOBUSJUMPSPR,BOOBUSJUMPSPR,think,false,\r
+       false,0, 0,0, ProjectileThink, NULL, BoobusAirReact, NULL};\r
+\r
+statetype s_boobusdie  = {BOOBUSJUMPSPR,BOOBUSJUMPSPR,step,false,\r
+       false,4, 0,0, FragThink, NULL, DrawReact, &s_boobusdie};\r
+statetype s_boobusdie2 = {NULL,NULL,step,false,\r
+       false,4, 0,0, FragThink, NULL, NULL, &s_boobusdie2};\r
+statetype s_boobusdie3 = {NULL,NULL,step,false,\r
+       false,250, 0,0, FinishThink, NULL, NULL, NULL};\r
+\r
+statetype s_deathboom1 = {BOOBUSBOOM1SPR,BOOBUSBOOM1SPR,step,false,\r
+       false,20, 0,0, ProjectileThink, NULL, DrawReact3, &s_deathboom2};\r
+statetype s_deathboom2 = {BOOBUSBOOM2SPR,BOOBUSBOOM2SPR,step,false,\r
+       false,20, 0,0, ProjectileThink, NULL, DrawReact3, &s_deathboom3};\r
+statetype s_deathboom3 = {POOF1SPR,POOF1SPR,step,false,\r
+       false,40, 0,0, ProjectileThink, NULL, DrawReact3, &s_deathboom4};\r
+statetype s_deathboom4 = {POOF2SPR,POOF2SPR,step,false,\r
+       false,30, 0,0, ProjectileThink, NULL, DrawReact3, &s_deathboom5};\r
+statetype s_deathboom5 = {POOF3SPR,POOF3SPR,step,false,\r
+       false,30, 0,0, ProjectileThink, NULL, DrawReact3, &s_deathboom6};\r
+statetype s_deathboom6 = {POOF4SPR,POOF4SPR,step,false,\r
+       false,30, 0,0, ProjectileThink, NULL, DrawReact3, NULL};\r
+\r
+\r
+#pragma warn +sus\r
+\r
+/*\r
+====================\r
+=\r
+= SpawnBoobus\r
+=\r
+====================\r
+*/\r
+\r
+void SpawnBoobus (int tilex, int tiley)\r
+{\r
+       GetNewObj (false);\r
+\r
+       new->obclass = boobusobj;\r
+       new->x = tilex<<G_T_SHIFT;\r
+       new->y = (tiley<<G_T_SHIFT)-11*BLOCKSIZE;\r
+       new->xdir = -1;\r
+       NewState (new,&s_boobuswalk1);\r
+       new->temp4 = 12;                        // hit points\r
+}\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= FragThink\r
+=\r
+===================\r
+*/\r
+\r
+void FragThink (objtype *ob)\r
+{\r
+       if (++ob->temp1 == PREFRAGTHINK)\r
+               ob->state = &s_boobusdie2;\r
+       if (++ob->temp1 == POSTFRAGTHINK)\r
+       {\r
+               RF_RemoveSprite (&ob->sprite);\r
+               ob->state = &s_boobusdie3;\r
+       }\r
+\r
+       SD_PlaySound (BOMBBOOMSND);\r
+       GetNewObj (true);\r
+       new->x = ob->x-BLOCKSIZE + 5*US_RndT();\r
+       new->y = ob->y-BLOCKSIZE + 5*US_RndT();\r
+       new->xspeed = 0; //US_RndT()/4-32;\r
+       new->yspeed = 0; //US_RndT()/4-32;\r
+       US_RndT();                                      // keep rnd from even wrapping\r
+       ChangeState (new,&s_deathboom1);\r
+}\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= FinishThink\r
+=\r
+===================\r
+*/\r
+\r
+void FinishThink (objtype *ob)\r
+{\r
+       playstate = victorious;\r
+       ob++;\r
+       SD_PlaySound (BOOBUSGONESND);\r
+}\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= BoobusThink\r
+=\r
+====================\r
+*/\r
+\r
+void BoobusThink (objtype *ob)\r
+{\r
+       unsigned        move;\r
+       boolean inline = false;\r
+\r
+       if (ob->left > player->right)\r
+               ob->xdir = -1;\r
+       else if (ob->right < player->left)\r
+               ob->xdir = 1;\r
+       else\r
+               inline = true;\r
+\r
+       if (player->top < ob->bottom && player->bottom > ob->top)\r
+       {\r
+       // on same level as player, so charge!\r
+\r
+       }\r
+       else\r
+       {\r
+       // above or below player, so get directly in line and jump\r
+               if (inline)\r
+               {\r
+                       if (ob->y < player->y)\r
+                       {\r
+                       // drop down\r
+                               move = PIXGLOBAL*8;\r
+                               ob->tilebottom++;\r
+                               ob->bottom += move;\r
+                               ob->y += move;\r
+                               ob->state = &s_boobusjump;\r
+                               ob->yspeed = ob->xmove = ob->xspeed = ob->ymove = 0;\r
+                       }\r
+                       else\r
+                       {\r
+                       // jump up\r
+                               ob->state = &s_boobusjump;\r
+                               ob->yspeed = -SPDBOOBUSJUMP;\r
+                               ob->xspeed = 0;\r
+                       }\r
+\r
+               }\r
+       }\r
+}\r
+\r
+/*\r
+====================\r
+=\r
+= BoobusGroundReact\r
+=\r
+====================\r
+*/\r
+\r
+void BoobusGroundReact (objtype *ob)\r
+{\r
+       if (ob->xdir == 1 && ob->hitwest)\r
+       {\r
+               ob->x -= ob->xmove;\r
+               ob->xdir = -1;\r
+               ob->nothink = US_RndT()>>5;\r
+               ChangeState (ob,ob->state);\r
+       }\r
+       else if (ob->xdir == -1 && ob->hiteast)\r
+       {\r
+               ob->x -= ob->xmove;\r
+               ob->xdir = 1;\r
+               ob->nothink = US_RndT()>>5;\r
+               ChangeState (ob,ob->state);\r
+       }\r
+       else if (!ob->hitnorth)\r
+       {\r
+               if (ob->bottom >= player->bottom)\r
+               {\r
+                // jump over\r
+                       ob->x -= ob->xmove;\r
+                       ob->y -= ob->ymove;\r
+                       ob->yspeed = -SPDBOOBUSJUMP;\r
+                       ob->xspeed = ob->xdir * SPDBOOBUSRUNJUMP;\r
+               }\r
+               else\r
+               {\r
+               // drop down\r
+                       ob->xspeed = ob->yspeed = 0;\r
+               }\r
+               ChangeState (ob,&s_boobusjump);\r
+       }\r
+\r
+       PLACESPRITE;\r
+}\r
+\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= BoobusAirReact\r
+=\r
+====================\r
+*/\r
+\r
+void BoobusAirReact (objtype *ob)\r
+{\r
+       if (ob->hitsouth)\r
+               ob->yspeed = 0;\r
+\r
+       if (ob->hitnorth)\r
+               ChangeState (ob,&s_boobuswalk1);\r
+\r
+       PLACESPRITE;\r
+}\r
diff --git a/src/lib/hb/kd_def.h b/src/lib/hb/kd_def.h
new file mode 100755 (executable)
index 0000000..c2728a6
--- /dev/null
@@ -0,0 +1,366 @@
+/* Keen Dreams Source Code\r
+ * Copyright (C) 2014 Javier M. Chavez\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License along\r
+ * with this program; if not, write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+ */\r
+\r
+// KD_DEF.H\r
+\r
+#include "ID_HEADS.H"\r
+#include <BIOS.H>\r
+#include "SOFT.H"\r
+#include "SL_FILE.H"\r
+\r
+#define FRILLS 0                       // Cut out frills for 360K - MIKE MAYNARD\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                               GLOBAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+#define CREDITS 0\r
+\r
+#define        MAXACTORS       MAXSPRITES\r
+\r
+#define ACCGRAVITY     3\r
+#define SPDMAXY                80\r
+\r
+#define BLOCKSIZE      (8*PIXGLOBAL)           // for positioning starting actors\r
+\r
+//\r
+// movement scrolling edges\r
+//\r
+#define SCROLLEAST (TILEGLOBAL*11)\r
+#define SCROLLWEST (TILEGLOBAL*9)\r
+#define SCROLLSOUTH (TILEGLOBAL*8)\r
+#define SCROLLNORTH (TILEGLOBAL*4)\r
+\r
+#define CLIPMOVE       24                                      // speed to push out of a solid wall\r
+\r
+#define GAMELEVELS     17\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                        TYPES\r
+\r
+=============================================================================\r
+*/\r
+\r
+typedef        enum    {notdone,resetgame,levelcomplete,warptolevel,died,victorious}\r
+                               exittype;\r
+\r
+typedef        enum    {nothing,keenobj,powerobj,doorobj,\r
+       bonusobj,broccoobj,tomatobj,carrotobj,celeryobj,asparobj,grapeobj,\r
+       taterobj,cartobj,frenchyobj,melonobj,turnipobj,cauliobj,brusselobj,\r
+       mushroomobj,squashobj,apelobj,peapodobj,peabrainobj,boobusobj,\r
+       shotobj,inertobj}       classtype;\r
+\r
+typedef struct\r
+{\r
+  int          leftshapenum,rightshapenum;\r
+  enum         {step,slide,think,stepthink,slidethink} progress;\r
+  boolean      skippable;\r
+\r
+  boolean      pushtofloor;\r
+  int tictime;\r
+  int xmove;\r
+  int ymove;\r
+  void (*think) ();\r
+  void (*contact) ();\r
+  void (*react) ();\r
+  void *nextstate;\r
+} statetype;\r
+\r
+\r
+typedef        struct\r
+{\r
+       unsigned        worldx,worldy;\r
+       boolean leveldone[GAMELEVELS];\r
+       long    score,nextextra;\r
+       int             flowerpowers;\r
+       int             boobusbombs,bombsthislevel;\r
+       int             keys;\r
+       int             mapon;\r
+       int             lives;\r
+       int             difficulty;\r
+} gametype;\r
+\r
+\r
+typedef struct objstruct\r
+{\r
+       classtype       obclass;\r
+       enum            {no,yes,allways,removable} active;\r
+       boolean         needtoreact,needtoclip;\r
+       unsigned        nothink;\r
+       unsigned        x,y;\r
+\r
+       int                     xdir,ydir;\r
+       int                     xmove,ymove;\r
+       int                     xspeed,yspeed;\r
+\r
+       int                     ticcount,ticadjust;\r
+       statetype       *state;\r
+\r
+       unsigned        shapenum;\r
+\r
+       unsigned        left,top,right,bottom;  // hit rectangle\r
+       unsigned        midx;\r
+       unsigned        tileleft,tiletop,tileright,tilebottom;  // hit rect in tiles\r
+       unsigned        tilemidx;\r
+\r
+       int                     hitnorth,hiteast,hitsouth,hitwest;      // wall numbers contacted\r
+\r
+       int                     temp1,temp2,temp3,temp4;\r
+\r
+       void            *sprite;\r
+\r
+       struct  objstruct       *next,*prev;\r
+} objtype;\r
+\r
+\r
+struct BitMapHeader {\r
+       unsigned int    w,h,x,y;\r
+       unsigned char   d,trans,comp,pad;\r
+};\r
+\r
+struct BitMap {\r
+       unsigned int Width;\r
+       unsigned int Height;\r
+       unsigned int Depth;\r
+       unsigned int BytesPerRow;\r
+       char far *Planes[8];\r
+};\r
+\r
+struct Shape {\r
+       memptr Data;\r
+       long size;\r
+       unsigned int BPR;\r
+       struct BitMapHeader bmHdr;\r
+};\r
+\r
+typedef struct {\r
+       int handle;                     // handle of file\r
+       memptr buffer;          // pointer to buffer\r
+       word offset;            // offset into buffer\r
+       word status;            // read/write status\r
+} BufferedIO;\r
+\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                        KD_MAIN.C DEFINITIONS\r
+\r
+=============================================================================\r
+*/\r
+\r
+extern char    str[80],str2[20];\r
+extern boolean singlestep,jumpcheat,godmode,tedlevel;\r
+extern unsigned        tedlevelnum;\r
+\r
+void   DebugMemory (void);\r
+void   TestSprites(void);\r
+int            DebugKeys (void);\r
+void   StartupId (void);\r
+void   ShutdownId (void);\r
+void   Quit (char *error);\r
+void   InitGame (void);\r
+void   main (void);\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                         KD_DEMO.C DEFINITIONS\r
+\r
+=============================================================================\r
+*/\r
+\r
+void   Finale (void);\r
+void   GameOver (void);\r
+void   DemoLoop (void);\r
+void   StatusWindow (void);\r
+void   NewGame (void);\r
+void   TEDDeath (void);\r
+\r
+boolean        LoadGame (int file);\r
+boolean        SaveGame (int file);\r
+void   ResetGame (void);\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                         KD_PLAY.C DEFINITIONS\r
+\r
+=============================================================================\r
+*/\r
+\r
+extern gametype        gamestate;\r
+extern exittype        playstate;\r
+extern boolean         button0held,button1held;\r
+extern unsigned        originxtilemax,originytilemax;\r
+extern objtype         *new,*check,*player,*scoreobj;\r
+\r
+extern ControlInfo     c;\r
+\r
+extern objtype dummyobj;\r
+\r
+extern char            *levelnames[21];\r
+\r
+void   CheckKeys (void);\r
+void   CalcInactivate (void);\r
+void   InitObjArray (void);\r
+void   GetNewObj (boolean usedummy);\r
+void   RemoveObj (objtype *gone);\r
+void   ScanInfoPlane (void);\r
+void   PatchWorldMap (void);\r
+void   MarkTileGraphics (void);\r
+void   FadeAndUnhook (void);\r
+void   SetupGameLevel (boolean loadnow);\r
+void   ScrollScreen (void);\r
+void   MoveObjVert (objtype *ob, int ymove);\r
+void   MoveObjHoriz (objtype *ob, int xmove);\r
+void   GivePoints (unsigned points);\r
+void   ClipToEnds (objtype *ob);\r
+void   ClipToEastWalls (objtype *ob);\r
+void   ClipToWestWalls (objtype *ob);\r
+void   ClipToWalls (objtype *ob);\r
+void   ClipToSprite (objtype *push, objtype *solid, boolean squish);\r
+void   ClipToSpriteSide (objtype *push, objtype *solid);\r
+int    DoActor (objtype *ob,int tics);\r
+void   StateMachine (objtype *ob);\r
+void   NewState (objtype *ob,statetype *state);\r
+void   PlayLoop (void);\r
+void   GameLoop (void);\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                         KD_KEEN.C DEFINITIONS\r
+\r
+=============================================================================\r
+*/\r
+\r
+void   CalcSingleGravity (void);\r
+\r
+void   ProjectileThink         (objtype *ob);\r
+void   VelocityThink           (objtype *ob);\r
+void   DrawReact                       (objtype *ob);\r
+\r
+void   SpawnScore (void);\r
+void   FixScoreBox (void);\r
+void   SpawnWorldKeen (int tilex, int tiley);\r
+void   SpawnKeen (int tilex, int tiley, int dir);\r
+\r
+void   KillKeen (void);\r
+\r
+extern int     singlegravity;\r
+extern unsigned        bounceangle[8][8];\r
+\r
+extern statetype s_keendie1;\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                         KD_ACT1.C DEFINITIONS\r
+\r
+=============================================================================\r
+*/\r
+\r
+void WalkReact (objtype *ob);\r
+\r
+void   DoGravity (objtype *ob);\r
+void   AccelerateX (objtype *ob,int dir,int max);\r
+void   FrictionX (objtype *ob);\r
+\r
+void   ProjectileThink         (objtype *ob);\r
+void   VelocityThink           (objtype *ob);\r
+void   DrawReact                       (objtype *ob);\r
+void   DrawReact2                      (objtype *ob);\r
+void   DrawReact3                      (objtype *ob);\r
+void   ChangeState (objtype *ob, statetype *state);\r
+\r
+void   ChangeToFlower (objtype *ob);\r
+\r
+void   SpawnBonus (int tilex, int tiley, int type);\r
+void   SpawnDoor (int tilex, int tiley);\r
+void   SpawnBrocco (int tilex, int tiley);\r
+void   SpawnTomat (int tilex, int tiley);\r
+void   SpawnCarrot (int tilex, int tiley);\r
+void   SpawnAspar (int tilex, int tiley);\r
+void   SpawnGrape (int tilex, int tiley);\r
+\r
+extern statetype s_doorraise;\r
+\r
+extern statetype s_bonus;\r
+extern statetype s_bonusrise;\r
+\r
+extern statetype s_broccosmash3;\r
+extern statetype s_broccosmash4;\r
+\r
+extern statetype s_grapefall;\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                         KD_ACT2.C DEFINITIONS\r
+\r
+=============================================================================\r
+*/\r
+\r
+void SpawnTater (int tilex, int tiley);\r
+void SpawnCart (int tilex, int tiley);\r
+void SpawnFrenchy (int tilex, int tiley);\r
+void SpawnMelon (int tilex, int tiley,int dir);\r
+void SpawnSquasher (int tilex, int tiley);\r
+void SpawnApel (int tilex, int tiley);\r
+void SpawnPeaPod (int tilex, int tiley);\r
+void SpawnPeaBrain (int tilex, int tiley);\r
+void SpawnBoobus (int tilex, int tiley);\r
+\r
+extern statetype s_taterattack2;\r
+extern statetype s_squasherjump2;\r
+extern statetype s_boobusdie;\r
+\r
+extern statetype s_deathwait1;\r
+extern statetype s_deathwait2;\r
+extern statetype s_deathwait3;\r
+extern statetype s_deathboom1;\r
+extern statetype s_deathboom2;\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+//                                             GELIB.C DEFINITIONS\r
+//\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+void FreeShape(struct Shape *shape);\r
+int UnpackEGAShapeToScreen(struct Shape *SHP,int startx,int starty);\r
+\r
+long Verify(char *filename);\r
+memptr InitBufferedIO(int handle, BufferedIO *bio);\r
+void FreeBufferedIO(BufferedIO *bio);\r
+byte bio_readch(BufferedIO *bio);\r
+void bio_fillbuffer(BufferedIO *bio);\r
+void SwapLong(long far *Var);\r
+void SwapWord(unsigned int far *Var);\r
+void MoveGfxDst(short x, short y);
\ No newline at end of file
diff --git a/src/lib/hb/kd_demo.c b/src/lib/hb/kd_demo.c
new file mode 100755 (executable)
index 0000000..4469a92
--- /dev/null
@@ -0,0 +1,545 @@
+/* Keen Dreams Source Code\r
+ * Copyright (C) 2014 Javier M. Chavez\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License along\r
+ * with this program; if not, write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+ */\r
+\r
+// KD_DEMO.C\r
+\r
+#include <dir.h>\r
+#include "KD_DEF.H"\r
+\r
+#pragma        hdrstop\r
+\r
+#define RLETAG 0xABCD\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                GLOBAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\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
+       word    i;\r
+\r
+       gamestate.worldx = 0;           // spawn keen at starting spot\r
+\r
+       gamestate.mapon = 0;\r
+       gamestate.score = 0;\r
+       gamestate.nextextra = 20000;\r
+       gamestate.lives = 3;\r
+       gamestate.flowerpowers = gamestate.boobusbombs = 0;\r
+       for (i = 0;i < GAMELEVELS;i++)\r
+               gamestate.leveldone[i] = false;\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+=====================\r
+=\r
+= WaitOrKey\r
+=\r
+=====================\r
+*/\r
+\r
+int WaitOrKey (int vbls)\r
+{\r
+       while (vbls--)\r
+       {\r
+               IN_ReadControl(0,&c);           // get player input\r
+               if (LastScan || c.button0 || c.button1)\r
+               {\r
+                       IN_ClearKeysDown ();\r
+                       return 1;\r
+               }\r
+               VW_WaitVBL(1);\r
+       }\r
+       return 0;\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+=====================\r
+=\r
+= GameOver\r
+=\r
+=====================\r
+*/\r
+\r
+void\r
+GameOver (void)\r
+{\r
+       VW_InitDoubleBuffer ();\r
+       US_CenterWindow (16,3);\r
+\r
+       US_PrintCentered("Game Over!");\r
+\r
+       VW_UpdateScreen ();\r
+       IN_ClearKeysDown ();\r
+       IN_Ack ();\r
+\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+==================\r
+=\r
+= StatusWindow\r
+=\r
+==================\r
+*/\r
+\r
+void StatusWindow (void)\r
+{\r
+       word    x;\r
+\r
+       // DEBUG - make this look better\r
+\r
+       US_CenterWindow(22,7);\r
+       US_CPrint("Status Window");\r
+\r
+       WindowX += 8;\r
+       WindowW -= 8;\r
+       WindowY += 20;\r
+       WindowH -= 20;\r
+       PrintX = WindowX;\r
+       PrintY = WindowY;\r
+\r
+       VWB_DrawTile8(PrintX,PrintY,26);\r
+       VWB_DrawTile8(PrintX + 8,PrintY,27);\r
+       PrintX += 24;\r
+       US_PrintUnsigned(gamestate.lives);\r
+       US_Print("\n");\r
+\r
+       VWB_DrawTile8(PrintX,PrintY,32);\r
+       VWB_DrawTile8(PrintX + 8,PrintY,33);\r
+       VWB_DrawTile8(PrintX,PrintY + 8,34);\r
+       VWB_DrawTile8(PrintX + 8,PrintY + 8,35);\r
+       PrintX += 24;\r
+       US_PrintUnsigned(gamestate.boobusbombs);\r
+       US_Print("\n");\r
+\r
+       WindowX += 50;\r
+       WindowW -= 50;\r
+       PrintX = WindowX;\r
+       PrintY = WindowY;\r
+\r
+       fontcolor = F_FIRSTCOLOR;\r
+       US_Print("Next ");\r
+       fontcolor = F_BLACK;\r
+       x = PrintX;\r
+       VWB_DrawTile8(PrintX,PrintY,26);\r
+       VWB_DrawTile8(PrintX + 8,PrintY,27);\r
+       PrintX += 24;\r
+       US_PrintUnsigned(gamestate.nextextra);\r
+       US_Print("\n");\r
+\r
+       PrintX = x;\r
+       VWB_DrawTile8(PrintX,PrintY,24);\r
+       VWB_DrawTile8(PrintX + 8,PrintY,25);\r
+       PrintX += 24;\r
+       US_PrintUnsigned(gamestate.keys);\r
+       US_Print("\n");\r
+\r
+       // DEBUG - add flower powers (#36)\r
+\r
+       VW_UpdateScreen();\r
+       IN_Ack();\r
+}\r
+\r
+boolean\r
+SaveGame(int file)\r
+{\r
+       word    i,size,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++)   // Write all three planes of the map\r
+       {\r
+//\r
+// leave a word at start of compressed data for compressed length\r
+//\r
+               compressed = 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
+       return(true);\r
+}\r
+\r
+\r
+boolean\r
+LoadGame(int file)\r
+{\r
+       word    i,j,size;\r
+       objtype *o;\r
+       int orgx,orgy;\r
+       objtype         *prev,*next,*followed;\r
+       unsigned        compressed,expanded;\r
+       memptr  bigbuffer;\r
+\r
+       if (!CA_FarRead(file,(void far *)&gamestate,sizeof(gamestate)))\r
+               return(false);\r
+\r
+// drop down a cache level and mark everything, so when the option screen\r
+// is exited it will be cached\r
+\r
+       ca_levelbit >>= 1;\r
+       ca_levelnum--;\r
+\r
+       SetupGameLevel (false);         // load in and cache the base old level\r
+       titleptr[ca_levelnum] = levelnames[mapon];\r
+\r
+       ca_levelbit <<= 1;\r
+       ca_levelnum ++;\r
+\r
+       expanded = mapwidth * mapheight * 2;\r
+       MM_GetPtr (&bigbuffer,expanded);\r
+\r
+       for (i = 0;i < 3;i++)   // Read all three planes of the map\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],compressed,RLETAG);\r
+       }\r
+\r
+       MM_FreePtr (&bigbuffer);\r
+\r
+       // Read the object list back in - assumes at least one object in list\r
+\r
+       InitObjArray ();\r
+       new = player;\r
+       prev = new->prev;\r
+       next = new->next;\r
+       if (!CA_FarRead(file,(void far *)new,sizeof(objtype)))\r
+               return(false);\r
+       new->prev = prev;\r
+       new->next = next;\r
+       new->needtoreact = true;\r
+       new->sprite = NULL;\r
+       new = scoreobj;\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
+               new->needtoreact = true;\r
+               new->sprite = NULL;\r
+\r
+               if (followed)\r
+                       GetNewObj (false);\r
+               else\r
+                       break;\r
+       }\r
+\r
+       *((long *)&(scoreobj->temp1)) = -1;             // force score to be updated\r
+       scoreobj->temp3 = -1;                   // and flower power\r
+       scoreobj->temp4 = -1;                   // and lives\r
+\r
+       return(true);\r
+}\r
+\r
+void\r
+ResetGame(void)\r
+{\r
+       NewGame ();\r
+\r
+       ca_levelnum--;\r
+       CA_ClearMarks();\r
+       titleptr[ca_levelnum] = NULL;           // don't reload old level\r
+       ca_levelnum++;\r
+}\r
+\r
+#if FRILLS\r
+void\r
+TEDDeath(void)\r
+{\r
+       ShutdownId();\r
+       execlp("TED5.EXE","TED5.EXE","/LAUNCH","KDREAMS",NULL);\r
+}\r
+#endif\r
+\r
+static boolean\r
+MoveTitleTo(int offset)\r
+{\r
+       boolean         done;\r
+       int                     dir,\r
+                               chunk,\r
+                               move;\r
+       longword        lasttime,delay;\r
+\r
+       if (offset < originxglobal)\r
+               dir = -1;\r
+       else\r
+               dir = +1;\r
+\r
+       chunk = dir * PIXGLOBAL;\r
+\r
+       done = false;\r
+       delay = 1;\r
+       while (!done)\r
+       {\r
+               lasttime = TimeCount;\r
+               move = delay * chunk;\r
+               if (chunk < 0)\r
+                       done = originxglobal + move <= offset;\r
+               else\r
+                       done = originxglobal + move >= offset;\r
+               if (!done)\r
+               {\r
+                       RF_Scroll(move,0);\r
+                       RF_Refresh();\r
+               }\r
+               if (IN_IsUserInput())\r
+                       return(true);\r
+               delay = TimeCount - lasttime;\r
+       }\r
+       if (originxglobal != offset)\r
+       {\r
+               RF_Scroll(offset - originxglobal,0);\r
+               RF_Refresh();\r
+       }\r
+       return(false);\r
+}\r
+\r
+static boolean\r
+Wait(longword time)\r
+{\r
+       time += TimeCount;\r
+       while ((TimeCount < time) && (!IN_IsUserInput()))\r
+       {\r
+               if (!(TimeCount % MINTICS))\r
+                       RF_Refresh();\r
+       }\r
+       return(IN_IsUserInput());\r
+}\r
+\r
+static boolean\r
+ShowText(int offset,WindowRec *wr,char *s)\r
+{\r
+       if (MoveTitleTo(offset))\r
+               return(true);\r
+\r
+       US_RestoreWindow(wr);\r
+       US_CPrint(s);\r
+       VW_UpdateScreen();\r
+\r
+       if (Wait(TickBase * 5))\r
+               return(true);\r
+\r
+       US_RestoreWindow(wr);\r
+       US_CPrint(s);\r
+       VW_UpdateScreen();\r
+       return(false);\r
+}\r
+\r
+/*\r
+=====================\r
+=\r
+= DemoLoop\r
+=\r
+=====================\r
+*/\r
+\r
+void\r
+DemoLoop (void)\r
+{\r
+       char            *s;\r
+       word            move;\r
+       longword        lasttime;\r
+       char *FileName1;\r
+       struct Shape FileShape1;\r
+#if CREDITS\r
+       char *FileName2;\r
+       struct Shape FileShape2;\r
+#endif\r
+       struct ffblk ffblk;\r
+       WindowRec       mywin;\r
+       int bufsave     = bufferofs;\r
+       int dissave     = displayofs;\r
+\r
+\r
+#if FRILLS\r
+//\r
+// check for launch from ted\r
+//\r
+       if (tedlevel)\r
+       {\r
+               NewGame();\r
+               gamestate.mapon = tedlevelnum;\r
+               GameLoop();\r
+               TEDDeath();\r
+       }\r
+#endif\r
+\r
+//\r
+// demo loop\r
+//\r
+       US_SetLoadSaveHooks(LoadGame,SaveGame,ResetGame);\r
+       restartgame = gd_Continue;\r
+\r
+       if (findfirst("KDREAMS.CMP", &ffblk, 0) == -1)\r
+               Quit("Couldn't find KDREAMS.CMP");\r
+\r
+       while (true)\r
+       {\r
+\r
+               loadedgame = false;\r
+\r
+               FileName1 = "TITLESCR.LBM";\r
+               if (LoadLIBShape("KDREAMS.CMP", FileName1, &FileShape1))\r
+                       Quit("Can't load TITLE SCREEN");\r
+#if CREDITS\r
+               FileName2 = "CREDITS.LBM";\r
+               if (LoadLIBShape("KDREAMS.CMP", FileName2, &FileShape2))\r
+                       Quit("Can't load CREDITS SCREEN");\r
+#endif\r
+\r
+               while (!restartgame && !loadedgame)\r
+               {\r
+\r
+                       VW_InitDoubleBuffer();\r
+                       IN_ClearKeysDown();\r
+\r
+                       while (true)\r
+                       {\r
+\r
+                               VW_SetScreen(0, 0);\r
+                               MoveGfxDst(0, 200);\r
+                               UnpackEGAShapeToScreen(&FileShape1, 0, 0);\r
+                               VW_ScreenToScreen (64*200,0,40,200);\r
+\r
+#if CREDITS\r
+                               if (IN_UserInput(TickBase * 8, false))\r
+                                       break;\r
+#else\r
+                               if (IN_UserInput(TickBase * 4, false))\r
+                                       break;\r
+#endif\r
+\r
+#if CREDITS\r
+                               MoveGfxDst(0, 200);\r
+                               UnpackEGAShapeToScreen(&FileShape2, 0, 0);\r
+                               VW_ScreenToScreen (64*200,0,40,200);\r
+\r
+                               if (IN_UserInput(TickBase * 7, false))\r
+                                       break;\r
+#else\r
+                               MoveGfxDst(0, 200);\r
+                               UnpackEGAShapeToScreen(&FileShape1, 0, 0);\r
+                               VW_ScreenToScreen (64*200,0,40,200);\r
+\r
+                               if (IN_UserInput(TickBase * 3, false))\r
+                                       break;\r
+#endif\r
+\r
+                               displayofs = 0;\r
+                               VWB_Bar(0,0,320,200,FIRSTCOLOR);\r
+                               US_DisplayHighScores(-1);\r
+\r
+                               if (IN_UserInput(TickBase * 6, false))\r
+                                       break;\r
+\r
+                       }\r
+\r
+                       bufferofs = bufsave;\r
+                       displayofs = dissave;\r
+\r
+                       VW_FixRefreshBuffer();\r
+                       US_ControlPanel ();\r
+               }\r
+\r
+               if (!loadedgame)\r
+                       NewGame();\r
+\r
+               FreeShape(&FileShape1);\r
+#if CREDITS\r
+               FreeShape(&FileShape2);\r
+#endif\r
+               GameLoop();\r
+       }\r
+}\r
diff --git a/src/lib/hb/kd_keen.c b/src/lib/hb/kd_keen.c
new file mode 100755 (executable)
index 0000000..a134931
--- /dev/null
@@ -0,0 +1,2528 @@
+/* Keen Dreams Source Code\r
+ * Copyright (C) 2014 Javier M. Chavez\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License along\r
+ * with this program; if not, write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+ */\r
+\r
+// KD_KEEN.C\r
+\r
+#include "KD_DEF.H"\r
+#pragma hdrstop\r
+\r
+/*\r
+\r
+player->temp1 = pausetime / pointer to zees when sleeping\r
+player->temp2 = pausecount / stagecount\r
+player->temp3 =\r
+player->temp4 =\r
+\r
+\r
+*/\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+#define KEENPRIORITY   1\r
+\r
+#define PLACESPRITE RF_PlaceSprite (&ob->sprite,ob->x,ob->y,ob->shapenum, \\r
+       spritedraw,KEENPRIORITY);\r
+\r
+#define        MINPOLEJUMPTICS 19      // wait tics before allowing a pole regram\r
+\r
+#define SPDRUNJUMP             16\r
+#define SPDPOLESIDEJUMP        8\r
+#define WALKAIRSPEED   8\r
+#define DIVESPEED              32\r
+#define        JUMPTIME                16\r
+#define        POLEJUMPTIME    10\r
+#define        SPDJUMP                 40\r
+#define        SPDDIVEUP               16\r
+#define        SPDPOLEJUMP             20\r
+\r
+#define SPDPOWERUP             -64\r
+#define SPDPOWER               64\r
+#define SPDPOWERY              -20\r
+#define POWERCOUNT             50\r
+\r
+#define MAXXSPEED   24\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                GLOBAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+int    singlegravity;\r
+unsigned       bounceangle[8][8] =\r
+{\r
+{0,0,0,0,0,0,0,0},\r
+{7,6,5,4,3,2,1,0},\r
+{5,4,3,2,1,0,15,14},\r
+{5,4,3,2,1,0,15,14},\r
+{3,2,1,0,15,14,13,12},\r
+{9,8,7,6,5,4,3,2},\r
+{9,8,7,6,5,4,3,2},\r
+{11,10,9,8,7,6,5,4}\r
+};\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+int    jumptime;\r
+long   leavepoletime;          // TimeCount when jumped off pole\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                SCORE BOX ROUTINES\r
+\r
+=============================================================================\r
+*/\r
+\r
+void   SpawnScore (void);\r
+void ScoreThink (objtype *ob);\r
+void ScoreReact (objtype *ob);\r
+\r
+void MemDrawChar (int char8,byte far *dest,unsigned width,unsigned planesize);\r
+\r
+statetype s_score      = {NULL,NULL,think,false,\r
+       false,0, 0,0, ScoreThink , NULL, ScoreReact, NULL};\r
+\r
+\r
+/*\r
+======================\r
+=\r
+= SpawnScore\r
+=\r
+======================\r
+*/\r
+\r
+void   SpawnScore (void)\r
+{\r
+       scoreobj->obclass = inertobj;\r
+       scoreobj->active = allways;\r
+       scoreobj->needtoclip = false;\r
+       *((long *)&(scoreobj->temp1)) = -1;             // force score to be updated\r
+       scoreobj->temp3 = -1;                   // and flower power\r
+       scoreobj->temp4 = -1;                   // and lives\r
+       NewState (scoreobj,&s_score);\r
+}\r
+\r
+\r
+void   FixScoreBox (void)\r
+{\r
+       unsigned        width, planesize;\r
+       unsigned smallplane,bigplane;\r
+       spritetype      _seg    *block;\r
+       byte    far     *dest;\r
+\r
+// draw boobus bomb if on level 15, else flower power\r
+       block = (spritetype _seg *)grsegs[SCOREBOXSPR];\r
+       width = block->width[0];\r
+       planesize = block->planesize[0];\r
+       dest = (byte far *)grsegs[SCOREBOXSPR]+block->sourceoffset[0]\r
+               + planesize + width*16 + 4*CHARWIDTH;\r
+       if (mapon == 15)\r
+       {\r
+               MemDrawChar (20,dest,width,planesize);\r
+               MemDrawChar (21,dest+CHARWIDTH,width,planesize);\r
+               MemDrawChar (22,dest+width*8,width,planesize);\r
+               MemDrawChar (23,dest+width*8+CHARWIDTH,width,planesize);\r
+       }\r
+       else\r
+       {\r
+               MemDrawChar (28,dest,width,planesize);\r
+               MemDrawChar (29,dest+CHARWIDTH,width,planesize);\r
+               MemDrawChar (30,dest+width*8,width,planesize);\r
+               MemDrawChar (31,dest+width*8+CHARWIDTH,width,planesize);\r
+       }\r
+\r
+}\r
+\r
+\r
+/*\r
+======================\r
+=\r
+= MemDrawChar\r
+=\r
+======================\r
+*/\r
+\r
+#if GRMODE == EGAGR\r
+\r
+void MemDrawChar (int char8,byte far *dest,unsigned width,unsigned planesize)\r
+{\r
+asm    mov     si,[char8]\r
+asm    shl     si,1\r
+asm    shl     si,1\r
+asm    shl     si,1\r
+asm    shl     si,1\r
+asm    shl     si,1            // index into char 8 segment\r
+\r
+asm    mov     ds,[WORD PTR grsegs+STARTTILE8*2]\r
+asm    mov     es,[WORD PTR dest+2]\r
+\r
+asm    mov     cx,4            // draw four planes\r
+asm    mov     bx,[width]\r
+asm    dec     bx\r
+\r
+planeloop:\r
+\r
+asm    mov     di,[WORD PTR 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,[planesize]\r
+asm    add     [WORD PTR dest],ax\r
+\r
+asm    loop    planeloop\r
+\r
+asm    mov     ax,ss\r
+asm    mov     ds,ax\r
+\r
+}\r
+#endif\r
+\r
+#if GRMODE == CGAGR\r
+void MemDrawChar (int char8,byte far *dest,unsigned width,unsigned planesize)\r
+{\r
+asm    mov     si,[char8]\r
+asm    shl     si,1\r
+asm    shl     si,1\r
+asm    shl     si,1\r
+asm    shl     si,1            // index into char 8 segment\r
+\r
+asm    mov     ds,[WORD PTR grsegs+STARTTILE8*2]\r
+asm    mov     es,[WORD PTR dest+2]\r
+\r
+asm    mov     bx,[width]\r
+asm    sub     bx,2\r
+\r
+asm    mov     di,[WORD PTR dest]\r
+\r
+asm    movsw\r
+asm    add     di,bx\r
+asm    movsw\r
+asm    add     di,bx\r
+asm    movsw\r
+asm    add     di,bx\r
+asm    movsw\r
+asm    add     di,bx\r
+asm    movsw\r
+asm    add     di,bx\r
+asm    movsw\r
+asm    add     di,bx\r
+asm    movsw\r
+asm    add     di,bx\r
+asm    movsw\r
+\r
+asm    mov     ax,ss\r
+asm    mov     ds,ax\r
+\r
+       planesize++;            // shut the compiler up\r
+}\r
+#endif\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= ShiftScore\r
+=\r
+====================\r
+*/\r
+#if GRMODE == EGAGR\r
+void ShiftScore (void)\r
+{\r
+       spritetabletype far *spr;\r
+       spritetype _seg *dest;\r
+\r
+       spr = &spritetable[SCOREBOXSPR-STARTSPRITES];\r
+       dest = (spritetype _seg *)grsegs[SCOREBOXSPR];\r
+\r
+       CAL_ShiftSprite (FP_SEG(dest),dest->sourceoffset[0],\r
+               dest->sourceoffset[1],spr->width,spr->height,2);\r
+\r
+       CAL_ShiftSprite (FP_SEG(dest),dest->sourceoffset[0],\r
+               dest->sourceoffset[2],spr->width,spr->height,4);\r
+\r
+       CAL_ShiftSprite (FP_SEG(dest),dest->sourceoffset[0],\r
+               dest->sourceoffset[3],spr->width,spr->height,6);\r
+}\r
+#endif\r
+\r
+/*\r
+===============\r
+=\r
+= ScoreThink\r
+=\r
+===============\r
+*/\r
+\r
+void ScoreThink (objtype *ob)\r
+{\r
+       char            str[10],*ch;\r
+       spritetype      _seg    *block;\r
+       byte            far *dest;\r
+       unsigned        i, length, width, planesize, number;\r
+\r
+//\r
+// score changed\r
+//\r
+       if ((gamestate.score>>16) != ob->temp1\r
+               || (unsigned)gamestate.score != ob->temp2 )\r
+       {\r
+               block = (spritetype _seg *)grsegs[SCOREBOXSPR];\r
+               width = block->width[0];\r
+               planesize = block->planesize[0];\r
+               dest = (byte far *)grsegs[SCOREBOXSPR]+block->sourceoffset[0]\r
+                       + planesize + width*4 + 1*CHARWIDTH;\r
+\r
+               ltoa (gamestate.score,str,10);\r
+\r
+               // erase leading spaces\r
+               length = strlen(str);\r
+               for (i=6;i>length;i--)\r
+                       MemDrawChar (0,dest+=CHARWIDTH,width,planesize);\r
+\r
+               // draw digits\r
+               ch = str;\r
+               while (*ch)\r
+                       MemDrawChar (*ch++ - '0'+1,dest+=CHARWIDTH,width,planesize);\r
+\r
+#if GRMODE == EGAGR\r
+               ShiftScore ();\r
+#endif\r
+               ob->needtoreact = true;\r
+               ob->temp1 = gamestate.score>>16;\r
+               ob->temp2 = gamestate.score;\r
+       }\r
+\r
+//\r
+// flower power changed\r
+//\r
+       if (mapon == 15)\r
+               number = gamestate.boobusbombs;\r
+       else\r
+               number = gamestate.flowerpowers;\r
+       if (number != ob->temp3)\r
+       {\r
+               block = (spritetype _seg *)grsegs[SCOREBOXSPR];\r
+               width = block->width[0];\r
+               planesize = block->planesize[0];\r
+               dest = (byte far *)grsegs[SCOREBOXSPR]+block->sourceoffset[0]\r
+                       + planesize + width*20 + 5*CHARWIDTH;\r
+\r
+               if (number > 99)\r
+                       strcpy (str,"99");\r
+               else\r
+                       ltoa (number,str,10);\r
+\r
+               // erase leading spaces\r
+               length = strlen(str);\r
+               for (i=2;i>length;i--)\r
+                       MemDrawChar (0,dest+=CHARWIDTH,width,planesize);\r
+\r
+               // draw digits\r
+               ch = str;\r
+               while (*ch)\r
+                       MemDrawChar (*ch++ - '0'+1,dest+=CHARWIDTH,width,planesize);\r
+\r
+#if GRMODE == EGAGR\r
+               ShiftScore ();\r
+#endif\r
+               ob->needtoreact = true;\r
+               ob->temp3 = gamestate.flowerpowers;\r
+       }\r
+\r
+//\r
+// lives changed\r
+//\r
+       if (gamestate.lives != ob->temp4)\r
+       {\r
+               block = (spritetype _seg *)grsegs[SCOREBOXSPR];\r
+               width = block->width[0];\r
+               planesize = block->planesize[0];\r
+               dest = (byte far *)grsegs[SCOREBOXSPR]+block->sourceoffset[0]\r
+                       + planesize + width*20 + 2*CHARWIDTH;\r
+\r
+               if (gamestate.lives>9)\r
+                       MemDrawChar ('9' - '0'+1,dest,width,planesize);\r
+               else\r
+                       MemDrawChar (gamestate.lives +1,dest,width,planesize);\r
+\r
+#if GRMODE == EGAGR\r
+               ShiftScore ();\r
+#endif\r
+               ob->needtoreact = true;\r
+               ob->temp4 = gamestate.lives;\r
+       }\r
+\r
+       if (originxglobal != ob->x || originyglobal != ob->y)\r
+               ob->needtoreact = true;\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= ScoreReact\r
+=\r
+===============\r
+*/\r
+\r
+void ScoreReact (objtype *ob)\r
+{\r
+       ob->x = originxglobal;\r
+       ob->y = originyglobal;\r
+\r
+#if GRMODE == EGAGR\r
+       RF_PlaceSprite (&ob->sprite\r
+               ,ob->x+4*PIXGLOBAL\r
+               ,ob->y+4*PIXGLOBAL\r
+               ,SCOREBOXSPR\r
+               ,spritedraw\r
+               ,PRIORITIES-1);\r
+#endif\r
+#if GRMODE == CGAGR\r
+       RF_PlaceSprite (&ob->sprite\r
+               ,ob->x+8*PIXGLOBAL\r
+               ,ob->y+8*PIXGLOBAL\r
+               ,SCOREBOXSPR\r
+               ,spritedraw\r
+               ,PRIORITIES-1);\r
+#endif\r
+}\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                               FLOWER POWER ROUTINES\r
+\r
+temp1 = 8, same as power bonus\r
+temp2 = initial direction\r
+\r
+=============================================================================\r
+*/\r
+\r
+void   PowerCount                      (objtype *ob);\r
+void   PowerContact            (objtype *ob, objtype *hit);\r
+void   PowerReact                      (objtype *ob);\r
+\r
+extern statetype s_flowerpower1;\r
+extern statetype s_flowerpower2;\r
+\r
+extern statetype s_boobusbomb1;\r
+extern statetype s_boobusbomb2;\r
+\r
+extern statetype s_bombexplode;\r
+extern statetype s_bombexplode2;\r
+extern statetype s_bombexplode3;\r
+extern statetype s_bombexplode4;\r
+extern statetype s_bombexplode5;\r
+extern statetype s_bombexplode6;\r
+\r
+extern statetype s_powerblink1;\r
+extern statetype s_powerblink2;\r
+\r
+statetype s_flowerpower1       = {FLOWERPOWER1SPR,FLOWERPOWER1SPR,stepthink,false,\r
+       false,10, 0,0, ProjectileThink, PowerContact, PowerReact, &s_flowerpower2};\r
+statetype s_flowerpower2       = {FLOWERPOWER2SPR,FLOWERPOWER2SPR,stepthink,false,\r
+       false,10, 0,0, ProjectileThink, PowerContact, PowerReact, &s_flowerpower1};\r
+\r
+statetype s_boobusbomb1        = {BOOBUSBOMB1SPR,BOOBUSBOMB1SPR,stepthink,false,\r
+       false,5, 0,0, ProjectileThink, PowerContact, PowerReact, &s_boobusbomb2};\r
+statetype s_boobusbomb2        = {BOOBUSBOMB3SPR,BOOBUSBOMB3SPR,stepthink,false,\r
+       false,5, 0,0, ProjectileThink, PowerContact, PowerReact, &s_boobusbomb1};\r
+\r
+statetype s_bombexplode        = {BOOBUSBOOM1SPR,BOOBUSBOOM1SPR,step,false,\r
+       false,5, 0,0, NULL, NULL, DrawReact, &s_bombexplode2};\r
+statetype s_bombexplode2= {BOOBUSBOOM2SPR,BOOBUSBOOM2SPR,step,false,\r
+       false,5, 0,0, NULL, NULL, DrawReact, &s_bombexplode3};\r
+statetype s_bombexplode3= {BOOBUSBOOM1SPR,BOOBUSBOOM1SPR,step,false,\r
+       false,5, 0,0, NULL, NULL, DrawReact, &s_bombexplode4};\r
+statetype s_bombexplode4= {BOOBUSBOOM2SPR,BOOBUSBOOM2SPR,step,false,\r
+       false,5, 0,0, NULL, NULL, DrawReact, &s_bombexplode5};\r
+statetype s_bombexplode5= {BOOBUSBOOM1SPR,BOOBUSBOOM1SPR,step,false,\r
+       false,5, 0,0, NULL, NULL, DrawReact, &s_bombexplode6};\r
+statetype s_bombexplode6= {BOOBUSBOOM2SPR,BOOBUSBOOM2SPR,step,false,\r
+       false,5, 0,0, NULL, NULL, DrawReact, NULL};\r
+\r
+statetype s_powerblink1        = {FLOWERPOWER1SPR,FLOWERPOWER1SPR,step,false,\r
+       false,5, 0,0, PowerCount, NULL, DrawReact, &s_powerblink2};\r
+statetype s_powerblink2        = {-1,-1,step,false,\r
+       false,5, 0,0, PowerCount, NULL, DrawReact, &s_powerblink1};\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= ThrowPower\r
+=\r
+===============\r
+*/\r
+\r
+void ThrowPower (unsigned x, unsigned y, int dir)\r
+{\r
+       statetype *startstate;\r
+\r
+       if (mapon == 15)\r
+       {\r
+               if (!gamestate.boobusbombs)\r
+               {\r
+                       SD_PlaySound (NOWAYSND);\r
+                       return;                                         // no bombs to throw\r
+               }\r
+               SD_PlaySound (THROWBOMBSND);\r
+               gamestate.bombsthislevel--;\r
+               gamestate.boobusbombs--;\r
+       }\r
+       else\r
+       {\r
+               if (!gamestate.flowerpowers)\r
+               {\r
+                       SD_PlaySound (NOWAYSND);\r
+                       return;                                         // no flower power to throw\r
+               }\r
+               SD_PlaySound (THROWSND);\r
+               gamestate.flowerpowers--;\r
+       }\r
+\r
+\r
+\r
+       GetNewObj (true);\r
+       new->obclass = powerobj;\r
+       new->temp2 = dir;\r
+       new->x = x;\r
+       new->y = y;\r
+       new->tileleft = new->tileright = x>>G_T_SHIFT;\r
+       new->tiletop = new->tilebottom = y>>G_T_SHIFT;\r
+       new->ydir = -1;\r
+\r
+       switch (dir)\r
+       {\r
+       case dir_North:\r
+               new->xspeed = 0;\r
+               new->yspeed = SPDPOWERUP;\r
+               break;\r
+       case dir_East:\r
+               new->xspeed = SPDPOWER;\r
+               new->yspeed = SPDPOWERY;\r
+               break;\r
+       case dir_South:\r
+               new->xspeed = 0;\r
+               new->yspeed = SPDPOWER;\r
+               break;\r
+       case dir_West:\r
+               new->xspeed = -SPDPOWER;\r
+               new->yspeed = SPDPOWERY;\r
+               break;\r
+       default:\r
+               Quit ("ThrowPower: Bad dir!");\r
+       }\r
+\r
+       if (mapon != 15)\r
+       {\r
+               new->temp1 = 8;                                 // flower power bonus\r
+               startstate = &s_flowerpower1;\r
+       }\r
+       else\r
+       {\r
+               new->temp1 = 10;                                // boobus bomb bonus\r
+               startstate = &s_boobusbomb1;\r
+       }\r
+       new->active = removable;\r
+\r
+#if 0\r
+       new->x -= 5*new->xspeed;                // make sure they hit nearby walls\r
+       new->y -= 5*new->yspeed;\r
+#endif\r
+       NewState (new,startstate);\r
+#if 0\r
+       new->xmove = 5*new->xspeed;\r
+       new->ymove = 5*new->yspeed;\r
+       ClipToWalls (new);\r
+#endif\r
+}\r
+\r
+/*\r
+============================\r
+=\r
+= PowerCount\r
+=\r
+============================\r
+*/\r
+\r
+void   PowerCount (objtype *ob)\r
+{\r
+       ob->temp2+=tics;\r
+\r
+       ob->shapenum = 0;\r
+\r
+       if (ob->temp2 > POWERCOUNT)\r
+               RemoveObj(ob);\r
+}\r
+\r
+\r
+/*\r
+============================\r
+=\r
+= CalcSingleGravity\r
+=\r
+============================\r
+*/\r
+\r
+void   CalcSingleGravity (void)\r
+{\r
+       unsigned        speed;\r
+       long    i;\r
+//\r
+// only accelerate on odd tics, because of limited precision\r
+//\r
+       speed = 0;\r
+       singlegravity = 0;\r
+       for (i=lasttimecount-tics;i<lasttimecount;i++)\r
+       {\r
+               if (i&1)\r
+               {\r
+                       speed+=ACCGRAVITY;\r
+                       if (speed>SPDMAXY)\r
+                         speed=SPDMAXY;\r
+               }\r
+               singlegravity+=speed;\r
+       }\r
+\r
+       singlegravity/=2;\r
+}\r
+\r
+\r
+/*\r
+============================\r
+=\r
+= PowerContact\r
+=\r
+============================\r
+*/\r
+\r
+void   PowerContact (objtype *ob, objtype *hit)\r
+{\r
+       unsigned        x,y,yspot,xspot;\r
+\r
+       switch (hit->obclass)\r
+       {\r
+       case    broccoobj:\r
+       case    tomatobj:\r
+       case    carrotobj:\r
+       case    celeryobj:\r
+       case    asparobj:\r
+       case    taterobj:\r
+       case    frenchyobj:\r
+       case    squashobj:\r
+       case    apelobj:\r
+       case    peapodobj:\r
+       case    peabrainobj:\r
+               ChangeToFlower (hit);\r
+               RemoveObj (ob);\r
+               break;\r
+       case    boobusobj:\r
+               if (!--hit->temp4)\r
+               {\r
+               // killed boobus\r
+                       GivePoints (50000);\r
+                       GivePoints (50000);\r
+                       hit->obclass = inertobj;\r
+                       ChangeState (hit,&s_boobusdie);\r
+                       hit->temp1 = 0;         // death count\r
+               }\r
+               SD_PlaySound (BOMBBOOMSND);\r
+               ChangeState (ob,&s_bombexplode);\r
+               break;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+============================\r
+=\r
+= PowerReact\r
+=\r
+============================\r
+*/\r
+\r
+void   PowerReact (objtype *ob)\r
+{\r
+       unsigned wall,absx,absy,angle,newangle;\r
+       unsigned long speed;\r
+\r
+       PLACESPRITE;\r
+       if (ob->hiteast || ob->hitwest)\r
+       {\r
+               ob->xspeed= -ob->xspeed/2;\r
+               ob->obclass = bonusobj;\r
+       }\r
+\r
+       if (ob->hitsouth)\r
+       {\r
+               if ( ob->hitsouth == 17)        // go through pole holes\r
+               {\r
+                       if (ob->temp2 != dir_North)\r
+                               ob->obclass = bonusobj;\r
+                       ob->top-=32;\r
+                       ob->y-=32;\r
+                       ob->xspeed = 0;\r
+                       ob->x = ob->tilemidx*TILEGLOBAL + 4*PIXGLOBAL;\r
+               }\r
+               else\r
+               {\r
+                       ob->yspeed= -ob->yspeed/2;\r
+               }\r
+               return;\r
+       }\r
+\r
+       wall = ob->hitnorth;\r
+       if ( wall == 17)        // go through pole holes\r
+       {\r
+               if (ob->temp2 != dir_South)\r
+                       ob->obclass = bonusobj;\r
+               ob->bottom+=32;\r
+               ob->y+=32;\r
+               ob->xspeed = 0;\r
+               ob->x = ob->tilemidx*TILEGLOBAL + 4*PIXGLOBAL;\r
+       }\r
+       else if (wall)\r
+       {\r
+               ob->obclass = bonusobj;\r
+               if (ob->yspeed < 0)\r
+                       ob->yspeed = 0;\r
+\r
+               absx = abs(ob->xspeed);\r
+               absy = ob->yspeed;\r
+               if (absx>absy)\r
+               {\r
+                       if (absx>absy*2)        // 22 degrees\r
+                       {\r
+                               angle = 0;\r
+                               speed = absx*286;       // x*sqrt(5)/2\r
+                       }\r
+                       else                            // 45 degrees\r
+                       {\r
+                               angle = 1;\r
+                               speed = absx*362;       // x*sqrt(2)\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       if (absy>absx*2)        // 90 degrees\r
+                       {\r
+                               angle = 3;\r
+                               speed = absy*256;\r
+                       }\r
+                       else\r
+                       {\r
+                               angle = 2;              // 67 degrees\r
+                               speed = absy*286;       // y*sqrt(5)/2\r
+                       }\r
+               }\r
+               if (ob->xspeed > 0)\r
+                       angle = 7-angle;\r
+\r
+               speed >>= 1;\r
+               newangle = bounceangle[ob->hitnorth][angle];\r
+               switch (newangle)\r
+               {\r
+               case 0:\r
+                       ob->xspeed = speed / 286;\r
+                       ob->yspeed = -ob->xspeed / 2;\r
+                       break;\r
+               case 1:\r
+                       ob->xspeed = speed / 362;\r
+                       ob->yspeed = -ob->xspeed;\r
+                       break;\r
+               case 2:\r
+                       ob->yspeed = -(speed / 286);\r
+                       ob->xspeed = -ob->yspeed / 2;\r
+                       break;\r
+               case 3:\r
+\r
+               case 4:\r
+                       ob->xspeed = 0;\r
+                       ob->yspeed = -(speed / 256);\r
+                       break;\r
+               case 5:\r
+                       ob->yspeed = -(speed / 286);\r
+                       ob->xspeed = ob->yspeed / 2;\r
+                       break;\r
+               case 6:\r
+                       ob->xspeed = ob->yspeed = -(speed / 362);\r
+                       break;\r
+               case 7:\r
+                       ob->xspeed = -(speed / 286);\r
+                       ob->yspeed = ob->xspeed / 2;\r
+                       break;\r
+\r
+               case 8:\r
+                       ob->xspeed = -(speed / 286);\r
+                       ob->yspeed = -ob->xspeed / 2;\r
+                       break;\r
+               case 9:\r
+                       ob->xspeed = -(speed / 362);\r
+                       ob->yspeed = -ob->xspeed;\r
+                       break;\r
+               case 10:\r
+                       ob->yspeed = speed / 286;\r
+                       ob->xspeed = -ob->yspeed / 2;\r
+                       break;\r
+               case 11:\r
+\r
+               case 12:\r
+                       ob->xspeed = 0;\r
+                       ob->yspeed = -(speed / 256);\r
+                       break;\r
+               case 13:\r
+                       ob->yspeed = speed / 286;\r
+                       ob->xspeed = ob->yspeed / 2;\r
+                       break;\r
+               case 14:\r
+                       ob->xspeed = speed / 362;\r
+                       ob->yspeed = speed / 362;\r
+                       break;\r
+               case 15:\r
+                       ob->xspeed = speed / 286;\r
+                       ob->yspeed = ob->xspeed / 2;\r
+                       break;\r
+               }\r
+\r
+               if (speed < 256*16)\r
+               {\r
+                       if (mapon == 15)\r
+                       {\r
+                               ob->ydir = -1;                  // bonus stuff flies up when touched\r
+                               ob->temp2 = ob->shapenum = BOOBUSBOMB1SPR;\r
+                               ob->temp3 = ob->temp2 + 2;\r
+                               ob->needtoclip = 0;\r
+                               ChangeState (ob,&s_bonus);\r
+                       }\r
+                       else\r
+                       {\r
+                               ChangeState (ob,&s_powerblink1);\r
+                               ob->needtoclip = 0;\r
+                               ob->temp2 = 0;          // blink time\r
+                       }\r
+               }\r
+       }\r
+}\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                          MINI KEEN\r
+\r
+player->temp1 = dir\r
+player->temp2 = animation stage\r
+\r
+#define WORLDKEENSLEEP1SPR             238\r
+#define WORLDKEENSLEEP2SPR             239\r
+#define WORLDKEENWAVE1SPR              240\r
+#define WORLDKEENWAVE2SPR              241\r
+=============================================================================\r
+*/\r
+\r
+void   SpawnWorldKeen (int tilex, int tiley);\r
+void   KeenWorldThink          (objtype *ob);\r
+void   KeenWorldWalk           (objtype *ob);\r
+\r
+extern statetype s_worldkeen;\r
+\r
+extern statetype s_worldkeenwave1;\r
+extern statetype s_worldkeenwave2;\r
+extern statetype s_worldkeenwave3;\r
+extern statetype s_worldkeenwave4;\r
+extern statetype s_worldkeenwave5;\r
+\r
+extern statetype s_worldkeenwait;\r
+\r
+extern statetype s_worldkeensleep1;\r
+extern statetype s_worldkeensleep2;\r
+\r
+extern statetype s_worldwalk;\r
+\r
+#pragma warn -sus\r
+\r
+statetype s_worldkeen  = {NULL,NULL,stepthink,false,\r
+       false,360, 0,0, KeenWorldThink, NULL, DrawReact, &s_worldkeenwave1};\r
+\r
+statetype s_worldkeenwave1= {WORLDKEENWAVE1SPR,WORLDKEENWAVE1SPR,stepthink,false,\r
+       false,20, 0,0, KeenWorldThink, NULL, DrawReact, &s_worldkeenwave2};\r
+statetype s_worldkeenwave2= {WORLDKEENWAVE2SPR,WORLDKEENWAVE2SPR,stepthink,false,\r
+       false,20, 0,0, KeenWorldThink, NULL, DrawReact, &s_worldkeenwave3};\r
+statetype s_worldkeenwave3= {WORLDKEENWAVE1SPR,WORLDKEENWAVE1SPR,stepthink,false,\r
+       false,20, 0,0, KeenWorldThink, NULL, DrawReact, &s_worldkeenwave4};\r
+statetype s_worldkeenwave4= {WORLDKEENWAVE2SPR,WORLDKEENWAVE2SPR,stepthink,false,\r
+       false,20, 0,0, KeenWorldThink, NULL, DrawReact, &s_worldkeenwave5};\r
+statetype s_worldkeenwave5= {WORLDKEENWAVE1SPR,WORLDKEENWAVE1SPR,stepthink,false,\r
+       false,20, 0,0, KeenWorldThink, NULL, DrawReact, &s_worldkeenwait};\r
+\r
+statetype s_worldkeenwait      = {WORLDKEEND3SPR,WORLDKEEND3SPR,stepthink,false,\r
+       false,400, 0,0, KeenWorldThink, NULL, DrawReact, &s_worldkeensleep1};\r
+\r
+statetype s_worldkeensleep1    = {WORLDKEENSLEEP1SPR,WORLDKEENSLEEP1SPR,stepthink,false,\r
+       false,30, 0,0, KeenWorldThink, NULL, DrawReact, &s_worldkeensleep2};\r
+statetype s_worldkeensleep2    = {WORLDKEENSLEEP2SPR,WORLDKEENSLEEP2SPR,stepthink,false,\r
+       false,90, 0,0, KeenWorldThink, NULL, DrawReact, &s_worldkeensleep2};\r
+\r
+statetype s_worldwalk  = {NULL,NULL,slide,false,\r
+       false,4, 16,16, KeenWorldWalk, NULL, DrawReact, &s_worldwalk};\r
+\r
+#pragma warn +sus\r
+\r
+/*\r
+======================\r
+=\r
+= SpawnWorldKeen\r
+=\r
+======================\r
+*/\r
+\r
+void   SpawnWorldKeen (int tilex, int tiley)\r
+{\r
+       player->obclass = keenobj;\r
+       if (!gamestate.worldx)\r
+       {\r
+               player->x = tilex<<G_T_SHIFT;\r
+               player->y = tiley<<G_T_SHIFT;\r
+       }\r
+       else\r
+       {\r
+               player->x = gamestate.worldx;\r
+               player->y = gamestate.worldy;\r
+       }\r
+\r
+       player->active = yes;\r
+       player->needtoclip = true;\r
+       player->xdir = 0;\r
+       player->ydir = 0;\r
+       player->temp1 = dir_West;\r
+       player->temp2 = 3;\r
+       player->shapenum = 3+WORLDKEENL1SPR-1;                          // feet together\r
+       NewState (player,&s_worldkeen);\r
+}\r
+\r
+\r
+/*\r
+======================\r
+=\r
+= CheckEnterLevel\r
+=\r
+======================\r
+*/\r
+\r
+void   CheckEnterLevel (objtype *ob)\r
+{\r
+       int     x,y,tile;\r
+\r
+       for (y=ob->tiletop;y<=ob->tilebottom;y++)\r
+               for (x=ob->tileleft;x<=ob->tileright;x++)\r
+               {\r
+                       tile = *((unsigned _seg *)mapsegs[2]+mapbwidthtable[y]/2+x);\r
+                       if (tile >= 3 && tile <=18)\r
+                       {\r
+                       //\r
+                       // enter level!\r
+                       //\r
+                               if (tile == 17)\r
+                               {\r
+                                       if (gamestate.boobusbombs < 12)\r
+                                       {\r
+                                               VW_FixRefreshBuffer ();\r
+                                               US_CenterWindow (26,6);\r
+                                               PrintY+= 8;\r
+                                               US_CPrint ("You can't possibly\n"\r
+                                                                  "defeat King Boobus Tuber\n"\r
+                                                                  "with less than 12 bombs!");\r
+                                               VW_UpdateScreen ();\r
+                                               IN_Ack ();\r
+                                               RF_ForceRefresh ();\r
+                                               return;\r
+                                       }\r
+                               }\r
+                               gamestate.worldx = ob->x;\r
+                               gamestate.worldy = ob->y;\r
+                               gamestate.mapon = tile-2;\r
+                               playstate = levelcomplete;\r
+                               SD_PlaySound (ENTERLEVELSND);\r
+                       }\r
+               }\r
+}\r
+\r
+\r
+/*\r
+======================\r
+=\r
+= KeenWorldThink\r
+=\r
+======================\r
+*/\r
+\r
+void   KeenWorldThink (objtype *ob)\r
+{\r
+       if (c.dir!=dir_None)\r
+       {\r
+               ob->state = &s_worldwalk;\r
+               ob->temp2 = 0;\r
+               KeenWorldWalk (ob);\r
+       }\r
+\r
+       if (c.button0 || c.button1)\r
+               CheckEnterLevel(ob);\r
+}\r
+\r
+\r
+/*\r
+======================\r
+=\r
+= KeenWorldWalk\r
+=\r
+======================\r
+*/\r
+\r
+int worldshapes[8] = {WORLDKEENU1SPR-1,WORLDKEENUR1SPR-1,WORLDKEENR1SPR-1,\r
+       WORLDKEENDR1SPR-1,WORLDKEEND1SPR-1,WORLDKEENDL1SPR-1,WORLDKEENL1SPR-1,\r
+       WORLDKEENUL1SPR-1};\r
+\r
+int worldanims[4] ={2,3,1,3};\r
+\r
+void   KeenWorldWalk (objtype *ob)\r
+{\r
+       ob->xdir = c.xaxis;\r
+       ob->ydir = c.yaxis;\r
+\r
+       if (++ob->temp2==4)\r
+               ob->temp2 = 0;\r
+\r
+       if (c.button0 || c.button1)\r
+               CheckEnterLevel(ob);\r
+\r
+       if (c.dir == dir_None)\r
+       {\r
+               ob->state = &s_worldkeen;\r
+               ob->shapenum = worldshapes[ob->temp1]+3;\r
+               return;\r
+       }\r
+\r
+       ob->temp1 = c.dir;\r
+       ob->shapenum = worldshapes[ob->temp1]+worldanims[ob->temp2];\r
+}\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                               KEEN\r
+\r
+player->temp1 = pausetime / pointer to zees when sleeping\r
+player->temp2 = pausecount / stagecount\r
+player->temp3 =\r
+player->temp4 = pole x location\r
+\r
+=============================================================================\r
+*/\r
+\r
+void   KeenStandThink          (objtype *ob);\r
+void   KeenPauseThink          (objtype *ob);\r
+void   KeenGoSleepThink        (objtype *ob);\r
+void   KeenSleepThink          (objtype *ob);\r
+void   KeenDieThink            (objtype *ob);\r
+void   KeenDuckThink           (objtype *ob);\r
+void   KeenDropDownThink       (objtype *ob);\r
+void   KeenWalkThink           (objtype *ob);\r
+void   KeenAirThink            (objtype *ob);\r
+void   KeenPoleThink           (objtype *ob);\r
+void   KeenClimbThink          (objtype *ob);\r
+void   KeenDropThink           (objtype *ob);\r
+void   KeenDive                        (objtype *ob);\r
+void   KeenThrow                       (objtype *ob);\r
+\r
+void   KeenContact             (objtype *ob, objtype *hit);\r
+void   KeenSimpleReact         (objtype *ob);\r
+void   KeenStandReact          (objtype *ob);\r
+void   KeenWalkReact           (objtype *ob);\r
+void   KeenPoleReact           (objtype *ob);\r
+void   KeenAirReact            (objtype *ob);\r
+void   KeenDiveReact           (objtype *ob);\r
+void   KeenSlideReact          (objtype *ob);\r
+\r
+//-------------------\r
+\r
+extern statetype s_keenzee1;\r
+extern statetype s_keenzee2;\r
+extern statetype s_keenzee3;\r
+extern statetype s_keenzee4;\r
+extern statetype s_keenzee5;\r
+\r
+//-------------------\r
+\r
+extern statetype       s_keenstand;\r
+extern statetype s_keenpauselook;\r
+extern statetype s_keenyawn1;\r
+extern statetype s_keenyawn2;\r
+extern statetype s_keenyawn3;\r
+extern statetype s_keenyawn4;\r
+\r
+extern statetype s_keenwait1;\r
+extern statetype s_keenwait2;\r
+extern statetype s_keenwait3;\r
+extern statetype s_keenwait4;\r
+extern statetype s_keenwait5;\r
+extern statetype s_keenwait6;\r
+\r
+extern statetype s_keenmoon1;\r
+extern statetype s_keenmoon2;\r
+extern statetype s_keenmoon3;\r
+\r
+extern statetype s_keengosleep1;\r
+extern statetype s_keengosleep2;\r
+extern statetype s_keensleep1;\r
+extern statetype s_keensleep2;\r
+\r
+extern statetype s_keendie1;\r
+extern statetype s_keendie2;\r
+extern statetype s_keendie3;\r
+extern statetype s_keendie4;\r
+\r
+extern statetype       s_keenlookup;\r
+extern statetype       s_keenduck;\r
+extern statetype       s_keendrop;\r
+\r
+//-------------------\r
+\r
+extern statetype s_keenreach;\r
+\r
+extern statetype s_keenpole;\r
+\r
+extern statetype s_keenclimb1;\r
+extern statetype s_keenclimb2;\r
+extern statetype s_keenclimb3;\r
+\r
+extern statetype s_keenslide1;\r
+extern statetype s_keenslide2;\r
+extern statetype s_keenslide3;\r
+extern statetype s_keenslide4;\r
+\r
+extern statetype s_keenpolethrow1;\r
+extern statetype s_keenpolethrow2;\r
+extern statetype s_keenpolethrow3;\r
+\r
+extern statetype s_keenpolethrowup1;\r
+extern statetype s_keenpolethrowup2;\r
+extern statetype s_keenpolethrowup3;\r
+\r
+extern statetype s_keenpolethrowdown1;\r
+extern statetype s_keenpolethrowdown2;\r
+extern statetype s_keenpolethrowdown3;\r
+\r
+//-------------------\r
+\r
+extern statetype       s_keenwalk1;\r
+extern statetype       s_keenwalk2;\r
+extern statetype       s_keenwalk3;\r
+extern statetype       s_keenwalk4;\r
+\r
+extern statetype       s_keenthrow1;\r
+extern statetype       s_keenthrow2;\r
+extern statetype       s_keenthrow3;\r
+extern statetype       s_keenthrow4;\r
+\r
+extern statetype       s_keenthrowup1;\r
+extern statetype       s_keenthrowup2;\r
+extern statetype       s_keenthrowup3;\r
+\r
+extern statetype       s_keendive1;\r
+extern statetype       s_keendive2;\r
+extern statetype       s_keendive3;\r
+\r
+//-------------------\r
+\r
+extern statetype s_keenjumpup1;\r
+extern statetype s_keenjumpup2;\r
+extern statetype s_keenjumpup3;\r
+\r
+extern statetype s_keenjump1;\r
+extern statetype s_keenjump2;\r
+extern statetype s_keenjump3;\r
+\r
+extern statetype s_keenairthrow1;\r
+extern statetype s_keenairthrow2;\r
+extern statetype s_keenairthrow3;\r
+\r
+extern statetype s_keenairthrowup1;\r
+extern statetype s_keenairthrowup2;\r
+extern statetype s_keenairthrowup3;\r
+\r
+extern statetype s_keenairthrowdown1;\r
+extern statetype s_keenairthrowdown2;\r
+extern statetype s_keenairthrowdown3;\r
+\r
+#pragma warn -sus\r
+\r
+//-------------------\r
+\r
+statetype s_keenzee1   = {KEENZEES1SPR,KEENZEES1SPR,step,false,\r
+       false,30, 0,0, NULL, NULL, DrawReact, &s_keenzee2};\r
+statetype s_keenzee2   = {KEENZEES2SPR,KEENZEES2SPR,step,false,\r
+       false,30, 0,0, NULL, NULL, DrawReact, &s_keenzee3};\r
+statetype s_keenzee3   = {KEENZEES3SPR,KEENZEES3SPR,step,false,\r
+       false,30, 0,0, NULL, NULL, DrawReact, &s_keenzee1};\r
+\r
+//-------------------\r
+\r
+statetype s_keenstand  = {KEENSTANDLSPR,KEENSTANDRSPR,stepthink,false,\r
+       true,4, 0,16, KeenPauseThink, KeenContact, KeenStandReact, &s_keenstand};\r
+statetype s_keenpauselook= {KEENLOOKULSPR,KEENLOOKURSPR,stepthink,false,\r
+       true,60, 0,0, KeenPauseThink, KeenContact, KeenStandReact, &s_keenstand};\r
+statetype s_keenyawn1  = {KEENYAWN1SPR,KEENYAWN1SPR,stepthink,false,\r
+       true,40, 0,0, KeenPauseThink, KeenContact, KeenStandReact, &s_keenyawn2};\r
+statetype s_keenyawn2  = {KEENYAWN2SPR,KEENYAWN2SPR,stepthink,false,\r
+       true,40, 0,0, KeenPauseThink, KeenContact, KeenStandReact, &s_keenyawn3};\r
+statetype s_keenyawn3  = {KEENYAWN3SPR,KEENYAWN3SPR,stepthink,false,\r
+       true,40, 0,0, KeenPauseThink, KeenContact, KeenStandReact, &s_keenyawn4};\r
+statetype s_keenyawn4  = {KEENYAWN4SPR,KEENYAWN4SPR,stepthink,false,\r
+       true,40, 0,0, KeenPauseThink, KeenContact, KeenStandReact, &s_keenstand};\r
+\r
+statetype s_keenwait1  = {KEENWAITL2SPR,KEENWAITR2SPR,stepthink,false,\r
+       true,90, 0,0, KeenPauseThink, KeenContact, KeenStandReact, &s_keenwait2};\r
+statetype s_keenwait2  = {KEENWAITL1SPR,KEENWAITR1SPR,stepthink,false,\r
+       true,10, 0,0, KeenPauseThink, KeenContact, KeenStandReact, &s_keenwait3};\r
+statetype s_keenwait3  = {KEENWAITL2SPR,KEENWAITR2SPR,stepthink,false,\r
+       true,90, 0,0, KeenPauseThink, KeenContact, KeenStandReact, &s_keenwait4};\r
+statetype s_keenwait4  = {KEENWAITL1SPR,KEENWAITR1SPR,stepthink,false,\r
+       true,10, 0,0, KeenPauseThink, KeenContact, KeenStandReact, &s_keenwait5};\r
+statetype s_keenwait5  = {KEENWAITL2SPR,KEENWAITR2SPR,stepthink,false,\r
+       true,90, 0,0, KeenPauseThink, KeenContact, KeenStandReact, &s_keenwait6};\r
+statetype s_keenwait6  = {KEENWAITL3SPR,KEENWAITR3SPR,stepthink,false,\r
+       true,70, 0,0, KeenPauseThink, KeenContact, KeenStandReact, &s_keenstand};\r
+\r
+statetype s_keengosleep1= {KEENSLEEP1SPR,KEENSLEEP1SPR,stepthink,false,\r
+       true,20, 0,0, KeenPauseThink, KeenContact, KeenStandReact, &s_keengosleep2};\r
+statetype s_keengosleep2= {KEENSLEEP2SPR,KEENSLEEP2SPR,step,false,\r
+       true,20, 0,0, KeenGoSleepThink, KeenContact, KeenStandReact, &s_keensleep1};\r
+statetype s_keensleep1= {KEENSLEEP3SPR,KEENSLEEP3SPR,stepthink,false,\r
+       true,120, 0,0, KeenSleepThink, KeenContact, KeenStandReact, &s_keensleep2};\r
+statetype s_keensleep2= {KEENSLEEP4SPR,KEENSLEEP4SPR,stepthink,false,\r
+       true,120, 0,0, KeenSleepThink, KeenContact, KeenStandReact, &s_keensleep1};\r
+\r
+statetype s_keengetup  = {KEENGETUPLSPR,KEENGETUPRSPR,step,false,\r
+       true,15, 0,0, NULL, KeenContact, KeenSimpleReact, &s_keenstand};\r
+\r
+statetype s_keendie1           = {KEENDREAM1SPR,KEENDREAM1SPR,step,false,\r
+       false,20, 0,0, NULL, NULL, KeenSimpleReact, &s_keendie2};\r
+statetype s_keendie2           = {KEENDREAM2SPR,KEENDREAM2SPR,step,false,\r
+       false,20, 0,0, NULL, NULL, KeenSimpleReact, &s_keendie3};\r
+statetype s_keendie3           = {KEENDREAM3SPR,KEENDREAM3SPR,step,false,\r
+       false,120, 0,0, KeenDieThink, NULL, KeenSimpleReact, &s_keendie3};\r
+\r
+statetype s_keenlookup = {KEENLOOKULSPR,KEENLOOKURSPR,think,false,\r
+       true,0, 0,0, KeenStandThink, KeenContact, KeenStandReact, &s_keenlookup};\r
+\r
+statetype s_keenduck   = {KEENDUCKLSPR,KEENDUCKRSPR,think,false,\r
+       true,0, 0,0, KeenDuckThink, KeenContact, KeenStandReact, &s_keenduck};\r
+\r
+statetype s_keendrop   = {KEENDUCKLSPR,KEENDUCKRSPR,step,false,\r
+       false,0, 0,0, KeenDropDownThink, KeenContact, KeenSimpleReact, &s_keenjumpup3};\r
+\r
+//-------------------\r
+\r
+statetype s_keenpole   = {KEENSHINNYL1SPR,KEENSHINNYR1SPR,think,false,\r
+       false,0, 0,0, KeenPoleThink, KeenContact, KeenSimpleReact, &s_keenpole};\r
+\r
+statetype s_keenclimb1 = {KEENSHINNYL1SPR,KEENSHINNYR1SPR,slidethink,false,\r
+       false,8, 0,8, KeenClimbThink, KeenContact, KeenSimpleReact, &s_keenclimb2};\r
+statetype s_keenclimb2 = {KEENSHINNYL2SPR,KEENSHINNYR2SPR,slidethink,false,\r
+       false,8, 0,8, KeenClimbThink, KeenContact, KeenSimpleReact, &s_keenclimb3};\r
+statetype s_keenclimb3 = {KEENSHINNYL3SPR,KEENSHINNYR3SPR,slidethink,false,\r
+       false,8, 0,8, KeenClimbThink, KeenContact, KeenSimpleReact, &s_keenclimb1};\r
+\r
+statetype s_keenslide1 = {KEENSLIDED1SPR,KEENSLIDED1SPR,slide,false,\r
+       false,8, 0,24, KeenDropThink, KeenContact, KeenSimpleReact, &s_keenslide2};\r
+statetype s_keenslide2 = {KEENSLIDED2SPR,KEENSLIDED2SPR,slide,false,\r
+       false,8, 0,24, KeenDropThink, KeenContact, KeenSimpleReact, &s_keenslide3};\r
+statetype s_keenslide3 = {KEENSLIDED3SPR,KEENSLIDED3SPR,slide,false,\r
+       false,8, 0,24, KeenDropThink, KeenContact, KeenSimpleReact, &s_keenslide4};\r
+statetype s_keenslide4 = {KEENSLIDED4SPR,KEENSLIDED4SPR,slide,false,\r
+       false,8, 0,24, KeenDropThink, KeenContact, KeenSimpleReact, &s_keenslide1};\r
+\r
+statetype s_keenpolethrow1     = {KEENPTHROWL1SPR,KEENPTHROWR1SPR,step,false,\r
+       false,8, 0,0, NULL, KeenContact, KeenSimpleReact, &s_keenpolethrow2};\r
+statetype s_keenpolethrow2     = {KEENPTHROWL2SPR,KEENPTHROWR2SPR,step,true,\r
+       false,1, 0,0, KeenThrow, KeenContact, KeenSimpleReact, &s_keenpolethrow3};\r
+statetype s_keenpolethrow3     = {KEENPTHROWL2SPR,KEENPTHROWR2SPR,step,false,\r
+       false,10, 0,0, NULL, KeenContact, KeenSimpleReact, &s_keenpole};\r
+\r
+statetype s_keenpolethrowup1 = {KEENPLTHROWU1SPR,KEENPRTHROWU1SPR,step,false,\r
+       false,8, 0,0, NULL, KeenContact, KeenSimpleReact, &s_keenpolethrowup2};\r
+statetype s_keenpolethrowup2 = {KEENPLTHROWU2SPR,KEENPRTHROWU2SPR,step,true,\r
+       false,1, 0,0, KeenThrow, KeenContact, KeenSimpleReact, &s_keenpolethrowup3};\r
+statetype s_keenpolethrowup3 = {KEENPLTHROWU2SPR,KEENPRTHROWU2SPR,step,false,\r
+       false,10, 0,0, NULL, KeenContact, KeenSimpleReact, &s_keenpole};\r
+\r
+statetype s_keenpolethrowdown1 = {KEENPLTHROWD1SPR,KEENPRTHROWD1SPR,step,false,\r
+       false,8, 0,0, NULL, KeenContact, KeenSimpleReact, &s_keenpolethrowdown2};\r
+statetype s_keenpolethrowdown2 = {KEENPLTHROWD2SPR,KEENPRTHROWD2SPR,step,true,\r
+       false,1, 0,0, KeenThrow, KeenContact, KeenSimpleReact, &s_keenpolethrowdown3};\r
+statetype s_keenpolethrowdown3 = {KEENPLTHROWD2SPR,KEENPRTHROWD2SPR,step,false,\r
+       false,10, 0,0, NULL, KeenContact, KeenSimpleReact, &s_keenpole};\r
+\r
+\r
+//-------------------\r
+\r
+statetype s_keenwalk1  = {KEENRUNL1SPR,KEENRUNR1SPR,slidethink,true,\r
+       true,6, 24,0, KeenWalkThink, KeenContact, KeenWalkReact, &s_keenwalk2};\r
+statetype s_keenwalk2  = {KEENRUNL2SPR,KEENRUNR2SPR,slidethink,true,\r
+       true,6, 24,0, KeenWalkThink, KeenContact, KeenWalkReact, &s_keenwalk3};\r
+statetype s_keenwalk3  = {KEENRUNL3SPR,KEENRUNR3SPR,slidethink,true,\r
+       true,6, 24,0, KeenWalkThink, KeenContact, KeenWalkReact, &s_keenwalk4};\r
+statetype s_keenwalk4  = {KEENRUNL4SPR,KEENRUNR4SPR,slidethink,true,\r
+       true,6, 24,0, KeenWalkThink, KeenContact, KeenWalkReact, &s_keenwalk1};\r
+\r
+statetype s_keenthrow1 = {KEENTHROWL1SPR,KEENTHROWR1SPR,step,true,\r
+       true,4, 0,0, NULL, KeenContact, KeenStandReact, &s_keenthrow2};\r
+statetype s_keenthrow2 = {KEENTHROWL2SPR,KEENTHROWR2SPR,step,false,\r
+       true,4, 0,0, NULL, KeenContact, KeenStandReact, &s_keenthrow3};\r
+statetype s_keenthrow3 = {KEENTHROWL3SPR,KEENTHROWR3SPR,step,true,\r
+       true,1, 0,0, KeenThrow, KeenContact, KeenStandReact, &s_keenthrow4};\r
+statetype s_keenthrow4 = {KEENTHROWL3SPR,KEENTHROWR3SPR,step,false,\r
+       true,10, 0,0, NULL, KeenContact, KeenStandReact, &s_keenstand};\r
+\r
+statetype s_keenthrowup1       = {KEENTHROWU1SPR,KEENTHROWU1SPR,step,false,\r
+       true,8, 0,0, NULL, KeenContact, KeenStandReact, &s_keenthrowup2};\r
+statetype s_keenthrowup2       = {KEENTHROWU2SPR,KEENTHROWU2SPR,step,true,\r
+       true,1, 0,0, KeenThrow, KeenContact, KeenStandReact, &s_keenthrowup3};\r
+statetype s_keenthrowup3       = {KEENTHROWU2SPR,KEENTHROWU2SPR,step,false,\r
+       true,10, 0,0, NULL, KeenContact, KeenStandReact, &s_keenstand};\r
+\r
+//-------------------\r
+\r
+statetype s_keenjumpup1        = {KEENJUMPUL1SPR,KEENJUMPUR1SPR,think,false,\r
+       false,0, 0,0, KeenAirThink, KeenContact, KeenAirReact, &s_keenjumpup2};\r
+statetype s_keenjumpup2        = {KEENJUMPUL2SPR,KEENJUMPUR2SPR,think,false,\r
+       false,0, 0,0, KeenAirThink, KeenContact, KeenAirReact, &s_keenjumpup3};\r
+statetype s_keenjumpup3        = {KEENJUMPUL1SPR,KEENJUMPUR1SPR,think,false,\r
+       false,0, 0,0, KeenAirThink, KeenContact, KeenAirReact, &s_keenstand};\r
+\r
+statetype s_keenjump1  = {KEENJUMPL1SPR,KEENJUMPR1SPR,think,false,\r
+       false,0, 0,0, KeenAirThink, KeenContact, KeenAirReact, &s_keenjump2};\r
+statetype s_keenjump2  = {KEENJUMPL2SPR,KEENJUMPR2SPR,think,false,\r
+       false,0, 0,0, KeenAirThink, KeenContact, KeenAirReact, &s_keenjump3};\r
+statetype s_keenjump3  = {KEENJUMPL3SPR,KEENJUMPR3SPR,think,false,\r
+       false,0, 0,0, KeenAirThink, KeenContact, KeenAirReact, &s_keenstand};\r
+\r
+statetype s_keenairthrow1= {KEENJLTHROWL1SPR,KEENJRTHROWR1SPR,stepthink,false,\r
+       false,8, 0,0, ProjectileThink, KeenContact, KeenAirReact, &s_keenairthrow2};\r
+statetype s_keenairthrow2= {KEENJLTHROWL2SPR,KEENJRTHROWR2SPR,step,true,\r
+       false,1, 0,0, KeenThrow, KeenContact, KeenAirReact, &s_keenairthrow3};\r
+statetype s_keenairthrow3= {KEENJLTHROWL2SPR,KEENJRTHROWR2SPR,stepthink,false,\r
+       false,10, 0,0, ProjectileThink, KeenContact, KeenAirReact, &s_keenjumpup3};\r
+\r
+statetype s_keenairthrowup1= {KEENJLTHROWU1SPR,KEENJRTHROWU1SPR,stepthink,false,\r
+       false,8, 0,0, ProjectileThink, KeenContact, KeenAirReact, &s_keenairthrowup2};\r
+statetype s_keenairthrowup2= {KEENJLTHROWU2SPR,KEENJRTHROWU2SPR,step,true,\r
+       false,1, 0,0, KeenThrow, KeenContact, KeenAirReact, &s_keenairthrowup3};\r
+statetype s_keenairthrowup3= {KEENJLTHROWU2SPR,KEENJRTHROWU2SPR,stepthink,false,\r
+       false,10, 0,0, ProjectileThink, KeenContact, KeenAirReact, &s_keenjumpup3};\r
+\r
+statetype s_keenairthrowdown1= {KEENJLTHROWD1SPR,KEENJRTHROWD1SPR,stepthink,false,\r
+       false,8, 0,0, ProjectileThink, KeenContact, KeenAirReact, &s_keenairthrowdown2};\r
+statetype s_keenairthrowdown2= {KEENJLTHROWD2SPR,KEENJRTHROWD2SPR,step,true,\r
+       false,1, 0,0, KeenThrow, KeenContact, KeenAirReact, &s_keenairthrowdown3};\r
+statetype s_keenairthrowdown3= {KEENJLTHROWD2SPR,KEENJRTHROWD2SPR,stepthink,false,\r
+       false,10, 0,0, ProjectileThink, KeenContact, KeenAirReact, &s_keenjumpup3};\r
+\r
+\r
+//===========================================================================\r
+\r
+#pragma warn +sus\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnKeen\r
+=\r
+===============\r
+*/\r
+\r
+void SpawnKeen (int tilex, int tiley, int dir)\r
+{\r
+       player->obclass = keenobj;\r
+       player->active = yes;\r
+       player->needtoclip = true;\r
+       player->x = tilex<<G_T_SHIFT;\r
+       player->y = (tiley<<G_T_SHIFT) - BLOCKSIZE*2;\r
+\r
+       player->xdir = dir;\r
+       player->ydir = 1;\r
+       NewState (player,&s_keenstand);\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+======================\r
+=\r
+= CheckGrabPole\r
+=\r
+======================\r
+*/\r
+\r
+boolean        CheckGrabPole (objtype *ob)\r
+{\r
+       int     x;\r
+       unsigned far *map;\r
+\r
+//\r
+// kludgy bit to not let you grab a pole the instant you jump off it\r
+//\r
+       if (TimeCount < leavepoletime)\r
+               leavepoletime = 0;\r
+       else if (TimeCount - leavepoletime < MINPOLEJUMPTICS)\r
+               return false;\r
+\r
+       if (c.yaxis == -1)\r
+               map = (unsigned _seg *)mapsegs[1]+\r
+                       mapbwidthtable[(ob->top+6*PIXGLOBAL)/TILEGLOBAL]/2;\r
+       else\r
+               map = (unsigned _seg *)mapsegs[1]+\r
+                       mapbwidthtable[ob->tilebottom]/2;\r
+\r
+       x = (ob->left + (ob->right - ob->left)/2) >>G_T_SHIFT;\r
+\r
+       map += x;\r
+\r
+       if ((tinf[INTILE+*map]&0x7f) == 1)\r
+       {\r
+               ob->xmove = ((x<<G_T_SHIFT)-8*PIXGLOBAL) - ob->x;\r
+               ob->ymove = c.yaxis*32;\r
+               ob->temp4 = x;                          // for future reference\r
+               ob->needtoclip = false;         // can climb through pole holes\r
+               ob->state = &s_keenpole;\r
+               return true;\r
+       }\r
+\r
+       return false;\r
+}\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+============================\r
+=\r
+= KeenStandThink\r
+=\r
+============================\r
+*/\r
+\r
+void KeenStandThink (objtype *ob)\r
+{\r
+       if (c.xaxis)\r
+       {\r
+       // started walking\r
+               ob->xdir = c.xaxis;\r
+               ob->state = &s_keenwalk1;\r
+               ob->xmove = ob->xdir*s_keenwalk1.xmove*tics;\r
+               KeenWalkThink(ob);\r
+               return;\r
+       }\r
+\r
+       if (c.button0 && !button0held)\r
+       {\r
+       // jump straight up\r
+               SD_PlaySound (JUMPSND);\r
+               ob->xspeed = 0;\r
+               ob->yspeed = -SPDJUMP;\r
+               ob->xmove = 0;\r
+               ob->ymove = 0;          // ob->yspeed*tics;                     // DEBUG\r
+               jumptime = JUMPTIME;    // -tics;\r
+               ob->state = &s_keenjumpup1;\r
+               button0held = true;\r
+               return;\r
+       }\r
+\r
+       if (c.button1 && !button1held)\r
+       {\r
+       // throw current xdir\r
+               if (c.yaxis == -1)\r
+                       ob->state = &s_keenthrowup1;\r
+               else\r
+                       ob->state = &s_keenthrow1;\r
+               button1held = true;\r
+               return;\r
+       }\r
+\r
+       switch (c.yaxis)\r
+       {\r
+       case -1:\r
+               if (!CheckGrabPole(ob))                 // try to go up/down pole first\r
+                       ob->state = &s_keenlookup;\r
+               return;\r
+       case 0:\r
+               ob->state = &s_keenstand;\r
+               return;\r
+       case 1:\r
+               if (!CheckGrabPole(ob))                 // try to go up/down pole first\r
+                       ob->state = &s_keenduck;\r
+               return;\r
+       }\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+=======================\r
+=\r
+= KeenPauseThink\r
+=\r
+= Do special animations in time\r
+=\r
+=======================\r
+*/\r
+\r
+void KeenPauseThink (objtype *ob)\r
+{\r
+       if (c.dir != dir_None || c.button0 || c.button1)\r
+       {\r
+               ob->temp1 = ob->temp2 = 0;                      // not paused any more\r
+               ob->state = &s_keenstand;\r
+               KeenStandThink(ob);\r
+               return;\r
+       }\r
+\r
+       if ((ob->hitnorth & ~7) != 24)  // if it is 0 now, keen is standing on a sprite\r
+               ob->temp1 += tics;\r
+\r
+       switch (ob->temp2)\r
+       {\r
+       case 0:\r
+               if (ob->temp1 > 200)\r
+               {\r
+                       ob->temp2++;\r
+                       ob->state = &s_keenpauselook;\r
+                       ob->temp1 = 0;\r
+               }\r
+               break;\r
+       case 1:\r
+               if (ob->temp1 > 300)\r
+               {\r
+                       ob->temp2++;\r
+                       ob->state = &s_keenwait1;\r
+                       ob->temp1 = 0;\r
+               }\r
+               break;\r
+       case 2:\r
+               if (ob->temp1 > 700)\r
+               {\r
+                       ob->temp2++;\r
+                       ob->state = &s_keenyawn1;\r
+                       ob->temp1 = 0;\r
+               }\r
+               break;\r
+       case 3:\r
+               if (ob->temp1 > 400)\r
+               {\r
+                       ob->temp2++;\r
+                       ob->state = &s_keenpauselook;\r
+                       ob->temp1 = 0;\r
+               }\r
+               break;\r
+       case 4:\r
+               if (ob->temp1 > 700)\r
+               {\r
+                       ob->temp2++;\r
+                       ob->state = &s_keenyawn1;\r
+                       ob->temp1 = 0;\r
+               }\r
+               break;\r
+       case 5:\r
+               if (ob->temp1 > 400)\r
+               {\r
+                       ob->temp2++;\r
+                       ob->state = &s_keengosleep1;\r
+               }\r
+               break;\r
+       }\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+=======================\r
+=\r
+= KeenGoSleepThink\r
+=\r
+=======================\r
+*/\r
+\r
+void KeenGoSleepThink (objtype *ob)\r
+{\r
+//\r
+// spawn the zees above keens head\r
+//\r
+       GetNewObj (true);\r
+\r
+       new->obclass = inertobj;\r
+       new->x = player->x;\r
+       new->y = player->y-4*PIXGLOBAL;\r
+       new->xdir = 1;\r
+       new->ydir = -1;\r
+       NewState (new,&s_keenzee1);\r
+\r
+       ob->temp1 = (int)new;                           // so they can be removed later\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+=======================\r
+=\r
+= KeenSleepThink\r
+=\r
+=======================\r
+*/\r
+\r
+void KeenSleepThink (objtype *ob)\r
+{\r
+       if (c.dir != dir_None || c.button0 || c.button1)\r
+       {\r
+               if (ob->temp1 != (unsigned)&dummyobj)\r
+                       RemoveObj ((objtype *)ob->temp1);       // remove the zees\r
+               ob->temp1 = ob->temp2 = 0;                      // not paused any more\r
+               ob->state = &s_keengetup;\r
+       }\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+=======================\r
+=\r
+= KeenDieThink\r
+=\r
+=======================\r
+*/\r
+\r
+void KeenDieThink (objtype *ob)\r
+{\r
+       ob++;                   // shut up compiler\r
+       playstate = died;\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+=======================\r
+=\r
+= KeenDuckThink\r
+=\r
+=======================\r
+*/\r
+\r
+void KeenDuckThink (objtype *ob)\r
+{\r
+       unsigned far *map, tile;\r
+       int midtile,bottomtile,move;\r
+\r
+       if (c.yaxis != 1)\r
+       {\r
+               ob->state = &s_keenstand;\r
+               KeenStandThink(ob);\r
+               return;\r
+       }\r
+\r
+       if (c.xaxis)\r
+               ob->xdir = c.xaxis;\r
+\r
+       if (c.button0 && !button0held)\r
+       {\r
+       //\r
+       // drop down a level\r
+       //\r
+               button0held = true;\r
+\r
+               midtile = (ob->tileleft + ob->tileright) >> 1;\r
+               bottomtile = ob->tilebottom;\r
+               map = (unsigned far *)mapsegs[1] + mapbwidthtable[bottomtile]/2\r
+                       + midtile;\r
+               tile = *map;\r
+               if (tinf[WESTWALL+tile] || tinf[EASTWALL+tile]\r
+                       || tinf[SOUTHWALL+tile])\r
+                       return;                         // wall prevents drop down\r
+\r
+               map += mapwidth;\r
+               tile = *map;\r
+               if (tinf[WESTWALL+tile] || tinf[EASTWALL+tile]\r
+                       || tinf[SOUTHWALL+tile])\r
+                       return;                         // wall prevents drop down\r
+\r
+               move = PIXGLOBAL*(tics<4 ? 4: tics);\r
+               ob->bottom += move;\r
+               ob->y += move;\r
+               ob->xmove = ob->ymove = 0;\r
+               ob->state = &s_keenjumpup3;\r
+               ob->temp2 = 1;          // allready in last stage\r
+               ob->xspeed = ob->yspeed = 0;\r
+               SD_PlaySound (PLUMMETSND);\r
+       }\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+=======================\r
+=\r
+= KeenDropDownThink\r
+=\r
+=======================\r
+*/\r
+\r
+void KeenDropDownThink (objtype *ob)\r
+{\r
+       ob->needtoclip = true;\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+=======================\r
+=\r
+= KeenWalkThink\r
+=\r
+=======================\r
+*/\r
+\r
+unsigned slopespeed[8] = {0,0,4,4,8,-4,-4,-8};\r
+\r
+void KeenWalkThink (objtype *ob)\r
+{\r
+       int move;\r
+\r
+       if (!c.xaxis)\r
+       {\r
+       //\r
+       // stopped running\r
+       //\r
+               KeenStandThink (ob);\r
+               return;\r
+       }\r
+\r
+       ob->xdir = c.xaxis;\r
+\r
+       if (c.yaxis && CheckGrabPole(ob))               // try to go up/down pole\r
+               return;\r
+\r
+       if (c.button0 && !button0held)\r
+       {\r
+       //\r
+       // running jump\r
+       //\r
+               SD_PlaySound (JUMPSND);\r
+               ob->xspeed = ob->xdir * SPDRUNJUMP;\r
+               ob->yspeed = -SPDJUMP;\r
+               ob->xmove = 0;\r
+               ob->ymove = 0;                                  // ob->yspeed*tics;\r
+               button0held = true;\r
+               jumptime = JUMPTIME; //-tics;           // DEBUG\r
+               ob->state = &s_keenjump1;\r
+       }\r
+\r
+       if (c.button1 && !button1held)\r
+       {\r
+       //\r
+       // throw\r
+       //\r
+               ob->state = &s_keenthrow1;\r
+               button1held = true;\r
+               return;\r
+       }\r
+\r
+       //\r
+       // give speed for slopes\r
+       //\r
+       move = tics*slopespeed[ob->hitnorth&7];\r
+\r
+       ob->xmove += move;\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+=======================\r
+=\r
+= KeenAirThink\r
+=\r
+=======================\r
+*/\r
+\r
+void   KeenAirThink            (objtype *ob)\r
+{\r
+       if (jumptime)\r
+       {\r
+               if (jumptime<tics)\r
+               {\r
+                       ob->ymove = ob->yspeed*jumptime;\r
+                       jumptime = 0;\r
+               }\r
+               else\r
+               {\r
+                       ob->ymove = ob->yspeed*tics;\r
+                       if (!jumpcheat)\r
+                               jumptime-=tics;\r
+               }\r
+               if (!c.button0)\r
+                       jumptime = 0;\r
+\r
+               if (!jumptime)\r
+               {\r
+                       ob->temp2 = 0;\r
+                       ob->state = ob->state->nextstate;       // switch to second jump stage\r
+               }\r
+       }\r
+       else\r
+       {\r
+               DoGravity(ob);\r
+\r
+               if (ob->yspeed>0 && !ob->temp2)\r
+               {\r
+                       ob->state = ob->state->nextstate;       // switch to third jump stage\r
+                       ob->temp2 = 1;\r
+               }\r
+       }\r
+\r
+//-------------\r
+\r
+       if (c.xaxis)\r
+       {\r
+               ob->xdir = c.xaxis;\r
+               AccelerateX(ob,c.xaxis*2,MAXXSPEED);\r
+       }\r
+       else\r
+               FrictionX(ob);\r
+\r
+       if (c.button1 && !button1held)\r
+       {\r
+               button1held = true;\r
+       //\r
+       // throw\r
+       //\r
+               switch (c.yaxis)\r
+               {\r
+               case -1:\r
+                       ob->state = &s_keenairthrowup1;\r
+                       return;\r
+               case 0:\r
+                       ob->state = &s_keenairthrow1;\r
+                       return;\r
+               case 1:\r
+                       ob->state = &s_keenairthrowdown1;\r
+                       return;\r
+               }\r
+       }\r
+\r
+       if (ob->hitsouth==17)           // going through a pole hole\r
+       {\r
+               ob->xspeed = ob->xmove = 0;\r
+       }\r
+\r
+\r
+       if (c.yaxis == -1)\r
+               CheckGrabPole (ob);\r
+\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+=======================\r
+=\r
+= KeenPoleThink\r
+=\r
+=======================\r
+*/\r
+\r
+int    polexspeed[3] = {-SPDPOLESIDEJUMP,0,SPDPOLESIDEJUMP};\r
+\r
+void   PoleActions (objtype *ob)\r
+{\r
+       if (c.xaxis)\r
+               ob->xdir = c.xaxis;\r
+\r
+       if (c.button0 && !button0held)          // jump off the pole\r
+       {\r
+               SD_PlaySound (JUMPSND);\r
+               ob->xspeed = polexspeed[c.xaxis+1];\r
+               ob->yspeed = -SPDPOLEJUMP;\r
+               ob->needtoclip = true;\r
+               jumptime = POLEJUMPTIME;\r
+               ob->state = &s_keenjump1;\r
+               ob->ydir = 1;\r
+               button0held = true;\r
+               leavepoletime = TimeCount;\r
+               return;\r
+       }\r
+\r
+       if (c.button1 && !button1held)\r
+       {\r
+               button1held = true;\r
+\r
+               switch (c.yaxis)\r
+               {\r
+               case -1:\r
+                       ob->state = &s_keenpolethrowup1;\r
+                       break;\r
+               case 0:\r
+                       ob->state = &s_keenpolethrow1;\r
+                       break;\r
+               case 1:\r
+                       ob->state = &s_keenpolethrowdown1;\r
+                       break;\r
+               }\r
+       }\r
+}\r
+\r
+\r
+void   KeenPoleThink           (objtype *ob)\r
+{\r
+       unsigned far *map, tile;\r
+\r
+       switch (c.yaxis)\r
+       {\r
+       case -1:\r
+               ob->state = &s_keenclimb1;\r
+               ob->ydir = -1;\r
+               return;\r
+\r
+       case 1:\r
+               ob->state = &s_keenslide1;\r
+               ob->ydir = 1;\r
+               KeenDropThink (ob);\r
+               return;\r
+       }\r
+\r
+       if (c.xaxis)\r
+       {\r
+       //\r
+       // walk off pole if right next to ground\r
+       //\r
+               map = mapsegs[1] + (mapbwidthtable[ob->tilebottom+1]/2 + ob->tilemidx);\r
+               tile = *map;\r
+               if (tinf[NORTHWALL+tile])\r
+               {\r
+                       ob->xspeed = 0;\r
+                       ob->yspeed = 0;\r
+                       ob->needtoclip = true;\r
+                       jumptime = 0;\r
+                       ob->state = &s_keenjump3;\r
+                       ob->ydir = 1;\r
+                       SD_PlaySound (PLUMMETSND);\r
+                       return;\r
+               }\r
+       }\r
+\r
+       PoleActions (ob);\r
+}\r
+\r
+\r
+/*\r
+=======================\r
+=\r
+= KeenClimbThink\r
+=\r
+=======================\r
+*/\r
+\r
+void   KeenClimbThink          (objtype *ob)\r
+{\r
+       unsigned far *map;\r
+\r
+       map = (unsigned _seg *)mapsegs[1]+mapbwidthtable[ob->tiletop]/2+ob->temp4;\r
+\r
+       if ((tinf[INTILE+*map]&0x7f) != 1)\r
+       {\r
+               ob->ymove=0;\r
+               ob->state = &s_keenpole;                // ran out of pole\r
+               return;\r
+       }\r
+\r
+       switch (c.yaxis)\r
+       {\r
+       case 0:\r
+               ob->state = &s_keenpole;\r
+               ob->ydir = 0;\r
+               break;\r
+\r
+       case 1:\r
+               ob->state = &s_keenslide1;\r
+               ob->ydir = 1;\r
+               KeenDropThink (ob);\r
+               break;\r
+       }\r
+\r
+       PoleActions (ob);\r
+}\r
+\r
+\r
+/*\r
+=======================\r
+=\r
+= KeenDropThink\r
+=\r
+=======================\r
+*/\r
+\r
+void   KeenDropThink           (objtype *ob)\r
+{\r
+       unsigned far *map;\r
+\r
+       map = (unsigned _seg *)mapsegs[1]+mapbwidthtable[ob->tilebottom]/2+ob->temp4;\r
+\r
+       if ((tinf[INTILE+*map]&0x7f) != 1)\r
+       {\r
+               SD_PlaySound (PLUMMETSND);\r
+               ob->state = &s_keenjump3;               // ran out of pole\r
+               jumptime = 0;\r
+               ob->temp2 = 1;\r
+               ob->xspeed = polexspeed[c.xaxis+1];\r
+               ob->yspeed = 0;\r
+               ob->needtoclip = true;\r
+               ob->tilebottom--;\r
+               return;\r
+       }\r
+\r
+       switch (c.yaxis)\r
+       {\r
+       case -1:\r
+               ob->state = &s_keenclimb1;\r
+               ob->ydir = -1;\r
+               break;\r
+\r
+       case 0:\r
+               ob->state = &s_keenpole;\r
+               ob->ydir = 0;\r
+               break;\r
+       }\r
+\r
+       PoleActions (ob);\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+=======================\r
+=\r
+= KeenThrow\r
+=\r
+=======================\r
+*/\r
+\r
+void   KeenThrow       (objtype *ob)\r
+{\r
+// can't use &<var> in a switch statement...\r
+\r
+       if (ob->state == &s_keenthrow3)\r
+       {\r
+               if (ob->xdir > 0)\r
+                       ThrowPower (ob->midx-4*PIXGLOBAL,ob->y+8*PIXGLOBAL,dir_East);\r
+               else\r
+                       ThrowPower (ob->midx-4*PIXGLOBAL,ob->y+8*PIXGLOBAL,dir_West);\r
+               return;\r
+       }\r
+\r
+       if (ob->state == &s_keenpolethrow2)\r
+       {\r
+               if (ob->xdir > 0)\r
+                       ThrowPower (ob->x+24*PIXGLOBAL,ob->y,dir_East);\r
+               else\r
+                       ThrowPower (ob->x-8*PIXGLOBAL,ob->y,dir_West);\r
+               return;\r
+       }\r
+\r
+       if (ob->state == &s_keenthrowup2)\r
+       {\r
+               ThrowPower (ob->x+4*PIXGLOBAL,ob->y-8*PIXGLOBAL,dir_North);\r
+               return;\r
+       }\r
+\r
+       if (ob->state == &s_keenpolethrowup2)\r
+       {\r
+               ThrowPower (ob->x+8*PIXGLOBAL,ob->y-8*PIXGLOBAL,dir_North);\r
+               return;\r
+       }\r
+\r
+       if (ob->state == &s_keenpolethrowdown2)\r
+       {\r
+               ThrowPower (ob->x+8*PIXGLOBAL,ob->y+8*PIXGLOBAL,dir_South);\r
+               return;\r
+       }\r
+\r
+       if (ob->state == &s_keenairthrow2)\r
+       {\r
+               if (ob->xdir > 0)\r
+                       ThrowPower (ob->midx-4*PIXGLOBAL,ob->y+8*PIXGLOBAL,dir_East);\r
+               else\r
+                       ThrowPower (ob->midx-4*PIXGLOBAL,ob->y+8*PIXGLOBAL,dir_West);\r
+#if 0\r
+               if (ob->xdir > 0)\r
+                       ThrowPower (ob->x+32*PIXGLOBAL,ob->y+8*PIXGLOBAL,dir_East);\r
+               else\r
+                       ThrowPower (ob->x-16*PIXGLOBAL,ob->y+8*PIXGLOBAL,dir_West);\r
+#endif\r
+\r
+               new->xspeed += ob->xspeed/2;\r
+               new->yspeed += ob->yspeed/2;\r
+               return;\r
+       }\r
+\r
+       if (ob->state == &s_keenairthrowup2)\r
+       {\r
+               if (ob->xdir > 0)\r
+                       ThrowPower (ob->x+16*PIXGLOBAL,ob->y,dir_North);\r
+               else\r
+                       ThrowPower (ob->x+4*PIXGLOBAL,ob->y,dir_North);\r
+               new->xspeed += ob->xspeed/2;\r
+               new->yspeed += ob->yspeed/2;\r
+               return;\r
+       }\r
+\r
+       if (ob->state == &s_keenairthrowdown2)\r
+       {\r
+               if (ob->xdir > 0)\r
+                       ThrowPower (ob->x+3*PIXGLOBAL,ob->y+16*PIXGLOBAL,dir_South);\r
+               else\r
+                       ThrowPower (ob->x+12*PIXGLOBAL,ob->y+16*PIXGLOBAL,dir_South);\r
+               new->xspeed += ob->xspeed/2;\r
+               new->yspeed += ob->yspeed/2;\r
+               return;\r
+       }\r
+\r
+       Quit ("KeenThrow: Bad state!");\r
+}\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                               CONTACT ROUTINES\r
+\r
+=============================================================================\r
+*/\r
+\r
+/*\r
+============================\r
+=\r
+= KillKeen\r
+=\r
+============================\r
+*/\r
+\r
+void KillKeen (void)\r
+{\r
+       if (!godmode)\r
+       {\r
+               SD_PlaySound (WAKEUPSND);\r
+               player->needtoclip = false;\r
+               ChangeState (player,&s_keendie1);\r
+       }\r
+}\r
+\r
+\r
+\r
+/*\r
+============================\r
+=\r
+= KeenContact\r
+=\r
+============================\r
+*/\r
+\r
+unsigned bonuspoints[6] = {100,200,500,1000,2000,5000};\r
+\r
+void   KeenContact (objtype *ob, objtype *hit)\r
+{\r
+       switch (hit->obclass)\r
+       {\r
+       case    bonusobj:\r
+               hit->obclass = inertobj;\r
+               switch (hit->temp1)\r
+               {\r
+               case 0:\r
+               case 1:\r
+               case 2:\r
+               case 3:\r
+               case 4:\r
+               case 5:\r
+                       SD_PlaySound (GETPOINTSSND);\r
+                       hit->shapenum = BONUS100SPR+hit->temp1;\r
+                       GivePoints (bonuspoints[hit->temp1]);\r
+                       ChangeState (hit,&s_bonusrise);\r
+                       break;\r
+               case 6:\r
+                       SD_PlaySound (EXTRAKEENSND);\r
+                       hit->shapenum = BONUS1UPSPR;\r
+                       gamestate.lives++;\r
+                       ChangeState (hit,&s_bonusrise);\r
+                       break;\r
+               case 7:\r
+                       SD_PlaySound (EXTRAKEENSND);\r
+                       hit->shapenum = BONUSSUPERSPR;\r
+                       gamestate.lives+=3;\r
+                       gamestate.flowerpowers+=8;\r
+                       GivePoints (10000);\r
+                       ChangeState (hit,&s_bonusrise);\r
+                       break;\r
+               case 8:\r
+                       SD_PlaySound (GETPOWERSND);\r
+                       hit->shapenum = BONUSFLOWERSPR;\r
+                       gamestate.flowerpowers++;\r
+                       ChangeState (hit,&s_bonusrise);\r
+                       break;\r
+               case 9:\r
+                       SD_PlaySound (GETPOWERSND);\r
+                       hit->shapenum = BONUSFLOWERUPSPR;\r
+                       gamestate.flowerpowers+=5;\r
+                       ChangeState (hit,&s_bonusrise);\r
+                       break;\r
+               case 10:\r
+                       SD_PlaySound (GETBOMBSND);\r
+                       hit->shapenum = BONUSBOMBSPR;\r
+                       gamestate.boobusbombs++;\r
+                       gamestate.bombsthislevel++;\r
+                       ChangeState (hit,&s_bonusrise);\r
+                       break;\r
+               case 11:\r
+                       SD_PlaySound (GETKEYSND);\r
+                       hit->shapenum = BONUSKEYSPR;\r
+                       gamestate.keys++;\r
+                       ChangeState (hit,&s_bonusrise);\r
+                       break;\r
+               }\r
+               break;\r
+\r
+       case    doorobj:\r
+               if (gamestate.keys)\r
+               {\r
+                       if (hit->state != &s_doorraise)\r
+                       {\r
+                               SD_PlaySound (OPENDOORSND);\r
+                               gamestate.keys--;\r
+                               ChangeState (hit,&s_doorraise);\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       SD_PlaySound (NOWAYSND);\r
+                       ClipToSpriteSide (ob,hit);\r
+               }\r
+               break;\r
+       case    taterobj:\r
+               if (hit->state == &s_taterattack2)\r
+                       KillKeen ();\r
+               break;\r
+       case    carrotobj:\r
+               ClipToSpriteSide (ob,hit);\r
+               if (!ob->needtoclip)            // got pushed off a pole\r
+               {\r
+                       SD_PlaySound (PLUMMETSND);\r
+                       ob->needtoclip = true;\r
+                       ob->xspeed = ob->yspeed = 0;\r
+                       ChangeState(ob,&s_keenjump3);\r
+                       ob->temp2 = 1;\r
+                       jumptime = 0;\r
+               }\r
+               break;\r
+       case    cartobj:\r
+               ClipToSprite (ob,hit,true);\r
+               break;\r
+       case    broccoobj:\r
+               if (hit->state == &s_broccosmash3 || hit->state == &s_broccosmash4)\r
+                       KillKeen ();\r
+               break;\r
+       case    squashobj:\r
+               if (hit->state == &s_squasherjump2)\r
+                       KillKeen ();\r
+               else\r
+               {\r
+                       ClipToSpriteSide (ob,hit);\r
+                       if (!ob->needtoclip)            // got pushed off a pole\r
+                       {\r
+                               SD_PlaySound (PLUMMETSND);\r
+                               ob->needtoclip = true;\r
+                               ob->xspeed = ob->yspeed = 0;\r
+                               ChangeState(ob,&s_keenjump3);\r
+                               ob->temp2 = 1;\r
+                               jumptime = 0;\r
+                       }\r
+               }\r
+               break;\r
+       case    grapeobj:\r
+               if (hit->state == &s_grapefall)\r
+                       KillKeen ();\r
+               break;\r
+       case    tomatobj:\r
+       case    celeryobj:\r
+       case    asparobj:\r
+       case    turnipobj:\r
+       case    cauliobj:\r
+       case    brusselobj:\r
+       case    mushroomobj:\r
+       case    apelobj:\r
+       case    peabrainobj:\r
+       case    boobusobj:\r
+       case    shotobj:\r
+                       KillKeen ();\r
+               break;\r
+\r
+       }\r
+}\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                REACTION ROUTINES\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+/*\r
+============================\r
+=\r
+= KeenSimpleReact\r
+=\r
+============================\r
+*/\r
+\r
+void   KeenSimpleReact (objtype *ob)\r
+{\r
+       PLACESPRITE;\r
+}\r
+\r
+\r
+/*\r
+============================\r
+=\r
+= KeenStandReact\r
+=\r
+============================\r
+*/\r
+\r
+void   KeenStandReact (objtype *ob)\r
+{\r
+       if (!ob->hitnorth)\r
+       {\r
+       //\r
+       // walked off an edge\r
+       //\r
+               SD_PlaySound (PLUMMETSND);\r
+               ob->xspeed = ob->xdir*WALKAIRSPEED;\r
+               ChangeState (ob,&s_keenjump3);\r
+               ob->temp2 = 1;\r
+               jumptime = 0;\r
+       }\r
+       else if ( (ob->hitnorth & ~7) == 8)     // deadly floor!\r
+       {\r
+               KillKeen ();\r
+       }\r
+\r
+       PLACESPRITE;\r
+}\r
+\r
+/*\r
+============================\r
+=\r
+= KeenWalkReact\r
+=\r
+============================\r
+*/\r
+\r
+void   KeenWalkReact (objtype *ob)\r
+{\r
+       if (!ob->hitnorth)\r
+       {\r
+       //\r
+       // walked off an edge\r
+       //\r
+               ob->xspeed = ob->xdir*WALKAIRSPEED;\r
+               ob->yspeed = 0;\r
+               ChangeState (ob,&s_keenjump3);\r
+               ob->temp2 = 1;\r
+               jumptime = 0;\r
+       }\r
+       else if ( (ob->hitnorth & ~7) == 8)     // deadly floor!\r
+       {\r
+               KillKeen ();\r
+               goto placeit;\r
+       }\r
+\r
+       if (ob->hiteast == 2)                   // doors\r
+       {\r
+\r
+       }\r
+       else if (ob->hitwest == 2)              // doors\r
+       {\r
+\r
+       }\r
+       else if (ob->hiteast || ob->hitwest)\r
+       {\r
+       //\r
+       // ran into a wall\r
+       //\r
+               ob->ticcount = 0;\r
+               ob->state = &s_keenstand;\r
+               ob->shapenum = ob->xdir == 1 ? s_keenstand.rightshapenum :\r
+                       s_keenstand.leftshapenum;\r
+       }\r
+placeit:\r
+\r
+       PLACESPRITE;\r
+}\r
+\r
+\r
+/*\r
+============================\r
+=\r
+= KeenAirReact\r
+=\r
+============================\r
+*/\r
+\r
+void   KeenAirReact (objtype *ob)\r
+{\r
+       int x,y;\r
+       unsigned far *map,mapextra;\r
+\r
+       if (ob->hiteast || ob->hitwest)\r
+               ob->xspeed = 0;\r
+\r
+       map = mapsegs[1] + (mapbwidthtable[ob->tiletop]/2) + ob->tileleft;\r
+       mapextra = mapwidth - (ob->tileright - ob->tileleft+1);\r
+       for (y=ob->tiletop;y<=ob->tilebottom;y++,map+=mapextra)\r
+               for (x=ob->tileleft;x<=ob->tileright;x++,map++)\r
+                       if (tinf[SOUTHWALL+*map] == 17) // jumping up through a pole hole\r
+                       {\r
+                               ob->xspeed = 0;\r
+                               ob->x = ob->tilemidx*TILEGLOBAL - 2*PIXGLOBAL;\r
+                               goto checknorth;\r
+                       }\r
+\r
+       if (ob->hitsouth)\r
+       {\r
+               if (ob->hitsouth == 17) // jumping up through a pole hole\r
+               {\r
+                       ob->y -= 32;\r
+                       ob->top -= 32;\r
+                       ob->xspeed = 0;\r
+                       ob->x = ob->tilemidx*TILEGLOBAL - 2*PIXGLOBAL;\r
+               }\r
+               else\r
+               {\r
+                       SD_PlaySound (HITHEADSND);\r
+\r
+                       if (ob->hitsouth > 1)\r
+                       {\r
+                               ob->yspeed += 16;\r
+                               if (ob->yspeed<0)       // push away from slopes\r
+                                       ob->yspeed = 0;\r
+                       }\r
+                       else\r
+                               ob->yspeed = 0;\r
+                       jumptime = 0;\r
+               }\r
+       }\r
+\r
+checknorth:\r
+       if (ob->hitnorth)\r
+       {\r
+               if (!(ob->hitnorth == 25 && jumptime))  // KLUDGE to allow jumping off\r
+               {                                                                               // sprites\r
+                       ob->temp1 = ob->temp2 = 0;\r
+                       ChangeState (ob,&s_keenstand);\r
+                       SD_PlaySound (LANDSND);\r
+               }\r
+       }\r
+\r
+       PLACESPRITE;\r
+}\r
+\r
+/*\r
+============================\r
+=\r
+= KeenSlideReact\r
+=\r
+============================\r
+*/\r
+\r
+void   KeenSlideReact (objtype *ob)\r
+{\r
+       unsigned far *map;\r
+\r
+       if (ob->hitnorth)                       // friction slow down\r
+       {\r
+               map = mapsegs[2] + (mapbwidthtable[ob->tiletop]/2 + ob->tileleft);\r
+               if (!tinf[SOUTHWALL+*map] && !tinf[SOUTHWALL+*(map+1)])\r
+                       FrictionX(ob);\r
+       }\r
+\r
+\r
+       if (ob->hitwest || ob->hiteast || !ob->xspeed)\r
+               ChangeState (ob,&s_keengetup);\r
+\r
+       PLACESPRITE;\r
+}\r
+\r
diff --git a/src/lib/hb/kd_main.c b/src/lib/hb/kd_main.c
new file mode 100755 (executable)
index 0000000..69a6d3e
--- /dev/null
@@ -0,0 +1,533 @@
+/* Keen Dreams Source Code\r
+ * Copyright (C) 2014 Javier M. Chavez\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License along\r
+ * with this program; if not, write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+ */\r
+\r
+// KD_MAIN.C\r
+/*\r
+=============================================================================\r
+\r
+                                                       KEEN DREAMS\r
+\r
+                                       An Id Software production\r
+\r
+=============================================================================\r
+*/\r
+\r
+#include "mem.h"\r
+#include "string.h"\r
+\r
+#include "KD_DEF.H"\r
+#pragma hdrstop\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                GLOBAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+char           str[80],str2[20];\r
+boolean                singlestep,jumpcheat,godmode,tedlevel;\r
+unsigned       tedlevelnum;\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+void   DebugMemory (void);\r
+void   TestSprites(void);\r
+int            DebugKeys (void);\r
+void   ShutdownId (void);\r
+void   Quit (char *error);\r
+void   InitGame (void);\r
+void   main (void);\r
+\r
+//===========================================================================\r
+\r
+#if FRILLS\r
+\r
+/*\r
+==================\r
+=\r
+= DebugMemory\r
+=\r
+==================\r
+*/\r
+\r
+void DebugMemory (void)\r
+{\r
+       VW_FixRefreshBuffer ();\r
+       US_CenterWindow (16,7);\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
+#if GRMODE == EGAGR\r
+       MM_ShowMemory ();\r
+#endif\r
+}\r
+\r
+/*\r
+===================\r
+=\r
+= TestSprites\r
+=\r
+===================\r
+*/\r
+\r
+#define DISPWIDTH      110\r
+#define        TEXTWIDTH   40\r
+void TestSprites(void)\r
+{\r
+       int hx,hy,sprite,oldsprite,bottomy,topx,shift;\r
+       spritetabletype far *spr;\r
+       spritetype _seg *block;\r
+       unsigned        mem,scan;\r
+\r
+\r
+       VW_FixRefreshBuffer ();\r
+       US_CenterWindow (30,17);\r
+\r
+       US_CPrint ("Sprite Test");\r
+       US_CPrint ("-----------");\r
+\r
+       hy=PrintY;\r
+       hx=(PrintX+56)&(~7);\r
+       topx = hx+TEXTWIDTH;\r
+\r
+       US_Print ("Chunk:\nWidth:\nHeight:\nOrgx:\nOrgy:\nXl:\nYl:\nXh:\nYh:\n"\r
+                         "Shifts:\nMem:\n");\r
+\r
+       bottomy = PrintY;\r
+\r
+       sprite = STARTSPRITES;\r
+       shift = 0;\r
+\r
+       do\r
+       {\r
+               if (sprite>=STARTTILE8)\r
+                       sprite = STARTTILE8-1;\r
+               else if (sprite<STARTSPRITES)\r
+                       sprite = STARTSPRITES;\r
+\r
+               spr = &spritetable[sprite-STARTSPRITES];\r
+               block = (spritetype _seg *)grsegs[sprite];\r
+\r
+               VWB_Bar (hx,hy,TEXTWIDTH,bottomy-hy,WHITE);\r
+\r
+               PrintX=hx;\r
+               PrintY=hy;\r
+               US_PrintUnsigned (sprite);US_Print ("\n");PrintX=hx;\r
+               US_PrintUnsigned (spr->width);US_Print ("\n");PrintX=hx;\r
+               US_PrintUnsigned (spr->height);US_Print ("\n");PrintX=hx;\r
+               US_PrintSigned (spr->orgx);US_Print ("\n");PrintX=hx;\r
+               US_PrintSigned (spr->orgy);US_Print ("\n");PrintX=hx;\r
+               US_PrintSigned (spr->xl);US_Print ("\n");PrintX=hx;\r
+               US_PrintSigned (spr->yl);US_Print ("\n");PrintX=hx;\r
+               US_PrintSigned (spr->xh);US_Print ("\n");PrintX=hx;\r
+               US_PrintSigned (spr->yh);US_Print ("\n");PrintX=hx;\r
+               US_PrintSigned (spr->shifts);US_Print ("\n");PrintX=hx;\r
+               if (!block)\r
+               {\r
+                       US_Print ("-----");\r
+               }\r
+               else\r
+               {\r
+                       mem = block->sourceoffset[3]+5*block->planesize[3];\r
+                       mem = (mem+15)&(~15);           // round to paragraphs\r
+                       US_PrintUnsigned (mem);\r
+               }\r
+\r
+               oldsprite = sprite;\r
+               do\r
+               {\r
+               //\r
+               // draw the current shift, then wait for key\r
+               //\r
+                       VWB_Bar(topx,hy,DISPWIDTH,bottomy-hy,WHITE);\r
+                       if (block)\r
+                       {\r
+                               PrintX = topx;\r
+                               PrintY = hy;\r
+                               US_Print ("Shift:");\r
+                               US_PrintUnsigned (shift);\r
+                               US_Print ("\n");\r
+                               VWB_DrawSprite (topx+16+shift*2,PrintY,sprite);\r
+                       }\r
+\r
+                       VW_UpdateScreen();\r
+\r
+                       scan = IN_WaitForKey ();\r
+\r
+                       switch (scan)\r
+                       {\r
+                       case sc_UpArrow:\r
+                               sprite++;\r
+                               break;\r
+                       case sc_DownArrow:\r
+                               sprite--;\r
+                               break;\r
+                       case sc_LeftArrow:\r
+                               if (--shift == -1)\r
+                                       shift = 3;\r
+                               break;\r
+                       case sc_RightArrow:\r
+                               if (++shift == 4)\r
+                                       shift = 0;\r
+                               break;\r
+                       case sc_Escape:\r
+                               return;\r
+                       }\r
+\r
+               } while (sprite == oldsprite);\r
+\r
+  } while (1);\r
+\r
+\r
+}\r
+\r
+#endif\r
+\r
+\r
+/*\r
+================\r
+=\r
+= DebugKeys\r
+=\r
+================\r
+*/\r
+int DebugKeys (void)\r
+{\r
+       boolean esc;\r
+       int level;\r
+\r
+#if FRILLS\r
+       if (Keyboard[0x12] && ingame)   // DEBUG: end + 'E' to quit level\r
+       {\r
+               if (tedlevel)\r
+                       TEDDeath();\r
+               playstate = levelcomplete;\r
+       }\r
+#endif\r
+\r
+       if (Keyboard[0x22] && ingame)           // G = god mode\r
+       {\r
+               VW_FixRefreshBuffer ();\r
+               US_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
+       else if (Keyboard[0x17])                        // I = item cheat\r
+       {\r
+               VW_FixRefreshBuffer ();\r
+               US_CenterWindow (12,3);\r
+               US_PrintCentered ("Free items!");\r
+               gamestate.boobusbombs=99;\r
+               gamestate.flowerpowers=99;\r
+               gamestate.keys=99;\r
+               VW_UpdateScreen();\r
+               IN_Ack ();\r
+               return 1;\r
+       }\r
+       else if (Keyboard[0x24])                        // J = jump cheat\r
+       {\r
+               jumpcheat^=1;\r
+               VW_FixRefreshBuffer ();\r
+               US_CenterWindow (18,3);\r
+               if (jumpcheat)\r
+                       US_PrintCentered ("Jump cheat ON");\r
+               else\r
+                       US_PrintCentered ("Jump cheat OFF");\r
+               VW_UpdateScreen();\r
+               IN_Ack ();\r
+               return 1;\r
+       }\r
+#if FRILLS\r
+       else if (Keyboard[0x32])                        // M = memory info\r
+       {\r
+               DebugMemory();\r
+               return 1;\r
+       }\r
+#endif\r
+       else if (Keyboard[0x19])                        // P = pause with no screen disruptioon\r
+       {\r
+               IN_Ack();\r
+       }\r
+       else if (Keyboard[0x1f] && ingame)      // S = slow motion\r
+       {\r
+               singlestep^=1;\r
+               VW_FixRefreshBuffer ();\r
+               US_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
+#if FRILLS\r
+       else if (Keyboard[0x14])                        // T = sprite test\r
+       {\r
+               TestSprites();\r
+               return 1;\r
+       }\r
+#endif\r
+       else if (Keyboard[0x11] && ingame)      // W = warp to level\r
+       {\r
+               VW_FixRefreshBuffer ();\r
+               US_CenterWindow(26,3);\r
+               PrintY+=6;\r
+               US_Print("  Warp to which level(0-16):");\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<=16)\r
+                       {\r
+                               gamestate.mapon = level;\r
+                               playstate = warptolevel;\r
+                       }\r
+               }\r
+               return 1;\r
+       }\r
+       return 0;\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
+  SD_Shutdown ();\r
+  IN_Shutdown ();\r
+  RF_Shutdown ();\r
+  VW_Shutdown ();\r
+  CA_Shutdown ();\r
+  MM_Shutdown ();\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+==========================\r
+=\r
+= Quit\r
+=\r
+==========================\r
+*/\r
+\r
+void Quit (char *error)\r
+{\r
+  ShutdownId ();\r
+  if (error && *error)\r
+  {\r
+       clrscr();\r
+       puts(error);\r
+       puts("\n");\r
+       exit(1);\r
+  }\r
+       exit (0);\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+==========================\r
+=\r
+= InitGame\r
+=\r
+= Load a few things right away\r
+=\r
+==========================\r
+*/\r
+\r
+#if 0\r
+#include "piracy.h"\r
+#endif\r
+\r
+void InitGame (void)\r
+{\r
+       int i;\r
+\r
+       MM_Startup ();\r
+\r
+\r
+#if 0\r
+       // Handle piracy screen...\r
+       //\r
+       movedata(FP_SEG(PIRACY),(unsigned)PIRACY,0xb800,displayofs,4000);\r
+       while ((bioskey(0)>>8) != sc_Return);\r
+#endif\r
+\r
+\r
+#if GRMODE == EGAGR\r
+       if (mminfo.mainmem < 335l*1024)\r
+       {\r
+#pragma        warn    -pro\r
+#pragma        warn    -nod\r
+               clrscr();                       // we can't include CONIO because of a name conflict\r
+#pragma        warn    +nod\r
+#pragma        warn    +pro\r
+               puts ("There is not enough memory available to play the game reliably.  You can");\r
+               puts ("play anyway, but an out of memory condition will eventually pop up.  The");\r
+               puts ("correct solution is to unload some TSRs or rename your CONFIG.SYS and");\r
+               puts ("AUTOEXEC.BAT to free up more memory.\n");\r
+               puts ("Do you want to (Q)uit, or (C)ontinue?");\r
+               i = bioskey (0);\r
+               if ( (i>>8) != sc_C)\r
+                       Quit ("");\r
+       }\r
+#endif\r
+\r
+       US_TextScreen();\r
+\r
+       VW_Startup ();\r
+       RF_Startup ();\r
+       IN_Startup ();\r
+       SD_Startup ();\r
+       US_Startup ();\r
+\r
+//     US_UpdateTextScreen();\r
+\r
+       CA_Startup ();\r
+       US_Setup ();\r
+\r
+//\r
+// load in and lock down some basic chunks\r
+//\r
+\r
+       CA_ClearMarks ();\r
+\r
+       CA_MarkGrChunk(STARTFONT);\r
+       CA_MarkGrChunk(STARTFONTM);\r
+       CA_MarkGrChunk(STARTTILE8);\r
+       CA_MarkGrChunk(STARTTILE8M);\r
+       for (i=KEEN_LUMP_START;i<=KEEN_LUMP_END;i++)\r
+               CA_MarkGrChunk(i);\r
+\r
+       CA_CacheMarks (NULL, 0);\r
+\r
+       MM_SetLock (&grsegs[STARTFONT],true);\r
+       MM_SetLock (&grsegs[STARTFONTM],true);\r
+       MM_SetLock (&grsegs[STARTTILE8],true);\r
+       MM_SetLock (&grsegs[STARTTILE8M],true);\r
+       for (i=KEEN_LUMP_START;i<=KEEN_LUMP_END;i++)\r
+               MM_SetLock (&grsegs[i],true);\r
+\r
+       CA_LoadAllSounds ();\r
+\r
+       fontcolor = WHITE;\r
+\r
+       US_FinishTextScreen();\r
+\r
+       VW_SetScreenMode (GRMODE);\r
+       VW_ClearVideo (BLACK);\r
+}\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("\nKeen Dreams version 1.93  (Rev 1)\n");\r
+               printf("developed for use with 100%% IBM compatibles\n");\r
+               printf("that have 640K memory, DOS version 3.3 or later,\n");\r
+               printf("and an EGA or VGA display adapter.\n");\r
+               printf("Copyright 1991-1993 Softdisk Publishing.\n");\r
+               printf("Commander Keen is a trademark of Id Software.\n");\r
+               exit(0);\r
+       }\r
+\r
+       if (stricmp(_argv[1], "/?") == 0)\r
+       {\r
+               printf("\nKeen Dreams version 1.93\n");\r
+               printf("Copyright 1991-1993 Softdisk Publishing.\n\n");\r
+               printf("Commander Keen is a trademark of Id Software.\n");\r
+               printf("Type KDREAMS from the DOS prompt to run.\n\n");\r
+               printf("KDREAMS /COMP for SVGA compatibility mode\n");\r
+               printf("KDREAMS /NODR stops program hang with the drive still on\n");\r
+               printf("KDREAMS /NOAL disables AdLib and Sound Blaster detection\n");\r
+               printf("KDREAMS /NOSB disables Sound Blaster detection\n");\r
+               printf("KDREAMS /NOJOYS ignores joystick\n");\r
+               printf("KDREAMS /NOMOUSE ignores mouse\n");\r
+               printf("KDREAMS /HIDDENCARD overrides video card detection\n");\r
+               printf("KDREAMS /VER  for version and compatibility information\n");\r
+               printf("KDREAMS /? for this help information\n");\r
+               exit(0);\r
+       }\r
+\r
+       textcolor(7);\r
+       textbackground(0);\r
+\r
+       InitGame();\r
+\r
+       DemoLoop();                                     // DemoLoop calls Quit when everything is done\r
+       Quit("Demo loop exited???");\r
+}\r
+\r
diff --git a/src/lib/hb/kd_play.c b/src/lib/hb/kd_play.c
new file mode 100755 (executable)
index 0000000..02bdccd
--- /dev/null
@@ -0,0 +1,1928 @@
+/* Keen Dreams Source Code\r
+ * Copyright (C) 2014 Javier M. Chavez\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License along\r
+ * with this program; if not, write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+ */\r
+\r
+// KD_PLAY.C\r
+\r
+#include "KD_DEF.H"\r
+#pragma        hdrstop\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+#define        INACTIVATEDIST  10\r
+\r
+#define MAXMOVE        (TILEGLOBAL-17)\r
+\r
+#define NUMLUMPS       22\r
+\r
+\r
+#define CONTROLSLUMP   0\r
+#define KEENLUMP               1\r
+#define WORLDKEENLUMP  2\r
+#define BROCCOLUMP             3\r
+#define        TOMATLUMP       4\r
+#define        CARROTLUMP              5\r
+#define        ASPARLUMP               6\r
+#define        GRAPELUMP               7\r
+#define        TATERLUMP               8\r
+#define        CARTLUMP                9\r
+#define        FRENCHYLUMP             10\r
+#define        MELONLUMP               11\r
+#define        SQUASHLUMP              12\r
+#define        APELLUMP                13\r
+#define        PEALUMP                 14\r
+#define        BOOBUSLUMP              15\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                GLOBAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+exittype       playstate;\r
+gametype       gamestate;\r
+\r
+boolean                button0held,button1held;\r
+objtype                *new,*check,*player,*scoreobj;\r
+\r
+unsigned       originxtilemax,originytilemax;\r
+\r
+ControlInfo    c;\r
+\r
+objtype dummyobj;\r
+\r
+char           *levelnames[21] =\r
+{\r
+"The Land of Tuberia",\r
+"Horseradish Hill",\r
+"The Melon Mines",\r
+"Bridge Bottoms",\r
+"Rhubarb Rapids",\r
+"Parsnip Pass",\r
+"Level 6",\r
+"Spud City",\r
+"Level 8",\r
+"Apple Acres",\r
+"Grape Grove",\r
+"Level 11",\r
+"Brussels Sprout Bay",\r
+"Level 13",\r
+"Squash Swamp",\r
+"Boobus' Chamber",\r
+"Castle Tuberia",\r
+"",\r
+"Title Page"\r
+};\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+// for asm scaning of map planes\r
+unsigned       mapx,mapy,mapxcount,mapycount,maptile,mapspot;\r
+\r
+int                    plummet;\r
+\r
+int                    objectcount;\r
+\r
+objtype                objarray[MAXACTORS],*lastobj,*objfreelist;\r
+\r
+int                    oldtileleft,oldtiletop,oldtileright,oldtilebottom,oldtilemidx;\r
+int                    oldleft,oldtop,oldright,oldbottom,oldmidx;\r
+int                    leftmoved,topmoved,rightmoved,bottommoved,midxmoved;\r
+\r
+int                    topmove,bottommove,midxmove;\r
+\r
+int                    inactivateleft,inactivateright,inactivatetop,inactivatebottom;\r
+\r
+int                    fadecount;\r
+\r
+boolean                bombspresent;\r
+\r
+boolean                lumpneeded[NUMLUMPS];\r
+int                    lumpstart[NUMLUMPS] =\r
+{\r
+CONTROLS_LUMP_START,\r
+KEEN_LUMP_START,\r
+WORLDKEEN_LUMP_START,\r
+BROCCOLASH_LUMP_START,\r
+TOMATO_LUMP_START,\r
+CARROT_LUMP_START,\r
+ASPAR_LUMP_START,\r
+GRAPE_LUMP_START,\r
+TATER_LUMP_START,\r
+CANTA_LUMP_START,\r
+FRENCHY_LUMP_START,\r
+MELONLIPS_LUMP_START,\r
+SQUASHER_LUMP_START,\r
+APEL_LUMP_START,\r
+PEAS_LUMP_START,\r
+BOOBUS_LUMP_START,\r
+};\r
+\r
+int                    lumpend[NUMLUMPS] =\r
+{\r
+CONTROLS_LUMP_END,\r
+KEEN_LUMP_END,\r
+WORLDKEEN_LUMP_END,\r
+BROCCOLASH_LUMP_END,\r
+TOMATO_LUMP_END,\r
+CARROT_LUMP_END,\r
+ASPAR_LUMP_END,\r
+GRAPE_LUMP_END,\r
+TATER_LUMP_END,\r
+CANTA_LUMP_END,\r
+FRENCHY_LUMP_END,\r
+MELONLIPS_LUMP_END,\r
+SQUASHER_LUMP_END,\r
+APEL_LUMP_END,\r
+PEAS_LUMP_END,\r
+BOOBUS_LUMP_END,\r
+};\r
+\r
+\r
+void   CheckKeys (void);\r
+void   CalcInactivate (void);\r
+void   InitObjArray (void);\r
+void   GetNewObj (boolean usedummy);\r
+void   RemoveObj (objtype *gone);\r
+void   ScanInfoPlane (void);\r
+void   PatchWorldMap (void);\r
+void   MarkTileGraphics (void);\r
+void   FadeAndUnhook (void);\r
+void   SetupGameLevel (boolean loadnow);\r
+void   ScrollScreen (void);\r
+void   MoveObjVert (objtype *ob, int ymove);\r
+void   MoveObjHoriz (objtype *ob, int xmove);\r
+void   GivePoints (unsigned points);\r
+void   ClipToEnds (objtype *ob);\r
+void   ClipToEastWalls (objtype *ob);\r
+void   ClipToWestWalls (objtype *ob);\r
+void   ClipToWalls (objtype *ob);\r
+void   ClipToSpriteSide (objtype *push, objtype *solid);\r
+void   ClipToSprite (objtype *push, objtype *solid, boolean squish);\r
+int    DoActor (objtype *ob,int tics);\r
+void   StateMachine (objtype *ob);\r
+void   NewState (objtype *ob,statetype *state);\r
+void   PlayLoop (void);\r
+void   GameLoop (void);\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
+// space for status screen\r
+//\r
+       if (Keyboard[sc_Space])\r
+       {\r
+               StatusWindow ();\r
+               IN_ClearKeysDown();\r
+               RF_ForceRefresh();\r
+               lasttimecount = TimeCount;\r
+       }\r
+\r
+//\r
+// pause key wierdness can't be checked as a scan code\r
+//\r
+       if (Paused)\r
+       {\r
+               VW_FixRefreshBuffer ();\r
+               US_CenterWindow (8,3);\r
+               US_PrintCentered ("PAUSED");\r
+               VW_UpdateScreen ();\r
+               IN_Ack();\r
+               RF_ForceRefresh ();\r
+               Paused = false;\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
+               VW_FixRefreshBuffer ();\r
+               US_CenterWindow (20,8);\r
+               US_CPrint ("Loading");\r
+               VW_UpdateScreen ();\r
+               US_ControlPanel();\r
+               IN_ClearKeysDown();\r
+               if (restartgame)\r
+                       playstate = resetgame;\r
+               else if (!loadedgame)\r
+                       RF_ForceRefresh();              // don't refresh if loading a new game\r
+\r
+               lasttimecount = TimeCount;\r
+       }\r
+\r
+//\r
+// F10-? debug keys\r
+//\r
+       if (Keyboard[sc_F10] && DebugKeys() )\r
+       {\r
+               RF_ForceRefresh();\r
+               lasttimecount = TimeCount;\r
+       }\r
+\r
+}\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+=======================\r
+=\r
+= CalcInactivate\r
+=\r
+=======================\r
+*/\r
+\r
+void CalcInactivate (void)\r
+{\r
+       originxtilemax = originxtile+PORTTILESWIDE-1;\r
+       originytilemax = originytile+PORTTILESHIGH-1;\r
+\r
+       inactivateleft = originxtile-INACTIVATEDIST;\r
+       if (inactivateleft < 0)\r
+               inactivateleft = 0;\r
+       inactivateright = originxtilemax+INACTIVATEDIST;\r
+       inactivatetop = originytile-INACTIVATEDIST;\r
+       if (inactivatetop < 0)\r
+               inactivatetop = 0;\r
+       inactivatebottom = originytilemax+INACTIVATEDIST;\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+#############################################################################\r
+\r
+                                 The objarray data structure\r
+\r
+#############################################################################\r
+\r
+Objarray 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
+= InitObjArray\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 InitObjArray (void)\r
+{\r
+       int     i;\r
+\r
+       for (i=0;i<MAXACTORS;i++)\r
+       {\r
+               objarray[i].prev = &objarray[i+1];\r
+               objarray[i].next = NULL;\r
+       }\r
+\r
+       objarray[MAXACTORS-1].prev = NULL;\r
+\r
+       objfreelist = &objarray[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
+       GetNewObj (false);\r
+       scoreobj = new;\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+=========================\r
+=\r
+= GetNewObj\r
+=\r
+= Sets the global variable new to point to a free spot in objarray.\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 objarray!");\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 = yes;\r
+       new->needtoclip = true;\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
+       if (gone == player)\r
+               Quit ("RemoveObj: Tried to remove the player!");\r
+\r
+//\r
+// erase it from the refresh manager\r
+//\r
+       RF_RemoveSprite (&gone->sprite);\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
+void near HandleInfo (void)\r
+{\r
+       switch (maptile)\r
+       {\r
+       case 1:\r
+               SpawnKeen(mapx,mapy,1);\r
+               break;\r
+       case 2:\r
+               SpawnKeen(mapx,mapy,-1);\r
+               break;\r
+       case 19:\r
+               SpawnWorldKeen(mapx,mapy);\r
+               lumpneeded[WORLDKEENLUMP] = true;\r
+               break;\r
+\r
+       case 31:\r
+               bombspresent = true;\r
+       case 21:\r
+       case 22:\r
+       case 23:\r
+       case 24:\r
+       case 25:\r
+       case 26:\r
+       case 27:\r
+       case 28:\r
+       case 29:\r
+       case 30:\r
+       case 32:\r
+               SpawnBonus(mapx,mapy,maptile-21);\r
+               new->active = false;\r
+               break;\r
+       case 33:\r
+               SpawnDoor(mapx,mapy);\r
+               new->active = false;\r
+               break;\r
+       case 41:\r
+               SpawnBrocco(mapx,mapy);\r
+               new->active = false;\r
+               lumpneeded[BROCCOLUMP] = true;\r
+               break;\r
+       case 42:\r
+               SpawnTomat(mapx,mapy);\r
+               new->active = false;\r
+               lumpneeded[TOMATLUMP] = true;\r
+               break;\r
+       case 43:\r
+               SpawnCarrot(mapx,mapy);\r
+               new->active = false;\r
+               lumpneeded[CARROTLUMP] = true;\r
+               break;\r
+       case 45:\r
+               SpawnAspar(mapx,mapy);\r
+               new->active = false;\r
+               lumpneeded[ASPARLUMP] = true;\r
+               break;\r
+       case 46:\r
+               SpawnGrape(mapx,mapy);\r
+               new->active = false;\r
+               lumpneeded[GRAPELUMP] = true;\r
+               break;\r
+       case 47:\r
+               SpawnTater(mapx,mapy);\r
+               new->active = false;\r
+               lumpneeded[TATERLUMP] = true;\r
+               break;\r
+       case 48:\r
+               SpawnCart(mapx,mapy);\r
+               lumpneeded[CARTLUMP] = true;\r
+               break;\r
+       case 49:\r
+               SpawnFrenchy(mapx,mapy);\r
+               new->active = false;\r
+               lumpneeded[FRENCHYLUMP] = true;\r
+               break;\r
+       case 50:\r
+       case 51:\r
+       case 52:\r
+               SpawnMelon(mapx,mapy,maptile-50);\r
+               new->active = false;\r
+               lumpneeded[MELONLUMP] = true;\r
+               break;\r
+       case 57:\r
+               SpawnSquasher(mapx,mapy);\r
+               new->active = false;\r
+               lumpneeded[SQUASHLUMP] = true;\r
+               break;\r
+       case 58:\r
+               SpawnApel(mapx,mapy);\r
+               new->active = false;\r
+               lumpneeded[APELLUMP] = true;\r
+               break;\r
+       case 59:\r
+               SpawnPeaPod(mapx,mapy);\r
+               new->active = false;\r
+               lumpneeded[PEALUMP] = true;\r
+               break;\r
+       case 60:\r
+               SpawnPeaBrain(mapx,mapy);\r
+               new->active = false;\r
+               lumpneeded[PEALUMP] = true;\r
+               break;\r
+       case 61:\r
+               SpawnBoobus(mapx,mapy);\r
+               lumpneeded[BOOBUSLUMP] = true;\r
+               break;\r
+       }\r
+\r
+       if (new->active != allways)\r
+               new->active = false;\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
+       InitObjArray();                 // start spawning things with a clean slate\r
+\r
+       memset (lumpneeded,0,sizeof(lumpneeded));\r
+\r
+#if 0\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
+#endif\r
+\r
+//\r
+// This doesn't really need to be in asm.  I thought it was a bottleneck,\r
+// but I was wrong...\r
+//\r
+\r
+       asm     mov     es,[WORD PTR mapsegs+4]\r
+       asm     xor     si,si\r
+       asm     mov     [mapy],0\r
+       asm     mov     ax,[mapheight]\r
+       asm     mov     [mapycount],ax\r
+yloop:\r
+       asm     mov     [mapx],0\r
+       asm     mov     ax,[mapwidth]\r
+       asm     mov     [mapxcount],ax\r
+xloop:\r
+       asm     mov     ax,[es:si]\r
+       asm     or      ax,ax\r
+       asm     jz      nothing\r
+       asm     mov     [maptile],ax\r
+       HandleInfo ();                                          // si is saved\r
+       asm     mov     es,[WORD PTR mapsegs+4]\r
+nothing:\r
+       asm     inc     [mapx]\r
+       asm     add     si,2\r
+       asm     dec     [mapxcount]\r
+       asm     jnz     xloop\r
+       asm     inc     [mapy]\r
+       asm     dec     [mapycount]\r
+       asm     jnz     yloop\r
+\r
+       for (i=0;i<NUMLUMPS;i++)\r
+               if (lumpneeded[i])\r
+                       for (j=lumpstart[i];j<=lumpend[i];j++)\r
+                               CA_MarkGrChunk(j);\r
+}\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+==========================\r
+=\r
+= PatchWorldMap\r
+=\r
+= Takes out blocking squares and puts in dones\r
+=\r
+==========================\r
+*/\r
+\r
+void PatchWorldMap (void)\r
+{\r
+       unsigned        size,spot,info,foreground;\r
+\r
+       size = mapwidth*mapheight;\r
+       spot = 0;\r
+       do\r
+       {\r
+               info = *(mapsegs[2] + spot);\r
+               // finished a city here?\r
+               if (info>=3 && info<=18 && gamestate.leveldone[info-2])\r
+               {\r
+                       *(mapsegs[2] + spot) = 0;\r
+                       foreground = *(mapsegs[1] + spot);\r
+                       if (foreground == 130)\r
+                               *(mapsegs[1]+spot) = 0; // not blocking now\r
+                       else if (foreground == 90)\r
+                       {\r
+                       // plant done flag\r
+                               *(mapsegs[1]+spot) = 133;\r
+                               *(mapsegs[1]+(spot-mapwidth-1)) = 131;\r
+                               *(mapsegs[1]+(spot-mapwidth)) = 132;\r
+                       }\r
+               }\r
+               spot++;\r
+       } while (spot<size);\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+==========================\r
+=\r
+= FadeAndUnhook\r
+=\r
+= Latch this onto the refresh so the screen only gets faded in after two\r
+= refreshes.  This lets all actors draw themselves to both pages before\r
+= fading the screen in.\r
+=\r
+==========================\r
+*/\r
+\r
+void FadeAndUnhook (void)\r
+{\r
+       if (++fadecount==2)\r
+       {\r
+               RF_ForceRefresh();\r
+               VW_FadeIn ();\r
+               RF_SetRefreshHook (NULL);\r
+               lasttimecount = TimeCount;      // don't adaptively time the fade\r
+       }\r
+}\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+==========================\r
+=\r
+= SetupGameLevel\r
+=\r
+= Load in map mapon and cache everything needed for it\r
+=\r
+==========================\r
+*/\r
+\r
+void   SetupGameLevel (boolean loadnow)\r
+{\r
+       long    orgx,orgy;\r
+\r
+       bombspresent = false;\r
+//\r
+// load the level header and three map planes\r
+//\r
+       CA_CacheMap (gamestate.mapon);\r
+\r
+//\r
+// let the refresh manager set up some variables\r
+//\r
+       RF_NewMap ();\r
+\r
+//\r
+// decide which graphics are needed and spawn actors\r
+//\r
+       CA_ClearMarks ();\r
+\r
+       if (!mapon)\r
+               PatchWorldMap ();\r
+\r
+       if (mapon!=20)                  // map 20 is the title screen\r
+               ScanInfoPlane ();\r
+       RF_MarkTileGraphics ();\r
+\r
+//\r
+// have the caching manager load and purge stuff to make sure all marks\r
+// are in memory\r
+//\r
+       if (loadnow)\r
+       {\r
+               if (bombspresent)\r
+               {\r
+                       VW_FixRefreshBuffer ();\r
+                       US_DrawWindow (10,1,20,2);\r
+                       US_PrintCentered ("Boobus Bombs Near!");\r
+                       VW_UpdateScreen ();\r
+               }\r
+               CA_CacheMarks (levelnames[mapon], 0);\r
+       }\r
+\r
+#if 0\r
+       VW_FixRefreshBuffer ();\r
+       US_CenterWindow (20,8);\r
+       US_Print ("\n\n\nObject count:");\r
+       itoa (objectcount,str,10);\r
+       US_Print (str);\r
+       VW_UpdateScreen ();\r
+       IN_Ack ();\r
+#endif\r
+\r
+       if (mapon!=20 && loadnow)                       // map 20 is the title screen\r
+       {\r
+               VW_FadeOut ();\r
+               fadecount = 0;\r
+               RF_SetRefreshHook (&FadeAndUnhook);\r
+               SpawnScore ();\r
+\r
+//\r
+// start the initial view position to center the player\r
+//\r
+               orgx = (long)player->x - (150<<G_P_SHIFT);\r
+               orgy = (long)player->y-(84<<G_P_SHIFT);\r
+               if (orgx<0)\r
+                       orgx=0;\r
+               if (orgy<0)\r
+                       orgy=0;\r
+\r
+               RF_NewPosition (orgx,orgy);\r
+               CalcInactivate ();\r
+       }\r
+\r
+\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= ScrollScreen\r
+=\r
+= Scroll if Keen is nearing an edge\r
+= Set playstate to levelcomplete\r
+=\r
+===============\r
+*/\r
+\r
+void ScrollScreen (void)\r
+{\r
+       int     xscroll,yscroll;\r
+\r
+//\r
+// walked off edge of map?\r
+//\r
+       if (player->left < originxmin\r
+       || player->right > originxmax+20*TILEGLOBAL)\r
+       {\r
+               playstate = levelcomplete;\r
+               return;\r
+       }\r
+\r
+//\r
+// fallen off bottom of world?\r
+//\r
+       if (!plummet && player->bottom > originymax+13*TILEGLOBAL)\r
+       {\r
+               godmode = 0;\r
+               plummet = 1;\r
+               KillKeen ();\r
+               return;\r
+       }\r
+\r
+       if (player->x < originxglobal+SCROLLWEST)\r
+               xscroll = player->x - (originxglobal+SCROLLWEST);\r
+       else if (player->x > originxglobal+SCROLLEAST)\r
+               xscroll = player->x - (originxglobal+SCROLLEAST);\r
+       else\r
+               xscroll = 0;\r
+\r
+       if (player->y < originyglobal+SCROLLNORTH)\r
+               yscroll = player->y - (originyglobal+SCROLLNORTH);\r
+       else if (player->y > originyglobal+SCROLLSOUTH)\r
+               yscroll = player->y - (originyglobal+SCROLLSOUTH);\r
+       else yscroll = 0;\r
+\r
+       if (xscroll || yscroll)\r
+       {\r
+               RF_Scroll (xscroll,yscroll);\r
+               CalcInactivate ();\r
+               scoreobj->needtoreact = true;\r
+       }\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+====================\r
+=\r
+= GivePoints\r
+=\r
+= Grants extra men at 20k,40k,80k,160k,320k\r
+=\r
+====================\r
+*/\r
+\r
+void GivePoints (unsigned points)\r
+{\r
+       gamestate.score += points;\r
+       if (gamestate.score >= gamestate.nextextra)\r
+       {\r
+               SD_PlaySound (EXTRAKEENSND);\r
+               gamestate.lives++;\r
+               gamestate.nextextra*=2;\r
+       }\r
+}\r
+\r
+\r
+//==========================================================================\r
+\r
+/*\r
+====================\r
+=\r
+= MoveObjVert\r
+=\r
+====================\r
+*/\r
+\r
+void MoveObjVert (objtype *ob, int ymove)\r
+{\r
+       ob->y += ymove;\r
+       ob->top += ymove;\r
+       ob->bottom += ymove;\r
+       ob->tiletop = ob->top >> G_T_SHIFT;\r
+       ob->tilebottom = ob->bottom >> G_T_SHIFT;\r
+}\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= MoveObjHoriz\r
+=\r
+====================\r
+*/\r
+\r
+void MoveObjHoriz (objtype *ob, int xmove)\r
+{\r
+       ob->x += xmove;\r
+       ob->left += xmove;\r
+       ob->right += xmove;\r
+       ob->tileleft = ob->left >> G_T_SHIFT;\r
+       ob->tileright = ob->right >> G_T_SHIFT;\r
+}\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                       Actor to tile clipping rouitnes\r
+\r
+=============================================================================\r
+*/\r
+\r
+// walltype / x coordinate (0-15)\r
+\r
+int    wallclip[8][16] = {                     // the height of a given point in a tile\r
+{ 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256},\r
+{   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0},\r
+{   0,0x08,0x10,0x18,0x20,0x28,0x30,0x38,0x40,0x48,0x50,0x58,0x60,0x68,0x70,0x78},\r
+{0x80,0x88,0x90,0x98,0xa0,0xa8,0xb0,0xb8,0xc0,0xc8,0xd0,0xd8,0xe0,0xe8,0xf0,0xf8},\r
+{   0,0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80,0x90,0xa0,0xb0,0xc0,0xd0,0xe0,0xf0},\r
+{0x78,0x70,0x68,0x60,0x58,0x50,0x48,0x40,0x38,0x30,0x28,0x20,0x18,0x10,0x08,   0},\r
+{0xf8,0xf0,0xe8,0xe0,0xd8,0xd0,0xc8,0xc0,0xb8,0xb0,0xa8,0xa0,0x98,0x90,0x88,0x80},\r
+{0xf0,0xe0,0xd0,0xc0,0xb0,0xa0,0x90,0x80,0x70,0x60,0x50,0x40,0x30,0x20,0x10,   0}\r
+};\r
+\r
+// assignment within ifs are used heavily here, so turn off the warning\r
+#pragma warn -pia\r
+\r
+/*\r
+===========================\r
+=\r
+= ClipToEnds\r
+=\r
+===========================\r
+*/\r
+\r
+void ClipToEnds (objtype *ob)\r
+{\r
+       unsigned        far *map,tile,facetile,info,wall;\r
+       int     leftpix,rightpix,midtiles,toppix,bottompix;\r
+       int     x,y,clip,move,totalmove,maxmove,midxpix;\r
+\r
+       midxpix = (ob->midx&0xf0) >> 4;\r
+\r
+       maxmove = -abs(midxmoved) - bottommoved - 16;\r
+       map = (unsigned far *)mapsegs[1] +\r
+               mapbwidthtable[oldtilebottom-1]/2 + ob->tilemidx;\r
+       for (y=oldtilebottom-1 ; y<=ob->tilebottom ; y++,map+=mapwidth)\r
+       {\r
+               if (wall = tinf[NORTHWALL+*map])\r
+               {\r
+                       clip = wallclip[wall&7][midxpix];\r
+                       move = ( (y<<G_T_SHIFT)+clip - 1) - ob->bottom;\r
+                       if (move<0 && move>=maxmove)\r
+                       {\r
+                               ob->hitnorth = wall;\r
+                               MoveObjVert (ob,move);\r
+                               return;\r
+                       }\r
+               }\r
+       }\r
+\r
+       maxmove = abs(midxmoved) - topmoved + 16;\r
+       map = (unsigned far *)mapsegs[1] +\r
+               mapbwidthtable[oldtiletop+1]/2 + ob->tilemidx;\r
+       for (y=oldtiletop+1 ; y>=ob->tiletop ; y--,map-=mapwidth)\r
+       {\r
+               if (wall = tinf[SOUTHWALL+*map])\r
+               {\r
+                       clip = wallclip[wall&7][midxpix];\r
+                       move = ( ((y+1)<<G_T_SHIFT)-clip ) - ob->top;\r
+                       if (move > 0 && move<=maxmove)\r
+                       {\r
+                               totalmove = ob->ymove + move;\r
+                               if (totalmove < TILEGLOBAL && totalmove > -TILEGLOBAL)\r
+                               {\r
+                                       ob->hitsouth = wall;\r
+                                       MoveObjVert (ob,move);\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+}\r
+\r
+\r
+/*\r
+===========================\r
+=\r
+= ClipToEastWalls / ClipToWestWalls\r
+=\r
+===========================\r
+*/\r
+\r
+void ClipToEastWalls (objtype *ob)\r
+{\r
+       int                     y,move,top,bottom;\r
+       unsigned        far *map,tile,info,wall;\r
+\r
+       // clip to east walls if moving west\r
+\r
+       top = ob->tiletop;\r
+       if (ob->hitsouth>1)\r
+               top++;                  // on a slope inside a tile\r
+       bottom = ob->tilebottom;\r
+       if (ob->hitnorth>1)\r
+               bottom--;                       // on a slope inside a tile\r
+\r
+       for (y=top;y<=bottom;y++)\r
+       {\r
+               map = (unsigned far *)mapsegs[1] +\r
+                       mapbwidthtable[y]/2 + ob->tileleft;\r
+\r
+               if (ob->hiteast = tinf[EASTWALL+*map])\r
+               {\r
+                       move = ( (ob->tileleft+1)<<G_T_SHIFT ) - ob->left;\r
+                       MoveObjHoriz (ob,move);\r
+                       return;\r
+               }\r
+       }\r
+}\r
+\r
+\r
+void ClipToWestWalls (objtype *ob)\r
+{\r
+       int                     y,move,top,bottom;\r
+       unsigned        far *map,tile,info,wall;\r
+\r
+       // check west walls if moving east\r
+\r
+       top = ob->tiletop;\r
+       if (ob->hitsouth>1)\r
+               top++;                  // on a slope inside a tile\r
+       bottom = ob->tilebottom;\r
+       if (ob->hitnorth>1)\r
+               bottom--;                       // on a slope inside a tile\r
+\r
+       for (y=top;y<=bottom;y++)\r
+       {\r
+               map = (unsigned far *)mapsegs[1] +\r
+                       mapbwidthtable[y]/2 + ob->tileright;\r
+\r
+               if (ob->hitwest = tinf[WESTWALL+*map])\r
+               {\r
+                       move = ( (ob->tileright<<G_T_SHIFT ) -1) - ob->right;\r
+                       MoveObjHoriz (ob,move);\r
+                       return;\r
+               }\r
+       }\r
+}\r
+\r
+// turn 'possibly incorrect assignment' warnings back on\r
+#pragma warn +pia\r
+\r
+\r
+//==========================================================================\r
+\r
+/*\r
+================\r
+=\r
+= ClipToWalls\r
+=\r
+= Moves the current object xmove/ymove units, clipping to walls\r
+=\r
+================\r
+*/\r
+\r
+void ClipToWalls (objtype *ob)\r
+{\r
+       unsigned        x,y,tile;\r
+       spritetabletype far *shape;\r
+       boolean endfirst;\r
+\r
+//\r
+// make sure it stays in contact with a 45 degree slope\r
+//\r
+       if (ob->state->pushtofloor)\r
+       {\r
+               if (ob->xmove > 0)\r
+                       ob->ymove = ob->xmove + 16;\r
+               else\r
+                       ob->ymove = -ob->xmove + 16;\r
+       }\r
+\r
+//\r
+// move the shape\r
+//\r
+       if (ob->xmove > MAXMOVE)\r
+               ob->xmove = MAXMOVE;\r
+       else if (ob->xmove < -MAXMOVE)\r
+               ob->xmove = -MAXMOVE;\r
+\r
+       if (ob->ymove > MAXMOVE+16)                     // +16 for push to floor\r
+               ob->ymove = MAXMOVE+16;\r
+       else if (ob->ymove < -MAXMOVE)\r
+               ob->ymove = -MAXMOVE;\r
+\r
+       ob->x += ob->xmove;\r
+       ob->y += ob->ymove;\r
+\r
+       ob->needtoreact = true;\r
+\r
+       if (!ob->shapenum)                              // can't get a hit rect with no shape!\r
+               return;\r
+\r
+       shape = &spritetable[ob->shapenum-STARTSPRITES];\r
+\r
+       oldtileright = ob->tileright;\r
+       oldtiletop = ob->tiletop;\r
+       oldtileleft = ob->tileleft;\r
+       oldtilebottom = ob->tilebottom;\r
+       oldtilemidx = ob->tilemidx;\r
+\r
+       oldright = ob->right;\r
+       oldtop = ob->top;\r
+       oldleft = ob->left;\r
+       oldbottom = ob->bottom;\r
+       oldmidx = ob->midx;\r
+\r
+       ob->left = ob->x + shape->xl;\r
+       ob->right = ob->x + shape->xh;\r
+       ob->top = ob->y + shape->yl;\r
+       ob->bottom = ob->y + shape->yh;\r
+       ob->midx = ob->left + (ob->right - ob->left)/2;\r
+\r
+       ob->tileleft = ob->left >> G_T_SHIFT;\r
+       ob->tileright = ob->right >> G_T_SHIFT;\r
+       ob->tiletop = ob->top >> G_T_SHIFT;\r
+       ob->tilebottom = ob->bottom >> G_T_SHIFT;\r
+       ob->tilemidx = ob->midx >> G_T_SHIFT;\r
+\r
+       ob->hitnorth = ob->hiteast = ob->hitsouth = ob->hitwest = 0;\r
+\r
+       if (!ob->needtoclip)\r
+               return;\r
+\r
+       leftmoved = ob->left - oldleft;\r
+       rightmoved = ob->right - oldright;\r
+       topmoved = ob->top - oldtop;\r
+       bottommoved = ob->bottom - oldbottom;\r
+       midxmoved = ob->midx - oldmidx;\r
+\r
+//\r
+// clip it\r
+//\r
+\r
+       ClipToEnds(ob);\r
+\r
+       if (leftmoved < 0 || ob == player)      // make sure player gets cliped\r
+               ClipToEastWalls (ob);\r
+       if (rightmoved > 0 || ob == player)\r
+               ClipToWestWalls (ob);\r
+}\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+==================\r
+=\r
+= ClipToSpriteSide\r
+=\r
+= Clips push to solid\r
+=\r
+==================\r
+*/\r
+\r
+void ClipToSpriteSide (objtype *push, objtype *solid)\r
+{\r
+       int xmove,leftinto,rightinto;\r
+\r
+       //\r
+       // amount the push shape can be pushed\r
+       //\r
+       xmove = solid->xmove - push->xmove;\r
+\r
+       //\r
+       // amount it is inside\r
+       //\r
+       leftinto = solid->right - push->left;\r
+       rightinto = push->right - solid->left;\r
+\r
+       if (leftinto>0 && leftinto<= xmove)\r
+       {\r
+               push->xmove = leftinto;\r
+               if (push->state->pushtofloor)\r
+                       push->ymove = leftinto+16;\r
+               ClipToWalls (push);\r
+               push->hiteast = 1;\r
+               return;\r
+       }\r
+\r
+       if (rightinto>0 && rightinto<= -xmove)\r
+       {\r
+               push->xmove = -rightinto;\r
+               if (push->state->pushtofloor)\r
+                       push->ymove = rightinto+16;\r
+               ClipToWalls (push);\r
+               push->hitwest = 1;\r
+               return;\r
+       }\r
+\r
+}\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+==================\r
+=\r
+= ClipToSprite\r
+=\r
+= Clips push to solid\r
+=\r
+==================\r
+*/\r
+\r
+void ClipToSprite (objtype *push, objtype *solid, boolean squish)\r
+{\r
+       boolean temp;\r
+       int walltemp,xmove,leftinto,rightinto,topinto,bottominto;\r
+\r
+       xmove = solid->xmove - push->xmove;\r
+\r
+       push->xmove = push->ymove = 0;\r
+\r
+       //\r
+       // left / right\r
+       //\r
+       leftinto = solid->right - push->left;\r
+       rightinto = push->right - solid->left;\r
+\r
+       if (leftinto>0 && leftinto<=xmove)\r
+       {\r
+               push->xmove = leftinto;\r
+               walltemp = push->hitnorth;\r
+               ClipToWalls (push);\r
+               if (!push->hitnorth)\r
+                       push->hitnorth = walltemp;\r
+               if (squish && push->hitwest)\r
+                       KillKeen ();\r
+               push->hiteast = 1;\r
+               return;\r
+       }\r
+       else if (rightinto>0 && rightinto<=-xmove)\r
+       {\r
+               push->xmove = -rightinto;\r
+               walltemp = push->hitnorth;\r
+               ClipToWalls (push);\r
+               if (!push->hitnorth)\r
+                       push->hitnorth = walltemp;\r
+               if (squish && push->hiteast)\r
+                       KillKeen ();\r
+               push->hitwest = 1;\r
+               return;\r
+       }\r
+\r
+       //\r
+       // top / bottom\r
+       //\r
+       topinto = solid->bottom - push->top;\r
+       bottominto = push->bottom - solid->top;\r
+\r
+       if (bottominto>0)\r
+       {\r
+               push->ymove = -bottominto+16;\r
+               push->xmove = solid->xmove;\r
+               temp = push->state->pushtofloor;\r
+               push->state->pushtofloor = false;\r
+               walltemp = push->hitnorth;\r
+               ClipToWalls (push);\r
+               if (!push->hitnorth)\r
+                       push->hitnorth = walltemp;\r
+               push->state->pushtofloor = temp;\r
+               push->hitnorth = 25;\r
+       }\r
+       else if (topinto>0)\r
+       {\r
+               push->ymove = topinto;\r
+               ClipToWalls (push);\r
+               push->hitsouth = 25;\r
+       }\r
+}\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+==================\r
+=\r
+= DoActor\r
+=\r
+= Moves an actor in its current state by a given number of tics.\r
+= If that time takes it into the next state, it changes the state\r
+= and returns the number of excess tics after the state change\r
+=\r
+==================\r
+*/\r
+\r
+int DoActor (objtype *ob,int tics)\r
+{\r
+       int     newtics,movetics,excesstics;\r
+       statetype *state;\r
+\r
+       state = ob->state;\r
+\r
+       if (state->progress == think)\r
+       {\r
+               if (state->think)\r
+               {\r
+                       if (ob->nothink)\r
+                               ob->nothink--;\r
+                       else\r
+#pragma warn -pro\r
+                               state->think(ob);\r
+#pragma warn +pro\r
+               }\r
+               return 0;\r
+       }\r
+\r
+       newtics = ob->ticcount+tics;\r
+\r
+       if (newtics < state->tictime || state->tictime == 0)\r
+       {\r
+               ob->ticcount = newtics;\r
+               if (state->progress == slide || state->progress == slidethink)\r
+               {\r
+                       if (ob->xdir)\r
+                               ob->xmove += ob->xdir == 1 ? tics*state->xmove\r
+                               : -tics*state->xmove;\r
+                       if (ob->ydir)\r
+                               ob->ymove += ob->ydir == 1 ? tics*state->ymove\r
+                               : -tics*state->ymove;\r
+               }\r
+               if (state->progress == slidethink || state->progress == stepthink)\r
+               {\r
+                       if (state->think)\r
+                       {\r
+                               if (ob->nothink)\r
+                                       ob->nothink--;\r
+                               else\r
+#pragma warn -pro\r
+                                       state->think(ob);\r
+#pragma warn +pro\r
+                       }\r
+               }\r
+               return 0;\r
+       }\r
+       else\r
+       {\r
+               movetics = state->tictime - ob->ticcount;\r
+               excesstics = newtics - state->tictime;\r
+               ob->ticcount = 0;\r
+               if (state->progress == slide || state->progress == slidethink)\r
+               {\r
+                       if (ob->xdir)\r
+                               ob->xmove += ob->xdir == 1 ? movetics*state->xmove\r
+                               : -movetics*state->xmove;\r
+                       if (ob->ydir)\r
+                               ob->ymove += ob->ydir == 1 ? movetics*state->ymove\r
+                               : -movetics*state->ymove;\r
+               }\r
+               else\r
+               {\r
+                       if (ob->xdir)\r
+                               ob->xmove += ob->xdir == 1 ? state->xmove : -state->xmove;\r
+                       if (ob->ydir)\r
+                               ob->ymove += ob->ydir == 1 ? state->ymove : -state->ymove;\r
+               }\r
+\r
+               if (state->think)\r
+               {\r
+                       if (ob->nothink)\r
+                               ob->nothink--;\r
+                       else\r
+#pragma warn -pro\r
+                               state->think(ob);\r
+#pragma warn +pro\r
+               }\r
+\r
+               if (ob->state == state)\r
+                       ob->state = state->nextstate;   // go to next state\r
+               else if (!ob->state)\r
+                       return 0;                       // object removed itself\r
+               return excesstics;\r
+       }\r
+}\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= StateMachine\r
+=\r
+= Change state and give directions\r
+=\r
+====================\r
+*/\r
+\r
+void StateMachine (objtype *ob)\r
+{\r
+       int excesstics,oldshapenum;\r
+       statetype *state;\r
+\r
+       ob->xmove = ob->ymove = 0;\r
+       oldshapenum = ob->shapenum;\r
+\r
+       state = ob->state;\r
+\r
+       excesstics = DoActor(ob,tics);\r
+       if (ob->state != state)\r
+       {\r
+               ob->ticcount = 0;               // start the new state at 0, then use excess\r
+               state = ob->state;\r
+       }\r
+\r
+       while (excesstics)\r
+       {\r
+       //\r
+       // passed through to next state\r
+       //\r
+               if (!state->skippable && excesstics >= state->tictime)\r
+                       excesstics = DoActor(ob,state->tictime-1);\r
+               else\r
+                       excesstics = DoActor(ob,excesstics);\r
+               if (ob->state != state)\r
+               {\r
+                       ob->ticcount = 0;               // start the new state at 0, then use excess\r
+                       state = ob->state;\r
+               }\r
+       }\r
+\r
+       if (!state)                     // object removed itself\r
+       {\r
+               RemoveObj (ob);\r
+               return;\r
+       }\r
+\r
+\r
+       //\r
+       // if state->rightshapenum == NULL, the state does not have a standard\r
+       // shape (the think routine should have set it)\r
+       //\r
+       if (state->rightshapenum)\r
+       {\r
+               if (ob->xdir>0)\r
+                       ob->shapenum = state->rightshapenum;\r
+               else\r
+                       ob->shapenum = state->leftshapenum;\r
+       }\r
+       if (ob->shapenum == (unsigned)-1)\r
+               ob->shapenum = 0;               // make it invisable this time\r
+\r
+       if (ob->xmove || ob->ymove || ob->shapenum != oldshapenum)\r
+       {\r
+       //\r
+       // actor moved or changed shape\r
+       // make sure the movement is within limits (one tile)\r
+       //\r
+               ClipToWalls (ob);\r
+       }\r
+}\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= NewState\r
+=\r
+====================\r
+*/\r
+\r
+void NewState (objtype *ob,statetype *state)\r
+{\r
+       boolean temp;\r
+\r
+       ob->state = state;\r
+\r
+       if (state->rightshapenum)\r
+       {\r
+               if (ob->xdir>0)\r
+                       ob->shapenum = state->rightshapenum;\r
+               else\r
+                       ob->shapenum = state->leftshapenum;\r
+       }\r
+\r
+       temp = ob->needtoclip;\r
+\r
+       ob->needtoclip = false;\r
+\r
+       ClipToWalls (ob);                                       // just calculate values\r
+\r
+       ob->needtoclip = temp;\r
+\r
+       if (ob->needtoclip)\r
+               ClipToWalls (ob);\r
+\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+============================\r
+=\r
+= PlayLoop\r
+=\r
+============================\r
+*/\r
+\r
+void PlayLoop (void)\r
+{\r
+       objtype *obj, *check;\r
+       long    newtime;\r
+\r
+       button0held = button1held = false;\r
+\r
+       ingame = true;\r
+       playstate = 0;\r
+       plummet = 0;\r
+\r
+       FixScoreBox ();                                 // draw bomb/flower\r
+\r
+       do\r
+       {\r
+               CalcSingleGravity ();\r
+               IN_ReadControl(0,&c);           // get player input\r
+               if (!c.button0)\r
+                       button0held = 0;\r
+               if (!c.button1)\r
+                       button1held = 0;\r
+\r
+//\r
+// go through state changes and propose movements\r
+//\r
+               obj = player;\r
+               do\r
+               {\r
+                       if (!obj->active\r
+                       && obj->tileright >= originxtile\r
+                       && obj->tileleft <= originxtilemax\r
+                       && obj->tiletop <= originytilemax\r
+                       && obj->tilebottom >= originytile)\r
+                       {\r
+                               obj->needtoreact = true;\r
+                               obj->active = yes;\r
+                       }\r
+\r
+                       if (obj->active)\r
+                               StateMachine(obj);\r
+\r
+                       if ( (obj->active == true || obj->active == removable) &&\r
+                       (  obj->tileright < inactivateleft\r
+                       || obj->tileleft > inactivateright\r
+                       || obj->tiletop > inactivatebottom\r
+                       || obj->tilebottom < inactivatetop) )\r
+                       {\r
+                               if (obj->active == removable)\r
+                                       RemoveObj (obj);                                // temp thing (shots, etc)\r
+                               else\r
+                               {\r
+                                       if (US_RndT()<tics)                             // let them get a random dist\r
+                                       {\r
+                                               RF_RemoveSprite (&obj->sprite);\r
+                                               obj->active = no;\r
+                                       }\r
+                               }\r
+                       }\r
+\r
+                       obj = (objtype *)obj->next;\r
+               } while (obj);\r
+\r
+//\r
+// check for and handle collisions between objects\r
+//\r
+               obj = player;\r
+               do\r
+               {\r
+                       if (obj->active)\r
+                       {\r
+                               check = (objtype *)obj->next;\r
+                               while (check)\r
+                               {\r
+                                       if ( check->active\r
+                                       && obj->right > check->left\r
+                                       && obj->left < check->right\r
+                                       && obj->top < check->bottom\r
+                                       && obj->bottom > check->top)\r
+                                       {\r
+#pragma warn -pro\r
+                                               if (obj->state->contact)\r
+                                                       obj->state->contact(obj,check);\r
+                                               if (check->state->contact)\r
+                                                       check->state->contact(check,obj);\r
+#pragma warn +pro\r
+                                               if (!obj->obclass)\r
+                                                       break;                          // contact removed object\r
+                                       }\r
+                                       check = (objtype *)check->next;\r
+                               }\r
+                       }\r
+                       obj = (objtype *)obj->next;\r
+               } while (obj);\r
+\r
+\r
+               ScrollScreen();\r
+\r
+//\r
+// react to whatever happened, and post sprites to the refresh manager\r
+//\r
+               obj = player;\r
+               do\r
+               {\r
+                       if (obj->needtoreact && obj->state->react)\r
+                       {\r
+                               obj->needtoreact = false;\r
+#pragma warn -pro\r
+                               obj->state->react(obj);\r
+#pragma warn +pro\r
+                       }\r
+                       obj = (objtype *)obj->next;\r
+               } while (obj);\r
+\r
+\r
+//\r
+// update the screen and calculate the number of tics it took to execute\r
+// this cycle of events (for adaptive timing of next cycle)\r
+//\r
+               RF_Refresh();\r
+\r
+//\r
+// single step debug mode\r
+//\r
+               if (singlestep)\r
+               {\r
+                       VW_WaitVBL(14);\r
+                       lasttimecount = TimeCount;\r
+               }\r
+\r
+               CheckKeys();\r
+       } while (!loadedgame && !playstate);\r
+\r
+       ingame = false;\r
+}\r
+\r
+\r
+//==========================================================================\r
+\r
+/*\r
+==========================\r
+=\r
+= GameFinale\r
+=\r
+==========================\r
+*/\r
+\r
+void GameFinale (void)\r
+{\r
+struct date d;\r
+\r
+       VW_FixRefreshBuffer ();\r
+\r
+/* screen 1 of finale text (16 lines) */\r
+       US_CenterWindow (30,21);\r
+       PrintY += 4;\r
+       US_CPrint (\r
+"Yes!  Boobus Tuber's hash-brown-\n"\r
+"like remains rained down from\n"\r
+"the skies as Commander Keen\n"\r
+"walked up to the Dream Machine.\n"\r
+"He analyzed all the complex\n"\r
+"controls and readouts on it, then\n"\r
+"pulled down a huge red lever\n"\r
+"marked \"On/Off Switch.\"  The\n"\r
+"machine clanked and rattled,\n"\r
+"then went silent. He had freed\n"\r
+"all the children from their\n"\r
+"vegetable-enforced slavery!\n"\r
+"Everything around Keen wobbled\n"\r
+"in a disconcerting manner, his\n"\r
+"eyelids grew heavy, and he\n"\r
+"fell asleep....\n"\r
+       );\r
+       VW_UpdateScreen();\r
+       VW_WaitVBL(60);\r
+       SD_WaitSoundDone ();\r
+       IN_ClearKeysDown ();\r
+       IN_Ack();\r
+\r
+/* screen 2 of finale (15 lines) */\r
+       US_CenterWindow (30,21);\r
+       PrintY += 9;\r
+       US_CPrint (\r
+"Billy woke up, looking around the\n"\r
+"room, the early morning sun\n"\r
+"shining in his face.  Nothing.\n"\r
+"No vegetables to be seen.  Was it\n"\r
+"all just a dream?\n\n"\r
+"Billy's mom entered the room.\n\n"\r
+"\"Good morning, dear. I heard some\n"\r
+"news on TV that you'd be\n"\r
+"interested in,\" she said, sitting\n"\r
+"by him on the bed.\n\n"\r
+"\"What news?\" Billy asked,\n"\r
+"still groggy.\n\n"\r
+       );\r
+       VW_UpdateScreen();\r
+       VW_WaitVBL(60);\r
+       IN_ClearKeysDown ();\r
+       IN_Ack();\r
+\r
+/* screen 3 of finale (12 lines)*/\r
+       US_CenterWindow (30,21);\r
+       PrintY += 23;\r
+       US_CPrint (\r
+"\"The President declared today\n"\r
+"National 'I Hate Broccoli' Day.\n"\r
+"He said kids are allowed to pick\n"\r
+"one vegetable today, and they\n"\r
+"don't have to eat it.\"\n\n"\r
+"\"Aw, mom, I'm not afraid of any\n"\r
+"stupid vegetables,\" Billy said.\n"\r
+"\"But if it's okay with you, I'd\n"\r
+"rather not have any french fries\n"\r
+"for awhile.\"\n\n"\r
+"THE END"\r
+       );\r
+       VW_UpdateScreen();\r
+       VW_WaitVBL(60);\r
+       IN_ClearKeysDown ();\r
+       IN_Ack();\r
+\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+==========================\r
+=\r
+= HandleDeath\r
+=\r
+==========================\r
+*/\r
+\r
+void HandleDeath (void)\r
+{\r
+       unsigned        top,bottom,selection,y,color;\r
+\r
+       gamestate.keys = 0;\r
+       gamestate.boobusbombs -= gamestate.bombsthislevel;\r
+       gamestate.lives--;\r
+       if (gamestate.lives < 0)\r
+               return;\r
+\r
+       VW_FixRefreshBuffer ();\r
+       US_CenterWindow (20,8);\r
+       PrintY += 4;\r
+       US_CPrint ("You didn't make it past");\r
+       US_CPrint (levelnames[mapon]);\r
+       PrintY += 8;\r
+       top = PrintY-2;\r
+       US_CPrint ("Try Again");\r
+       PrintY += 4;\r
+       bottom = PrintY-2;\r
+       US_CPrint ("Exit to Tuberia");\r
+\r
+       selection = 0;\r
+       do\r
+       {\r
+               if (selection)\r
+                       y = bottom;\r
+               else\r
+                       y = top;\r
+\r
+// draw select bar\r
+               if ( (TimeCount / 16)&1 )\r
+                       color = SECONDCOLOR;\r
+               else\r
+                       color = FIRSTCOLOR;\r
+\r
+               VWB_Hlin (WindowX+4,WindowX+WindowW-4,y,color);\r
+               VWB_Hlin (WindowX+4,WindowX+WindowW-4,y+1,color);\r
+               VWB_Hlin (WindowX+4,WindowX+WindowW-4,y+12,color);\r
+               VWB_Hlin (WindowX+4,WindowX+WindowW-4,y+13,color);\r
+               VWB_Vlin (y+1,y+11, WindowX+4,color);\r
+               VWB_Vlin (y+1,y+11, WindowX+5,color);\r
+               VWB_Vlin (y+1,y+11, WindowX+WindowW-4,color);\r
+               VWB_Vlin (y+1,y+11, WindowX+WindowW-5,color);\r
+\r
+               VW_UpdateScreen ();\r
+\r
+// erase select bar\r
+               VWB_Hlin (WindowX+4,WindowX+WindowW-4,y,WHITE);\r
+               VWB_Hlin (WindowX+4,WindowX+WindowW-4,y+1,WHITE);\r
+               VWB_Hlin (WindowX+4,WindowX+WindowW-4,y+12,WHITE);\r
+               VWB_Hlin (WindowX+4,WindowX+WindowW-4,y+13,WHITE);\r
+               VWB_Vlin (y+1,y+11, WindowX+4,WHITE);\r
+               VWB_Vlin (y+1,y+11, WindowX+5,WHITE);\r
+               VWB_Vlin (y+1,y+11, WindowX+WindowW-4,WHITE);\r
+               VWB_Vlin (y+1,y+11, WindowX+WindowW-5,WHITE);\r
+\r
+               if (LastScan == sc_Escape)\r
+               {\r
+                       gamestate.mapon = 0;            // exit to tuberia\r
+                       IN_ClearKeysDown ();\r
+                       return;\r
+               }\r
+\r
+               IN_ReadControl(0,&c);           // get player input\r
+               if (c.button0 || c.button1 || LastScan == sc_Return\r
+               || LastScan == sc_Space)\r
+               {\r
+                       if (selection)\r
+                               gamestate.mapon = 0;            // exit to tuberia\r
+                       return;\r
+               }\r
+               if (c.yaxis == -1 || LastScan == sc_UpArrow)\r
+                       selection = 0;\r
+               else if (c.yaxis == 1 || LastScan == sc_DownArrow)\r
+                       selection = 1;\r
+       } while (1);\r
+\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+============================\r
+=\r
+= GameLoop\r
+=\r
+= A game has just started (after the cinematic or load game)\r
+=\r
+============================\r
+*/\r
+\r
+void GameLoop (void)\r
+{\r
+       unsigned        cities,i;\r
+       long    orgx,orgy;\r
+\r
+       gamestate.difficulty = restartgame;\r
+       restartgame = gd_Continue;\r
+\r
+       do\r
+       {\r
+startlevel:\r
+               if (loadedgame)\r
+               {\r
+                       loadedgame = false;\r
+                       //\r
+                       // start the initial view position to center the player\r
+                       //\r
+                       orgx = (long)player->x - (150<<G_P_SHIFT);\r
+                       orgy = (long)player->y-(84<<G_P_SHIFT);\r
+                       if (orgx<0)\r
+                               orgx=0;\r
+                       if (orgy<0)\r
+                               orgy=0;\r
+\r
+                       VW_FadeOut ();\r
+                       fadecount = 0;\r
+                       RF_SetRefreshHook (&FadeAndUnhook);\r
+                       RF_NewPosition (orgx,orgy);\r
+                       CalcInactivate ();\r
+               }\r
+               else\r
+               {\r
+                       VW_FixRefreshBuffer ();\r
+                       US_CenterWindow (20,8);\r
+                       US_CPrint ("Loading");\r
+                       VW_UpdateScreen ();\r
+                       gamestate.bombsthislevel = 0;\r
+                       SetupGameLevel (true);\r
+               }\r
+\r
+\r
+               PlayLoop ();\r
+\r
+#if FRILLS\r
+               if (tedlevel)\r
+               {\r
+                       if (playstate == died)\r
+                               goto startlevel;\r
+                       else\r
+                               TEDDeath ();\r
+               }\r
+#endif\r
+\r
+               if (loadedgame)\r
+                       goto startlevel;\r
+\r
+               switch (playstate)\r
+               {\r
+               case warptolevel:\r
+                       goto startlevel;\r
+\r
+               case died:\r
+                       HandleDeath ();\r
+                       break;\r
+\r
+               case levelcomplete:\r
+                       if (mapon)\r
+                               SD_PlaySound (LEVELDONESND);\r
+                       gamestate.leveldone[mapon] = true;      // finished the level\r
+                       if (mapon != 0)\r
+                               gamestate.mapon = 0;\r
+                       break;\r
+\r
+               case resetgame:\r
+                       return;\r
+\r
+               case victorious:\r
+                       GameFinale ();\r
+                       goto done;\r
+               }\r
+\r
+\r
+       } while (gamestate.lives>-1 && playstate!=victorious);\r
+\r
+       GameOver ();\r
+\r
+done:\r
+       cities = 0;\r
+       for (i= 1; i<=16; i++)\r
+               if (gamestate.leveldone[i])\r
+                       cities++;\r
+       US_CheckHighScore (gamestate.score,cities);\r
+       VW_ClearVideo (FIRSTCOLOR);\r
+}\r
+\r
diff --git a/src/lib/hb/wl_act1.c b/src/lib/hb/wl_act1.c
new file mode 100755 (executable)
index 0000000..10d84e4
--- /dev/null
@@ -0,0 +1,900 @@
+// WL_ACT1.C\r
+\r
+#include "WL_DEF.H"\r
+#pragma hdrstop\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                       STATICS\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+statobj_t      statobjlist[MAXSTATS],*laststatobj;\r
+\r
+\r
+struct\r
+{\r
+       int             picnum;\r
+       stat_t  type;\r
+} statinfo[] =\r
+{\r
+{SPR_STAT_0},                                  // puddle          spr1v\r
+{SPR_STAT_1,block},                            // Green Barrel    "\r
+{SPR_STAT_2,block},                            // Table/chairs    "\r
+{SPR_STAT_3,block},                            // Floor lamp      "\r
+{SPR_STAT_4},                                  // Chandelier      "\r
+{SPR_STAT_5,block},                            // Hanged man      "\r
+{SPR_STAT_6,bo_alpo},                  // Bad food        "\r
+{SPR_STAT_7,block},                            // Red pillar      "\r
+//\r
+// NEW PAGE\r
+//\r
+{SPR_STAT_8,block},                            // Tree            spr2v\r
+{SPR_STAT_9},                                  // Skeleton flat   "\r
+{SPR_STAT_10,block},                   // Sink            " (SOD:gibs)\r
+{SPR_STAT_11,block},                   // Potted plant    "\r
+{SPR_STAT_12,block},                   // Urn             "\r
+{SPR_STAT_13,block},                   // Bare table      "\r
+{SPR_STAT_14},                                 // Ceiling light   "\r
+#ifndef SPEAR\r
+{SPR_STAT_15},                                 // Kitchen stuff   "\r
+#else\r
+{SPR_STAT_15,block},                   // Gibs!\r
+#endif\r
+//\r
+// NEW PAGE\r
+//\r
+{SPR_STAT_16,block},                   // suit of armor   spr3v\r
+{SPR_STAT_17,block},                   // Hanging cage    "\r
+{SPR_STAT_18,block},                   // SkeletoninCage  "\r
+{SPR_STAT_19},                                 // Skeleton relax  "\r
+{SPR_STAT_20,bo_key1},                 // Key 1           "\r
+{SPR_STAT_21,bo_key2},                 // Key 2           "\r
+{SPR_STAT_22,block},                   // stuff                                (SOD:gibs)\r
+{SPR_STAT_23},                                 // stuff\r
+//\r
+// NEW PAGE\r
+//\r
+{SPR_STAT_24,bo_food},                         // Good food       spr4v\r
+{SPR_STAT_25,bo_firstaid},             // First aid       "\r
+{SPR_STAT_26,bo_clip},                 // Clip            "\r
+{SPR_STAT_27,bo_machinegun},   // Machine gun     "\r
+{SPR_STAT_28,bo_chaingun},             // Gatling gun     "\r
+{SPR_STAT_29,bo_cross},                        // Cross           "\r
+{SPR_STAT_30,bo_chalice},              // Chalice         "\r
+{SPR_STAT_31,bo_bible},                        // Bible           "\r
+//\r
+// NEW PAGE\r
+//\r
+{SPR_STAT_32,bo_crown},                        // crown           spr5v\r
+{SPR_STAT_33,bo_fullheal},             // one up          "\r
+{SPR_STAT_34,bo_gibs},                 // gibs            "\r
+{SPR_STAT_35,block},                   // barrel          "\r
+{SPR_STAT_36,block},                   // well            "\r
+{SPR_STAT_37,block},                   // Empty well      "\r
+{SPR_STAT_38,bo_gibs},                 // Gibs 2          "\r
+{SPR_STAT_39,block},                   // flag                         "\r
+//\r
+// NEW PAGE\r
+//\r
+#ifndef SPEAR\r
+{SPR_STAT_40,block},                   // Call Apogee          spr7v\r
+#else\r
+{SPR_STAT_40},                                 // Red light\r
+#endif\r
+//\r
+// NEW PAGE\r
+//\r
+{SPR_STAT_41},                                 // junk            "\r
+{SPR_STAT_42},                                 // junk                    "\r
+{SPR_STAT_43},                                 // junk            "\r
+#ifndef SPEAR\r
+{SPR_STAT_44},                                 // pots            "\r
+#else\r
+{SPR_STAT_44,block},                   // Gibs!\r
+#endif\r
+{SPR_STAT_45,block},                   // stove           " (SOD:gibs)\r
+{SPR_STAT_46,block},                   // spears          " (SOD:gibs)\r
+{SPR_STAT_47},                                 // vines                        "\r
+//\r
+// NEW PAGE\r
+//\r
+#ifdef SPEAR\r
+{SPR_STAT_48,block},                   // marble pillar\r
+{SPR_STAT_49,bo_25clip},               // bonus 25 clip\r
+{SPR_STAT_50,block},                   // truck\r
+{SPR_STAT_51,bo_spear},                        // SPEAR OF DESTINY!\r
+#endif\r
+\r
+{SPR_STAT_26,bo_clip2},                        // Clip            "\r
+{-1}                                                   // terminator\r
+};\r
+\r
+/*\r
+===============\r
+=\r
+= InitStaticList\r
+=\r
+===============\r
+*/\r
+\r
+void InitStaticList (void)\r
+{\r
+       laststatobj = &statobjlist[0];\r
+}\r
+\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnStatic\r
+=\r
+===============\r
+*/\r
+\r
+void SpawnStatic (int tilex, int tiley, int type)\r
+{\r
+       laststatobj->shapenum = statinfo[type].picnum;\r
+       laststatobj->tilex = tilex;\r
+       laststatobj->tiley = tiley;\r
+       laststatobj->visspot = &spotvis[tilex][tiley];\r
+\r
+       switch (statinfo[type].type)\r
+       {\r
+       case block:\r
+               (unsigned)actorat[tilex][tiley] = 1;            // consider it a blocking tile\r
+       case dressing:\r
+               laststatobj->flags = 0;\r
+               break;\r
+\r
+       case    bo_cross:\r
+       case    bo_chalice:\r
+       case    bo_bible:\r
+       case    bo_crown:\r
+       case    bo_fullheal:\r
+               if (!loadedgame)\r
+                 gamestate.treasuretotal++;\r
+\r
+       case    bo_firstaid:\r
+       case    bo_key1:\r
+       case    bo_key2:\r
+       case    bo_key3:\r
+       case    bo_key4:\r
+       case    bo_clip:\r
+       case    bo_25clip:\r
+       case    bo_machinegun:\r
+       case    bo_chaingun:\r
+       case    bo_food:\r
+       case    bo_alpo:\r
+       case    bo_gibs:\r
+       case    bo_spear:\r
+               laststatobj->flags = FL_BONUS;\r
+               laststatobj->itemnumber = statinfo[type].type;\r
+               break;\r
+       }\r
+\r
+       laststatobj++;\r
+\r
+       if (laststatobj == &statobjlist[MAXSTATS])\r
+               Quit ("Too many static objects!\n");\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= PlaceItemType\r
+=\r
+= Called during game play to drop actors' items.  It finds the proper\r
+= item number based on the item type (bo_???).  If there are no free item\r
+= spots, nothing is done.\r
+=\r
+===============\r
+*/\r
+\r
+void PlaceItemType (int itemtype, int tilex, int tiley)\r
+{\r
+       int                     type;\r
+       statobj_t       *spot;\r
+\r
+//\r
+// find the item number\r
+//\r
+       for (type=0 ;  ; type++)\r
+       {\r
+               if (statinfo[type].picnum == -1)                // end of list\r
+                       Quit ("PlaceItemType: couldn't find type!");\r
+               if (statinfo[type].type == itemtype)\r
+                       break;\r
+       }\r
+\r
+//\r
+// find a spot in statobjlist to put it in\r
+//\r
+       for (spot=&statobjlist[0] ; ; spot++)\r
+       {\r
+               if (spot==laststatobj)\r
+               {\r
+                       if (spot == &statobjlist[MAXSTATS])\r
+                               return;                                                 // no free spots\r
+                       laststatobj++;                                          // space at end\r
+                       break;\r
+               }\r
+\r
+               if (spot->shapenum == -1)                               // -1 is a free spot\r
+                       break;\r
+       }\r
+//\r
+// place it\r
+//\r
+       spot->shapenum = statinfo[type].picnum;\r
+       spot->tilex = tilex;\r
+       spot->tiley = tiley;\r
+       spot->visspot = &spotvis[tilex][tiley];\r
+       spot->flags = FL_BONUS;\r
+       spot->itemnumber = statinfo[type].type;\r
+}\r
+\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                       DOORS\r
+\r
+doorobjlist[] holds most of the information for the doors\r
+\r
+doorposition[] holds the amount the door is open, ranging from 0 to 0xffff\r
+       this is directly accessed by AsmRefresh during rendering\r
+\r
+The number of doors is limited to 64 because a spot in tilemap holds the\r
+       door number in the low 6 bits, with the high bit meaning a door center\r
+       and bit 6 meaning a door side tile\r
+\r
+Open doors conect two areas, so sounds will travel between them and sight\r
+       will be checked when the player is in a connected area.\r
+\r
+Areaconnect is incremented/decremented by each door. If >0 they connect\r
+\r
+Every time a door opens or closes the areabyplayer matrix gets recalculated.\r
+       An area is true if it connects with the player's current spor.\r
+\r
+=============================================================================\r
+*/\r
+\r
+#define DOORWIDTH      0x7800\r
+#define OPENTICS       300\r
+\r
+doorobj_t      doorobjlist[MAXDOORS],*lastdoorobj;\r
+int                    doornum;\r
+\r
+unsigned       doorposition[MAXDOORS];         // leading edge of door 0=closed\r
+                                                                               // 0xffff = fully open\r
+\r
+byte           far areaconnect[NUMAREAS][NUMAREAS];\r
+\r
+boolean                areabyplayer[NUMAREAS];\r
+\r
+\r
+/*\r
+==============\r
+=\r
+= ConnectAreas\r
+=\r
+= Scans outward from playerarea, marking all connected areas\r
+=\r
+==============\r
+*/\r
+\r
+void RecursiveConnect (int areanumber)\r
+{\r
+       int     i;\r
+\r
+       for (i=0;i<NUMAREAS;i++)\r
+       {\r
+               if (areaconnect[areanumber][i] && !areabyplayer[i])\r
+               {\r
+                       areabyplayer[i] = true;\r
+                       RecursiveConnect (i);\r
+               }\r
+       }\r
+}\r
+\r
+\r
+void ConnectAreas (void)\r
+{\r
+       memset (areabyplayer,0,sizeof(areabyplayer));\r
+       areabyplayer[player->areanumber] = true;\r
+       RecursiveConnect (player->areanumber);\r
+}\r
+\r
+\r
+void InitAreas (void)\r
+{\r
+       memset (areabyplayer,0,sizeof(areabyplayer));\r
+       areabyplayer[player->areanumber] = true;\r
+}\r
+\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= InitDoorList\r
+=\r
+===============\r
+*/\r
+\r
+void InitDoorList (void)\r
+{\r
+       memset (areabyplayer,0,sizeof(areabyplayer));\r
+       _fmemset (areaconnect,0,sizeof(areaconnect));\r
+\r
+       lastdoorobj = &doorobjlist[0];\r
+       doornum = 0;\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnDoor\r
+=\r
+===============\r
+*/\r
+\r
+void SpawnDoor (int tilex, int tiley, boolean vertical, int lock)\r
+{\r
+       int     areanumber;\r
+       unsigned        far *map;\r
+\r
+       if (doornum==64)\r
+               Quit ("64+ doors on level!");\r
+\r
+       doorposition[doornum] = 0;              // doors start out fully closed\r
+       lastdoorobj->tilex = tilex;\r
+       lastdoorobj->tiley = tiley;\r
+       lastdoorobj->vertical = vertical;\r
+       lastdoorobj->lock = lock;\r
+       lastdoorobj->action = dr_closed;\r
+\r
+       (unsigned)actorat[tilex][tiley] = doornum | 0x80;       // consider it a solid wall\r
+\r
+//\r
+// make the door tile a special tile, and mark the adjacent tiles\r
+// for door sides\r
+//\r
+       tilemap[tilex][tiley] = doornum | 0x80;\r
+       map = mapsegs[0] + farmapylookup[tiley]+tilex;\r
+       if (vertical)\r
+       {\r
+               *map = *(map-1);                        // set area number\r
+               tilemap[tilex][tiley-1] |= 0x40;\r
+               tilemap[tilex][tiley+1] |= 0x40;\r
+       }\r
+       else\r
+       {\r
+               *map = *(map-mapwidth);                                 // set area number\r
+               tilemap[tilex-1][tiley] |= 0x40;\r
+               tilemap[tilex+1][tiley] |= 0x40;\r
+       }\r
+\r
+       doornum++;\r
+       lastdoorobj++;\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+=====================\r
+=\r
+= OpenDoor\r
+=\r
+=====================\r
+*/\r
+\r
+void OpenDoor (int door)\r
+{\r
+       if (doorobjlist[door].action == dr_open)\r
+               doorobjlist[door].ticcount = 0;                 // reset open time\r
+       else\r
+               doorobjlist[door].action = dr_opening;  // start it opening\r
+}\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= CloseDoor\r
+=\r
+=====================\r
+*/\r
+\r
+void CloseDoor (int door)\r
+{\r
+       int     tilex,tiley,area;\r
+       objtype *check;\r
+\r
+//\r
+// don't close on anything solid\r
+//\r
+       tilex = doorobjlist[door].tilex;\r
+       tiley = doorobjlist[door].tiley;\r
+\r
+       if (actorat[tilex][tiley])\r
+               return;\r
+\r
+       if (player->tilex == tilex && player->tiley == tiley)\r
+               return;\r
+\r
+       if (doorobjlist[door].vertical)\r
+       {\r
+               if ( player->tiley == tiley )\r
+               {\r
+                       if ( ((player->x+MINDIST) >>TILESHIFT) == tilex )\r
+                               return;\r
+                       if ( ((player->x-MINDIST) >>TILESHIFT) == tilex )\r
+                               return;\r
+               }\r
+               check = actorat[tilex-1][tiley];\r
+               if (check && ((check->x+MINDIST) >> TILESHIFT) == tilex )\r
+                       return;\r
+               check = actorat[tilex+1][tiley];\r
+               if (check && ((check->x-MINDIST) >> TILESHIFT) == tilex )\r
+                       return;\r
+       }\r
+       else if (!doorobjlist[door].vertical)\r
+       {\r
+               if (player->tilex == tilex)\r
+               {\r
+                       if ( ((player->y+MINDIST) >>TILESHIFT) == tiley )\r
+                               return;\r
+                       if ( ((player->y-MINDIST) >>TILESHIFT) == tiley )\r
+                               return;\r
+               }\r
+               check = actorat[tilex][tiley-1];\r
+               if (check && ((check->y+MINDIST) >> TILESHIFT) == tiley )\r
+                       return;\r
+               check = actorat[tilex][tiley+1];\r
+               if (check && ((check->y-MINDIST) >> TILESHIFT) == tiley )\r
+                       return;\r
+       }\r
+\r
+\r
+//\r
+// play door sound if in a connected area\r
+//\r
+       area = *(mapsegs[0] + farmapylookup[doorobjlist[door].tiley]\r
+                       +doorobjlist[door].tilex)-AREATILE;\r
+       if (areabyplayer[area])\r
+       {\r
+               PlaySoundLocTile(CLOSEDOORSND,doorobjlist[door].tilex,doorobjlist[door].tiley); // JAB\r
+       }\r
+\r
+       doorobjlist[door].action = dr_closing;\r
+//\r
+// make the door space solid\r
+//\r
+       (unsigned)actorat[tilex][tiley]\r
+               = door | 0x80;\r
+}\r
+\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= OperateDoor\r
+=\r
+= The player wants to change the door's direction\r
+=\r
+=====================\r
+*/\r
+\r
+void OperateDoor (int door)\r
+{\r
+       int     lock;\r
+\r
+       lock = doorobjlist[door].lock;\r
+       if (lock >= dr_lock1 && lock <= dr_lock4)\r
+       {\r
+               if ( ! (gamestate.keys & (1 << (lock-dr_lock1) ) ) )\r
+               {\r
+                       SD_PlaySound (NOWAYSND);                // locked\r
+                       return;\r
+               }\r
+       }\r
+\r
+       switch (doorobjlist[door].action)\r
+       {\r
+       case dr_closed:\r
+       case dr_closing:\r
+               OpenDoor (door);\r
+               break;\r
+       case dr_open:\r
+       case dr_opening:\r
+               CloseDoor (door);\r
+               break;\r
+       }\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= DoorOpen\r
+=\r
+= Close the door after three seconds\r
+=\r
+===============\r
+*/\r
+\r
+void DoorOpen (int door)\r
+{\r
+       if ( (doorobjlist[door].ticcount += tics) >= OPENTICS)\r
+               CloseDoor (door);\r
+}\r
+\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= DoorOpening\r
+=\r
+===============\r
+*/\r
+\r
+void DoorOpening (int door)\r
+{\r
+       int             area1,area2;\r
+       unsigned        far     *map;\r
+       long    position;\r
+\r
+       position = doorposition[door];\r
+       if (!position)\r
+       {\r
+       //\r
+       // door is just starting to open, so connect the areas\r
+       //\r
+               map = mapsegs[0] + farmapylookup[doorobjlist[door].tiley]\r
+                       +doorobjlist[door].tilex;\r
+\r
+               if (doorobjlist[door].vertical)\r
+               {\r
+                       area1 = *(map+1);\r
+                       area2 = *(map-1);\r
+               }\r
+               else\r
+               {\r
+                       area1 = *(map-mapwidth);\r
+                       area2 = *(map+mapwidth);\r
+               }\r
+               area1 -= AREATILE;\r
+               area2 -= AREATILE;\r
+               areaconnect[area1][area2]++;\r
+               areaconnect[area2][area1]++;\r
+               ConnectAreas ();\r
+               if (areabyplayer[area1])\r
+               {\r
+                       PlaySoundLocTile(OPENDOORSND,doorobjlist[door].tilex,doorobjlist[door].tiley);  // JAB\r
+               }\r
+       }\r
+\r
+//\r
+// slide the door by an adaptive amount\r
+//\r
+       position += tics<<10;\r
+       if (position >= 0xffff)\r
+       {\r
+       //\r
+       // door is all the way open\r
+       //\r
+               position = 0xffff;\r
+               doorobjlist[door].ticcount = 0;\r
+               doorobjlist[door].action = dr_open;\r
+               actorat[doorobjlist[door].tilex][doorobjlist[door].tiley] = 0;\r
+       }\r
+\r
+       doorposition[door] = position;\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= DoorClosing\r
+=\r
+===============\r
+*/\r
+\r
+void DoorClosing (int door)\r
+{\r
+       int             area1,area2,move;\r
+       unsigned        far     *map;\r
+       long    position;\r
+       int             tilex,tiley;\r
+\r
+       tilex = doorobjlist[door].tilex;\r
+       tiley = doorobjlist[door].tiley;\r
+\r
+       if ( ((unsigned)actorat[tilex][tiley] != (door | 0x80))\r
+       || (player->tilex == tilex && player->tiley == tiley) )\r
+       {                       // something got inside the door\r
+               OpenDoor (door);\r
+               return;\r
+       };\r
+\r
+       position = doorposition[door];\r
+\r
+//\r
+// slide the door by an adaptive amount\r
+//\r
+       position -= tics<<10;\r
+       if (position <= 0)\r
+       {\r
+       //\r
+       // door is closed all the way, so disconnect the areas\r
+       //\r
+               position = 0;\r
+\r
+               doorobjlist[door].action = dr_closed;\r
+\r
+               map = mapsegs[0] + farmapylookup[doorobjlist[door].tiley]\r
+                       +doorobjlist[door].tilex;\r
+\r
+               if (doorobjlist[door].vertical)\r
+               {\r
+                       area1 = *(map+1);\r
+                       area2 = *(map-1);\r
+               }\r
+               else\r
+               {\r
+                       area1 = *(map-mapwidth);\r
+                       area2 = *(map+mapwidth);\r
+               }\r
+               area1 -= AREATILE;\r
+               area2 -= AREATILE;\r
+               areaconnect[area1][area2]--;\r
+               areaconnect[area2][area1]--;\r
+\r
+               ConnectAreas ();\r
+       }\r
+\r
+       doorposition[door] = position;\r
+}\r
+\r
+\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= MoveDoors\r
+=\r
+= Called from PlayLoop\r
+=\r
+=====================\r
+*/\r
+\r
+void MoveDoors (void)\r
+{\r
+       int             door;\r
+\r
+       if (gamestate.victoryflag)              // don't move door during victory sequence\r
+               return;\r
+\r
+       for (door = 0 ; door < doornum ; door++)\r
+               switch (doorobjlist[door].action)\r
+               {\r
+               case dr_open:\r
+                       DoorOpen (door);\r
+                       break;\r
+\r
+               case dr_opening:\r
+                       DoorOpening(door);\r
+                       break;\r
+\r
+               case dr_closing:\r
+                       DoorClosing(door);\r
+                       break;\r
+               }\r
+}\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                               PUSHABLE WALLS\r
+\r
+=============================================================================\r
+*/\r
+\r
+unsigned       pwallstate;\r
+unsigned       pwallpos;                       // amount a pushable wall has been moved (0-63)\r
+unsigned       pwallx,pwally;\r
+int                    pwalldir;\r
+\r
+/*\r
+===============\r
+=\r
+= PushWall\r
+=\r
+===============\r
+*/\r
+\r
+void PushWall (int checkx, int checky, int dir)\r
+{\r
+       int             oldtile;\r
+\r
+       if (pwallstate)\r
+         return;\r
+\r
+\r
+       oldtile = tilemap[checkx][checky];\r
+       if (!oldtile)\r
+               return;\r
+\r
+       switch (dir)\r
+       {\r
+       case di_north:\r
+               if (actorat[checkx][checky-1])\r
+               {\r
+                       SD_PlaySound (NOWAYSND);\r
+                       return;\r
+               }\r
+               (unsigned)actorat[checkx][checky-1] =\r
+               tilemap[checkx][checky-1] = oldtile;\r
+               break;\r
+\r
+       case di_east:\r
+               if (actorat[checkx+1][checky])\r
+               {\r
+                       SD_PlaySound (NOWAYSND);\r
+                       return;\r
+               }\r
+               (unsigned)actorat[checkx+1][checky] =\r
+               tilemap[checkx+1][checky] = oldtile;\r
+               break;\r
+\r
+       case di_south:\r
+               if (actorat[checkx][checky+1])\r
+               {\r
+                       SD_PlaySound (NOWAYSND);\r
+                       return;\r
+               }\r
+               (unsigned)actorat[checkx][checky+1] =\r
+               tilemap[checkx][checky+1] = oldtile;\r
+               break;\r
+\r
+       case di_west:\r
+               if (actorat[checkx-1][checky])\r
+               {\r
+                       SD_PlaySound (NOWAYSND);\r
+                       return;\r
+               }\r
+               (unsigned)actorat[checkx-1][checky] =\r
+               tilemap[checkx-1][checky] = oldtile;\r
+               break;\r
+       }\r
+\r
+       gamestate.secretcount++;\r
+       pwallx = checkx;\r
+       pwally = checky;\r
+       pwalldir = dir;\r
+       pwallstate = 1;\r
+       pwallpos = 0;\r
+       tilemap[pwallx][pwally] |= 0xc0;\r
+       *(mapsegs[1]+farmapylookup[pwally]+pwallx) = 0; // remove P tile info\r
+\r
+       SD_PlaySound (PUSHWALLSND);\r
+}\r
+\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= MovePWalls\r
+=\r
+=================\r
+*/\r
+\r
+void MovePWalls (void)\r
+{\r
+       int             oldblock,oldtile;\r
+\r
+       if (!pwallstate)\r
+               return;\r
+\r
+       oldblock = pwallstate/128;\r
+\r
+       pwallstate += tics;\r
+\r
+       if (pwallstate/128 != oldblock)\r
+       {\r
+       // block crossed into a new block\r
+               oldtile = tilemap[pwallx][pwally] & 63;\r
+\r
+               //\r
+               // the tile can now be walked into\r
+               //\r
+               tilemap[pwallx][pwally] = 0;\r
+               (unsigned)actorat[pwallx][pwally] = 0;\r
+               *(mapsegs[0]+farmapylookup[pwally]+pwallx) = player->areanumber+AREATILE;\r
+\r
+               //\r
+               // see if it should be pushed farther\r
+               //\r
+               if (pwallstate>256)\r
+               {\r
+               //\r
+               // the block has been pushed two tiles\r
+               //\r
+                       pwallstate = 0;\r
+                       return;\r
+               }\r
+               else\r
+               {\r
+                       switch (pwalldir)\r
+                       {\r
+                       case di_north:\r
+                               pwally--;\r
+                               if (actorat[pwallx][pwally-1])\r
+                               {\r
+                                       pwallstate = 0;\r
+                                       return;\r
+                               }\r
+                               (unsigned)actorat[pwallx][pwally-1] =\r
+                               tilemap[pwallx][pwally-1] = oldtile;\r
+                               break;\r
+\r
+                       case di_east:\r
+                               pwallx++;\r
+                               if (actorat[pwallx+1][pwally])\r
+                               {\r
+                                       pwallstate = 0;\r
+                                       return;\r
+                               }\r
+                               (unsigned)actorat[pwallx+1][pwally] =\r
+                               tilemap[pwallx+1][pwally] = oldtile;\r
+                               break;\r
+\r
+                       case di_south:\r
+                               pwally++;\r
+                               if (actorat[pwallx][pwally+1])\r
+                               {\r
+                                       pwallstate = 0;\r
+                                       return;\r
+                               }\r
+                               (unsigned)actorat[pwallx][pwally+1] =\r
+                               tilemap[pwallx][pwally+1] = oldtile;\r
+                               break;\r
+\r
+                       case di_west:\r
+                               pwallx--;\r
+                               if (actorat[pwallx-1][pwally])\r
+                               {\r
+                                       pwallstate = 0;\r
+                                       return;\r
+                               }\r
+                               (unsigned)actorat[pwallx-1][pwally] =\r
+                               tilemap[pwallx-1][pwally] = oldtile;\r
+                               break;\r
+                       }\r
+\r
+                       tilemap[pwallx][pwally] = oldtile | 0xc0;\r
+               }\r
+       }\r
+\r
+\r
+       pwallpos = (pwallstate/2)&63;\r
+\r
+}\r
+\r
diff --git a/src/lib/hb/wl_act2.c b/src/lib/hb/wl_act2.c
new file mode 100755 (executable)
index 0000000..d9d99a0
--- /dev/null
@@ -0,0 +1,3872 @@
+// WL_ACT2.C\r
+\r
+#include "WL_DEF.H"\r
+#pragma hdrstop\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+#define PROJECTILESIZE 0xc000l\r
+\r
+#define BJRUNSPEED     2048\r
+#define BJJUMPSPEED    680\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
+int    starthitpoints[4][NUMENEMIES] =\r
+        //\r
+        // BABY MODE\r
+        //\r
+        {\r
+        {25,   // guards\r
+         50,   // officer\r
+         100,  // SS\r
+         1,    // dogs\r
+         850,  // Hans\r
+         850,  // Schabbs\r
+         200,  // fake hitler\r
+         800,  // mecha hitler\r
+         45,   // mutants\r
+         25,   // ghosts\r
+         25,   // ghosts\r
+         25,   // ghosts\r
+         25,   // ghosts\r
+\r
+         850,  // Gretel\r
+         850,  // Gift\r
+         850,  // Fat\r
+         5,    // en_spectre,\r
+         1450, // en_angel,\r
+         850,  // en_trans,\r
+         1050, // en_uber,\r
+         950,  // en_will,\r
+         1250  // en_death\r
+         },\r
+        //\r
+        // DON'T HURT ME MODE\r
+        //\r
+        {25,   // guards\r
+         50,   // officer\r
+         100,  // SS\r
+         1,    // dogs\r
+         950,  // Hans\r
+         950,  // Schabbs\r
+         300,  // fake hitler\r
+         950,  // mecha hitler\r
+         55,   // mutants\r
+         25,   // ghosts\r
+         25,   // ghosts\r
+         25,   // ghosts\r
+         25,   // ghosts\r
+\r
+         950,  // Gretel\r
+         950,  // Gift\r
+         950,  // Fat\r
+         10,   // en_spectre,\r
+         1550, // en_angel,\r
+         950,  // en_trans,\r
+         1150, // en_uber,\r
+         1050, // en_will,\r
+         1350  // en_death\r
+         },\r
+        //\r
+        // BRING 'EM ON MODE\r
+        //\r
+        {25,   // guards\r
+         50,   // officer\r
+         100,  // SS\r
+         1,    // dogs\r
+\r
+         1050, // Hans\r
+         1550, // Schabbs\r
+         400,  // fake hitler\r
+         1050, // mecha hitler\r
+\r
+         55,   // mutants\r
+         25,   // ghosts\r
+         25,   // ghosts\r
+         25,   // ghosts\r
+         25,   // ghosts\r
+\r
+         1050, // Gretel\r
+         1050, // Gift\r
+         1050, // Fat\r
+         15,   // en_spectre,\r
+         1650, // en_angel,\r
+         1050, // en_trans,\r
+         1250, // en_uber,\r
+         1150, // en_will,\r
+         1450  // en_death\r
+         },\r
+        //\r
+        // DEATH INCARNATE MODE\r
+        //\r
+        {25,   // guards\r
+         50,   // officer\r
+         100,  // SS\r
+         1,    // dogs\r
+\r
+         1200, // Hans\r
+         2400, // Schabbs\r
+         500,  // fake hitler\r
+         1200, // mecha hitler\r
+\r
+         65,   // mutants\r
+         25,   // ghosts\r
+         25,   // ghosts\r
+         25,   // ghosts\r
+         25,   // ghosts\r
+\r
+         1200, // Gretel\r
+         1200, // Gift\r
+         1200, // Fat\r
+         25,   // en_spectre,\r
+         2000, // en_angel,\r
+         1200, // en_trans,\r
+         1400, // en_uber,\r
+         1300, // en_will,\r
+         1600  // en_death\r
+         }}\r
+         ;\r
+\r
+void   A_StartDeathCam (objtype *ob);\r
+\r
+\r
+void   T_Path (objtype *ob);\r
+void   T_Shoot (objtype *ob);\r
+void   T_Bite (objtype *ob);\r
+void   T_DogChase (objtype *ob);\r
+void   T_Chase (objtype *ob);\r
+void   T_Projectile (objtype *ob);\r
+void   T_Stand (objtype *ob);\r
+\r
+void A_DeathScream (objtype *ob);\r
+\r
+extern statetype s_rocket;\r
+extern statetype s_smoke1;\r
+extern statetype s_smoke2;\r
+extern statetype s_smoke3;\r
+extern statetype s_smoke4;\r
+extern statetype s_boom2;\r
+extern statetype s_boom3;\r
+\r
+void A_Smoke (objtype *ob);\r
+\r
+statetype s_rocket             = {true,SPR_ROCKET_1,3,T_Projectile,A_Smoke,&s_rocket};\r
+statetype s_smoke1             = {false,SPR_SMOKE_1,3,NULL,NULL,&s_smoke2};\r
+statetype s_smoke2             = {false,SPR_SMOKE_2,3,NULL,NULL,&s_smoke3};\r
+statetype s_smoke3             = {false,SPR_SMOKE_3,3,NULL,NULL,&s_smoke4};\r
+statetype s_smoke4             = {false,SPR_SMOKE_4,3,NULL,NULL,NULL};\r
+\r
+statetype s_boom1              = {false,SPR_BOOM_1,6,NULL,NULL,&s_boom2};\r
+statetype s_boom2              = {false,SPR_BOOM_2,6,NULL,NULL,&s_boom3};\r
+statetype s_boom3              = {false,SPR_BOOM_3,6,NULL,NULL,NULL};\r
+\r
+#ifdef SPEAR\r
+\r
+extern statetype s_hrocket;\r
+extern statetype s_hsmoke1;\r
+extern statetype s_hsmoke2;\r
+extern statetype s_hsmoke3;\r
+extern statetype s_hsmoke4;\r
+extern statetype s_hboom2;\r
+extern statetype s_hboom3;\r
+\r
+void A_Smoke (objtype *ob);\r
+\r
+statetype s_hrocket            = {true,SPR_HROCKET_1,3,T_Projectile,A_Smoke,&s_hrocket};\r
+statetype s_hsmoke1            = {false,SPR_HSMOKE_1,3,NULL,NULL,&s_hsmoke2};\r
+statetype s_hsmoke2            = {false,SPR_HSMOKE_2,3,NULL,NULL,&s_hsmoke3};\r
+statetype s_hsmoke3            = {false,SPR_HSMOKE_3,3,NULL,NULL,&s_hsmoke4};\r
+statetype s_hsmoke4            = {false,SPR_HSMOKE_4,3,NULL,NULL,NULL};\r
+\r
+statetype s_hboom1             = {false,SPR_HBOOM_1,6,NULL,NULL,&s_hboom2};\r
+statetype s_hboom2             = {false,SPR_HBOOM_2,6,NULL,NULL,&s_hboom3};\r
+statetype s_hboom3             = {false,SPR_HBOOM_3,6,NULL,NULL,NULL};\r
+\r
+#endif\r
+\r
+void   T_Schabb (objtype *ob);\r
+void   T_SchabbThrow (objtype *ob);\r
+void   T_Fake (objtype *ob);\r
+void   T_FakeFire (objtype *ob);\r
+void   T_Ghosts (objtype *ob);\r
+\r
+void A_Slurpie (objtype *ob);\r
+void A_HitlerMorph (objtype *ob);\r
+void A_MechaSound (objtype *ob);\r
+\r
+/*\r
+=================\r
+=\r
+= A_Smoke\r
+=\r
+=================\r
+*/\r
+\r
+void A_Smoke (objtype *ob)\r
+{\r
+       GetNewActor ();\r
+#ifdef SPEAR\r
+       if (ob->obclass == hrocketobj)\r
+               new->state = &s_hsmoke1;\r
+       else\r
+#endif\r
+               new->state = &s_smoke1;\r
+       new->ticcount = 6;\r
+\r
+       new->tilex = ob->tilex;\r
+       new->tiley = ob->tiley;\r
+       new->x = ob->x;\r
+       new->y = ob->y;\r
+       new->obclass = inertobj;\r
+       new->active = true;\r
+\r
+       new->flags = FL_NEVERMARK;\r
+}\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= ProjectileTryMove\r
+=\r
+= returns true if move ok\r
+===================\r
+*/\r
+\r
+#define PROJSIZE       0x2000\r
+\r
+boolean ProjectileTryMove (objtype *ob)\r
+{\r
+       int                     xl,yl,xh,yh,x,y;\r
+       objtype         *check;\r
+       long            deltax,deltay;\r
+\r
+       xl = (ob->x-PROJSIZE) >>TILESHIFT;\r
+       yl = (ob->y-PROJSIZE) >>TILESHIFT;\r
+\r
+       xh = (ob->x+PROJSIZE) >>TILESHIFT;\r
+       yh = (ob->y+PROJSIZE) >>TILESHIFT;\r
+\r
+//\r
+// check for solid walls\r
+//\r
+       for (y=yl;y<=yh;y++)\r
+               for (x=xl;x<=xh;x++)\r
+               {\r
+                       check = actorat[x][y];\r
+                       if (check && check<objlist)\r
+                               return false;\r
+               }\r
+\r
+       return true;\r
+}\r
+\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= T_Projectile\r
+=\r
+=================\r
+*/\r
+\r
+void T_Projectile (objtype *ob)\r
+{\r
+       long    deltax,deltay;\r
+       int             damage;\r
+       long    speed;\r
+\r
+       speed = (long)ob->speed*tics;\r
+\r
+       deltax = FixedByFrac(speed,costable[ob->angle]);\r
+       deltay = -FixedByFrac(speed,sintable[ob->angle]);\r
+\r
+       if (deltax>0x10000l)\r
+               deltax = 0x10000l;\r
+       if (deltay>0x10000l)\r
+               deltay = 0x10000l;\r
+\r
+       ob->x += deltax;\r
+       ob->y += deltay;\r
+\r
+       deltax = LABS(ob->x - player->x);\r
+       deltay = LABS(ob->y - player->y);\r
+\r
+       if (!ProjectileTryMove (ob))\r
+       {\r
+               if (ob->obclass == rocketobj)\r
+               {\r
+                       PlaySoundLocActor(MISSILEHITSND,ob);\r
+                       ob->state = &s_boom1;\r
+               }\r
+#ifdef SPEAR\r
+               else if (ob->obclass == hrocketobj)\r
+               {\r
+                       PlaySoundLocActor(MISSILEHITSND,ob);\r
+                       ob->state = &s_hboom1;\r
+               }\r
+#endif\r
+               else\r
+                       ob->state = NULL;               // mark for removal\r
+\r
+               return;\r
+       }\r
+\r
+       if (deltax < PROJECTILESIZE && deltay < PROJECTILESIZE)\r
+       {       // hit the player\r
+               switch (ob->obclass)\r
+               {\r
+               case needleobj:\r
+                       damage = (US_RndT() >>3) + 20;\r
+                       break;\r
+               case rocketobj:\r
+               case hrocketobj:\r
+               case sparkobj:\r
+                       damage = (US_RndT() >>3) + 30;\r
+                       break;\r
+               case fireobj:\r
+                       damage = (US_RndT() >>3);\r
+                       break;\r
+               }\r
+\r
+               TakeDamage (damage,ob);\r
+               ob->state = NULL;               // mark for removal\r
+               return;\r
+       }\r
+\r
+       ob->tilex = ob->x >> TILESHIFT;\r
+       ob->tiley = ob->y >> TILESHIFT;\r
+\r
+}\r
+\r
+\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                       GUARD\r
+\r
+=============================================================================\r
+*/\r
+\r
+//\r
+// guards\r
+//\r
+\r
+extern statetype s_grdstand;\r
+\r
+extern statetype s_grdpath1;\r
+extern statetype s_grdpath1s;\r
+extern statetype s_grdpath2;\r
+extern statetype s_grdpath3;\r
+extern statetype s_grdpath3s;\r
+extern statetype s_grdpath4;\r
+\r
+extern statetype s_grdpain;\r
+extern statetype s_grdpain1;\r
+\r
+extern statetype s_grdgiveup;\r
+\r
+extern statetype s_grdshoot1;\r
+extern statetype s_grdshoot2;\r
+extern statetype s_grdshoot3;\r
+extern statetype s_grdshoot4;\r
+\r
+extern statetype s_grdchase1;\r
+extern statetype s_grdchase1s;\r
+extern statetype s_grdchase2;\r
+extern statetype s_grdchase3;\r
+extern statetype s_grdchase3s;\r
+extern statetype s_grdchase4;\r
+\r
+extern statetype s_grddie1;\r
+extern statetype s_grddie1d;\r
+extern statetype s_grddie2;\r
+extern statetype s_grddie3;\r
+extern statetype s_grddie4;\r
+\r
+statetype s_grdstand   = {true,SPR_GRD_S_1,0,T_Stand,NULL,&s_grdstand};\r
+\r
+statetype s_grdpath1   = {true,SPR_GRD_W1_1,20,T_Path,NULL,&s_grdpath1s};\r
+statetype s_grdpath1s  = {true,SPR_GRD_W1_1,5,NULL,NULL,&s_grdpath2};\r
+statetype s_grdpath2   = {true,SPR_GRD_W2_1,15,T_Path,NULL,&s_grdpath3};\r
+statetype s_grdpath3   = {true,SPR_GRD_W3_1,20,T_Path,NULL,&s_grdpath3s};\r
+statetype s_grdpath3s  = {true,SPR_GRD_W3_1,5,NULL,NULL,&s_grdpath4};\r
+statetype s_grdpath4   = {true,SPR_GRD_W4_1,15,T_Path,NULL,&s_grdpath1};\r
+\r
+statetype s_grdpain    = {2,SPR_GRD_PAIN_1,10,NULL,NULL,&s_grdchase1};\r
+statetype s_grdpain1   = {2,SPR_GRD_PAIN_2,10,NULL,NULL,&s_grdchase1};\r
+\r
+statetype s_grdshoot1  = {false,SPR_GRD_SHOOT1,20,NULL,NULL,&s_grdshoot2};\r
+statetype s_grdshoot2  = {false,SPR_GRD_SHOOT2,20,NULL,T_Shoot,&s_grdshoot3};\r
+statetype s_grdshoot3  = {false,SPR_GRD_SHOOT3,20,NULL,NULL,&s_grdchase1};\r
+\r
+statetype s_grdchase1  = {true,SPR_GRD_W1_1,10,T_Chase,NULL,&s_grdchase1s};\r
+statetype s_grdchase1s         = {true,SPR_GRD_W1_1,3,NULL,NULL,&s_grdchase2};\r
+statetype s_grdchase2  = {true,SPR_GRD_W2_1,8,T_Chase,NULL,&s_grdchase3};\r
+statetype s_grdchase3  = {true,SPR_GRD_W3_1,10,T_Chase,NULL,&s_grdchase3s};\r
+statetype s_grdchase3s         = {true,SPR_GRD_W3_1,3,NULL,NULL,&s_grdchase4};\r
+statetype s_grdchase4  = {true,SPR_GRD_W4_1,8,T_Chase,NULL,&s_grdchase1};\r
+\r
+statetype s_grddie1            = {false,SPR_GRD_DIE_1,15,NULL,A_DeathScream,&s_grddie2};\r
+statetype s_grddie2            = {false,SPR_GRD_DIE_2,15,NULL,NULL,&s_grddie3};\r
+statetype s_grddie3            = {false,SPR_GRD_DIE_3,15,NULL,NULL,&s_grddie4};\r
+statetype s_grddie4            = {false,SPR_GRD_DEAD,0,NULL,NULL,&s_grddie4};\r
+\r
+\r
+#ifndef SPEAR\r
+//\r
+// ghosts\r
+//\r
+extern statetype s_blinkychase1;\r
+extern statetype s_blinkychase2;\r
+extern statetype s_inkychase1;\r
+extern statetype s_inkychase2;\r
+extern statetype s_pinkychase1;\r
+extern statetype s_pinkychase2;\r
+extern statetype s_clydechase1;\r
+extern statetype s_clydechase2;\r
+\r
+statetype s_blinkychase1       = {false,SPR_BLINKY_W1,10,T_Ghosts,NULL,&s_blinkychase2};\r
+statetype s_blinkychase2       = {false,SPR_BLINKY_W2,10,T_Ghosts,NULL,&s_blinkychase1};\r
+\r
+statetype s_inkychase1                 = {false,SPR_INKY_W1,10,T_Ghosts,NULL,&s_inkychase2};\r
+statetype s_inkychase2                 = {false,SPR_INKY_W2,10,T_Ghosts,NULL,&s_inkychase1};\r
+\r
+statetype s_pinkychase1        = {false,SPR_PINKY_W1,10,T_Ghosts,NULL,&s_pinkychase2};\r
+statetype s_pinkychase2        = {false,SPR_PINKY_W2,10,T_Ghosts,NULL,&s_pinkychase1};\r
+\r
+statetype s_clydechase1        = {false,SPR_CLYDE_W1,10,T_Ghosts,NULL,&s_clydechase2};\r
+statetype s_clydechase2        = {false,SPR_CLYDE_W2,10,T_Ghosts,NULL,&s_clydechase1};\r
+#endif\r
+\r
+//\r
+// dogs\r
+//\r
+\r
+extern statetype s_dogpath1;\r
+extern statetype s_dogpath1s;\r
+extern statetype s_dogpath2;\r
+extern statetype s_dogpath3;\r
+extern statetype s_dogpath3s;\r
+extern statetype s_dogpath4;\r
+\r
+extern statetype s_dogjump1;\r
+extern statetype s_dogjump2;\r
+extern statetype s_dogjump3;\r
+extern statetype s_dogjump4;\r
+extern statetype s_dogjump5;\r
+\r
+extern statetype s_dogchase1;\r
+extern statetype s_dogchase1s;\r
+extern statetype s_dogchase2;\r
+extern statetype s_dogchase3;\r
+extern statetype s_dogchase3s;\r
+extern statetype s_dogchase4;\r
+\r
+extern statetype s_dogdie1;\r
+extern statetype s_dogdie1d;\r
+extern statetype s_dogdie2;\r
+extern statetype s_dogdie3;\r
+extern statetype s_dogdead;\r
+\r
+statetype s_dogpath1   = {true,SPR_DOG_W1_1,20,T_Path,NULL,&s_dogpath1s};\r
+statetype s_dogpath1s  = {true,SPR_DOG_W1_1,5,NULL,NULL,&s_dogpath2};\r
+statetype s_dogpath2   = {true,SPR_DOG_W2_1,15,T_Path,NULL,&s_dogpath3};\r
+statetype s_dogpath3   = {true,SPR_DOG_W3_1,20,T_Path,NULL,&s_dogpath3s};\r
+statetype s_dogpath3s  = {true,SPR_DOG_W3_1,5,NULL,NULL,&s_dogpath4};\r
+statetype s_dogpath4   = {true,SPR_DOG_W4_1,15,T_Path,NULL,&s_dogpath1};\r
+\r
+statetype s_dogjump1   = {false,SPR_DOG_JUMP1,10,NULL,NULL,&s_dogjump2};\r
+statetype s_dogjump2   = {false,SPR_DOG_JUMP2,10,NULL,T_Bite,&s_dogjump3};\r
+statetype s_dogjump3   = {false,SPR_DOG_JUMP3,10,NULL,NULL,&s_dogjump4};\r
+statetype s_dogjump4   = {false,SPR_DOG_JUMP1,10,NULL,NULL,&s_dogjump5};\r
+statetype s_dogjump5   = {false,SPR_DOG_W1_1,10,NULL,NULL,&s_dogchase1};\r
+\r
+statetype s_dogchase1  = {true,SPR_DOG_W1_1,10,T_DogChase,NULL,&s_dogchase1s};\r
+statetype s_dogchase1s         = {true,SPR_DOG_W1_1,3,NULL,NULL,&s_dogchase2};\r
+statetype s_dogchase2  = {true,SPR_DOG_W2_1,8,T_DogChase,NULL,&s_dogchase3};\r
+statetype s_dogchase3  = {true,SPR_DOG_W3_1,10,T_DogChase,NULL,&s_dogchase3s};\r
+statetype s_dogchase3s         = {true,SPR_DOG_W3_1,3,NULL,NULL,&s_dogchase4};\r
+statetype s_dogchase4  = {true,SPR_DOG_W4_1,8,T_DogChase,NULL,&s_dogchase1};\r
+\r
+statetype s_dogdie1            = {false,SPR_DOG_DIE_1,15,NULL,A_DeathScream,&s_dogdie2};\r
+statetype s_dogdie2            = {false,SPR_DOG_DIE_2,15,NULL,NULL,&s_dogdie3};\r
+statetype s_dogdie3            = {false,SPR_DOG_DIE_3,15,NULL,NULL,&s_dogdead};\r
+statetype s_dogdead            = {false,SPR_DOG_DEAD,15,NULL,NULL,&s_dogdead};\r
+\r
+\r
+//\r
+// officers\r
+//\r
+\r
+extern statetype s_ofcstand;\r
+\r
+extern statetype s_ofcpath1;\r
+extern statetype s_ofcpath1s;\r
+extern statetype s_ofcpath2;\r
+extern statetype s_ofcpath3;\r
+extern statetype s_ofcpath3s;\r
+extern statetype s_ofcpath4;\r
+\r
+extern statetype s_ofcpain;\r
+extern statetype s_ofcpain1;\r
+\r
+extern statetype s_ofcgiveup;\r
+\r
+extern statetype s_ofcshoot1;\r
+extern statetype s_ofcshoot2;\r
+extern statetype s_ofcshoot3;\r
+extern statetype s_ofcshoot4;\r
+\r
+extern statetype s_ofcchase1;\r
+extern statetype s_ofcchase1s;\r
+extern statetype s_ofcchase2;\r
+extern statetype s_ofcchase3;\r
+extern statetype s_ofcchase3s;\r
+extern statetype s_ofcchase4;\r
+\r
+extern statetype s_ofcdie1;\r
+extern statetype s_ofcdie2;\r
+extern statetype s_ofcdie3;\r
+extern statetype s_ofcdie4;\r
+extern statetype s_ofcdie5;\r
+\r
+statetype s_ofcstand   = {true,SPR_OFC_S_1,0,T_Stand,NULL,&s_ofcstand};\r
+\r
+statetype s_ofcpath1   = {true,SPR_OFC_W1_1,20,T_Path,NULL,&s_ofcpath1s};\r
+statetype s_ofcpath1s  = {true,SPR_OFC_W1_1,5,NULL,NULL,&s_ofcpath2};\r
+statetype s_ofcpath2   = {true,SPR_OFC_W2_1,15,T_Path,NULL,&s_ofcpath3};\r
+statetype s_ofcpath3   = {true,SPR_OFC_W3_1,20,T_Path,NULL,&s_ofcpath3s};\r
+statetype s_ofcpath3s  = {true,SPR_OFC_W3_1,5,NULL,NULL,&s_ofcpath4};\r
+statetype s_ofcpath4   = {true,SPR_OFC_W4_1,15,T_Path,NULL,&s_ofcpath1};\r
+\r
+statetype s_ofcpain    = {2,SPR_OFC_PAIN_1,10,NULL,NULL,&s_ofcchase1};\r
+statetype s_ofcpain1   = {2,SPR_OFC_PAIN_2,10,NULL,NULL,&s_ofcchase1};\r
+\r
+statetype s_ofcshoot1  = {false,SPR_OFC_SHOOT1,6,NULL,NULL,&s_ofcshoot2};\r
+statetype s_ofcshoot2  = {false,SPR_OFC_SHOOT2,20,NULL,T_Shoot,&s_ofcshoot3};\r
+statetype s_ofcshoot3  = {false,SPR_OFC_SHOOT3,10,NULL,NULL,&s_ofcchase1};\r
+\r
+statetype s_ofcchase1  = {true,SPR_OFC_W1_1,10,T_Chase,NULL,&s_ofcchase1s};\r
+statetype s_ofcchase1s         = {true,SPR_OFC_W1_1,3,NULL,NULL,&s_ofcchase2};\r
+statetype s_ofcchase2  = {true,SPR_OFC_W2_1,8,T_Chase,NULL,&s_ofcchase3};\r
+statetype s_ofcchase3  = {true,SPR_OFC_W3_1,10,T_Chase,NULL,&s_ofcchase3s};\r
+statetype s_ofcchase3s         = {true,SPR_OFC_W3_1,3,NULL,NULL,&s_ofcchase4};\r
+statetype s_ofcchase4  = {true,SPR_OFC_W4_1,8,T_Chase,NULL,&s_ofcchase1};\r
+\r
+statetype s_ofcdie1            = {false,SPR_OFC_DIE_1,11,NULL,A_DeathScream,&s_ofcdie2};\r
+statetype s_ofcdie2            = {false,SPR_OFC_DIE_2,11,NULL,NULL,&s_ofcdie3};\r
+statetype s_ofcdie3            = {false,SPR_OFC_DIE_3,11,NULL,NULL,&s_ofcdie4};\r
+statetype s_ofcdie4            = {false,SPR_OFC_DIE_4,11,NULL,NULL,&s_ofcdie5};\r
+statetype s_ofcdie5            = {false,SPR_OFC_DEAD,0,NULL,NULL,&s_ofcdie5};\r
+\r
+\r
+//\r
+// mutant\r
+//\r
+\r
+extern statetype s_mutstand;\r
+\r
+extern statetype s_mutpath1;\r
+extern statetype s_mutpath1s;\r
+extern statetype s_mutpath2;\r
+extern statetype s_mutpath3;\r
+extern statetype s_mutpath3s;\r
+extern statetype s_mutpath4;\r
+\r
+extern statetype s_mutpain;\r
+extern statetype s_mutpain1;\r
+\r
+extern statetype s_mutgiveup;\r
+\r
+extern statetype s_mutshoot1;\r
+extern statetype s_mutshoot2;\r
+extern statetype s_mutshoot3;\r
+extern statetype s_mutshoot4;\r
+\r
+extern statetype s_mutchase1;\r
+extern statetype s_mutchase1s;\r
+extern statetype s_mutchase2;\r
+extern statetype s_mutchase3;\r
+extern statetype s_mutchase3s;\r
+extern statetype s_mutchase4;\r
+\r
+extern statetype s_mutdie1;\r
+extern statetype s_mutdie2;\r
+extern statetype s_mutdie3;\r
+extern statetype s_mutdie4;\r
+extern statetype s_mutdie5;\r
+\r
+statetype s_mutstand   = {true,SPR_MUT_S_1,0,T_Stand,NULL,&s_mutstand};\r
+\r
+statetype s_mutpath1   = {true,SPR_MUT_W1_1,20,T_Path,NULL,&s_mutpath1s};\r
+statetype s_mutpath1s  = {true,SPR_MUT_W1_1,5,NULL,NULL,&s_mutpath2};\r
+statetype s_mutpath2   = {true,SPR_MUT_W2_1,15,T_Path,NULL,&s_mutpath3};\r
+statetype s_mutpath3   = {true,SPR_MUT_W3_1,20,T_Path,NULL,&s_mutpath3s};\r
+statetype s_mutpath3s  = {true,SPR_MUT_W3_1,5,NULL,NULL,&s_mutpath4};\r
+statetype s_mutpath4   = {true,SPR_MUT_W4_1,15,T_Path,NULL,&s_mutpath1};\r
+\r
+statetype s_mutpain    = {2,SPR_MUT_PAIN_1,10,NULL,NULL,&s_mutchase1};\r
+statetype s_mutpain1   = {2,SPR_MUT_PAIN_2,10,NULL,NULL,&s_mutchase1};\r
+\r
+statetype s_mutshoot1  = {false,SPR_MUT_SHOOT1,6,NULL,T_Shoot,&s_mutshoot2};\r
+statetype s_mutshoot2  = {false,SPR_MUT_SHOOT2,20,NULL,NULL,&s_mutshoot3};\r
+statetype s_mutshoot3  = {false,SPR_MUT_SHOOT3,10,NULL,T_Shoot,&s_mutshoot4};\r
+statetype s_mutshoot4  = {false,SPR_MUT_SHOOT4,20,NULL,NULL,&s_mutchase1};\r
+\r
+statetype s_mutchase1  = {true,SPR_MUT_W1_1,10,T_Chase,NULL,&s_mutchase1s};\r
+statetype s_mutchase1s         = {true,SPR_MUT_W1_1,3,NULL,NULL,&s_mutchase2};\r
+statetype s_mutchase2  = {true,SPR_MUT_W2_1,8,T_Chase,NULL,&s_mutchase3};\r
+statetype s_mutchase3  = {true,SPR_MUT_W3_1,10,T_Chase,NULL,&s_mutchase3s};\r
+statetype s_mutchase3s         = {true,SPR_MUT_W3_1,3,NULL,NULL,&s_mutchase4};\r
+statetype s_mutchase4  = {true,SPR_MUT_W4_1,8,T_Chase,NULL,&s_mutchase1};\r
+\r
+statetype s_mutdie1            = {false,SPR_MUT_DIE_1,7,NULL,A_DeathScream,&s_mutdie2};\r
+statetype s_mutdie2            = {false,SPR_MUT_DIE_2,7,NULL,NULL,&s_mutdie3};\r
+statetype s_mutdie3            = {false,SPR_MUT_DIE_3,7,NULL,NULL,&s_mutdie4};\r
+statetype s_mutdie4            = {false,SPR_MUT_DIE_4,7,NULL,NULL,&s_mutdie5};\r
+statetype s_mutdie5            = {false,SPR_MUT_DEAD,0,NULL,NULL,&s_mutdie5};\r
+\r
+\r
+//\r
+// SS\r
+//\r
+\r
+extern statetype s_ssstand;\r
+\r
+extern statetype s_sspath1;\r
+extern statetype s_sspath1s;\r
+extern statetype s_sspath2;\r
+extern statetype s_sspath3;\r
+extern statetype s_sspath3s;\r
+extern statetype s_sspath4;\r
+\r
+extern statetype s_sspain;\r
+extern statetype s_sspain1;\r
+\r
+extern statetype s_ssshoot1;\r
+extern statetype s_ssshoot2;\r
+extern statetype s_ssshoot3;\r
+extern statetype s_ssshoot4;\r
+extern statetype s_ssshoot5;\r
+extern statetype s_ssshoot6;\r
+extern statetype s_ssshoot7;\r
+extern statetype s_ssshoot8;\r
+extern statetype s_ssshoot9;\r
+\r
+extern statetype s_sschase1;\r
+extern statetype s_sschase1s;\r
+extern statetype s_sschase2;\r
+extern statetype s_sschase3;\r
+extern statetype s_sschase3s;\r
+extern statetype s_sschase4;\r
+\r
+extern statetype s_ssdie1;\r
+extern statetype s_ssdie2;\r
+extern statetype s_ssdie3;\r
+extern statetype s_ssdie4;\r
+\r
+statetype s_ssstand    = {true,SPR_SS_S_1,0,T_Stand,NULL,&s_ssstand};\r
+\r
+statetype s_sspath1    = {true,SPR_SS_W1_1,20,T_Path,NULL,&s_sspath1s};\r
+statetype s_sspath1s   = {true,SPR_SS_W1_1,5,NULL,NULL,&s_sspath2};\r
+statetype s_sspath2    = {true,SPR_SS_W2_1,15,T_Path,NULL,&s_sspath3};\r
+statetype s_sspath3    = {true,SPR_SS_W3_1,20,T_Path,NULL,&s_sspath3s};\r
+statetype s_sspath3s   = {true,SPR_SS_W3_1,5,NULL,NULL,&s_sspath4};\r
+statetype s_sspath4    = {true,SPR_SS_W4_1,15,T_Path,NULL,&s_sspath1};\r
+\r
+statetype s_sspain             = {2,SPR_SS_PAIN_1,10,NULL,NULL,&s_sschase1};\r
+statetype s_sspain1    = {2,SPR_SS_PAIN_2,10,NULL,NULL,&s_sschase1};\r
+\r
+statetype s_ssshoot1   = {false,SPR_SS_SHOOT1,20,NULL,NULL,&s_ssshoot2};\r
+statetype s_ssshoot2   = {false,SPR_SS_SHOOT2,20,NULL,T_Shoot,&s_ssshoot3};\r
+statetype s_ssshoot3   = {false,SPR_SS_SHOOT3,10,NULL,NULL,&s_ssshoot4};\r
+statetype s_ssshoot4   = {false,SPR_SS_SHOOT2,10,NULL,T_Shoot,&s_ssshoot5};\r
+statetype s_ssshoot5   = {false,SPR_SS_SHOOT3,10,NULL,NULL,&s_ssshoot6};\r
+statetype s_ssshoot6   = {false,SPR_SS_SHOOT2,10,NULL,T_Shoot,&s_ssshoot7};\r
+statetype s_ssshoot7   = {false,SPR_SS_SHOOT3,10,NULL,NULL,&s_ssshoot8};\r
+statetype s_ssshoot8   = {false,SPR_SS_SHOOT2,10,NULL,T_Shoot,&s_ssshoot9};\r
+statetype s_ssshoot9   = {false,SPR_SS_SHOOT3,10,NULL,NULL,&s_sschase1};\r
+\r
+statetype s_sschase1   = {true,SPR_SS_W1_1,10,T_Chase,NULL,&s_sschase1s};\r
+statetype s_sschase1s  = {true,SPR_SS_W1_1,3,NULL,NULL,&s_sschase2};\r
+statetype s_sschase2   = {true,SPR_SS_W2_1,8,T_Chase,NULL,&s_sschase3};\r
+statetype s_sschase3   = {true,SPR_SS_W3_1,10,T_Chase,NULL,&s_sschase3s};\r
+statetype s_sschase3s  = {true,SPR_SS_W3_1,3,NULL,NULL,&s_sschase4};\r
+statetype s_sschase4   = {true,SPR_SS_W4_1,8,T_Chase,NULL,&s_sschase1};\r
+\r
+statetype s_ssdie1             = {false,SPR_SS_DIE_1,15,NULL,A_DeathScream,&s_ssdie2};\r
+statetype s_ssdie2             = {false,SPR_SS_DIE_2,15,NULL,NULL,&s_ssdie3};\r
+statetype s_ssdie3             = {false,SPR_SS_DIE_3,15,NULL,NULL,&s_ssdie4};\r
+statetype s_ssdie4             = {false,SPR_SS_DEAD,0,NULL,NULL,&s_ssdie4};\r
+\r
+\r
+#ifndef SPEAR\r
+//\r
+// hans\r
+//\r
+extern statetype s_bossstand;\r
+\r
+extern statetype s_bosschase1;\r
+extern statetype s_bosschase1s;\r
+extern statetype s_bosschase2;\r
+extern statetype s_bosschase3;\r
+extern statetype s_bosschase3s;\r
+extern statetype s_bosschase4;\r
+\r
+extern statetype s_bossdie1;\r
+extern statetype s_bossdie2;\r
+extern statetype s_bossdie3;\r
+extern statetype s_bossdie4;\r
+\r
+extern statetype s_bossshoot1;\r
+extern statetype s_bossshoot2;\r
+extern statetype s_bossshoot3;\r
+extern statetype s_bossshoot4;\r
+extern statetype s_bossshoot5;\r
+extern statetype s_bossshoot6;\r
+extern statetype s_bossshoot7;\r
+extern statetype s_bossshoot8;\r
+\r
+\r
+statetype s_bossstand  = {false,SPR_BOSS_W1,0,T_Stand,NULL,&s_bossstand};\r
+\r
+statetype s_bosschase1         = {false,SPR_BOSS_W1,10,T_Chase,NULL,&s_bosschase1s};\r
+statetype s_bosschase1s        = {false,SPR_BOSS_W1,3,NULL,NULL,&s_bosschase2};\r
+statetype s_bosschase2         = {false,SPR_BOSS_W2,8,T_Chase,NULL,&s_bosschase3};\r
+statetype s_bosschase3         = {false,SPR_BOSS_W3,10,T_Chase,NULL,&s_bosschase3s};\r
+statetype s_bosschase3s        = {false,SPR_BOSS_W3,3,NULL,NULL,&s_bosschase4};\r
+statetype s_bosschase4         = {false,SPR_BOSS_W4,8,T_Chase,NULL,&s_bosschase1};\r
+\r
+statetype s_bossdie1   = {false,SPR_BOSS_DIE1,15,NULL,A_DeathScream,&s_bossdie2};\r
+statetype s_bossdie2   = {false,SPR_BOSS_DIE2,15,NULL,NULL,&s_bossdie3};\r
+statetype s_bossdie3   = {false,SPR_BOSS_DIE3,15,NULL,NULL,&s_bossdie4};\r
+statetype s_bossdie4   = {false,SPR_BOSS_DEAD,0,NULL,NULL,&s_bossdie4};\r
+\r
+statetype s_bossshoot1         = {false,SPR_BOSS_SHOOT1,30,NULL,NULL,&s_bossshoot2};\r
+statetype s_bossshoot2         = {false,SPR_BOSS_SHOOT2,10,NULL,T_Shoot,&s_bossshoot3};\r
+statetype s_bossshoot3         = {false,SPR_BOSS_SHOOT3,10,NULL,T_Shoot,&s_bossshoot4};\r
+statetype s_bossshoot4         = {false,SPR_BOSS_SHOOT2,10,NULL,T_Shoot,&s_bossshoot5};\r
+statetype s_bossshoot5         = {false,SPR_BOSS_SHOOT3,10,NULL,T_Shoot,&s_bossshoot6};\r
+statetype s_bossshoot6         = {false,SPR_BOSS_SHOOT2,10,NULL,T_Shoot,&s_bossshoot7};\r
+statetype s_bossshoot7         = {false,SPR_BOSS_SHOOT3,10,NULL,T_Shoot,&s_bossshoot8};\r
+statetype s_bossshoot8         = {false,SPR_BOSS_SHOOT1,10,NULL,NULL,&s_bosschase1};\r
+\r
+\r
+//\r
+// gretel\r
+//\r
+extern statetype s_gretelstand;\r
+\r
+extern statetype s_gretelchase1;\r
+extern statetype s_gretelchase1s;\r
+extern statetype s_gretelchase2;\r
+extern statetype s_gretelchase3;\r
+extern statetype s_gretelchase3s;\r
+extern statetype s_gretelchase4;\r
+\r
+extern statetype s_greteldie1;\r
+extern statetype s_greteldie2;\r
+extern statetype s_greteldie3;\r
+extern statetype s_greteldie4;\r
+\r
+extern statetype s_gretelshoot1;\r
+extern statetype s_gretelshoot2;\r
+extern statetype s_gretelshoot3;\r
+extern statetype s_gretelshoot4;\r
+extern statetype s_gretelshoot5;\r
+extern statetype s_gretelshoot6;\r
+extern statetype s_gretelshoot7;\r
+extern statetype s_gretelshoot8;\r
+\r
+\r
+statetype s_gretelstand        = {false,SPR_GRETEL_W1,0,T_Stand,NULL,&s_gretelstand};\r
+\r
+statetype s_gretelchase1       = {false,SPR_GRETEL_W1,10,T_Chase,NULL,&s_gretelchase1s};\r
+statetype s_gretelchase1s      = {false,SPR_GRETEL_W1,3,NULL,NULL,&s_gretelchase2};\r
+statetype s_gretelchase2       = {false,SPR_GRETEL_W2,8,T_Chase,NULL,&s_gretelchase3};\r
+statetype s_gretelchase3       = {false,SPR_GRETEL_W3,10,T_Chase,NULL,&s_gretelchase3s};\r
+statetype s_gretelchase3s      = {false,SPR_GRETEL_W3,3,NULL,NULL,&s_gretelchase4};\r
+statetype s_gretelchase4       = {false,SPR_GRETEL_W4,8,T_Chase,NULL,&s_gretelchase1};\r
+\r
+statetype s_greteldie1 = {false,SPR_GRETEL_DIE1,15,NULL,A_DeathScream,&s_greteldie2};\r
+statetype s_greteldie2 = {false,SPR_GRETEL_DIE2,15,NULL,NULL,&s_greteldie3};\r
+statetype s_greteldie3 = {false,SPR_GRETEL_DIE3,15,NULL,NULL,&s_greteldie4};\r
+statetype s_greteldie4 = {false,SPR_GRETEL_DEAD,0,NULL,NULL,&s_greteldie4};\r
+\r
+statetype s_gretelshoot1       = {false,SPR_GRETEL_SHOOT1,30,NULL,NULL,&s_gretelshoot2};\r
+statetype s_gretelshoot2       = {false,SPR_GRETEL_SHOOT2,10,NULL,T_Shoot,&s_gretelshoot3};\r
+statetype s_gretelshoot3       = {false,SPR_GRETEL_SHOOT3,10,NULL,T_Shoot,&s_gretelshoot4};\r
+statetype s_gretelshoot4       = {false,SPR_GRETEL_SHOOT2,10,NULL,T_Shoot,&s_gretelshoot5};\r
+statetype s_gretelshoot5       = {false,SPR_GRETEL_SHOOT3,10,NULL,T_Shoot,&s_gretelshoot6};\r
+statetype s_gretelshoot6       = {false,SPR_GRETEL_SHOOT2,10,NULL,T_Shoot,&s_gretelshoot7};\r
+statetype s_gretelshoot7       = {false,SPR_GRETEL_SHOOT3,10,NULL,T_Shoot,&s_gretelshoot8};\r
+statetype s_gretelshoot8       = {false,SPR_GRETEL_SHOOT1,10,NULL,NULL,&s_gretelchase1};\r
+#endif\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnStand\r
+=\r
+===============\r
+*/\r
+\r
+void SpawnStand (enemy_t which, int tilex, int tiley, int dir)\r
+{\r
+       unsigned        far *map,tile;\r
+\r
+       switch (which)\r
+       {\r
+       case en_guard:\r
+               SpawnNewObj (tilex,tiley,&s_grdstand);\r
+               new->speed = SPDPATROL;\r
+               if (!loadedgame)\r
+                 gamestate.killtotal++;\r
+               break;\r
+\r
+       case en_officer:\r
+               SpawnNewObj (tilex,tiley,&s_ofcstand);\r
+               new->speed = SPDPATROL;\r
+               if (!loadedgame)\r
+                 gamestate.killtotal++;\r
+               break;\r
+\r
+       case en_mutant:\r
+               SpawnNewObj (tilex,tiley,&s_mutstand);\r
+               new->speed = SPDPATROL;\r
+               if (!loadedgame)\r
+                 gamestate.killtotal++;\r
+               break;\r
+\r
+       case en_ss:\r
+               SpawnNewObj (tilex,tiley,&s_ssstand);\r
+               new->speed = SPDPATROL;\r
+               if (!loadedgame)\r
+                 gamestate.killtotal++;\r
+               break;\r
+       }\r
+\r
+\r
+       map = mapsegs[0]+farmapylookup[tiley]+tilex;\r
+       if (*map == AMBUSHTILE)\r
+       {\r
+               tilemap[tilex][tiley] = 0;\r
+\r
+               if (*(map+1) >= AREATILE)\r
+                       tile = *(map+1);\r
+               if (*(map-mapwidth) >= AREATILE)\r
+                       tile = *(map-mapwidth);\r
+               if (*(map+mapwidth) >= AREATILE)\r
+                       tile = *(map+mapwidth);\r
+               if ( *(map-1) >= AREATILE)\r
+                       tile = *(map-1);\r
+\r
+               *map = tile;\r
+               new->areanumber = tile-AREATILE;\r
+\r
+               new->flags |= FL_AMBUSH;\r
+       }\r
+\r
+       new->obclass = guardobj+which;\r
+       new->hitpoints = starthitpoints[gamestate.difficulty][which];\r
+       new->dir = dir*2;\r
+       new->flags |= FL_SHOOTABLE;\r
+}\r
+\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnDeadGuard\r
+=\r
+===============\r
+*/\r
+\r
+void SpawnDeadGuard (int tilex, int tiley)\r
+{\r
+       SpawnNewObj (tilex,tiley,&s_grddie4);\r
+       new->obclass = inertobj;\r
+}\r
+\r
+\r
+\r
+#ifndef SPEAR\r
+/*\r
+===============\r
+=\r
+= SpawnBoss\r
+=\r
+===============\r
+*/\r
+\r
+void SpawnBoss (int tilex, int tiley)\r
+{\r
+       unsigned        far *map,tile;\r
+\r
+       SpawnNewObj (tilex,tiley,&s_bossstand);\r
+       new->speed = SPDPATROL;\r
+\r
+       new->obclass = bossobj;\r
+       new->hitpoints = starthitpoints[gamestate.difficulty][en_boss];\r
+       new->dir = south;\r
+       new->flags |= FL_SHOOTABLE|FL_AMBUSH;\r
+       if (!loadedgame)\r
+         gamestate.killtotal++;\r
+}\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnGretel\r
+=\r
+===============\r
+*/\r
+\r
+void SpawnGretel (int tilex, int tiley)\r
+{\r
+       unsigned        far *map,tile;\r
+\r
+       SpawnNewObj (tilex,tiley,&s_gretelstand);\r
+       new->speed = SPDPATROL;\r
+\r
+       new->obclass = gretelobj;\r
+       new->hitpoints = starthitpoints[gamestate.difficulty][en_gretel];\r
+       new->dir = north;\r
+       new->flags |= FL_SHOOTABLE|FL_AMBUSH;\r
+       if (!loadedgame)\r
+         gamestate.killtotal++;\r
+}\r
+#endif\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnPatrol\r
+=\r
+===============\r
+*/\r
+\r
+void SpawnPatrol (enemy_t which, int tilex, int tiley, int dir)\r
+{\r
+       switch (which)\r
+       {\r
+       case en_guard:\r
+               SpawnNewObj (tilex,tiley,&s_grdpath1);\r
+               new->speed = SPDPATROL;\r
+               if (!loadedgame)\r
+                 gamestate.killtotal++;\r
+               break;\r
+\r
+       case en_officer:\r
+               SpawnNewObj (tilex,tiley,&s_ofcpath1);\r
+               new->speed = SPDPATROL;\r
+               if (!loadedgame)\r
+                 gamestate.killtotal++;\r
+               break;\r
+\r
+       case en_ss:\r
+               SpawnNewObj (tilex,tiley,&s_sspath1);\r
+               new->speed = SPDPATROL;\r
+               if (!loadedgame)\r
+                 gamestate.killtotal++;\r
+               break;\r
+\r
+       case en_mutant:\r
+               SpawnNewObj (tilex,tiley,&s_mutpath1);\r
+               new->speed = SPDPATROL;\r
+               if (!loadedgame)\r
+                 gamestate.killtotal++;\r
+               break;\r
+\r
+       case en_dog:\r
+               SpawnNewObj (tilex,tiley,&s_dogpath1);\r
+               new->speed = SPDDOG;\r
+               if (!loadedgame)\r
+                 gamestate.killtotal++;\r
+               break;\r
+       }\r
+\r
+       new->obclass = guardobj+which;\r
+       new->dir = dir*2;\r
+       new->hitpoints = starthitpoints[gamestate.difficulty][which];\r
+       new->distance = tileglobal;\r
+       new->flags |= FL_SHOOTABLE;\r
+       new->active = true;\r
+\r
+       actorat[new->tilex][new->tiley] = NULL;         // don't use original spot\r
+\r
+       switch (dir)\r
+       {\r
+       case 0:\r
+               new->tilex++;\r
+               break;\r
+       case 1:\r
+               new->tiley--;\r
+               break;\r
+       case 2:\r
+               new->tilex--;\r
+               break;\r
+       case 3:\r
+               new->tiley++;\r
+               break;\r
+       }\r
+\r
+       actorat[new->tilex][new->tiley] = new;\r
+}\r
+\r
+\r
+\r
+/*\r
+==================\r
+=\r
+= A_DeathScream\r
+=\r
+==================\r
+*/\r
+\r
+void A_DeathScream (objtype *ob)\r
+{\r
+#ifndef UPLOAD\r
+#ifndef SPEAR\r
+       if (mapon==9 && !US_RndT())\r
+#else\r
+       if ((mapon==18 || mapon==19) && !US_RndT())\r
+#endif\r
+       {\r
+        switch(ob->obclass)\r
+        {\r
+         case mutantobj:\r
+         case guardobj:\r
+         case officerobj:\r
+         case ssobj:\r
+         case dogobj:\r
+               PlaySoundLocActor(DEATHSCREAM6SND,ob);\r
+               return;\r
+        }\r
+       }\r
+#endif\r
+\r
+       switch (ob->obclass)\r
+       {\r
+       case mutantobj:\r
+               PlaySoundLocActor(AHHHGSND,ob);\r
+               break;\r
+\r
+       case guardobj:\r
+               {\r
+                int sounds[9]={ DEATHSCREAM1SND,\r
+                                DEATHSCREAM2SND,\r
+                                DEATHSCREAM3SND,\r
+                                DEATHSCREAM4SND,\r
+                                DEATHSCREAM5SND,\r
+                                DEATHSCREAM7SND,\r
+                                DEATHSCREAM8SND,\r
+                                DEATHSCREAM9SND\r
+                                };\r
+\r
+                #ifndef UPLOAD\r
+                PlaySoundLocActor(sounds[US_RndT()%8],ob);\r
+                #else\r
+                PlaySoundLocActor(sounds[US_RndT()%2],ob);\r
+                #endif\r
+               }\r
+               break;\r
+       case officerobj:\r
+               PlaySoundLocActor(NEINSOVASSND,ob);\r
+               break;\r
+       case ssobj:\r
+               PlaySoundLocActor(LEBENSND,ob); // JAB\r
+               break;\r
+       case dogobj:\r
+               PlaySoundLocActor(DOGDEATHSND,ob);      // JAB\r
+               break;\r
+#ifndef SPEAR\r
+       case bossobj:\r
+               SD_PlaySound(MUTTISND);                         // JAB\r
+               break;\r
+       case schabbobj:\r
+               SD_PlaySound(MEINGOTTSND);\r
+               break;\r
+       case fakeobj:\r
+               SD_PlaySound(HITLERHASND);\r
+               break;\r
+       case mechahitlerobj:\r
+               SD_PlaySound(SCHEISTSND);\r
+               break;\r
+       case realhitlerobj:\r
+               SD_PlaySound(EVASND);\r
+               break;\r
+       case gretelobj:\r
+               SD_PlaySound(MEINSND);\r
+               break;\r
+       case giftobj:\r
+               SD_PlaySound(DONNERSND);\r
+               break;\r
+       case fatobj:\r
+               SD_PlaySound(ROSESND);\r
+               break;\r
+#else\r
+       case spectreobj:\r
+               SD_PlaySound(GHOSTFADESND);\r
+               break;\r
+       case angelobj:\r
+               SD_PlaySound(ANGELDEATHSND);\r
+               break;\r
+       case transobj:\r
+               SD_PlaySound(TRANSDEATHSND);\r
+               break;\r
+       case uberobj:\r
+               SD_PlaySound(UBERDEATHSND);\r
+               break;\r
+       case willobj:\r
+               SD_PlaySound(WILHELMDEATHSND);\r
+               break;\r
+       case deathobj:\r
+               SD_PlaySound(KNIGHTDEATHSND);\r
+               break;\r
+#endif\r
+       }\r
+}\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                SPEAR ACTORS\r
+\r
+=============================================================================\r
+*/\r
+\r
+#ifdef SPEAR\r
+\r
+void T_Launch (objtype *ob);\r
+void T_Will (objtype *ob);\r
+\r
+extern statetype s_angelshoot1;\r
+extern statetype s_deathshoot1;\r
+extern statetype s_spark1;\r
+\r
+//\r
+// trans\r
+//\r
+extern statetype s_transstand;\r
+\r
+extern statetype s_transchase1;\r
+extern statetype s_transchase1s;\r
+extern statetype s_transchase2;\r
+extern statetype s_transchase3;\r
+extern statetype s_transchase3s;\r
+extern statetype s_transchase4;\r
+\r
+extern statetype s_transdie0;\r
+extern statetype s_transdie01;\r
+extern statetype s_transdie1;\r
+extern statetype s_transdie2;\r
+extern statetype s_transdie3;\r
+extern statetype s_transdie4;\r
+\r
+extern statetype s_transshoot1;\r
+extern statetype s_transshoot2;\r
+extern statetype s_transshoot3;\r
+extern statetype s_transshoot4;\r
+extern statetype s_transshoot5;\r
+extern statetype s_transshoot6;\r
+extern statetype s_transshoot7;\r
+extern statetype s_transshoot8;\r
+\r
+\r
+statetype s_transstand = {false,SPR_TRANS_W1,0,T_Stand,NULL,&s_transstand};\r
+\r
+statetype s_transchase1        = {false,SPR_TRANS_W1,10,T_Chase,NULL,&s_transchase1s};\r
+statetype s_transchase1s       = {false,SPR_TRANS_W1,3,NULL,NULL,&s_transchase2};\r
+statetype s_transchase2        = {false,SPR_TRANS_W2,8,T_Chase,NULL,&s_transchase3};\r
+statetype s_transchase3        = {false,SPR_TRANS_W3,10,T_Chase,NULL,&s_transchase3s};\r
+statetype s_transchase3s       = {false,SPR_TRANS_W3,3,NULL,NULL,&s_transchase4};\r
+statetype s_transchase4        = {false,SPR_TRANS_W4,8,T_Chase,NULL,&s_transchase1};\r
+\r
+statetype s_transdie0  = {false,SPR_TRANS_W1,1,NULL,A_DeathScream,&s_transdie01};\r
+statetype s_transdie01 = {false,SPR_TRANS_W1,1,NULL,NULL,&s_transdie1};\r
+statetype s_transdie1  = {false,SPR_TRANS_DIE1,15,NULL,NULL,&s_transdie2};\r
+statetype s_transdie2  = {false,SPR_TRANS_DIE2,15,NULL,NULL,&s_transdie3};\r
+statetype s_transdie3  = {false,SPR_TRANS_DIE3,15,NULL,NULL,&s_transdie4};\r
+statetype s_transdie4  = {false,SPR_TRANS_DEAD,0,NULL,NULL,&s_transdie4};\r
+\r
+statetype s_transshoot1        = {false,SPR_TRANS_SHOOT1,30,NULL,NULL,&s_transshoot2};\r
+statetype s_transshoot2        = {false,SPR_TRANS_SHOOT2,10,NULL,T_Shoot,&s_transshoot3};\r
+statetype s_transshoot3        = {false,SPR_TRANS_SHOOT3,10,NULL,T_Shoot,&s_transshoot4};\r
+statetype s_transshoot4        = {false,SPR_TRANS_SHOOT2,10,NULL,T_Shoot,&s_transshoot5};\r
+statetype s_transshoot5        = {false,SPR_TRANS_SHOOT3,10,NULL,T_Shoot,&s_transshoot6};\r
+statetype s_transshoot6        = {false,SPR_TRANS_SHOOT2,10,NULL,T_Shoot,&s_transshoot7};\r
+statetype s_transshoot7        = {false,SPR_TRANS_SHOOT3,10,NULL,T_Shoot,&s_transshoot8};\r
+statetype s_transshoot8        = {false,SPR_TRANS_SHOOT1,10,NULL,NULL,&s_transchase1};\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnTrans\r
+=\r
+===============\r
+*/\r
+\r
+void SpawnTrans (int tilex, int tiley)\r
+{\r
+       unsigned        far *map,tile;\r
+\r
+       if (SoundBlasterPresent && DigiMode != sds_Off)\r
+               s_transdie01.tictime = 105;\r
+\r
+       SpawnNewObj (tilex,tiley,&s_transstand);\r
+       new->obclass = transobj;\r
+       new->hitpoints = starthitpoints[gamestate.difficulty][en_trans];\r
+       new->flags |= FL_SHOOTABLE|FL_AMBUSH;\r
+       if (!loadedgame)\r
+         gamestate.killtotal++;\r
+}\r
+\r
+\r
+//\r
+// uber\r
+//\r
+void T_UShoot (objtype *ob);\r
+\r
+extern statetype s_uberstand;\r
+\r
+extern statetype s_uberchase1;\r
+extern statetype s_uberchase1s;\r
+extern statetype s_uberchase2;\r
+extern statetype s_uberchase3;\r
+extern statetype s_uberchase3s;\r
+extern statetype s_uberchase4;\r
+\r
+extern statetype s_uberdie0;\r
+extern statetype s_uberdie01;\r
+extern statetype s_uberdie1;\r
+extern statetype s_uberdie2;\r
+extern statetype s_uberdie3;\r
+extern statetype s_uberdie4;\r
+extern statetype s_uberdie5;\r
+\r
+extern statetype s_ubershoot1;\r
+extern statetype s_ubershoot2;\r
+extern statetype s_ubershoot3;\r
+extern statetype s_ubershoot4;\r
+extern statetype s_ubershoot5;\r
+extern statetype s_ubershoot6;\r
+extern statetype s_ubershoot7;\r
+\r
+\r
+statetype s_uberstand  = {false,SPR_UBER_W1,0,T_Stand,NULL,&s_uberstand};\r
+\r
+statetype s_uberchase1         = {false,SPR_UBER_W1,10,T_Chase,NULL,&s_uberchase1s};\r
+statetype s_uberchase1s        = {false,SPR_UBER_W1,3,NULL,NULL,&s_uberchase2};\r
+statetype s_uberchase2         = {false,SPR_UBER_W2,8,T_Chase,NULL,&s_uberchase3};\r
+statetype s_uberchase3         = {false,SPR_UBER_W3,10,T_Chase,NULL,&s_uberchase3s};\r
+statetype s_uberchase3s        = {false,SPR_UBER_W3,3,NULL,NULL,&s_uberchase4};\r
+statetype s_uberchase4         = {false,SPR_UBER_W4,8,T_Chase,NULL,&s_uberchase1};\r
+\r
+statetype s_uberdie0   = {false,SPR_UBER_W1,1,NULL,A_DeathScream,&s_uberdie01};\r
+statetype s_uberdie01  = {false,SPR_UBER_W1,1,NULL,NULL,&s_uberdie1};\r
+statetype s_uberdie1   = {false,SPR_UBER_DIE1,15,NULL,NULL,&s_uberdie2};\r
+statetype s_uberdie2   = {false,SPR_UBER_DIE2,15,NULL,NULL,&s_uberdie3};\r
+statetype s_uberdie3   = {false,SPR_UBER_DIE3,15,NULL,NULL,&s_uberdie4};\r
+statetype s_uberdie4   = {false,SPR_UBER_DIE4,15,NULL,NULL,&s_uberdie5};\r
+statetype s_uberdie5   = {false,SPR_UBER_DEAD,0,NULL,NULL,&s_uberdie5};\r
+\r
+statetype s_ubershoot1         = {false,SPR_UBER_SHOOT1,30,NULL,NULL,&s_ubershoot2};\r
+statetype s_ubershoot2         = {false,SPR_UBER_SHOOT2,12,NULL,T_UShoot,&s_ubershoot3};\r
+statetype s_ubershoot3         = {false,SPR_UBER_SHOOT3,12,NULL,T_UShoot,&s_ubershoot4};\r
+statetype s_ubershoot4         = {false,SPR_UBER_SHOOT4,12,NULL,T_UShoot,&s_ubershoot5};\r
+statetype s_ubershoot5         = {false,SPR_UBER_SHOOT3,12,NULL,T_UShoot,&s_ubershoot6};\r
+statetype s_ubershoot6         = {false,SPR_UBER_SHOOT2,12,NULL,T_UShoot,&s_ubershoot7};\r
+statetype s_ubershoot7         = {false,SPR_UBER_SHOOT1,12,NULL,NULL,&s_uberchase1};\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnUber\r
+=\r
+===============\r
+*/\r
+\r
+void SpawnUber (int tilex, int tiley)\r
+{\r
+       unsigned        far *map,tile;\r
+\r
+       if (SoundBlasterPresent && DigiMode != sds_Off)\r
+               s_uberdie01.tictime = 70;\r
+\r
+       SpawnNewObj (tilex,tiley,&s_uberstand);\r
+       new->obclass = uberobj;\r
+       new->hitpoints = starthitpoints[gamestate.difficulty][en_uber];\r
+       new->flags |= FL_SHOOTABLE|FL_AMBUSH;\r
+       if (!loadedgame)\r
+         gamestate.killtotal++;\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= T_UShoot\r
+=\r
+===============\r
+*/\r
+\r
+void T_UShoot (objtype *ob)\r
+{\r
+       int     dx,dy,dist;\r
+\r
+       T_Shoot (ob);\r
+\r
+       dx = abs(ob->tilex - player->tilex);\r
+       dy = abs(ob->tiley - player->tiley);\r
+       dist = dx>dy ? dx : dy;\r
+       if (dist <= 1)\r
+               TakeDamage (10,ob);\r
+}\r
+\r
+\r
+//\r
+// will\r
+//\r
+extern statetype s_willstand;\r
+\r
+extern statetype s_willchase1;\r
+extern statetype s_willchase1s;\r
+extern statetype s_willchase2;\r
+extern statetype s_willchase3;\r
+extern statetype s_willchase3s;\r
+extern statetype s_willchase4;\r
+\r
+extern statetype s_willdie1;\r
+extern statetype s_willdie2;\r
+extern statetype s_willdie3;\r
+extern statetype s_willdie4;\r
+extern statetype s_willdie5;\r
+extern statetype s_willdie6;\r
+\r
+extern statetype s_willshoot1;\r
+extern statetype s_willshoot2;\r
+extern statetype s_willshoot3;\r
+extern statetype s_willshoot4;\r
+extern statetype s_willshoot5;\r
+extern statetype s_willshoot6;\r
+\r
+\r
+statetype s_willstand  = {false,SPR_WILL_W1,0,T_Stand,NULL,&s_willstand};\r
+\r
+statetype s_willchase1         = {false,SPR_WILL_W1,10,T_Will,NULL,&s_willchase1s};\r
+statetype s_willchase1s        = {false,SPR_WILL_W1,3,NULL,NULL,&s_willchase2};\r
+statetype s_willchase2         = {false,SPR_WILL_W2,8,T_Will,NULL,&s_willchase3};\r
+statetype s_willchase3         = {false,SPR_WILL_W3,10,T_Will,NULL,&s_willchase3s};\r
+statetype s_willchase3s        = {false,SPR_WILL_W3,3,NULL,NULL,&s_willchase4};\r
+statetype s_willchase4         = {false,SPR_WILL_W4,8,T_Will,NULL,&s_willchase1};\r
+\r
+statetype s_willdeathcam       = {false,SPR_WILL_W1,1,NULL,NULL,&s_willdie1};\r
+\r
+statetype s_willdie1   = {false,SPR_WILL_W1,1,NULL,A_DeathScream,&s_willdie2};\r
+statetype s_willdie2   = {false,SPR_WILL_W1,10,NULL,NULL,&s_willdie3};\r
+statetype s_willdie3   = {false,SPR_WILL_DIE1,10,NULL,NULL,&s_willdie4};\r
+statetype s_willdie4   = {false,SPR_WILL_DIE2,10,NULL,NULL,&s_willdie5};\r
+statetype s_willdie5   = {false,SPR_WILL_DIE3,10,NULL,NULL,&s_willdie6};\r
+statetype s_willdie6   = {false,SPR_WILL_DEAD,20,NULL,NULL,&s_willdie6};\r
+\r
+statetype s_willshoot1         = {false,SPR_WILL_SHOOT1,30,NULL,NULL,&s_willshoot2};\r
+statetype s_willshoot2         = {false,SPR_WILL_SHOOT2,10,NULL,T_Launch,&s_willshoot3};\r
+statetype s_willshoot3         = {false,SPR_WILL_SHOOT3,10,NULL,T_Shoot,&s_willshoot4};\r
+statetype s_willshoot4         = {false,SPR_WILL_SHOOT4,10,NULL,T_Shoot,&s_willshoot5};\r
+statetype s_willshoot5         = {false,SPR_WILL_SHOOT3,10,NULL,T_Shoot,&s_willshoot6};\r
+statetype s_willshoot6         = {false,SPR_WILL_SHOOT4,10,NULL,T_Shoot,&s_willchase1};\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnWill\r
+=\r
+===============\r
+*/\r
+\r
+void SpawnWill (int tilex, int tiley)\r
+{\r
+       unsigned        far *map,tile;\r
+\r
+       if (SoundBlasterPresent && DigiMode != sds_Off)\r
+               s_willdie2.tictime = 70;\r
+\r
+       SpawnNewObj (tilex,tiley,&s_willstand);\r
+       new->obclass = willobj;\r
+       new->hitpoints = starthitpoints[gamestate.difficulty][en_will];\r
+       new->flags |= FL_SHOOTABLE|FL_AMBUSH;\r
+       if (!loadedgame)\r
+         gamestate.killtotal++;\r
+}\r
+\r
+\r
+/*\r
+================\r
+=\r
+= T_Will\r
+=\r
+================\r
+*/\r
+\r
+void T_Will (objtype *ob)\r
+{\r
+       long move;\r
+       int     dx,dy,dist;\r
+       boolean dodge;\r
+\r
+       dodge = false;\r
+       dx = abs(ob->tilex - player->tilex);\r
+       dy = abs(ob->tiley - player->tiley);\r
+       dist = dx>dy ? dx : dy;\r
+\r
+       if (CheckLine(ob))                                              // got a shot at player?\r
+       {\r
+               if ( US_RndT() < (tics<<3) )\r
+               {\r
+               //\r
+               // go into attack frame\r
+               //\r
+                       if (ob->obclass == willobj)\r
+                               NewState (ob,&s_willshoot1);\r
+                       else if (ob->obclass == angelobj)\r
+                               NewState (ob,&s_angelshoot1);\r
+                       else\r
+                               NewState (ob,&s_deathshoot1);\r
+                       return;\r
+               }\r
+               dodge = true;\r
+       }\r
+\r
+       if (ob->dir == nodir)\r
+       {\r
+               if (dodge)\r
+                       SelectDodgeDir (ob);\r
+               else\r
+                       SelectChaseDir (ob);\r
+               if (ob->dir == nodir)\r
+                       return;                                                 // object is blocked in\r
+       }\r
+\r
+       move = ob->speed*tics;\r
+\r
+       while (move)\r
+       {\r
+               if (ob->distance < 0)\r
+               {\r
+               //\r
+               // waiting for a door to open\r
+               //\r
+                       OpenDoor (-ob->distance-1);\r
+                       if (doorobjlist[-ob->distance-1].action != dr_open)\r
+                               return;\r
+                       ob->distance = TILEGLOBAL;      // go ahead, the door is now opoen\r
+               }\r
+\r
+               if (move < ob->distance)\r
+               {\r
+                       MoveObj (ob,move);\r
+                       break;\r
+               }\r
+\r
+               //\r
+               // reached goal tile, so select another one\r
+               //\r
+\r
+               //\r
+               // fix position to account for round off during moving\r
+               //\r
+               ob->x = ((long)ob->tilex<<TILESHIFT)+TILEGLOBAL/2;\r
+               ob->y = ((long)ob->tiley<<TILESHIFT)+TILEGLOBAL/2;\r
+\r
+               move -= ob->distance;\r
+\r
+               if (dist <4)\r
+                       SelectRunDir (ob);\r
+               else if (dodge)\r
+                       SelectDodgeDir (ob);\r
+               else\r
+                       SelectChaseDir (ob);\r
+\r
+               if (ob->dir == nodir)\r
+                       return;                                                 // object is blocked in\r
+       }\r
+\r
+}\r
+\r
+\r
+//\r
+// death\r
+//\r
+extern statetype s_deathstand;\r
+\r
+extern statetype s_deathchase1;\r
+extern statetype s_deathchase1s;\r
+extern statetype s_deathchase2;\r
+extern statetype s_deathchase3;\r
+extern statetype s_deathchase3s;\r
+extern statetype s_deathchase4;\r
+\r
+extern statetype s_deathdie1;\r
+extern statetype s_deathdie2;\r
+extern statetype s_deathdie3;\r
+extern statetype s_deathdie4;\r
+extern statetype s_deathdie5;\r
+extern statetype s_deathdie6;\r
+extern statetype s_deathdie7;\r
+extern statetype s_deathdie8;\r
+extern statetype s_deathdie9;\r
+\r
+extern statetype s_deathshoot1;\r
+extern statetype s_deathshoot2;\r
+extern statetype s_deathshoot3;\r
+extern statetype s_deathshoot4;\r
+extern statetype s_deathshoot5;\r
+\r
+\r
+statetype s_deathstand = {false,SPR_DEATH_W1,0,T_Stand,NULL,&s_deathstand};\r
+\r
+statetype s_deathchase1        = {false,SPR_DEATH_W1,10,T_Will,NULL,&s_deathchase1s};\r
+statetype s_deathchase1s       = {false,SPR_DEATH_W1,3,NULL,NULL,&s_deathchase2};\r
+statetype s_deathchase2        = {false,SPR_DEATH_W2,8,T_Will,NULL,&s_deathchase3};\r
+statetype s_deathchase3        = {false,SPR_DEATH_W3,10,T_Will,NULL,&s_deathchase3s};\r
+statetype s_deathchase3s       = {false,SPR_DEATH_W3,3,NULL,NULL,&s_deathchase4};\r
+statetype s_deathchase4        = {false,SPR_DEATH_W4,8,T_Will,NULL,&s_deathchase1};\r
+\r
+statetype s_deathdeathcam      = {false,SPR_DEATH_W1,1,NULL,NULL,&s_deathdie1};\r
+\r
+statetype s_deathdie1  = {false,SPR_DEATH_W1,1,NULL,A_DeathScream,&s_deathdie2};\r
+statetype s_deathdie2  = {false,SPR_DEATH_W1,10,NULL,NULL,&s_deathdie3};\r
+statetype s_deathdie3  = {false,SPR_DEATH_DIE1,10,NULL,NULL,&s_deathdie4};\r
+statetype s_deathdie4  = {false,SPR_DEATH_DIE2,10,NULL,NULL,&s_deathdie5};\r
+statetype s_deathdie5  = {false,SPR_DEATH_DIE3,10,NULL,NULL,&s_deathdie6};\r
+statetype s_deathdie6  = {false,SPR_DEATH_DIE4,10,NULL,NULL,&s_deathdie7};\r
+statetype s_deathdie7  = {false,SPR_DEATH_DIE5,10,NULL,NULL,&s_deathdie8};\r
+statetype s_deathdie8  = {false,SPR_DEATH_DIE6,10,NULL,NULL,&s_deathdie9};\r
+statetype s_deathdie9  = {false,SPR_DEATH_DEAD,0,NULL,NULL,&s_deathdie9};\r
+\r
+statetype s_deathshoot1        = {false,SPR_DEATH_SHOOT1,30,NULL,NULL,&s_deathshoot2};\r
+statetype s_deathshoot2        = {false,SPR_DEATH_SHOOT2,10,NULL,T_Launch,&s_deathshoot3};\r
+statetype s_deathshoot3        = {false,SPR_DEATH_SHOOT4,10,NULL,T_Shoot,&s_deathshoot4};\r
+statetype s_deathshoot4        = {false,SPR_DEATH_SHOOT3,10,NULL,T_Launch,&s_deathshoot5};\r
+statetype s_deathshoot5        = {false,SPR_DEATH_SHOOT4,10,NULL,T_Shoot,&s_deathchase1};\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnDeath\r
+=\r
+===============\r
+*/\r
+\r
+void SpawnDeath (int tilex, int tiley)\r
+{\r
+       unsigned        far *map,tile;\r
+\r
+       if (SoundBlasterPresent && DigiMode != sds_Off)\r
+               s_deathdie2.tictime = 105;\r
+\r
+       SpawnNewObj (tilex,tiley,&s_deathstand);\r
+       new->obclass = deathobj;\r
+       new->hitpoints = starthitpoints[gamestate.difficulty][en_death];\r
+       new->flags |= FL_SHOOTABLE|FL_AMBUSH;\r
+       if (!loadedgame)\r
+         gamestate.killtotal++;\r
+}\r
+\r
+/*\r
+===============\r
+=\r
+= T_Launch\r
+=\r
+===============\r
+*/\r
+\r
+void T_Launch (objtype *ob)\r
+{\r
+       long    deltax,deltay;\r
+       float   angle;\r
+       int             iangle;\r
+\r
+       deltax = player->x - ob->x;\r
+       deltay = ob->y - player->y;\r
+       angle = atan2 (deltay,deltax);\r
+       if (angle<0)\r
+               angle = M_PI*2+angle;\r
+       iangle = angle/(M_PI*2)*ANGLES;\r
+       if (ob->obclass == deathobj)\r
+       {\r
+               T_Shoot (ob);\r
+               if (ob->state == &s_deathshoot2)\r
+               {\r
+                       iangle-=4;\r
+                       if (iangle<0)\r
+                               iangle+=ANGLES;\r
+               }\r
+               else\r
+               {\r
+                       iangle+=4;\r
+                       if (iangle>=ANGLES)\r
+                               iangle-=ANGLES;\r
+               }\r
+       }\r
+\r
+       GetNewActor ();\r
+       new->state = &s_rocket;\r
+       new->ticcount = 1;\r
+\r
+       new->tilex = ob->tilex;\r
+       new->tiley = ob->tiley;\r
+       new->x = ob->x;\r
+       new->y = ob->y;\r
+       new->obclass = rocketobj;\r
+       switch(ob->obclass)\r
+       {\r
+       case deathobj:\r
+               new->state = &s_hrocket;\r
+               new->obclass = hrocketobj;\r
+               PlaySoundLocActor (KNIGHTMISSILESND,new);\r
+               break;\r
+       case angelobj:\r
+               new->state = &s_spark1;\r
+               new->obclass = sparkobj;\r
+               PlaySoundLocActor (ANGELFIRESND,new);\r
+               break;\r
+       default:\r
+               PlaySoundLocActor (MISSILEFIRESND,new);\r
+       }\r
+\r
+       new->dir = nodir;\r
+       new->angle = iangle;\r
+       new->speed = 0x2000l;\r
+       new->flags = FL_NONMARK;\r
+       new->active = true;\r
+}\r
+\r
+\r
+\r
+//\r
+// angel\r
+//\r
+void A_Relaunch (objtype *ob);\r
+void A_Victory (objtype *ob);\r
+void A_StartAttack (objtype *ob);\r
+void A_Breathing (objtype *ob);\r
+\r
+extern statetype s_angelstand;\r
+\r
+extern statetype s_angelchase1;\r
+extern statetype s_angelchase1s;\r
+extern statetype s_angelchase2;\r
+extern statetype s_angelchase3;\r
+extern statetype s_angelchase3s;\r
+extern statetype s_angelchase4;\r
+\r
+extern statetype s_angeldie1;\r
+extern statetype s_angeldie11;\r
+extern statetype s_angeldie2;\r
+extern statetype s_angeldie3;\r
+extern statetype s_angeldie4;\r
+extern statetype s_angeldie5;\r
+extern statetype s_angeldie6;\r
+extern statetype s_angeldie7;\r
+extern statetype s_angeldie8;\r
+extern statetype s_angeldie9;\r
+\r
+extern statetype s_angelshoot1;\r
+extern statetype s_angelshoot2;\r
+extern statetype s_angelshoot3;\r
+extern statetype s_angelshoot4;\r
+extern statetype s_angelshoot5;\r
+extern statetype s_angelshoot6;\r
+\r
+extern statetype s_angeltired;\r
+extern statetype s_angeltired2;\r
+extern statetype s_angeltired3;\r
+extern statetype s_angeltired4;\r
+extern statetype s_angeltired5;\r
+extern statetype s_angeltired6;\r
+extern statetype s_angeltired7;\r
+\r
+extern statetype s_spark1;\r
+extern statetype s_spark2;\r
+extern statetype s_spark3;\r
+extern statetype s_spark4;\r
+\r
+\r
+statetype s_angelstand = {false,SPR_ANGEL_W1,0,T_Stand,NULL,&s_angelstand};\r
+\r
+statetype s_angelchase1        = {false,SPR_ANGEL_W1,10,T_Will,NULL,&s_angelchase1s};\r
+statetype s_angelchase1s       = {false,SPR_ANGEL_W1,3,NULL,NULL,&s_angelchase2};\r
+statetype s_angelchase2        = {false,SPR_ANGEL_W2,8,T_Will,NULL,&s_angelchase3};\r
+statetype s_angelchase3        = {false,SPR_ANGEL_W3,10,T_Will,NULL,&s_angelchase3s};\r
+statetype s_angelchase3s       = {false,SPR_ANGEL_W3,3,NULL,NULL,&s_angelchase4};\r
+statetype s_angelchase4        = {false,SPR_ANGEL_W4,8,T_Will,NULL,&s_angelchase1};\r
+\r
+statetype s_angeldie1  = {false,SPR_ANGEL_W1,1,NULL,A_DeathScream,&s_angeldie11};\r
+statetype s_angeldie11 = {false,SPR_ANGEL_W1,1,NULL,NULL,&s_angeldie2};\r
+statetype s_angeldie2  = {false,SPR_ANGEL_DIE1,10,NULL,A_Slurpie,&s_angeldie3};\r
+statetype s_angeldie3  = {false,SPR_ANGEL_DIE2,10,NULL,NULL,&s_angeldie4};\r
+statetype s_angeldie4  = {false,SPR_ANGEL_DIE3,10,NULL,NULL,&s_angeldie5};\r
+statetype s_angeldie5  = {false,SPR_ANGEL_DIE4,10,NULL,NULL,&s_angeldie6};\r
+statetype s_angeldie6  = {false,SPR_ANGEL_DIE5,10,NULL,NULL,&s_angeldie7};\r
+statetype s_angeldie7  = {false,SPR_ANGEL_DIE6,10,NULL,NULL,&s_angeldie8};\r
+statetype s_angeldie8  = {false,SPR_ANGEL_DIE7,10,NULL,NULL,&s_angeldie9};\r
+statetype s_angeldie9  = {false,SPR_ANGEL_DEAD,130,NULL,A_Victory,&s_angeldie9};\r
+\r
+statetype s_angelshoot1        = {false,SPR_ANGEL_SHOOT1,10,NULL,A_StartAttack,&s_angelshoot2};\r
+statetype s_angelshoot2        = {false,SPR_ANGEL_SHOOT2,20,NULL,T_Launch,&s_angelshoot3};\r
+statetype s_angelshoot3        = {false,SPR_ANGEL_SHOOT1,10,NULL,A_Relaunch,&s_angelshoot2};\r
+\r
+statetype s_angeltired         = {false,SPR_ANGEL_TIRED1,40,NULL,A_Breathing,&s_angeltired2};\r
+statetype s_angeltired2        = {false,SPR_ANGEL_TIRED2,40,NULL,NULL,&s_angeltired3};\r
+statetype s_angeltired3        = {false,SPR_ANGEL_TIRED1,40,NULL,A_Breathing,&s_angeltired4};\r
+statetype s_angeltired4        = {false,SPR_ANGEL_TIRED2,40,NULL,NULL,&s_angeltired5};\r
+statetype s_angeltired5        = {false,SPR_ANGEL_TIRED1,40,NULL,A_Breathing,&s_angeltired6};\r
+statetype s_angeltired6        = {false,SPR_ANGEL_TIRED2,40,NULL,NULL,&s_angeltired7};\r
+statetype s_angeltired7        = {false,SPR_ANGEL_TIRED1,40,NULL,A_Breathing,&s_angelchase1};\r
+\r
+statetype s_spark1     = {false,SPR_SPARK1,6,T_Projectile,NULL,&s_spark2};\r
+statetype s_spark2     = {false,SPR_SPARK2,6,T_Projectile,NULL,&s_spark3};\r
+statetype s_spark3     = {false,SPR_SPARK3,6,T_Projectile,NULL,&s_spark4};\r
+statetype s_spark4     = {false,SPR_SPARK4,6,T_Projectile,NULL,&s_spark1};\r
+\r
+\r
+#pragma argsused\r
+void A_Slurpie (objtype *ob)\r
+{\r
+ SD_PlaySound(SLURPIESND);\r
+}\r
+\r
+#pragma argsused\r
+void A_Breathing (objtype *ob)\r
+{\r
+ SD_PlaySound(ANGELTIREDSND);\r
+}\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnAngel\r
+=\r
+===============\r
+*/\r
+\r
+void SpawnAngel (int tilex, int tiley)\r
+{\r
+       unsigned        far *map,tile;\r
+\r
+\r
+       if (SoundBlasterPresent && DigiMode != sds_Off)\r
+               s_angeldie11.tictime = 105;\r
+\r
+       SpawnNewObj (tilex,tiley,&s_angelstand);\r
+       new->obclass = angelobj;\r
+       new->hitpoints = starthitpoints[gamestate.difficulty][en_angel];\r
+       new->flags |= FL_SHOOTABLE|FL_AMBUSH;\r
+       if (!loadedgame)\r
+         gamestate.killtotal++;\r
+}\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= A_Victory\r
+=\r
+=================\r
+*/\r
+\r
+#pragma argsused\r
+void A_Victory (objtype *ob)\r
+{\r
+       playstate = ex_victorious;\r
+}\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= A_StartAttack\r
+=\r
+=================\r
+*/\r
+\r
+void A_StartAttack (objtype *ob)\r
+{\r
+       ob->temp1 = 0;\r
+}\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= A_Relaunch\r
+=\r
+=================\r
+*/\r
+\r
+void A_Relaunch (objtype *ob)\r
+{\r
+       if (++ob->temp1 == 3)\r
+       {\r
+               NewState (ob,&s_angeltired);\r
+               return;\r
+       }\r
+\r
+       if (US_RndT()&1)\r
+       {\r
+               NewState (ob,&s_angelchase1);\r
+               return;\r
+       }\r
+}\r
+\r
+\r
+\r
+\r
+//\r
+// spectre\r
+//\r
+void T_SpectreWait (objtype *ob);\r
+void A_Dormant (objtype *ob);\r
+\r
+extern statetype s_spectrewait1;\r
+extern statetype s_spectrewait2;\r
+extern statetype s_spectrewait3;\r
+extern statetype s_spectrewait4;\r
+\r
+extern statetype s_spectrechase1;\r
+extern statetype s_spectrechase2;\r
+extern statetype s_spectrechase3;\r
+extern statetype s_spectrechase4;\r
+\r
+extern statetype s_spectredie1;\r
+extern statetype s_spectredie2;\r
+extern statetype s_spectredie3;\r
+extern statetype s_spectredie4;\r
+\r
+extern statetype s_spectrewake;\r
+\r
+statetype s_spectrewait1       = {false,SPR_SPECTRE_W1,10,T_Stand,NULL,&s_spectrewait2};\r
+statetype s_spectrewait2       = {false,SPR_SPECTRE_W2,10,T_Stand,NULL,&s_spectrewait3};\r
+statetype s_spectrewait3       = {false,SPR_SPECTRE_W3,10,T_Stand,NULL,&s_spectrewait4};\r
+statetype s_spectrewait4       = {false,SPR_SPECTRE_W4,10,T_Stand,NULL,&s_spectrewait1};\r
+\r
+statetype s_spectrechase1      = {false,SPR_SPECTRE_W1,10,T_Ghosts,NULL,&s_spectrechase2};\r
+statetype s_spectrechase2      = {false,SPR_SPECTRE_W2,10,T_Ghosts,NULL,&s_spectrechase3};\r
+statetype s_spectrechase3      = {false,SPR_SPECTRE_W3,10,T_Ghosts,NULL,&s_spectrechase4};\r
+statetype s_spectrechase4      = {false,SPR_SPECTRE_W4,10,T_Ghosts,NULL,&s_spectrechase1};\r
+\r
+statetype s_spectredie1        = {false,SPR_SPECTRE_F1,10,NULL,NULL,&s_spectredie2};\r
+statetype s_spectredie2        = {false,SPR_SPECTRE_F2,10,NULL,NULL,&s_spectredie3};\r
+statetype s_spectredie3        = {false,SPR_SPECTRE_F3,10,NULL,NULL,&s_spectredie4};\r
+statetype s_spectredie4        = {false,SPR_SPECTRE_F4,300,NULL,NULL,&s_spectrewake};\r
+statetype s_spectrewake        = {false,SPR_SPECTRE_F4,10,NULL,A_Dormant,&s_spectrewake};\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnSpectre\r
+=\r
+===============\r
+*/\r
+\r
+void SpawnSpectre (int tilex, int tiley)\r
+{\r
+       unsigned        far *map,tile;\r
+\r
+       SpawnNewObj (tilex,tiley,&s_spectrewait1);\r
+       new->obclass = spectreobj;\r
+       new->hitpoints = starthitpoints[gamestate.difficulty][en_spectre];\r
+       new->flags |= FL_SHOOTABLE|FL_AMBUSH; // |FL_NEVERMARK|FL_NONMARK;\r
+       if (!loadedgame)\r
+         gamestate.killtotal++;\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= A_Dormant\r
+=\r
+===============\r
+*/\r
+\r
+void A_Dormant (objtype *ob)\r
+{\r
+       long    deltax,deltay;\r
+       int     xl,xh,yl,yh;\r
+       int     x,y;\r
+       unsigned        tile;\r
+\r
+       deltax = ob->x - player->x;\r
+       if (deltax < -MINACTORDIST || deltax > MINACTORDIST)\r
+               goto moveok;\r
+       deltay = ob->y - player->y;\r
+       if (deltay < -MINACTORDIST || deltay > MINACTORDIST)\r
+               goto moveok;\r
+\r
+       return;\r
+moveok:\r
+\r
+       xl = (ob->x-MINDIST) >> TILESHIFT;\r
+       xh = (ob->x+MINDIST) >> TILESHIFT;\r
+       yl = (ob->y-MINDIST) >> TILESHIFT;\r
+       yh = (ob->y+MINDIST) >> TILESHIFT;\r
+\r
+       for (y=yl ; y<=yh ; y++)\r
+               for (x=xl ; x<=xh ; x++)\r
+               {\r
+                       tile = actorat[x][y];\r
+                       if (!tile)\r
+                               continue;\r
+                       if (tile<256)\r
+                               return;\r
+                       if (((objtype *)tile)->flags&FL_SHOOTABLE)\r
+                               return;\r
+               }\r
+\r
+       ob->flags |= FL_AMBUSH | FL_SHOOTABLE;\r
+       ob->flags &= ~FL_ATTACKMODE;\r
+       ob->dir = nodir;\r
+       NewState (ob,&s_spectrewait1);\r
+}\r
+\r
+\r
+#endif\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                SCHABBS / GIFT / FAT\r
+\r
+=============================================================================\r
+*/\r
+\r
+#ifndef SPEAR\r
+/*\r
+===============\r
+=\r
+= SpawnGhosts\r
+=\r
+===============\r
+*/\r
+\r
+void SpawnGhosts (int which, int tilex, int tiley)\r
+{\r
+       unsigned        far *map,tile;\r
+\r
+       switch(which)\r
+       {\r
+        case en_blinky:\r
+          SpawnNewObj (tilex,tiley,&s_blinkychase1);\r
+          break;\r
+        case en_clyde:\r
+          SpawnNewObj (tilex,tiley,&s_clydechase1);\r
+          break;\r
+        case en_pinky:\r
+          SpawnNewObj (tilex,tiley,&s_pinkychase1);\r
+          break;\r
+        case en_inky:\r
+          SpawnNewObj (tilex,tiley,&s_inkychase1);\r
+          break;\r
+       }\r
+\r
+       new->obclass = ghostobj;\r
+       new->speed = SPDDOG;\r
+\r
+       new->dir = east;\r
+       new->flags |= FL_AMBUSH;\r
+       if (!loadedgame)\r
+         gamestate.killtotal++;\r
+}\r
+\r
+\r
+\r
+void   T_Gift (objtype *ob);\r
+void   T_GiftThrow (objtype *ob);\r
+\r
+void   T_Fat (objtype *ob);\r
+void   T_FatThrow (objtype *ob);\r
+\r
+//\r
+// schabb\r
+//\r
+extern statetype s_schabbstand;\r
+\r
+extern statetype s_schabbchase1;\r
+extern statetype s_schabbchase1s;\r
+extern statetype s_schabbchase2;\r
+extern statetype s_schabbchase3;\r
+extern statetype s_schabbchase3s;\r
+extern statetype s_schabbchase4;\r
+\r
+extern statetype s_schabbdie1;\r
+extern statetype s_schabbdie2;\r
+extern statetype s_schabbdie3;\r
+extern statetype s_schabbdie4;\r
+extern statetype s_schabbdie5;\r
+extern statetype s_schabbdie6;\r
+\r
+extern statetype s_schabbshoot1;\r
+extern statetype s_schabbshoot2;\r
+\r
+extern statetype s_needle1;\r
+extern statetype s_needle2;\r
+extern statetype s_needle3;\r
+extern statetype s_needle4;\r
+\r
+extern statetype s_schabbdeathcam;\r
+\r
+\r
+statetype s_schabbstand        = {false,SPR_SCHABB_W1,0,T_Stand,NULL,&s_schabbstand};\r
+\r
+statetype s_schabbchase1       = {false,SPR_SCHABB_W1,10,T_Schabb,NULL,&s_schabbchase1s};\r
+statetype s_schabbchase1s      = {false,SPR_SCHABB_W1,3,NULL,NULL,&s_schabbchase2};\r
+statetype s_schabbchase2       = {false,SPR_SCHABB_W2,8,T_Schabb,NULL,&s_schabbchase3};\r
+statetype s_schabbchase3       = {false,SPR_SCHABB_W3,10,T_Schabb,NULL,&s_schabbchase3s};\r
+statetype s_schabbchase3s      = {false,SPR_SCHABB_W3,3,NULL,NULL,&s_schabbchase4};\r
+statetype s_schabbchase4       = {false,SPR_SCHABB_W4,8,T_Schabb,NULL,&s_schabbchase1};\r
+\r
+statetype s_schabbdeathcam     = {false,SPR_SCHABB_W1,1,NULL,NULL,&s_schabbdie1};\r
+\r
+statetype s_schabbdie1 = {false,SPR_SCHABB_W1,10,NULL,A_DeathScream,&s_schabbdie2};\r
+statetype s_schabbdie2 = {false,SPR_SCHABB_W1,10,NULL,NULL,&s_schabbdie3};\r
+statetype s_schabbdie3 = {false,SPR_SCHABB_DIE1,10,NULL,NULL,&s_schabbdie4};\r
+statetype s_schabbdie4 = {false,SPR_SCHABB_DIE2,10,NULL,NULL,&s_schabbdie5};\r
+statetype s_schabbdie5 = {false,SPR_SCHABB_DIE3,10,NULL,NULL,&s_schabbdie6};\r
+statetype s_schabbdie6 = {false,SPR_SCHABB_DEAD,20,NULL,A_StartDeathCam,&s_schabbdie6};\r
+\r
+statetype s_schabbshoot1       = {false,SPR_SCHABB_SHOOT1,30,NULL,NULL,&s_schabbshoot2};\r
+statetype s_schabbshoot2       = {false,SPR_SCHABB_SHOOT2,10,NULL,T_SchabbThrow,&s_schabbchase1};\r
+\r
+statetype s_needle1    = {false,SPR_HYPO1,6,T_Projectile,NULL,&s_needle2};\r
+statetype s_needle2    = {false,SPR_HYPO2,6,T_Projectile,NULL,&s_needle3};\r
+statetype s_needle3    = {false,SPR_HYPO3,6,T_Projectile,NULL,&s_needle4};\r
+statetype s_needle4    = {false,SPR_HYPO4,6,T_Projectile,NULL,&s_needle1};\r
+\r
+\r
+//\r
+// gift\r
+//\r
+extern statetype s_giftstand;\r
+\r
+extern statetype s_giftchase1;\r
+extern statetype s_giftchase1s;\r
+extern statetype s_giftchase2;\r
+extern statetype s_giftchase3;\r
+extern statetype s_giftchase3s;\r
+extern statetype s_giftchase4;\r
+\r
+extern statetype s_giftdie1;\r
+extern statetype s_giftdie2;\r
+extern statetype s_giftdie3;\r
+extern statetype s_giftdie4;\r
+extern statetype s_giftdie5;\r
+extern statetype s_giftdie6;\r
+\r
+extern statetype s_giftshoot1;\r
+extern statetype s_giftshoot2;\r
+\r
+extern statetype s_needle1;\r
+extern statetype s_needle2;\r
+extern statetype s_needle3;\r
+extern statetype s_needle4;\r
+\r
+extern statetype s_giftdeathcam;\r
+\r
+extern statetype s_boom1;\r
+extern statetype s_boom2;\r
+extern statetype s_boom3;\r
+\r
+\r
+statetype s_giftstand  = {false,SPR_GIFT_W1,0,T_Stand,NULL,&s_giftstand};\r
+\r
+statetype s_giftchase1         = {false,SPR_GIFT_W1,10,T_Gift,NULL,&s_giftchase1s};\r
+statetype s_giftchase1s        = {false,SPR_GIFT_W1,3,NULL,NULL,&s_giftchase2};\r
+statetype s_giftchase2         = {false,SPR_GIFT_W2,8,T_Gift,NULL,&s_giftchase3};\r
+statetype s_giftchase3         = {false,SPR_GIFT_W3,10,T_Gift,NULL,&s_giftchase3s};\r
+statetype s_giftchase3s        = {false,SPR_GIFT_W3,3,NULL,NULL,&s_giftchase4};\r
+statetype s_giftchase4         = {false,SPR_GIFT_W4,8,T_Gift,NULL,&s_giftchase1};\r
+\r
+statetype s_giftdeathcam       = {false,SPR_GIFT_W1,1,NULL,NULL,&s_giftdie1};\r
+\r
+statetype s_giftdie1   = {false,SPR_GIFT_W1,1,NULL,A_DeathScream,&s_giftdie2};\r
+statetype s_giftdie2   = {false,SPR_GIFT_W1,10,NULL,NULL,&s_giftdie3};\r
+statetype s_giftdie3   = {false,SPR_GIFT_DIE1,10,NULL,NULL,&s_giftdie4};\r
+statetype s_giftdie4   = {false,SPR_GIFT_DIE2,10,NULL,NULL,&s_giftdie5};\r
+statetype s_giftdie5   = {false,SPR_GIFT_DIE3,10,NULL,NULL,&s_giftdie6};\r
+statetype s_giftdie6   = {false,SPR_GIFT_DEAD,20,NULL,A_StartDeathCam,&s_giftdie6};\r
+\r
+statetype s_giftshoot1         = {false,SPR_GIFT_SHOOT1,30,NULL,NULL,&s_giftshoot2};\r
+statetype s_giftshoot2         = {false,SPR_GIFT_SHOOT2,10,NULL,T_GiftThrow,&s_giftchase1};\r
+\r
+\r
+//\r
+// fat\r
+//\r
+extern statetype s_fatstand;\r
+\r
+extern statetype s_fatchase1;\r
+extern statetype s_fatchase1s;\r
+extern statetype s_fatchase2;\r
+extern statetype s_fatchase3;\r
+extern statetype s_fatchase3s;\r
+extern statetype s_fatchase4;\r
+\r
+extern statetype s_fatdie1;\r
+extern statetype s_fatdie2;\r
+extern statetype s_fatdie3;\r
+extern statetype s_fatdie4;\r
+extern statetype s_fatdie5;\r
+extern statetype s_fatdie6;\r
+\r
+extern statetype s_fatshoot1;\r
+extern statetype s_fatshoot2;\r
+extern statetype s_fatshoot3;\r
+extern statetype s_fatshoot4;\r
+extern statetype s_fatshoot5;\r
+extern statetype s_fatshoot6;\r
+\r
+extern statetype s_needle1;\r
+extern statetype s_needle2;\r
+extern statetype s_needle3;\r
+extern statetype s_needle4;\r
+\r
+extern statetype s_fatdeathcam;\r
+\r
+\r
+statetype s_fatstand   = {false,SPR_FAT_W1,0,T_Stand,NULL,&s_fatstand};\r
+\r
+statetype s_fatchase1  = {false,SPR_FAT_W1,10,T_Fat,NULL,&s_fatchase1s};\r
+statetype s_fatchase1s = {false,SPR_FAT_W1,3,NULL,NULL,&s_fatchase2};\r
+statetype s_fatchase2  = {false,SPR_FAT_W2,8,T_Fat,NULL,&s_fatchase3};\r
+statetype s_fatchase3  = {false,SPR_FAT_W3,10,T_Fat,NULL,&s_fatchase3s};\r
+statetype s_fatchase3s = {false,SPR_FAT_W3,3,NULL,NULL,&s_fatchase4};\r
+statetype s_fatchase4  = {false,SPR_FAT_W4,8,T_Fat,NULL,&s_fatchase1};\r
+\r
+statetype s_fatdeathcam        = {false,SPR_FAT_W1,1,NULL,NULL,&s_fatdie1};\r
+\r
+statetype s_fatdie1    = {false,SPR_FAT_W1,1,NULL,A_DeathScream,&s_fatdie2};\r
+statetype s_fatdie2    = {false,SPR_FAT_W1,10,NULL,NULL,&s_fatdie3};\r
+statetype s_fatdie3    = {false,SPR_FAT_DIE1,10,NULL,NULL,&s_fatdie4};\r
+statetype s_fatdie4    = {false,SPR_FAT_DIE2,10,NULL,NULL,&s_fatdie5};\r
+statetype s_fatdie5    = {false,SPR_FAT_DIE3,10,NULL,NULL,&s_fatdie6};\r
+statetype s_fatdie6    = {false,SPR_FAT_DEAD,20,NULL,A_StartDeathCam,&s_fatdie6};\r
+\r
+statetype s_fatshoot1  = {false,SPR_FAT_SHOOT1,30,NULL,NULL,&s_fatshoot2};\r
+statetype s_fatshoot2  = {false,SPR_FAT_SHOOT2,10,NULL,T_GiftThrow,&s_fatshoot3};\r
+statetype s_fatshoot3  = {false,SPR_FAT_SHOOT3,10,NULL,T_Shoot,&s_fatshoot4};\r
+statetype s_fatshoot4  = {false,SPR_FAT_SHOOT4,10,NULL,T_Shoot,&s_fatshoot5};\r
+statetype s_fatshoot5  = {false,SPR_FAT_SHOOT3,10,NULL,T_Shoot,&s_fatshoot6};\r
+statetype s_fatshoot6  = {false,SPR_FAT_SHOOT4,10,NULL,T_Shoot,&s_fatchase1};\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnSchabbs\r
+=\r
+===============\r
+*/\r
+\r
+void SpawnSchabbs (int tilex, int tiley)\r
+{\r
+       unsigned        far *map,tile;\r
+\r
+       if (DigiMode != sds_Off)\r
+               s_schabbdie2.tictime = 140;\r
+       else\r
+               s_schabbdie2.tictime = 5;\r
+\r
+       SpawnNewObj (tilex,tiley,&s_schabbstand);\r
+       new->speed = SPDPATROL;\r
+\r
+       new->obclass = schabbobj;\r
+       new->hitpoints = starthitpoints[gamestate.difficulty][en_schabbs];\r
+       new->dir = south;\r
+       new->flags |= FL_SHOOTABLE|FL_AMBUSH;\r
+       if (!loadedgame)\r
+         gamestate.killtotal++;\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnGift\r
+=\r
+===============\r
+*/\r
+\r
+void SpawnGift (int tilex, int tiley)\r
+{\r
+       unsigned        far *map,tile;\r
+\r
+       if (DigiMode != sds_Off)\r
+         s_giftdie2.tictime = 140;\r
+       else\r
+         s_giftdie2.tictime = 5;\r
+\r
+       SpawnNewObj (tilex,tiley,&s_giftstand);\r
+       new->speed = SPDPATROL;\r
+\r
+       new->obclass = giftobj;\r
+       new->hitpoints = starthitpoints[gamestate.difficulty][en_gift];\r
+       new->dir = north;\r
+       new->flags |= FL_SHOOTABLE|FL_AMBUSH;\r
+       if (!loadedgame)\r
+         gamestate.killtotal++;\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnFat\r
+=\r
+===============\r
+*/\r
+\r
+void SpawnFat (int tilex, int tiley)\r
+{\r
+       unsigned        far *map,tile;\r
+\r
+       if (DigiMode != sds_Off)\r
+         s_fatdie2.tictime = 140;\r
+       else\r
+         s_fatdie2.tictime = 5;\r
+\r
+       SpawnNewObj (tilex,tiley,&s_fatstand);\r
+       new->speed = SPDPATROL;\r
+\r
+       new->obclass = fatobj;\r
+       new->hitpoints = starthitpoints[gamestate.difficulty][en_fat];\r
+       new->dir = south;\r
+       new->flags |= FL_SHOOTABLE|FL_AMBUSH;\r
+       if (!loadedgame)\r
+         gamestate.killtotal++;\r
+}\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= T_SchabbThrow\r
+=\r
+=================\r
+*/\r
+\r
+void T_SchabbThrow (objtype *ob)\r
+{\r
+       long    deltax,deltay;\r
+       float   angle;\r
+       int             iangle;\r
+\r
+       deltax = player->x - ob->x;\r
+       deltay = ob->y - player->y;\r
+       angle = atan2 (deltay,deltax);\r
+       if (angle<0)\r
+               angle = M_PI*2+angle;\r
+       iangle = angle/(M_PI*2)*ANGLES;\r
+\r
+       GetNewActor ();\r
+       new->state = &s_needle1;\r
+       new->ticcount = 1;\r
+\r
+       new->tilex = ob->tilex;\r
+       new->tiley = ob->tiley;\r
+       new->x = ob->x;\r
+       new->y = ob->y;\r
+       new->obclass = needleobj;\r
+       new->dir = nodir;\r
+       new->angle = iangle;\r
+       new->speed = 0x2000l;\r
+\r
+       new->flags = FL_NONMARK;\r
+       new->active = true;\r
+\r
+       PlaySoundLocActor (SCHABBSTHROWSND,new);\r
+}\r
+\r
+/*\r
+=================\r
+=\r
+= T_GiftThrow\r
+=\r
+=================\r
+*/\r
+\r
+void T_GiftThrow (objtype *ob)\r
+{\r
+       long    deltax,deltay;\r
+       float   angle;\r
+       int             iangle;\r
+\r
+       deltax = player->x - ob->x;\r
+       deltay = ob->y - player->y;\r
+       angle = atan2 (deltay,deltax);\r
+       if (angle<0)\r
+               angle = M_PI*2+angle;\r
+       iangle = angle/(M_PI*2)*ANGLES;\r
+\r
+       GetNewActor ();\r
+       new->state = &s_rocket;\r
+       new->ticcount = 1;\r
+\r
+       new->tilex = ob->tilex;\r
+       new->tiley = ob->tiley;\r
+       new->x = ob->x;\r
+       new->y = ob->y;\r
+       new->obclass = rocketobj;\r
+       new->dir = nodir;\r
+       new->angle = iangle;\r
+       new->speed = 0x2000l;\r
+       new->flags = FL_NONMARK;\r
+       new->active = true;\r
+\r
+       PlaySoundLocActor (MISSILEFIRESND,new);\r
+}\r
+\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= T_Schabb\r
+=\r
+=================\r
+*/\r
+\r
+void T_Schabb (objtype *ob)\r
+{\r
+       long move;\r
+       int     dx,dy,dist;\r
+       boolean dodge;\r
+\r
+       dodge = false;\r
+       dx = abs(ob->tilex - player->tilex);\r
+       dy = abs(ob->tiley - player->tiley);\r
+       dist = dx>dy ? dx : dy;\r
+\r
+       if (CheckLine(ob))                                              // got a shot at player?\r
+       {\r
+\r
+               if ( US_RndT() < (tics<<3) )\r
+               {\r
+               //\r
+               // go into attack frame\r
+               //\r
+                       NewState (ob,&s_schabbshoot1);\r
+                       return;\r
+               }\r
+               dodge = true;\r
+       }\r
+\r
+       if (ob->dir == nodir)\r
+       {\r
+               if (dodge)\r
+                       SelectDodgeDir (ob);\r
+               else\r
+                       SelectChaseDir (ob);\r
+               if (ob->dir == nodir)\r
+                       return;                                                 // object is blocked in\r
+       }\r
+\r
+       move = ob->speed*tics;\r
+\r
+       while (move)\r
+       {\r
+               if (ob->distance < 0)\r
+               {\r
+               //\r
+               // waiting for a door to open\r
+               //\r
+                       OpenDoor (-ob->distance-1);\r
+                       if (doorobjlist[-ob->distance-1].action != dr_open)\r
+                               return;\r
+                       ob->distance = TILEGLOBAL;      // go ahead, the door is now opoen\r
+               }\r
+\r
+               if (move < ob->distance)\r
+               {\r
+                       MoveObj (ob,move);\r
+                       break;\r
+               }\r
+\r
+               //\r
+               // reached goal tile, so select another one\r
+               //\r
+\r
+               //\r
+               // fix position to account for round off during moving\r
+               //\r
+               ob->x = ((long)ob->tilex<<TILESHIFT)+TILEGLOBAL/2;\r
+               ob->y = ((long)ob->tiley<<TILESHIFT)+TILEGLOBAL/2;\r
+\r
+               move -= ob->distance;\r
+\r
+               if (dist <4)\r
+                       SelectRunDir (ob);\r
+               else if (dodge)\r
+                       SelectDodgeDir (ob);\r
+               else\r
+                       SelectChaseDir (ob);\r
+\r
+               if (ob->dir == nodir)\r
+                       return;                                                 // object is blocked in\r
+       }\r
+\r
+}\r
+\r
+\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= T_Gift\r
+=\r
+=================\r
+*/\r
+\r
+void T_Gift (objtype *ob)\r
+{\r
+       long move;\r
+       int     dx,dy,dist;\r
+       boolean dodge;\r
+\r
+       dodge = false;\r
+       dx = abs(ob->tilex - player->tilex);\r
+       dy = abs(ob->tiley - player->tiley);\r
+       dist = dx>dy ? dx : dy;\r
+\r
+       if (CheckLine(ob))                                              // got a shot at player?\r
+       {\r
+\r
+               if ( US_RndT() < (tics<<3) )\r
+               {\r
+               //\r
+               // go into attack frame\r
+               //\r
+                       NewState (ob,&s_giftshoot1);\r
+                       return;\r
+               }\r
+               dodge = true;\r
+       }\r
+\r
+       if (ob->dir == nodir)\r
+       {\r
+               if (dodge)\r
+                       SelectDodgeDir (ob);\r
+               else\r
+                       SelectChaseDir (ob);\r
+               if (ob->dir == nodir)\r
+                       return;                                                 // object is blocked in\r
+       }\r
+\r
+       move = ob->speed*tics;\r
+\r
+       while (move)\r
+       {\r
+               if (ob->distance < 0)\r
+               {\r
+               //\r
+               // waiting for a door to open\r
+               //\r
+                       OpenDoor (-ob->distance-1);\r
+                       if (doorobjlist[-ob->distance-1].action != dr_open)\r
+                               return;\r
+                       ob->distance = TILEGLOBAL;      // go ahead, the door is now opoen\r
+               }\r
+\r
+               if (move < ob->distance)\r
+               {\r
+                       MoveObj (ob,move);\r
+                       break;\r
+               }\r
+\r
+               //\r
+               // reached goal tile, so select another one\r
+               //\r
+\r
+               //\r
+               // fix position to account for round off during moving\r
+               //\r
+               ob->x = ((long)ob->tilex<<TILESHIFT)+TILEGLOBAL/2;\r
+               ob->y = ((long)ob->tiley<<TILESHIFT)+TILEGLOBAL/2;\r
+\r
+               move -= ob->distance;\r
+\r
+               if (dist <4)\r
+                       SelectRunDir (ob);\r
+               else if (dodge)\r
+                       SelectDodgeDir (ob);\r
+               else\r
+                       SelectChaseDir (ob);\r
+\r
+               if (ob->dir == nodir)\r
+                       return;                                                 // object is blocked in\r
+       }\r
+\r
+}\r
+\r
+\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= T_Fat\r
+=\r
+=================\r
+*/\r
+\r
+void T_Fat (objtype *ob)\r
+{\r
+       long move;\r
+       int     dx,dy,dist;\r
+       boolean dodge;\r
+\r
+       dodge = false;\r
+       dx = abs(ob->tilex - player->tilex);\r
+       dy = abs(ob->tiley - player->tiley);\r
+       dist = dx>dy ? dx : dy;\r
+\r
+       if (CheckLine(ob))                                              // got a shot at player?\r
+       {\r
+\r
+               if ( US_RndT() < (tics<<3) )\r
+               {\r
+               //\r
+               // go into attack frame\r
+               //\r
+                       NewState (ob,&s_fatshoot1);\r
+                       return;\r
+               }\r
+               dodge = true;\r
+       }\r
+\r
+       if (ob->dir == nodir)\r
+       {\r
+               if (dodge)\r
+                       SelectDodgeDir (ob);\r
+               else\r
+                       SelectChaseDir (ob);\r
+               if (ob->dir == nodir)\r
+                       return;                                                 // object is blocked in\r
+       }\r
+\r
+       move = ob->speed*tics;\r
+\r
+       while (move)\r
+       {\r
+               if (ob->distance < 0)\r
+               {\r
+               //\r
+               // waiting for a door to open\r
+               //\r
+                       OpenDoor (-ob->distance-1);\r
+                       if (doorobjlist[-ob->distance-1].action != dr_open)\r
+                               return;\r
+                       ob->distance = TILEGLOBAL;      // go ahead, the door is now opoen\r
+               }\r
+\r
+               if (move < ob->distance)\r
+               {\r
+                       MoveObj (ob,move);\r
+                       break;\r
+               }\r
+\r
+               //\r
+               // reached goal tile, so select another one\r
+               //\r
+\r
+               //\r
+               // fix position to account for round off during moving\r
+               //\r
+               ob->x = ((long)ob->tilex<<TILESHIFT)+TILEGLOBAL/2;\r
+               ob->y = ((long)ob->tiley<<TILESHIFT)+TILEGLOBAL/2;\r
+\r
+               move -= ob->distance;\r
+\r
+               if (dist <4)\r
+                       SelectRunDir (ob);\r
+               else if (dodge)\r
+                       SelectDodgeDir (ob);\r
+               else\r
+                       SelectChaseDir (ob);\r
+\r
+               if (ob->dir == nodir)\r
+                       return;                                                 // object is blocked in\r
+       }\r
+\r
+}\r
+\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                       HITLERS\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+//\r
+// fake\r
+//\r
+extern statetype s_fakestand;\r
+\r
+extern statetype s_fakechase1;\r
+extern statetype s_fakechase1s;\r
+extern statetype s_fakechase2;\r
+extern statetype s_fakechase3;\r
+extern statetype s_fakechase3s;\r
+extern statetype s_fakechase4;\r
+\r
+extern statetype s_fakedie1;\r
+extern statetype s_fakedie2;\r
+extern statetype s_fakedie3;\r
+extern statetype s_fakedie4;\r
+extern statetype s_fakedie5;\r
+extern statetype s_fakedie6;\r
+\r
+extern statetype s_fakeshoot1;\r
+extern statetype s_fakeshoot2;\r
+extern statetype s_fakeshoot3;\r
+extern statetype s_fakeshoot4;\r
+extern statetype s_fakeshoot5;\r
+extern statetype s_fakeshoot6;\r
+extern statetype s_fakeshoot7;\r
+extern statetype s_fakeshoot8;\r
+extern statetype s_fakeshoot9;\r
+\r
+extern statetype s_fire1;\r
+extern statetype s_fire2;\r
+\r
+statetype s_fakestand  = {false,SPR_FAKE_W1,0,T_Stand,NULL,&s_fakestand};\r
+\r
+statetype s_fakechase1         = {false,SPR_FAKE_W1,10,T_Fake,NULL,&s_fakechase1s};\r
+statetype s_fakechase1s        = {false,SPR_FAKE_W1,3,NULL,NULL,&s_fakechase2};\r
+statetype s_fakechase2         = {false,SPR_FAKE_W2,8,T_Fake,NULL,&s_fakechase3};\r
+statetype s_fakechase3         = {false,SPR_FAKE_W3,10,T_Fake,NULL,&s_fakechase3s};\r
+statetype s_fakechase3s        = {false,SPR_FAKE_W3,3,NULL,NULL,&s_fakechase4};\r
+statetype s_fakechase4         = {false,SPR_FAKE_W4,8,T_Fake,NULL,&s_fakechase1};\r
+\r
+statetype s_fakedie1   = {false,SPR_FAKE_DIE1,10,NULL,A_DeathScream,&s_fakedie2};\r
+statetype s_fakedie2   = {false,SPR_FAKE_DIE2,10,NULL,NULL,&s_fakedie3};\r
+statetype s_fakedie3   = {false,SPR_FAKE_DIE3,10,NULL,NULL,&s_fakedie4};\r
+statetype s_fakedie4   = {false,SPR_FAKE_DIE4,10,NULL,NULL,&s_fakedie5};\r
+statetype s_fakedie5   = {false,SPR_FAKE_DIE5,10,NULL,NULL,&s_fakedie6};\r
+statetype s_fakedie6   = {false,SPR_FAKE_DEAD,0,NULL,NULL,&s_fakedie6};\r
+\r
+statetype s_fakeshoot1         = {false,SPR_FAKE_SHOOT,8,NULL,T_FakeFire,&s_fakeshoot2};\r
+statetype s_fakeshoot2         = {false,SPR_FAKE_SHOOT,8,NULL,T_FakeFire,&s_fakeshoot3};\r
+statetype s_fakeshoot3         = {false,SPR_FAKE_SHOOT,8,NULL,T_FakeFire,&s_fakeshoot4};\r
+statetype s_fakeshoot4         = {false,SPR_FAKE_SHOOT,8,NULL,T_FakeFire,&s_fakeshoot5};\r
+statetype s_fakeshoot5         = {false,SPR_FAKE_SHOOT,8,NULL,T_FakeFire,&s_fakeshoot6};\r
+statetype s_fakeshoot6         = {false,SPR_FAKE_SHOOT,8,NULL,T_FakeFire,&s_fakeshoot7};\r
+statetype s_fakeshoot7         = {false,SPR_FAKE_SHOOT,8,NULL,T_FakeFire,&s_fakeshoot8};\r
+statetype s_fakeshoot8         = {false,SPR_FAKE_SHOOT,8,NULL,T_FakeFire,&s_fakeshoot9};\r
+statetype s_fakeshoot9         = {false,SPR_FAKE_SHOOT,8,NULL,NULL,&s_fakechase1};\r
+\r
+statetype s_fire1      = {false,SPR_FIRE1,6,NULL,T_Projectile,&s_fire2};\r
+statetype s_fire2      = {false,SPR_FIRE2,6,NULL,T_Projectile,&s_fire1};\r
+\r
+//\r
+// hitler\r
+//\r
+extern statetype s_mechachase1;\r
+extern statetype s_mechachase1s;\r
+extern statetype s_mechachase2;\r
+extern statetype s_mechachase3;\r
+extern statetype s_mechachase3s;\r
+extern statetype s_mechachase4;\r
+\r
+extern statetype s_mechadie1;\r
+extern statetype s_mechadie2;\r
+extern statetype s_mechadie3;\r
+extern statetype s_mechadie4;\r
+\r
+extern statetype s_mechashoot1;\r
+extern statetype s_mechashoot2;\r
+extern statetype s_mechashoot3;\r
+extern statetype s_mechashoot4;\r
+extern statetype s_mechashoot5;\r
+extern statetype s_mechashoot6;\r
+\r
+\r
+extern statetype s_hitlerchase1;\r
+extern statetype s_hitlerchase1s;\r
+extern statetype s_hitlerchase2;\r
+extern statetype s_hitlerchase3;\r
+extern statetype s_hitlerchase3s;\r
+extern statetype s_hitlerchase4;\r
+\r
+extern statetype s_hitlerdie1;\r
+extern statetype s_hitlerdie2;\r
+extern statetype s_hitlerdie3;\r
+extern statetype s_hitlerdie4;\r
+extern statetype s_hitlerdie5;\r
+extern statetype s_hitlerdie6;\r
+extern statetype s_hitlerdie7;\r
+extern statetype s_hitlerdie8;\r
+extern statetype s_hitlerdie9;\r
+extern statetype s_hitlerdie10;\r
+\r
+extern statetype s_hitlershoot1;\r
+extern statetype s_hitlershoot2;\r
+extern statetype s_hitlershoot3;\r
+extern statetype s_hitlershoot4;\r
+extern statetype s_hitlershoot5;\r
+extern statetype s_hitlershoot6;\r
+\r
+extern statetype s_hitlerdeathcam;\r
+\r
+statetype s_mechastand = {false,SPR_MECHA_W1,0,T_Stand,NULL,&s_mechastand};\r
+\r
+statetype s_mechachase1        = {false,SPR_MECHA_W1,10,T_Chase,A_MechaSound,&s_mechachase1s};\r
+statetype s_mechachase1s       = {false,SPR_MECHA_W1,6,NULL,NULL,&s_mechachase2};\r
+statetype s_mechachase2        = {false,SPR_MECHA_W2,8,T_Chase,NULL,&s_mechachase3};\r
+statetype s_mechachase3        = {false,SPR_MECHA_W3,10,T_Chase,A_MechaSound,&s_mechachase3s};\r
+statetype s_mechachase3s       = {false,SPR_MECHA_W3,6,NULL,NULL,&s_mechachase4};\r
+statetype s_mechachase4        = {false,SPR_MECHA_W4,8,T_Chase,NULL,&s_mechachase1};\r
+\r
+statetype s_mechadie1  = {false,SPR_MECHA_DIE1,10,NULL,A_DeathScream,&s_mechadie2};\r
+statetype s_mechadie2  = {false,SPR_MECHA_DIE2,10,NULL,NULL,&s_mechadie3};\r
+statetype s_mechadie3  = {false,SPR_MECHA_DIE3,10,NULL,A_HitlerMorph,&s_mechadie4};\r
+statetype s_mechadie4  = {false,SPR_MECHA_DEAD,0,NULL,NULL,&s_mechadie4};\r
+\r
+statetype s_mechashoot1        = {false,SPR_MECHA_SHOOT1,30,NULL,NULL,&s_mechashoot2};\r
+statetype s_mechashoot2        = {false,SPR_MECHA_SHOOT2,10,NULL,T_Shoot,&s_mechashoot3};\r
+statetype s_mechashoot3        = {false,SPR_MECHA_SHOOT3,10,NULL,T_Shoot,&s_mechashoot4};\r
+statetype s_mechashoot4        = {false,SPR_MECHA_SHOOT2,10,NULL,T_Shoot,&s_mechashoot5};\r
+statetype s_mechashoot5        = {false,SPR_MECHA_SHOOT3,10,NULL,T_Shoot,&s_mechashoot6};\r
+statetype s_mechashoot6        = {false,SPR_MECHA_SHOOT2,10,NULL,T_Shoot,&s_mechachase1};\r
+\r
+\r
+statetype s_hitlerchase1       = {false,SPR_HITLER_W1,6,T_Chase,NULL,&s_hitlerchase1s};\r
+statetype s_hitlerchase1s      = {false,SPR_HITLER_W1,4,NULL,NULL,&s_hitlerchase2};\r
+statetype s_hitlerchase2       = {false,SPR_HITLER_W2,2,T_Chase,NULL,&s_hitlerchase3};\r
+statetype s_hitlerchase3       = {false,SPR_HITLER_W3,6,T_Chase,NULL,&s_hitlerchase3s};\r
+statetype s_hitlerchase3s      = {false,SPR_HITLER_W3,4,NULL,NULL,&s_hitlerchase4};\r
+statetype s_hitlerchase4       = {false,SPR_HITLER_W4,2,T_Chase,NULL,&s_hitlerchase1};\r
+\r
+statetype s_hitlerdeathcam     = {false,SPR_HITLER_W1,10,NULL,NULL,&s_hitlerdie1};\r
+\r
+statetype s_hitlerdie1 = {false,SPR_HITLER_W1,1,NULL,A_DeathScream,&s_hitlerdie2};\r
+statetype s_hitlerdie2 = {false,SPR_HITLER_W1,10,NULL,NULL,&s_hitlerdie3};\r
+statetype s_hitlerdie3 = {false,SPR_HITLER_DIE1,10,NULL,A_Slurpie,&s_hitlerdie4};\r
+statetype s_hitlerdie4 = {false,SPR_HITLER_DIE2,10,NULL,NULL,&s_hitlerdie5};\r
+statetype s_hitlerdie5 = {false,SPR_HITLER_DIE3,10,NULL,NULL,&s_hitlerdie6};\r
+statetype s_hitlerdie6 = {false,SPR_HITLER_DIE4,10,NULL,NULL,&s_hitlerdie7};\r
+statetype s_hitlerdie7 = {false,SPR_HITLER_DIE5,10,NULL,NULL,&s_hitlerdie8};\r
+statetype s_hitlerdie8 = {false,SPR_HITLER_DIE6,10,NULL,NULL,&s_hitlerdie9};\r
+statetype s_hitlerdie9 = {false,SPR_HITLER_DIE7,10,NULL,NULL,&s_hitlerdie10};\r
+statetype s_hitlerdie10        = {false,SPR_HITLER_DEAD,20,NULL,A_StartDeathCam,&s_hitlerdie10};\r
+\r
+statetype s_hitlershoot1       = {false,SPR_HITLER_SHOOT1,30,NULL,NULL,&s_hitlershoot2};\r
+statetype s_hitlershoot2       = {false,SPR_HITLER_SHOOT2,10,NULL,T_Shoot,&s_hitlershoot3};\r
+statetype s_hitlershoot3       = {false,SPR_HITLER_SHOOT3,10,NULL,T_Shoot,&s_hitlershoot4};\r
+statetype s_hitlershoot4       = {false,SPR_HITLER_SHOOT2,10,NULL,T_Shoot,&s_hitlershoot5};\r
+statetype s_hitlershoot5       = {false,SPR_HITLER_SHOOT3,10,NULL,T_Shoot,&s_hitlershoot6};\r
+statetype s_hitlershoot6       = {false,SPR_HITLER_SHOOT2,10,NULL,T_Shoot,&s_hitlerchase1};\r
+\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnFakeHitler\r
+=\r
+===============\r
+*/\r
+\r
+void SpawnFakeHitler (int tilex, int tiley)\r
+{\r
+       unsigned        far *map,tile;\r
+\r
+\r
+       if (DigiMode != sds_Off)\r
+         s_hitlerdie2.tictime = 140;\r
+       else\r
+         s_hitlerdie2.tictime = 5;\r
+\r
+       SpawnNewObj (tilex,tiley,&s_fakestand);\r
+       new->speed = SPDPATROL;\r
+\r
+       new->obclass = fakeobj;\r
+       new->hitpoints = starthitpoints[gamestate.difficulty][en_fake];\r
+       new->dir = north;\r
+       new->flags |= FL_SHOOTABLE|FL_AMBUSH;\r
+       if (!loadedgame)\r
+         gamestate.killtotal++;\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnHitler\r
+=\r
+===============\r
+*/\r
+\r
+void SpawnHitler (int tilex, int tiley)\r
+{\r
+       unsigned        far *map,tile;\r
+\r
+       if (DigiMode != sds_Off)\r
+               s_hitlerdie2.tictime = 140;\r
+       else\r
+               s_hitlerdie2.tictime = 5;\r
+\r
+\r
+       SpawnNewObj (tilex,tiley,&s_mechastand);\r
+       new->speed = SPDPATROL;\r
+\r
+       new->obclass = mechahitlerobj;\r
+       new->hitpoints = starthitpoints[gamestate.difficulty][en_hitler];\r
+       new->dir = south;\r
+       new->flags |= FL_SHOOTABLE|FL_AMBUSH;\r
+       if (!loadedgame)\r
+         gamestate.killtotal++;\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= A_HitlerMorph\r
+=\r
+===============\r
+*/\r
+\r
+void A_HitlerMorph (objtype *ob)\r
+{\r
+       unsigned        far *map,tile,hitpoints[4]={500,700,800,900};\r
+\r
+\r
+       SpawnNewObj (ob->tilex,ob->tiley,&s_hitlerchase1);\r
+       new->speed = SPDPATROL*5;\r
+\r
+       new->x = ob->x;\r
+       new->y = ob->y;\r
+\r
+       new->distance = ob->distance;\r
+       new->dir = ob->dir;\r
+       new->flags = ob->flags | FL_SHOOTABLE;\r
+\r
+       new->obclass = realhitlerobj;\r
+       new->hitpoints = hitpoints[gamestate.difficulty];\r
+}\r
+\r
+\r
+////////////////////////////////////////////////////////\r
+//\r
+// A_MechaSound\r
+// A_Slurpie\r
+//\r
+////////////////////////////////////////////////////////\r
+void A_MechaSound (objtype *ob)\r
+{\r
+       if (areabyplayer[ob->areanumber])\r
+               PlaySoundLocActor (MECHSTEPSND,ob);\r
+}\r
+\r
+\r
+#pragma argsused\r
+void A_Slurpie (objtype *ob)\r
+{\r
+ SD_PlaySound(SLURPIESND);\r
+}\r
+\r
+/*\r
+=================\r
+=\r
+= T_FakeFire\r
+=\r
+=================\r
+*/\r
+\r
+void T_FakeFire (objtype *ob)\r
+{\r
+       long    deltax,deltay;\r
+       float   angle;\r
+       int             iangle;\r
+\r
+       deltax = player->x - ob->x;\r
+       deltay = ob->y - player->y;\r
+       angle = atan2 (deltay,deltax);\r
+       if (angle<0)\r
+               angle = M_PI*2+angle;\r
+       iangle = angle/(M_PI*2)*ANGLES;\r
+\r
+       GetNewActor ();\r
+       new->state = &s_fire1;\r
+       new->ticcount = 1;\r
+\r
+       new->tilex = ob->tilex;\r
+       new->tiley = ob->tiley;\r
+       new->x = ob->x;\r
+       new->y = ob->y;\r
+       new->dir = nodir;\r
+       new->angle = iangle;\r
+       new->obclass = fireobj;\r
+       new->speed = 0x1200l;\r
+       new->flags = FL_NEVERMARK;\r
+       new->active = true;\r
+\r
+       PlaySoundLocActor (FLAMETHROWERSND,new);\r
+}\r
+\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= T_Fake\r
+=\r
+=================\r
+*/\r
+\r
+void T_Fake (objtype *ob)\r
+{\r
+       long move;\r
+       int     dx,dy,dist;\r
+       boolean dodge;\r
+\r
+       if (CheckLine(ob))                      // got a shot at player?\r
+       {\r
+               if ( US_RndT() < (tics<<1) )\r
+               {\r
+               //\r
+               // go into attack frame\r
+               //\r
+                       NewState (ob,&s_fakeshoot1);\r
+                       return;\r
+               }\r
+       }\r
+\r
+       if (ob->dir == nodir)\r
+       {\r
+               SelectDodgeDir (ob);\r
+               if (ob->dir == nodir)\r
+                       return;                                                 // object is blocked in\r
+       }\r
+\r
+       move = ob->speed*tics;\r
+\r
+       while (move)\r
+       {\r
+               if (move < ob->distance)\r
+               {\r
+                       MoveObj (ob,move);\r
+                       break;\r
+               }\r
+\r
+               //\r
+               // reached goal tile, so select another one\r
+               //\r
+\r
+               //\r
+               // fix position to account for round off during moving\r
+               //\r
+               ob->x = ((long)ob->tilex<<TILESHIFT)+TILEGLOBAL/2;\r
+               ob->y = ((long)ob->tiley<<TILESHIFT)+TILEGLOBAL/2;\r
+\r
+               move -= ob->distance;\r
+\r
+               SelectDodgeDir (ob);\r
+\r
+               if (ob->dir == nodir)\r
+                       return;                                                 // object is blocked in\r
+       }\r
+\r
+}\r
+\r
+#endif\r
+/*\r
+============================================================================\r
+\r
+                                                       STAND\r
+\r
+============================================================================\r
+*/\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= T_Stand\r
+=\r
+===============\r
+*/\r
+\r
+void T_Stand (objtype *ob)\r
+{\r
+       SightPlayer (ob);\r
+}\r
+\r
+\r
+/*\r
+============================================================================\r
+\r
+                                                               CHASE\r
+\r
+============================================================================\r
+*/\r
+\r
+/*\r
+=================\r
+=\r
+= T_Chase\r
+=\r
+=================\r
+*/\r
+\r
+void T_Chase (objtype *ob)\r
+{\r
+       long move;\r
+       int     dx,dy,dist,chance;\r
+       boolean dodge;\r
+\r
+       if (gamestate.victoryflag)\r
+               return;\r
+\r
+       dodge = false;\r
+       if (CheckLine(ob))      // got a shot at player?\r
+       {\r
+               dx = abs(ob->tilex - player->tilex);\r
+               dy = abs(ob->tiley - player->tiley);\r
+               dist = dx>dy ? dx : dy;\r
+               if (!dist || (dist==1 && ob->distance<0x4000) )\r
+                       chance = 300;\r
+               else\r
+                       chance = (tics<<4)/dist;\r
+\r
+               if ( US_RndT()<chance)\r
+               {\r
+               //\r
+               // go into attack frame\r
+               //\r
+                       switch (ob->obclass)\r
+                       {\r
+                       case guardobj:\r
+                               NewState (ob,&s_grdshoot1);\r
+                               break;\r
+                       case officerobj:\r
+                               NewState (ob,&s_ofcshoot1);\r
+                               break;\r
+                       case mutantobj:\r
+                               NewState (ob,&s_mutshoot1);\r
+                               break;\r
+                       case ssobj:\r
+                               NewState (ob,&s_ssshoot1);\r
+                               break;\r
+#ifndef SPEAR\r
+                       case bossobj:\r
+                               NewState (ob,&s_bossshoot1);\r
+                               break;\r
+                       case gretelobj:\r
+                               NewState (ob,&s_gretelshoot1);\r
+                               break;\r
+                       case mechahitlerobj:\r
+                               NewState (ob,&s_mechashoot1);\r
+                               break;\r
+                       case realhitlerobj:\r
+                               NewState (ob,&s_hitlershoot1);\r
+                               break;\r
+#else\r
+                       case angelobj:\r
+                               NewState (ob,&s_angelshoot1);\r
+                               break;\r
+                       case transobj:\r
+                               NewState (ob,&s_transshoot1);\r
+                               break;\r
+                       case uberobj:\r
+                               NewState (ob,&s_ubershoot1);\r
+                               break;\r
+                       case willobj:\r
+                               NewState (ob,&s_willshoot1);\r
+                               break;\r
+                       case deathobj:\r
+                               NewState (ob,&s_deathshoot1);\r
+                               break;\r
+#endif\r
+                       }\r
+                       return;\r
+               }\r
+               dodge = true;\r
+       }\r
+\r
+       if (ob->dir == nodir)\r
+       {\r
+               if (dodge)\r
+                       SelectDodgeDir (ob);\r
+               else\r
+                       SelectChaseDir (ob);\r
+               if (ob->dir == nodir)\r
+                       return;                                                 // object is blocked in\r
+       }\r
+\r
+       move = ob->speed*tics;\r
+\r
+       while (move)\r
+       {\r
+               if (ob->distance < 0)\r
+               {\r
+               //\r
+               // waiting for a door to open\r
+               //\r
+                       OpenDoor (-ob->distance-1);\r
+                       if (doorobjlist[-ob->distance-1].action != dr_open)\r
+                               return;\r
+                       ob->distance = TILEGLOBAL;      // go ahead, the door is now opoen\r
+               }\r
+\r
+               if (move < ob->distance)\r
+               {\r
+                       MoveObj (ob,move);\r
+                       break;\r
+               }\r
+\r
+               //\r
+               // reached goal tile, so select another one\r
+               //\r
+\r
+               //\r
+               // fix position to account for round off during moving\r
+               //\r
+               ob->x = ((long)ob->tilex<<TILESHIFT)+TILEGLOBAL/2;\r
+               ob->y = ((long)ob->tiley<<TILESHIFT)+TILEGLOBAL/2;\r
+\r
+               move -= ob->distance;\r
+\r
+               if (dodge)\r
+                       SelectDodgeDir (ob);\r
+               else\r
+                       SelectChaseDir (ob);\r
+\r
+               if (ob->dir == nodir)\r
+                       return;                                                 // object is blocked in\r
+       }\r
+\r
+}\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= T_Ghosts\r
+=\r
+=================\r
+*/\r
+\r
+void T_Ghosts (objtype *ob)\r
+{\r
+       long move;\r
+\r
+\r
+       if (ob->dir == nodir)\r
+       {\r
+               SelectChaseDir (ob);\r
+               if (ob->dir == nodir)\r
+                       return;                                                 // object is blocked in\r
+       }\r
+\r
+       move = ob->speed*tics;\r
+\r
+       while (move)\r
+       {\r
+               if (move < ob->distance)\r
+               {\r
+                       MoveObj (ob,move);\r
+                       break;\r
+               }\r
+\r
+               //\r
+               // reached goal tile, so select another one\r
+               //\r
+\r
+               //\r
+               // fix position to account for round off during moving\r
+               //\r
+               ob->x = ((long)ob->tilex<<TILESHIFT)+TILEGLOBAL/2;\r
+               ob->y = ((long)ob->tiley<<TILESHIFT)+TILEGLOBAL/2;\r
+\r
+               move -= ob->distance;\r
+\r
+               SelectChaseDir (ob);\r
+\r
+               if (ob->dir == nodir)\r
+                       return;                                                 // object is blocked in\r
+       }\r
+\r
+}\r
+\r
+/*\r
+=================\r
+=\r
+= T_DogChase\r
+=\r
+=================\r
+*/\r
+\r
+void T_DogChase (objtype *ob)\r
+{\r
+       long    move;\r
+       int             dist,chance;\r
+       long    dx,dy;\r
+\r
+\r
+       if (ob->dir == nodir)\r
+       {\r
+               SelectDodgeDir (ob);\r
+               if (ob->dir == nodir)\r
+                       return;                                                 // object is blocked in\r
+       }\r
+\r
+       move = ob->speed*tics;\r
+\r
+       while (move)\r
+       {\r
+       //\r
+       // check for byte range\r
+       //\r
+               dx = player->x - ob->x;\r
+               if (dx<0)\r
+                       dx = -dx;\r
+               dx -= move;\r
+               if (dx <= MINACTORDIST)\r
+               {\r
+                       dy = player->y - ob->y;\r
+                       if (dy<0)\r
+                               dy = -dy;\r
+                       dy -= move;\r
+                       if (dy <= MINACTORDIST)\r
+                       {\r
+                               NewState (ob,&s_dogjump1);\r
+                               return;\r
+                       }\r
+               }\r
+\r
+               if (move < ob->distance)\r
+               {\r
+                       MoveObj (ob,move);\r
+                       break;\r
+               }\r
+\r
+               //\r
+               // reached goal tile, so select another one\r
+               //\r
+\r
+               //\r
+               // fix position to account for round off during moving\r
+               //\r
+               ob->x = ((long)ob->tilex<<TILESHIFT)+TILEGLOBAL/2;\r
+               ob->y = ((long)ob->tiley<<TILESHIFT)+TILEGLOBAL/2;\r
+\r
+               move -= ob->distance;\r
+\r
+               SelectDodgeDir (ob);\r
+\r
+               if (ob->dir == nodir)\r
+                       return;                                                 // object is blocked in\r
+       }\r
+\r
+}\r
+\r
+\r
+\r
+/*\r
+============================================================================\r
+\r
+                                                               PATH\r
+\r
+============================================================================\r
+*/\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= SelectPathDir\r
+=\r
+===============\r
+*/\r
+\r
+void SelectPathDir (objtype *ob)\r
+{\r
+       unsigned spot;\r
+\r
+       spot = MAPSPOT(ob->tilex,ob->tiley,1)-ICONARROWS;\r
+\r
+       if (spot<8)\r
+       {\r
+       // new direction\r
+               ob->dir = spot;\r
+       }\r
+\r
+       ob->distance = TILEGLOBAL;\r
+\r
+       if (!TryWalk (ob))\r
+               ob->dir = nodir;\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= T_Path\r
+=\r
+===============\r
+*/\r
+\r
+void T_Path (objtype *ob)\r
+{\r
+       long    move;\r
+       long    deltax,deltay,size;\r
+\r
+       if (SightPlayer (ob))\r
+               return;\r
+\r
+       if (ob->dir == nodir)\r
+       {\r
+               SelectPathDir (ob);\r
+               if (ob->dir == nodir)\r
+                       return;                                 // all movement is blocked\r
+       }\r
+\r
+\r
+       move = ob->speed*tics;\r
+\r
+       while (move)\r
+       {\r
+               if (ob->distance < 0)\r
+               {\r
+               //\r
+               // waiting for a door to open\r
+               //\r
+                       OpenDoor (-ob->distance-1);\r
+                       if (doorobjlist[-ob->distance-1].action != dr_open)\r
+                               return;\r
+                       ob->distance = TILEGLOBAL;      // go ahead, the door is now opoen\r
+               }\r
+\r
+               if (move < ob->distance)\r
+               {\r
+                       MoveObj (ob,move);\r
+                       break;\r
+               }\r
+\r
+               if (ob->tilex>MAPSIZE || ob->tiley>MAPSIZE)\r
+               {\r
+                       sprintf (str,"T_Path hit a wall at %u,%u, dir %u"\r
+                       ,ob->tilex,ob->tiley,ob->dir);\r
+                       Quit (str);\r
+               }\r
+\r
+\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
+               SelectPathDir (ob);\r
+\r
+               if (ob->dir == nodir)\r
+                       return;                                 // all movement is blocked\r
+       }\r
+}\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                               FIGHT\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= T_Shoot\r
+=\r
+= Try to damage the player, based on skill level and player's speed\r
+=\r
+===============\r
+*/\r
+\r
+void T_Shoot (objtype *ob)\r
+{\r
+       int     dx,dy,dist;\r
+       int     hitchance,damage;\r
+\r
+       hitchance = 128;\r
+\r
+       if (!areabyplayer[ob->areanumber])\r
+               return;\r
+\r
+       if (!CheckLine (ob))                    // player is behind a wall\r
+         return;\r
+\r
+       dx = abs(ob->tilex - player->tilex);\r
+       dy = abs(ob->tiley - player->tiley);\r
+       dist = dx>dy ? dx:dy;\r
+\r
+       if (ob->obclass == ssobj || ob->obclass == bossobj)\r
+               dist = dist*2/3;                                        // ss are better shots\r
+\r
+       if (thrustspeed >= RUNSPEED)\r
+       {\r
+               if (ob->flags&FL_VISABLE)\r
+                       hitchance = 160-dist*16;                // player can see to dodge\r
+               else\r
+                       hitchance = 160-dist*8;\r
+       }\r
+       else\r
+       {\r
+               if (ob->flags&FL_VISABLE)\r
+                       hitchance = 256-dist*16;                // player can see to dodge\r
+               else\r
+                       hitchance = 256-dist*8;\r
+       }\r
+\r
+// see if the shot was a hit\r
+\r
+       if (US_RndT()<hitchance)\r
+       {\r
+               if (dist<2)\r
+                       damage = US_RndT()>>2;\r
+               else if (dist<4)\r
+                       damage = US_RndT()>>3;\r
+               else\r
+                       damage = US_RndT()>>4;\r
+\r
+               TakeDamage (damage,ob);\r
+       }\r
+\r
+       switch(ob->obclass)\r
+       {\r
+        case ssobj:\r
+          PlaySoundLocActor(SSFIRESND,ob);\r
+          break;\r
+#ifndef SPEAR\r
+        case giftobj:\r
+        case fatobj:\r
+          PlaySoundLocActor(MISSILEFIRESND,ob);\r
+          break;\r
+        case mechahitlerobj:\r
+        case realhitlerobj:\r
+        case bossobj:\r
+          PlaySoundLocActor(BOSSFIRESND,ob);\r
+          break;\r
+        case schabbobj:\r
+          PlaySoundLocActor(SCHABBSTHROWSND,ob);\r
+          break;\r
+        case fakeobj:\r
+          PlaySoundLocActor(FLAMETHROWERSND,ob);\r
+          break;\r
+#endif\r
+        default:\r
+          PlaySoundLocActor(NAZIFIRESND,ob);\r
+       }\r
+\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= T_Bite\r
+=\r
+===============\r
+*/\r
+\r
+void T_Bite (objtype *ob)\r
+{\r
+       long    dx,dy;\r
+       int     hitchance,damage;\r
+\r
+\r
+       PlaySoundLocActor(DOGATTACKSND,ob);     // JAB\r
+\r
+       dx = player->x - ob->x;\r
+       if (dx<0)\r
+               dx = -dx;\r
+       dx -= TILEGLOBAL;\r
+       if (dx <= MINACTORDIST)\r
+       {\r
+               dy = player->y - ob->y;\r
+               if (dy<0)\r
+                       dy = -dy;\r
+               dy -= TILEGLOBAL;\r
+               if (dy <= MINACTORDIST)\r
+               {\r
+                  if (US_RndT()<180)\r
+                  {\r
+                          TakeDamage (US_RndT()>>4,ob);\r
+                          return;\r
+                  }\r
+               }\r
+       }\r
+\r
+       return;\r
+}\r
+\r
+\r
+#ifndef SPEAR\r
+/*\r
+============================================================================\r
+\r
+                                                       BJ VICTORY\r
+\r
+============================================================================\r
+*/\r
+\r
+\r
+//\r
+// BJ victory\r
+//\r
+\r
+void T_BJRun (objtype *ob);\r
+void T_BJJump (objtype *ob);\r
+void T_BJDone (objtype *ob);\r
+void T_BJYell (objtype *ob);\r
+\r
+void T_DeathCam (objtype *ob);\r
+\r
+extern statetype s_bjrun1;\r
+extern statetype s_bjrun1s;\r
+extern statetype s_bjrun2;\r
+extern statetype s_bjrun3;\r
+extern statetype s_bjrun3s;\r
+extern statetype s_bjrun4;\r
+\r
+extern statetype s_bjjump1;\r
+extern statetype s_bjjump2;\r
+extern statetype s_bjjump3;\r
+extern statetype s_bjjump4;\r
+\r
+\r
+statetype s_bjrun1     = {false,SPR_BJ_W1,12,T_BJRun,NULL,&s_bjrun1s};\r
+statetype s_bjrun1s    = {false,SPR_BJ_W1,3, NULL,NULL,&s_bjrun2};\r
+statetype s_bjrun2     = {false,SPR_BJ_W2,8,T_BJRun,NULL,&s_bjrun3};\r
+statetype s_bjrun3     = {false,SPR_BJ_W3,12,T_BJRun,NULL,&s_bjrun3s};\r
+statetype s_bjrun3s    = {false,SPR_BJ_W3,3, NULL,NULL,&s_bjrun4};\r
+statetype s_bjrun4     = {false,SPR_BJ_W4,8,T_BJRun,NULL,&s_bjrun1};\r
+\r
+\r
+statetype s_bjjump1    = {false,SPR_BJ_JUMP1,14,T_BJJump,NULL,&s_bjjump2};\r
+statetype s_bjjump2    = {false,SPR_BJ_JUMP2,14,T_BJJump,T_BJYell,&s_bjjump3};\r
+statetype s_bjjump3    = {false,SPR_BJ_JUMP3,14,T_BJJump,NULL,&s_bjjump4};\r
+statetype s_bjjump4    = {false,SPR_BJ_JUMP4,300,NULL,T_BJDone,&s_bjjump4};\r
+\r
+\r
+statetype s_deathcam = {false,0,0,NULL,NULL,NULL};\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnBJVictory\r
+=\r
+===============\r
+*/\r
+\r
+void SpawnBJVictory (void)\r
+{\r
+       unsigned        far *map,tile;\r
+\r
+       SpawnNewObj (player->tilex,player->tiley+1,&s_bjrun1);\r
+       new->x = player->x;\r
+       new->y = player->y;\r
+       new->obclass = bjobj;\r
+       new->dir = north;\r
+       new->temp1 = 6;                 // tiles to run forward\r
+}\r
+\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= T_BJRun\r
+=\r
+===============\r
+*/\r
+\r
+void T_BJRun (objtype *ob)\r
+{\r
+       long    move;\r
+\r
+       move = BJRUNSPEED*tics;\r
+\r
+       while (move)\r
+       {\r
+               if (move < ob->distance)\r
+               {\r
+                       MoveObj (ob,move);\r
+                       break;\r
+               }\r
+\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
+               SelectPathDir (ob);\r
+\r
+               if ( !(--ob->temp1) )\r
+               {\r
+                       NewState (ob,&s_bjjump1);\r
+                       return;\r
+               }\r
+       }\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= T_BJJump\r
+=\r
+===============\r
+*/\r
+\r
+void T_BJJump (objtype *ob)\r
+{\r
+       long    move;\r
+\r
+       move = BJJUMPSPEED*tics;\r
+       MoveObj (ob,move);\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= T_BJYell\r
+=\r
+===============\r
+*/\r
+\r
+void T_BJYell (objtype *ob)\r
+{\r
+       PlaySoundLocActor(YEAHSND,ob);  // JAB\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= T_BJDone\r
+=\r
+===============\r
+*/\r
+\r
+#pragma argsused\r
+void T_BJDone (objtype *ob)\r
+{\r
+       playstate = ex_victorious;                              // exit castle tile\r
+}\r
+\r
+\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= CheckPosition\r
+=\r
+===============\r
+*/\r
+\r
+boolean        CheckPosition (objtype *ob)\r
+{\r
+       int     x,y,xl,yl,xh,yh;\r
+       objtype *check;\r
+\r
+       xl = (ob->x-PLAYERSIZE) >>TILESHIFT;\r
+       yl = (ob->y-PLAYERSIZE) >>TILESHIFT;\r
+\r
+       xh = (ob->x+PLAYERSIZE) >>TILESHIFT;\r
+       yh = (ob->y+PLAYERSIZE) >>TILESHIFT;\r
+\r
+       //\r
+       // check for solid walls\r
+       //\r
+       for (y=yl;y<=yh;y++)\r
+               for (x=xl;x<=xh;x++)\r
+               {\r
+                       check = actorat[x][y];\r
+                       if (check && check<objlist)\r
+                               return false;\r
+               }\r
+\r
+       return true;\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= A_StartDeathCam\r
+=\r
+===============\r
+*/\r
+\r
+void   A_StartDeathCam (objtype *ob)\r
+{\r
+       long    dx,dy;\r
+       float   fangle;\r
+       long    xmove,ymove;\r
+       long    dist;\r
+       int             temp,i;\r
+\r
+       FinishPaletteShifts ();\r
+\r
+       VW_WaitVBL (100);\r
+\r
+       if (gamestate.victoryflag)\r
+       {\r
+               playstate = ex_victorious;                              // exit castle tile\r
+               return;\r
+       }\r
+\r
+       gamestate.victoryflag = true;\r
+       VW_Bar (0,0,320,200-STATUSLINES,127);\r
+       FizzleFade(bufferofs,displayofs,320,200-STATUSLINES,70,false);\r
+\r
+       PM_UnlockMainMem ();\r
+       CA_UpLevel ();\r
+       CacheLump(LEVELEND_LUMP_START,LEVELEND_LUMP_END);\r
+       #ifdef JAPAN\r
+       #ifndef JAPDEMO\r
+       CA_CacheScreen(C_LETSSEEPIC);\r
+       #endif\r
+       #else\r
+       Write(0,7,STR_SEEAGAIN);\r
+       #endif\r
+       CA_DownLevel ();\r
+       PM_CheckMainMem ();\r
+\r
+       VW_UpdateScreen ();\r
+\r
+       IN_UserInput(300);\r
+\r
+//\r
+// line angle up exactly\r
+//\r
+       NewState (player,&s_deathcam);\r
+\r
+       player->x = gamestate.killx;\r
+       player->y = gamestate.killy;\r
+\r
+       dx = ob->x - player->x;\r
+       dy = player->y - ob->y;\r
+\r
+       fangle = atan2(dy,dx);                  // returns -pi to pi\r
+       if (fangle<0)\r
+               fangle = M_PI*2+fangle;\r
+\r
+       player->angle = fangle/(M_PI*2)*ANGLES;\r
+\r
+//\r
+// try to position as close as possible without being in a wall\r
+//\r
+       dist = 0x14000l;\r
+       do\r
+       {\r
+               xmove = FixedByFrac(dist,costable[player->angle]);\r
+               ymove = -FixedByFrac(dist,sintable[player->angle]);\r
+\r
+               player->x = ob->x - xmove;\r
+               player->y = ob->y - ymove;\r
+               dist += 0x1000;\r
+\r
+       } while (!CheckPosition (player));\r
+       plux = player->x >> UNSIGNEDSHIFT;                      // scale to fit in unsigned\r
+       pluy = player->y >> UNSIGNEDSHIFT;\r
+       player->tilex = player->x >> TILESHIFT;         // scale to tile values\r
+       player->tiley = player->y >> TILESHIFT;\r
+\r
+//\r
+// go back to the game\r
+//\r
+       temp = bufferofs;\r
+       for (i=0;i<3;i++)\r
+       {\r
+               bufferofs = screenloc[i];\r
+               DrawPlayBorder ();\r
+       }\r
+       bufferofs = temp;\r
+\r
+       fizzlein = true;\r
+       switch (ob->obclass)\r
+       {\r
+#ifndef SPEAR\r
+       case schabbobj:\r
+               NewState (ob,&s_schabbdeathcam);\r
+               break;\r
+       case realhitlerobj:\r
+               NewState (ob,&s_hitlerdeathcam);\r
+               break;\r
+       case giftobj:\r
+               NewState (ob,&s_giftdeathcam);\r
+               break;\r
+       case fatobj:\r
+               NewState (ob,&s_fatdeathcam);\r
+               break;\r
+#endif\r
+       }\r
+\r
+}\r
+\r
+#endif\r
diff --git a/src/lib/hb/wl_agent.c b/src/lib/hb/wl_agent.c
new file mode 100755 (executable)
index 0000000..631478d
--- /dev/null
@@ -0,0 +1,1421 @@
+// WL_AGENT.C\r
+\r
+#include "WL_DEF.H"\r
+#pragma hdrstop\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+#define MAXMOUSETURN   10\r
+\r
+\r
+#define MOVESCALE              150l\r
+#define BACKMOVESCALE  100l\r
+#define ANGLESCALE             20\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                GLOBAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+\r
+//\r
+// player state info\r
+//\r
+boolean                running;\r
+long           thrustspeed;\r
+\r
+unsigned       plux,pluy;                      // player coordinates scaled to unsigned\r
+\r
+int                    anglefrac;\r
+int                    gotgatgun;      // JR\r
+\r
+objtype                *LastAttacker;\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+void   T_Player (objtype *ob);\r
+void   T_Attack (objtype *ob);\r
+\r
+statetype s_player = {false,0,0,T_Player,NULL,NULL};\r
+statetype s_attack = {false,0,0,T_Attack,NULL,NULL};\r
+\r
+\r
+long   playerxmove,playerymove;\r
+\r
+struct atkinf\r
+{\r
+       char    tics,attack,frame;              // attack is 1 for gun, 2 for knife\r
+} attackinfo[4][14] =\r
+\r
+{\r
+{ {6,0,1},{6,2,2},{6,0,3},{6,-1,4} },\r
+{ {6,0,1},{6,1,2},{6,0,3},{6,-1,4} },\r
+{ {6,0,1},{6,1,2},{6,3,3},{6,-1,4} },\r
+{ {6,0,1},{6,1,2},{6,4,3},{6,-1,4} },\r
+};\r
+\r
+\r
+int    strafeangle[9] = {0,90,180,270,45,135,225,315,0};\r
+\r
+void DrawWeapon (void);\r
+void GiveWeapon (int weapon);\r
+void   GiveAmmo (int ammo);\r
+\r
+//===========================================================================\r
+\r
+//----------\r
+\r
+void Attack (void);\r
+void Use (void);\r
+void Search (objtype *ob);\r
+void SelectWeapon (void);\r
+void SelectItem (void);\r
+\r
+//----------\r
+\r
+boolean TryMove (objtype *ob);\r
+void T_Player (objtype *ob);\r
+\r
+void ClipMove (objtype *ob, long xmove, long ymove);\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                               CONTROL STUFF\r
+\r
+=============================================================================\r
+*/\r
+\r
+/*\r
+======================\r
+=\r
+= CheckWeaponChange\r
+=\r
+= Keys 1-4 change weapons\r
+=\r
+======================\r
+*/\r
+\r
+void CheckWeaponChange (void)\r
+{\r
+       int     i,buttons;\r
+\r
+       if (!gamestate.ammo)            // must use knife with no ammo\r
+               return;\r
+\r
+       for (i=wp_knife ; i<=gamestate.bestweapon ; i++)\r
+               if (buttonstate[bt_readyknife+i-wp_knife])\r
+               {\r
+                       gamestate.weapon = gamestate.chosenweapon = i;\r
+                       DrawWeapon ();\r
+                       return;\r
+               }\r
+}\r
+\r
+\r
+/*\r
+=======================\r
+=\r
+= ControlMovement\r
+=\r
+= Takes controlx,controly, and buttonstate[bt_strafe]\r
+=\r
+= Changes the player's angle and position\r
+=\r
+= There is an angle hack because when going 70 fps, the roundoff becomes\r
+= significant\r
+=\r
+=======================\r
+*/\r
+\r
+void ControlMovement (objtype *ob)\r
+{\r
+       long    oldx,oldy;\r
+       int             angle,maxxmove;\r
+       int             angleunits;\r
+       long    speed;\r
+\r
+       thrustspeed = 0;\r
+\r
+       oldx = player->x;\r
+       oldy = player->y;\r
+\r
+//\r
+// side to side move\r
+//\r
+       if (buttonstate[bt_strafe])\r
+       {\r
+       //\r
+       // strafing\r
+       //\r
+       //\r
+               if (controlx > 0)\r
+               {\r
+                       angle = ob->angle - ANGLES/4;\r
+                       if (angle < 0)\r
+                               angle += ANGLES;\r
+                       Thrust (angle,controlx*MOVESCALE);      // move to left\r
+               }\r
+               else if (controlx < 0)\r
+               {\r
+                       angle = ob->angle + ANGLES/4;\r
+                       if (angle >= ANGLES)\r
+                               angle -= ANGLES;\r
+                       Thrust (angle,-controlx*MOVESCALE);     // move to right\r
+               }\r
+       }\r
+       else\r
+       {\r
+       //\r
+       // not strafing\r
+       //\r
+               anglefrac += controlx;\r
+               angleunits = anglefrac/ANGLESCALE;\r
+               anglefrac -= angleunits*ANGLESCALE;\r
+               ob->angle -= angleunits;\r
+\r
+               if (ob->angle >= ANGLES)\r
+                       ob->angle -= ANGLES;\r
+               if (ob->angle < 0)\r
+                       ob->angle += ANGLES;\r
+\r
+       }\r
+\r
+//\r
+// forward/backwards move\r
+//\r
+       if (controly < 0)\r
+       {\r
+               Thrust (ob->angle,-controly*MOVESCALE); // move forwards\r
+       }\r
+       else if (controly > 0)\r
+       {\r
+               angle = ob->angle + ANGLES/2;\r
+               if (angle >= ANGLES)\r
+                       angle -= ANGLES;\r
+               Thrust (angle,controly*BACKMOVESCALE);          // move backwards\r
+       }\r
+\r
+       if (gamestate.victoryflag)              // watching the BJ actor\r
+               return;\r
+\r
+//\r
+// calculate total move\r
+//\r
+       playerxmove = player->x - oldx;\r
+       playerymove = player->y - oldy;\r
+}\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                       STATUS WINDOW STUFF\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+/*\r
+==================\r
+=\r
+= StatusDrawPic\r
+=\r
+==================\r
+*/\r
+\r
+void StatusDrawPic (unsigned x, unsigned y, unsigned picnum)\r
+{\r
+       unsigned        temp;\r
+\r
+       temp = bufferofs;\r
+       bufferofs = 0;\r
+\r
+       bufferofs = PAGE1START+(200-STATUSLINES)*SCREENWIDTH;\r
+       LatchDrawPic (x,y,picnum);\r
+       bufferofs = PAGE2START+(200-STATUSLINES)*SCREENWIDTH;\r
+       LatchDrawPic (x,y,picnum);\r
+       bufferofs = PAGE3START+(200-STATUSLINES)*SCREENWIDTH;\r
+       LatchDrawPic (x,y,picnum);\r
+\r
+       bufferofs = temp;\r
+}\r
+\r
+\r
+/*\r
+==================\r
+=\r
+= DrawFace\r
+=\r
+==================\r
+*/\r
+\r
+void DrawFace (void)\r
+{\r
+       if (gamestate.health)\r
+       {\r
+               #ifdef SPEAR\r
+               if (godmode)\r
+                       StatusDrawPic (17,4,GODMODEFACE1PIC+gamestate.faceframe);\r
+               else\r
+               #endif\r
+               StatusDrawPic (17,4,FACE1APIC+3*((100-gamestate.health)/16)+gamestate.faceframe);\r
+       }\r
+       else\r
+       {\r
+#ifndef SPEAR\r
+        if (LastAttacker->obclass == needleobj)\r
+          StatusDrawPic (17,4,MUTANTBJPIC);\r
+        else\r
+#endif\r
+          StatusDrawPic (17,4,FACE8APIC);\r
+       }\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= UpdateFace\r
+=\r
+= Calls draw face if time to change\r
+=\r
+===============\r
+*/\r
+\r
+#define FACETICS       70\r
+\r
+int    facecount;\r
+\r
+void   UpdateFace (void)\r
+{\r
+\r
+       if (SD_SoundPlaying() == GETGATLINGSND)\r
+         return;\r
+\r
+       facecount += tics;\r
+       if (facecount > US_RndT())\r
+       {\r
+               gamestate.faceframe = (US_RndT()>>6);\r
+               if (gamestate.faceframe==3)\r
+                       gamestate.faceframe = 1;\r
+\r
+               facecount = 0;\r
+               DrawFace ();\r
+       }\r
+}\r
+\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= LatchNumber\r
+=\r
+= right justifies and pads with blanks\r
+=\r
+===============\r
+*/\r
+\r
+void   LatchNumber (int x, int y, int width, long number)\r
+{\r
+       unsigned        length,c;\r
+       char    str[20];\r
+\r
+       ltoa (number,str,10);\r
+\r
+       length = strlen (str);\r
+\r
+       while (length<width)\r
+       {\r
+               StatusDrawPic (x,y,N_BLANKPIC);\r
+               x++;\r
+               width--;\r
+       }\r
+\r
+       c= length <= width ? 0 : length-width;\r
+\r
+       while (c<length)\r
+       {\r
+               StatusDrawPic (x,y,str[c]-'0'+ N_0PIC);\r
+               x++;\r
+               c++;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= DrawHealth\r
+=\r
+===============\r
+*/\r
+\r
+void   DrawHealth (void)\r
+{\r
+       LatchNumber (21,16,3,gamestate.health);\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= TakeDamage\r
+=\r
+===============\r
+*/\r
+\r
+void   TakeDamage (int points,objtype *attacker)\r
+{\r
+       LastAttacker = attacker;\r
+\r
+       if (gamestate.victoryflag)\r
+               return;\r
+       if (gamestate.difficulty==gd_baby)\r
+         points>>=2;\r
+\r
+       if (!godmode)\r
+               gamestate.health -= points;\r
+\r
+       if (gamestate.health<=0)\r
+       {\r
+               gamestate.health = 0;\r
+               playstate = ex_died;\r
+               killerobj = attacker;\r
+       }\r
+\r
+       StartDamageFlash (points);\r
+\r
+       gotgatgun=0;\r
+\r
+       DrawHealth ();\r
+       DrawFace ();\r
+\r
+       //\r
+       // MAKE BJ'S EYES BUG IF MAJOR DAMAGE!\r
+       //\r
+       #ifdef SPEAR\r
+       if (points > 30 && gamestate.health!=0 && !godmode)\r
+       {\r
+               StatusDrawPic (17,4,BJOUCHPIC);\r
+               facecount = 0;\r
+       }\r
+       #endif\r
+\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= HealSelf\r
+=\r
+===============\r
+*/\r
+\r
+void   HealSelf (int points)\r
+{\r
+       gamestate.health += points;\r
+       if (gamestate.health>100)\r
+               gamestate.health = 100;\r
+\r
+       DrawHealth ();\r
+       gotgatgun = 0;  // JR\r
+       DrawFace ();\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= DrawLevel\r
+=\r
+===============\r
+*/\r
+\r
+void   DrawLevel (void)\r
+{\r
+#ifdef SPEAR\r
+       if (gamestate.mapon == 20)\r
+               LatchNumber (2,16,2,18);\r
+       else\r
+#endif\r
+       LatchNumber (2,16,2,gamestate.mapon+1);\r
+}\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= DrawLives\r
+=\r
+===============\r
+*/\r
+\r
+void   DrawLives (void)\r
+{\r
+       LatchNumber (14,16,1,gamestate.lives);\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= GiveExtraMan\r
+=\r
+===============\r
+*/\r
+\r
+void   GiveExtraMan (void)\r
+{\r
+       if (gamestate.lives<9)\r
+               gamestate.lives++;\r
+       DrawLives ();\r
+       SD_PlaySound (BONUS1UPSND);\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= DrawScore\r
+=\r
+===============\r
+*/\r
+\r
+void   DrawScore (void)\r
+{\r
+       LatchNumber (6,16,6,gamestate.score);\r
+}\r
+\r
+/*\r
+===============\r
+=\r
+= GivePoints\r
+=\r
+===============\r
+*/\r
+\r
+void   GivePoints (long points)\r
+{\r
+       gamestate.score += points;\r
+       while (gamestate.score >= gamestate.nextextra)\r
+       {\r
+               gamestate.nextextra += EXTRAPOINTS;\r
+               GiveExtraMan ();\r
+       }\r
+       DrawScore ();\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+==================\r
+=\r
+= DrawWeapon\r
+=\r
+==================\r
+*/\r
+\r
+void DrawWeapon (void)\r
+{\r
+       StatusDrawPic (32,8,KNIFEPIC+gamestate.weapon);\r
+}\r
+\r
+\r
+/*\r
+==================\r
+=\r
+= DrawKeys\r
+=\r
+==================\r
+*/\r
+\r
+void DrawKeys (void)\r
+{\r
+       if (gamestate.keys & 1)\r
+               StatusDrawPic (30,4,GOLDKEYPIC);\r
+       else\r
+               StatusDrawPic (30,4,NOKEYPIC);\r
+\r
+       if (gamestate.keys & 2)\r
+               StatusDrawPic (30,20,SILVERKEYPIC);\r
+       else\r
+               StatusDrawPic (30,20,NOKEYPIC);\r
+}\r
+\r
+\r
+\r
+/*\r
+==================\r
+=\r
+= GiveWeapon\r
+=\r
+==================\r
+*/\r
+\r
+void GiveWeapon (int weapon)\r
+{\r
+       GiveAmmo (6);\r
+\r
+       if (gamestate.bestweapon<weapon)\r
+               gamestate.bestweapon = gamestate.weapon\r
+               = gamestate.chosenweapon = weapon;\r
+\r
+       DrawWeapon ();\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= DrawAmmo\r
+=\r
+===============\r
+*/\r
+\r
+void   DrawAmmo (void)\r
+{\r
+       LatchNumber (27,16,2,gamestate.ammo);\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= GiveAmmo\r
+=\r
+===============\r
+*/\r
+\r
+void   GiveAmmo (int ammo)\r
+{\r
+       if (!gamestate.ammo)                            // knife was out\r
+       {\r
+               if (!gamestate.attackframe)\r
+               {\r
+                       gamestate.weapon = gamestate.chosenweapon;\r
+                       DrawWeapon ();\r
+               }\r
+       }\r
+       gamestate.ammo += ammo;\r
+       if (gamestate.ammo > 99)\r
+               gamestate.ammo = 99;\r
+       DrawAmmo ();\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+==================\r
+=\r
+= GiveKey\r
+=\r
+==================\r
+*/\r
+\r
+void GiveKey (int key)\r
+{\r
+       gamestate.keys |= (1<<key);\r
+       DrawKeys ();\r
+}\r
+\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                       MOVEMENT\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= GetBonus\r
+=\r
+===================\r
+*/\r
+void GetBonus (statobj_t *check)\r
+{\r
+       switch (check->itemnumber)\r
+       {\r
+       case    bo_firstaid:\r
+               if (gamestate.health == 100)\r
+                       return;\r
+\r
+               SD_PlaySound (HEALTH2SND);\r
+               HealSelf (25);\r
+               break;\r
+\r
+       case    bo_key1:\r
+       case    bo_key2:\r
+       case    bo_key3:\r
+       case    bo_key4:\r
+               GiveKey (check->itemnumber - bo_key1);\r
+               SD_PlaySound (GETKEYSND);\r
+               break;\r
+\r
+       case    bo_cross:\r
+               SD_PlaySound (BONUS1SND);\r
+               GivePoints (100);\r
+               gamestate.treasurecount++;\r
+               break;\r
+       case    bo_chalice:\r
+               SD_PlaySound (BONUS2SND);\r
+               GivePoints (500);\r
+               gamestate.treasurecount++;\r
+               break;\r
+       case    bo_bible:\r
+               SD_PlaySound (BONUS3SND);\r
+               GivePoints (1000);\r
+               gamestate.treasurecount++;\r
+               break;\r
+       case    bo_crown:\r
+               SD_PlaySound (BONUS4SND);\r
+               GivePoints (5000);\r
+               gamestate.treasurecount++;\r
+               break;\r
+\r
+       case    bo_clip:\r
+               if (gamestate.ammo == 99)\r
+                       return;\r
+\r
+               SD_PlaySound (GETAMMOSND);\r
+               GiveAmmo (8);\r
+               break;\r
+       case    bo_clip2:\r
+               if (gamestate.ammo == 99)\r
+                       return;\r
+\r
+               SD_PlaySound (GETAMMOSND);\r
+               GiveAmmo (4);\r
+               break;\r
+\r
+#ifdef SPEAR\r
+       case    bo_25clip:\r
+               if (gamestate.ammo == 99)\r
+                 return;\r
+\r
+               SD_PlaySound (GETAMMOBOXSND);\r
+               GiveAmmo (25);\r
+               break;\r
+#endif\r
+\r
+       case    bo_machinegun:\r
+               SD_PlaySound (GETMACHINESND);\r
+               GiveWeapon (wp_machinegun);\r
+               break;\r
+       case    bo_chaingun:\r
+               SD_PlaySound (GETGATLINGSND);\r
+               GiveWeapon (wp_chaingun);\r
+\r
+               StatusDrawPic (17,4,GOTGATLINGPIC);\r
+               facecount = 0;\r
+               gotgatgun = 1;\r
+               break;\r
+\r
+       case    bo_fullheal:\r
+               SD_PlaySound (BONUS1UPSND);\r
+               HealSelf (99);\r
+               GiveAmmo (25);\r
+               GiveExtraMan ();\r
+               gamestate.treasurecount++;\r
+               break;\r
+\r
+       case    bo_food:\r
+               if (gamestate.health == 100)\r
+                       return;\r
+\r
+               SD_PlaySound (HEALTH1SND);\r
+               HealSelf (10);\r
+               break;\r
+\r
+       case    bo_alpo:\r
+               if (gamestate.health == 100)\r
+                       return;\r
+\r
+               SD_PlaySound (HEALTH1SND);\r
+               HealSelf (4);\r
+               break;\r
+\r
+       case    bo_gibs:\r
+               if (gamestate.health >10)\r
+                       return;\r
+\r
+               SD_PlaySound (SLURPIESND);\r
+               HealSelf (1);\r
+               break;\r
+\r
+       case    bo_spear:\r
+               spearflag = true;\r
+               spearx = player->x;\r
+               speary = player->y;\r
+               spearangle = player->angle;\r
+               playstate = ex_completed;\r
+       }\r
+\r
+       StartBonusFlash ();\r
+       check->shapenum = -1;                   // remove from list\r
+}\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= TryMove\r
+=\r
+= returns true if move ok\r
+= debug: use pointers to optimize\r
+===================\r
+*/\r
+\r
+boolean TryMove (objtype *ob)\r
+{\r
+       int                     xl,yl,xh,yh,x,y;\r
+       objtype         *check;\r
+       long            deltax,deltay;\r
+\r
+       xl = (ob->x-PLAYERSIZE) >>TILESHIFT;\r
+       yl = (ob->y-PLAYERSIZE) >>TILESHIFT;\r
+\r
+       xh = (ob->x+PLAYERSIZE) >>TILESHIFT;\r
+       yh = (ob->y+PLAYERSIZE) >>TILESHIFT;\r
+\r
+//\r
+// check for solid walls\r
+//\r
+       for (y=yl;y<=yh;y++)\r
+               for (x=xl;x<=xh;x++)\r
+               {\r
+                       check = actorat[x][y];\r
+                       if (check && check<objlist)\r
+                               return false;\r
+               }\r
+\r
+//\r
+// check for actors\r
+//\r
+       if (yl>0)\r
+               yl--;\r
+       if (yh<MAPSIZE-1)\r
+               yh++;\r
+       if (xl>0)\r
+               xl--;\r
+       if (xh<MAPSIZE-1)\r
+               xh++;\r
+\r
+       for (y=yl;y<=yh;y++)\r
+               for (x=xl;x<=xh;x++)\r
+               {\r
+                       check = actorat[x][y];\r
+                       if (check > objlist\r
+                       && (check->flags & FL_SHOOTABLE) )\r
+                       {\r
+                               deltax = ob->x - check->x;\r
+                               if (deltax < -MINACTORDIST || deltax > MINACTORDIST)\r
+                                       continue;\r
+                               deltay = ob->y - check->y;\r
+                               if (deltay < -MINACTORDIST || deltay > MINACTORDIST)\r
+                                       continue;\r
+\r
+                               return false;\r
+                       }\r
+               }\r
+\r
+       return true;\r
+}\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= ClipMove\r
+=\r
+===================\r
+*/\r
+\r
+void ClipMove (objtype *ob, long xmove, long ymove)\r
+{\r
+       long    basex,basey;\r
+\r
+       basex = ob->x;\r
+       basey = ob->y;\r
+\r
+       ob->x = basex+xmove;\r
+       ob->y = basey+ymove;\r
+       if (TryMove (ob))\r
+               return;\r
+\r
+       if (noclip && ob->x > 2*TILEGLOBAL && ob->y > 2*TILEGLOBAL &&\r
+       ob->x < (((long)(mapwidth-1))<<TILESHIFT)\r
+       && ob->y < (((long)(mapheight-1))<<TILESHIFT) )\r
+               return;         // walk through walls\r
+\r
+       if (!SD_SoundPlaying())\r
+               SD_PlaySound (HITWALLSND);\r
+\r
+       ob->x = basex+xmove;\r
+       ob->y = basey;\r
+       if (TryMove (ob))\r
+               return;\r
+\r
+       ob->x = basex;\r
+       ob->y = basey+ymove;\r
+       if (TryMove (ob))\r
+               return;\r
+\r
+       ob->x = basex;\r
+       ob->y = basey;\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+===================\r
+=\r
+= VictoryTile\r
+=\r
+===================\r
+*/\r
+\r
+void VictoryTile (void)\r
+{\r
+#ifndef SPEAR\r
+       SpawnBJVictory ();\r
+#endif\r
+\r
+       gamestate.victoryflag = true;\r
+}\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= Thrust\r
+=\r
+===================\r
+*/\r
+\r
+void Thrust (int angle, long speed)\r
+{\r
+       long xmove,ymove;\r
+       long    slowmax;\r
+       unsigned        offset;\r
+\r
+\r
+       //\r
+       // ZERO FUNNY COUNTER IF MOVED!\r
+       //\r
+       #ifdef SPEAR\r
+       if (speed)\r
+               funnyticount = 0;\r
+       #endif\r
+\r
+       thrustspeed += speed;\r
+//\r
+// moving bounds speed\r
+//\r
+       if (speed >= MINDIST*2)\r
+               speed = MINDIST*2-1;\r
+\r
+       xmove = FixedByFrac(speed,costable[angle]);\r
+       ymove = -FixedByFrac(speed,sintable[angle]);\r
+\r
+       ClipMove(player,xmove,ymove);\r
+\r
+       player->tilex = player->x >> TILESHIFT;         // scale to tile values\r
+       player->tiley = player->y >> TILESHIFT;\r
+\r
+       offset = farmapylookup[player->tiley]+player->tilex;\r
+       player->areanumber = *(mapsegs[0] + offset) -AREATILE;\r
+\r
+       if (*(mapsegs[1] + offset) == EXITTILE)\r
+               VictoryTile ();\r
+}\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                               ACTIONS\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= Cmd_Fire\r
+=\r
+===============\r
+*/\r
+\r
+void Cmd_Fire (void)\r
+{\r
+       buttonheld[bt_attack] = true;\r
+\r
+       gamestate.weaponframe = 0;\r
+\r
+       player->state = &s_attack;\r
+\r
+       gamestate.attackframe = 0;\r
+       gamestate.attackcount =\r
+               attackinfo[gamestate.weapon][gamestate.attackframe].tics;\r
+       gamestate.weaponframe =\r
+               attackinfo[gamestate.weapon][gamestate.attackframe].frame;\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= Cmd_Use\r
+=\r
+===============\r
+*/\r
+\r
+void Cmd_Use (void)\r
+{\r
+       objtype         *check;\r
+       int                     checkx,checky,doornum,dir;\r
+       boolean         elevatorok;\r
+\r
+\r
+//\r
+// find which cardinal direction the player is facing\r
+//\r
+       if (player->angle < ANGLES/8 || player->angle > 7*ANGLES/8)\r
+       {\r
+               checkx = player->tilex + 1;\r
+               checky = player->tiley;\r
+               dir = di_east;\r
+               elevatorok = true;\r
+       }\r
+       else if (player->angle < 3*ANGLES/8)\r
+       {\r
+               checkx = player->tilex;\r
+               checky = player->tiley-1;\r
+               dir = di_north;\r
+               elevatorok = false;\r
+       }\r
+       else if (player->angle < 5*ANGLES/8)\r
+       {\r
+               checkx = player->tilex - 1;\r
+               checky = player->tiley;\r
+               dir = di_west;\r
+               elevatorok = true;\r
+       }\r
+       else\r
+       {\r
+               checkx = player->tilex;\r
+               checky = player->tiley + 1;\r
+               dir = di_south;\r
+               elevatorok = false;\r
+       }\r
+\r
+       doornum = tilemap[checkx][checky];\r
+       if (*(mapsegs[1]+farmapylookup[checky]+checkx) == PUSHABLETILE)\r
+       {\r
+       //\r
+       // pushable wall\r
+       //\r
+\r
+               PushWall (checkx,checky,dir);\r
+               return;\r
+       }\r
+       if (!buttonheld[bt_use] && doornum == ELEVATORTILE && elevatorok)\r
+       {\r
+       //\r
+       // use elevator\r
+       //\r
+               buttonheld[bt_use] = true;\r
+\r
+               tilemap[checkx][checky]++;              // flip switch\r
+               if (*(mapsegs[0]+farmapylookup[player->tiley]+player->tilex) == ALTELEVATORTILE)\r
+                       playstate = ex_secretlevel;\r
+               else\r
+                       playstate = ex_completed;\r
+               SD_PlaySound (LEVELDONESND);\r
+               SD_WaitSoundDone();\r
+       }\r
+       else if (!buttonheld[bt_use] && doornum & 0x80)\r
+       {\r
+               buttonheld[bt_use] = true;\r
+               OperateDoor (doornum & ~0x80);\r
+       }\r
+       else\r
+               SD_PlaySound (DONOTHINGSND);\r
+\r
+}\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                  PLAYER CONTROL\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnPlayer\r
+=\r
+===============\r
+*/\r
+\r
+void SpawnPlayer (int tilex, int tiley, int dir)\r
+{\r
+       player->obclass = playerobj;\r
+       player->active = true;\r
+       player->tilex = tilex;\r
+       player->tiley = tiley;\r
+       player->areanumber =\r
+               *(mapsegs[0] + farmapylookup[player->tiley]+player->tilex);\r
+       player->x = ((long)tilex<<TILESHIFT)+TILEGLOBAL/2;\r
+       player->y = ((long)tiley<<TILESHIFT)+TILEGLOBAL/2;\r
+       player->state = &s_player;\r
+       player->angle = (1-dir)*90;\r
+       if (player->angle<0)\r
+               player->angle += ANGLES;\r
+       player->flags = FL_NEVERMARK;\r
+       Thrust (0,0);                           // set some variables\r
+\r
+       InitAreas ();\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= T_KnifeAttack\r
+=\r
+= Update player hands, and try to do damage when the proper frame is reached\r
+=\r
+===============\r
+*/\r
+\r
+void   KnifeAttack (objtype *ob)\r
+{\r
+       objtype *check,*closest;\r
+       long    dist;\r
+\r
+       SD_PlaySound (ATKKNIFESND);\r
+// actually fire\r
+       dist = 0x7fffffff;\r
+       closest = NULL;\r
+       for (check=ob->next ; check ; check=check->next)\r
+               if ( (check->flags & FL_SHOOTABLE)\r
+               && (check->flags & FL_VISABLE)\r
+               && abs (check->viewx-centerx) < shootdelta\r
+               )\r
+               {\r
+                       if (check->transx < dist)\r
+                       {\r
+                               dist = check->transx;\r
+                               closest = check;\r
+                       }\r
+               }\r
+\r
+       if (!closest || dist> 0x18000l)\r
+       {\r
+       // missed\r
+\r
+               return;\r
+       }\r
+\r
+// hit something\r
+       DamageActor (closest,US_RndT() >> 4);\r
+}\r
+\r
+\r
+\r
+void   GunAttack (objtype *ob)\r
+{\r
+       objtype *check,*closest,*oldclosest;\r
+       int             damage;\r
+       int             dx,dy,dist;\r
+       long    viewdist;\r
+\r
+       switch (gamestate.weapon)\r
+       {\r
+       case wp_pistol:\r
+               SD_PlaySound (ATKPISTOLSND);\r
+               break;\r
+       case wp_machinegun:\r
+               SD_PlaySound (ATKMACHINEGUNSND);\r
+               break;\r
+       case wp_chaingun:\r
+               SD_PlaySound (ATKGATLINGSND);\r
+               break;\r
+       }\r
+\r
+       madenoise = true;\r
+\r
+//\r
+// find potential targets\r
+//\r
+       viewdist = 0x7fffffffl;\r
+       closest = NULL;\r
+\r
+       while (1)\r
+       {\r
+               oldclosest = closest;\r
+\r
+               for (check=ob->next ; check ; check=check->next)\r
+                       if ( (check->flags & FL_SHOOTABLE)\r
+                       && (check->flags & FL_VISABLE)\r
+                       && abs (check->viewx-centerx) < shootdelta\r
+                       )\r
+                       {\r
+                               if (check->transx < viewdist)\r
+                               {\r
+                                       viewdist = check->transx;\r
+                                       closest = check;\r
+                               }\r
+                       }\r
+\r
+               if (closest == oldclosest)\r
+                       return;                                         // no more targets, all missed\r
+\r
+       //\r
+       // trace a line from player to enemey\r
+       //\r
+               if (CheckLine(closest))\r
+                       break;\r
+\r
+       }\r
+\r
+//\r
+// hit something\r
+//\r
+       dx = abs(closest->tilex - player->tilex);\r
+       dy = abs(closest->tiley - player->tiley);\r
+       dist = dx>dy ? dx:dy;\r
+\r
+       if (dist<2)\r
+               damage = US_RndT() / 4;\r
+       else if (dist<4)\r
+               damage = US_RndT() / 6;\r
+       else\r
+       {\r
+               if ( (US_RndT() / 12) < dist)           // missed\r
+                       return;\r
+               damage = US_RndT() / 6;\r
+       }\r
+\r
+       DamageActor (closest,damage);\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= VictorySpin\r
+=\r
+===============\r
+*/\r
+\r
+void VictorySpin (void)\r
+{\r
+       long    desty;\r
+\r
+       if (player->angle > 270)\r
+       {\r
+               player->angle -= tics * 3;\r
+               if (player->angle < 270)\r
+                       player->angle = 270;\r
+       }\r
+       else if (player->angle < 270)\r
+       {\r
+               player->angle += tics * 3;\r
+               if (player->angle > 270)\r
+                       player->angle = 270;\r
+       }\r
+\r
+       desty = (((long)player->tiley-5)<<TILESHIFT)-0x3000;\r
+\r
+       if (player->y > desty)\r
+       {\r
+               player->y -= tics*4096;\r
+               if (player->y < desty)\r
+                       player->y = desty;\r
+       }\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= T_Attack\r
+=\r
+===============\r
+*/\r
+\r
+void   T_Attack (objtype *ob)\r
+{\r
+       struct  atkinf  *cur;\r
+\r
+       UpdateFace ();\r
+\r
+       if (gamestate.victoryflag)              // watching the BJ actor\r
+       {\r
+               VictorySpin ();\r
+               return;\r
+       }\r
+\r
+       if ( buttonstate[bt_use] && !buttonheld[bt_use] )\r
+               buttonstate[bt_use] = false;\r
+\r
+       if ( buttonstate[bt_attack] && !buttonheld[bt_attack])\r
+               buttonstate[bt_attack] = false;\r
+\r
+       ControlMovement (ob);\r
+       if (gamestate.victoryflag)              // watching the BJ actor\r
+               return;\r
+\r
+       plux = player->x >> UNSIGNEDSHIFT;                      // scale to fit in unsigned\r
+       pluy = player->y >> UNSIGNEDSHIFT;\r
+       player->tilex = player->x >> TILESHIFT;         // scale to tile values\r
+       player->tiley = player->y >> TILESHIFT;\r
+\r
+//\r
+// change frame and fire\r
+//\r
+       gamestate.attackcount -= tics;\r
+       while (gamestate.attackcount <= 0)\r
+       {\r
+               cur = &attackinfo[gamestate.weapon][gamestate.attackframe];\r
+               switch (cur->attack)\r
+               {\r
+               case -1:\r
+                       ob->state = &s_player;\r
+                       if (!gamestate.ammo)\r
+                       {\r
+                               gamestate.weapon = wp_knife;\r
+                               DrawWeapon ();\r
+                       }\r
+                       else\r
+                       {\r
+                               if (gamestate.weapon != gamestate.chosenweapon)\r
+                               {\r
+                                       gamestate.weapon = gamestate.chosenweapon;\r
+                                       DrawWeapon ();\r
+                               }\r
+                       };\r
+                       gamestate.attackframe = gamestate.weaponframe = 0;\r
+                       return;\r
+\r
+               case 4:\r
+                       if (!gamestate.ammo)\r
+                               break;\r
+                       if (buttonstate[bt_attack])\r
+                               gamestate.attackframe -= 2;\r
+               case 1:\r
+                       if (!gamestate.ammo)\r
+                       {       // can only happen with chain gun\r
+                               gamestate.attackframe++;\r
+                               break;\r
+                       }\r
+                       GunAttack (ob);\r
+                       gamestate.ammo--;\r
+                       DrawAmmo ();\r
+                       break;\r
+\r
+               case 2:\r
+                       KnifeAttack (ob);\r
+                       break;\r
+\r
+               case 3:\r
+                       if (gamestate.ammo && buttonstate[bt_attack])\r
+                               gamestate.attackframe -= 2;\r
+                       break;\r
+               }\r
+\r
+               gamestate.attackcount += cur->tics;\r
+               gamestate.attackframe++;\r
+               gamestate.weaponframe =\r
+                       attackinfo[gamestate.weapon][gamestate.attackframe].frame;\r
+       }\r
+\r
+}\r
+\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= T_Player\r
+=\r
+===============\r
+*/\r
+\r
+void   T_Player (objtype *ob)\r
+{\r
+       if (gamestate.victoryflag)              // watching the BJ actor\r
+       {\r
+               VictorySpin ();\r
+               return;\r
+       }\r
+\r
+       UpdateFace ();\r
+       CheckWeaponChange ();\r
+\r
+       if ( buttonstate[bt_use] )\r
+               Cmd_Use ();\r
+\r
+       if ( buttonstate[bt_attack] && !buttonheld[bt_attack])\r
+               Cmd_Fire ();\r
+\r
+       ControlMovement (ob);\r
+       if (gamestate.victoryflag)              // watching the BJ actor\r
+               return;\r
+\r
+\r
+       plux = player->x >> UNSIGNEDSHIFT;                      // scale to fit in unsigned\r
+       pluy = player->y >> UNSIGNEDSHIFT;\r
+       player->tilex = player->x >> TILESHIFT;         // scale to tile values\r
+       player->tiley = player->y >> TILESHIFT;\r
+}\r
+\r
+\r
diff --git a/src/lib/hb/wl_asm.asm b/src/lib/hb/wl_asm.asm
new file mode 100755 (executable)
index 0000000..cca5d69
--- /dev/null
@@ -0,0 +1,69 @@
+; JABHACK.ASM\r
+\r
+.386C\r
+IDEAL\r
+MODEL  MEDIUM\r
+\r
+EXTRN  LDIV@:far\r
+\r
+;============================================================================\r
+\r
+DATASEG\r
+\r
+;============================================================================\r
+\r
+CODESEG\r
+\r
+;      Hacked up Juan Jimenez's code a bit to just return 386/not 386\r
+PROC   _CheckIs386\r
+PUBLIC _CheckIs386\r
+\r
+;hack to never look for a 386, for benchmark comparisons of same code on all CPUs\r
+;      pushf                   ; Save flag registers, we use them here\r
+;      xor     ax,ax           ; Clear AX and...\r
+;      push ax                 ; ...push it onto the stack\r
+;      popf                    ; Pop 0 into flag registers (all bits to 0),\r
+;      pushf                   ; attempting to set bits 12-15 of flags to 0's\r
+;      pop     ax                      ; Recover the save flags\r
+;      and     ax,08000h       ; If bits 12-15 of flags are set to\r
+;      cmp     ax,08000h       ; zero then it's 8088/86 or 80188/186\r
+;      jz      not386\r
+;\r
+;      mov     ax,07000h       ; Try to set flag bits 12-14 to 1's\r
+;      push ax                 ; Push the test value onto the stack\r
+;      popf                    ; Pop it into the flag register\r
+;      pushf                   ; Push it back onto the stack\r
+;      pop     ax                      ; Pop it into AX for check\r
+;      and     ax,07000h       ; if bits 12-14 are cleared then\r
+;      jz      not386          ; the chip is an 80286\r
+;\r
+;      mov     ax,1            ; We now assume it's a 80386 or better\r
+;      popf\r
+;      retf\r
+;end benchmark hack\r
+\r
+not386:\r
+       xor     ax,ax\r
+       popf\r
+       retf\r
+\r
+       ENDP\r
+\r
+\r
+PROC   _jabhack2\r
+PUBLIC _jabhack2\r
+\r
+       push    es\r
+\r
+       mov     ax,seg LDIV@\r
+       mov     es,ax\r
+       mov     ax,9090h                                        ;Two NOP's\r
+       mov     [WORD FAR es:LDIV@],ax          ;Patch over XOR AX,AX\r
+       mov     [WORD FAR es:LDIV@+2],ax        ;and over JMP SHORT COMMON\r
+\r
+       pop     es\r
+       retf\r
+\r
+       ENDP\r
+\r
+       END\r
similarity index 100%
rename from src/lib/wl_debug.c
rename to src/lib/hb/wl_debug.c
diff --git a/src/lib/hb/wl_def.h b/src/lib/hb/wl_def.h
new file mode 100755 (executable)
index 0000000..d1bc080
--- /dev/null
@@ -0,0 +1,1276 @@
+//#define BETA\r
+#define YEAR   1992\r
+#define MONTH  9\r
+#define DAY            30\r
+\r
+#include "ID_HEADS.H"\r
+#include <MATH.H>\r
+#include <VALUES.H>\r
+\r
+#include "WL_MENU.H"\r
+\r
+#ifdef SPANISH\r
+#include "SPANISH.H"\r
+#else\r
+#include "FOREIGN.H"\r
+#endif\r
+\r
+#ifdef SPEAR\r
+#include "F_SPEAR.H"\r
+#endif\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                       MACROS\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+#define COLORBORDER(color)             asm{mov dx,STATUS_REGISTER_1;in al,dx;\\r
+       mov dx,ATR_INDEX;mov al,ATR_OVERSCAN;out dx,al;mov al,color;out dx,al;\\r
+       mov     al,32;out dx,al};\r
+\r
+#define MAPSPOT(x,y,plane)             (*(mapsegs[plane]+farmapylookup[y]+x))\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
+/*\r
+=============================================================================\r
+\r
+                                                GLOBAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+#define MAXACTORS              150                             // max number of nazis, etc / map\r
+#define MAXSTATS               400                             // max number of lamps, bonus, etc\r
+#define MAXDOORS               64                              // max number of sliding doors\r
+#define MAXWALLTILES   64                              // max number of wall tiles\r
+\r
+//\r
+// tile constants\r
+//\r
+\r
+#define        ICONARROWS              90\r
+#define PUSHABLETILE   98\r
+#define EXITTILE               99                              // at end of castle\r
+#define AREATILE               107                             // first of NUMAREAS floor tiles\r
+#define NUMAREAS               37\r
+#define ELEVATORTILE   21\r
+#define AMBUSHTILE             106\r
+#define        ALTELEVATORTILE 107\r
+\r
+#define NUMBERCHARS    9\r
+\r
+\r
+//----------------\r
+\r
+#define EXTRAPOINTS            40000\r
+\r
+#define PLAYERSPEED            3000\r
+#define RUNSPEED               6000\r
+\r
+#define        SCREENSEG               0xa000\r
+\r
+#define SCREENBWIDE            80\r
+\r
+#define HEIGHTRATIO            0.50            // also defined in id_mm.c\r
+\r
+#define BORDERCOLOR    3\r
+#define FLASHCOLOR     5\r
+#define FLASHTICS      4\r
+\r
+\r
+#define PLAYERSIZE             MINDIST                 // player radius\r
+#define MINACTORDIST   0x10000l                // minimum dist from player center\r
+                                                                               // to any actor center\r
+\r
+#define NUMLATCHPICS   100\r
+\r
+\r
+#define PI     3.141592657\r
+\r
+#define GLOBAL1                (1l<<16)\r
+#define TILEGLOBAL  GLOBAL1\r
+#define PIXGLOBAL      (GLOBAL1/64)\r
+#define TILESHIFT              16l\r
+#define UNSIGNEDSHIFT  8\r
+\r
+#define ANGLES         360                                     // must be divisable by 4\r
+#define ANGLEQUAD      (ANGLES/4)\r
+#define FINEANGLES     3600\r
+#define ANG90          (FINEANGLES/4)\r
+#define ANG180         (ANG90*2)\r
+#define ANG270         (ANG90*3)\r
+#define ANG360         (ANG90*4)\r
+#define VANG90         (ANGLES/4)\r
+#define VANG180                (VANG90*2)\r
+#define VANG270                (VANG90*3)\r
+#define VANG360                (VANG90*4)\r
+\r
+#define MINDIST                (0x5800l)\r
+\r
+\r
+#define        MAXSCALEHEIGHT  256                             // largest scale on largest view\r
+\r
+#define MAXVIEWWIDTH           320\r
+\r
+#define MAPSIZE                64                                      // maps are 64*64 max\r
+#define NORTH  0\r
+#define EAST   1\r
+#define SOUTH  2\r
+#define WEST   3\r
+\r
+\r
+#define STATUSLINES            40\r
+\r
+#define SCREENSIZE             (SCREENBWIDE*208)\r
+#define PAGE1START             0\r
+#define PAGE2START             (SCREENSIZE)\r
+#define PAGE3START             (SCREENSIZE*2u)\r
+#define        FREESTART               (SCREENSIZE*3u)\r
+\r
+\r
+#define PIXRADIUS              512\r
+\r
+#define STARTAMMO              8\r
+\r
+\r
+// object flag values\r
+\r
+#define FL_SHOOTABLE   1\r
+#define FL_BONUS               2\r
+#define FL_NEVERMARK   4\r
+#define FL_VISABLE             8\r
+#define FL_ATTACKMODE  16\r
+#define FL_FIRSTATTACK 32\r
+#define FL_AMBUSH              64\r
+#define FL_NONMARK             128\r
+\r
+\r
+//\r
+// sprite constants\r
+//\r
+\r
+enum   {\r
+               SPR_DEMO,\r
+               SPR_DEATHCAM,\r
+//\r
+// static sprites\r
+//\r
+               SPR_STAT_0,SPR_STAT_1,SPR_STAT_2,SPR_STAT_3,\r
+               SPR_STAT_4,SPR_STAT_5,SPR_STAT_6,SPR_STAT_7,\r
+\r
+               SPR_STAT_8,SPR_STAT_9,SPR_STAT_10,SPR_STAT_11,\r
+               SPR_STAT_12,SPR_STAT_13,SPR_STAT_14,SPR_STAT_15,\r
+\r
+               SPR_STAT_16,SPR_STAT_17,SPR_STAT_18,SPR_STAT_19,\r
+               SPR_STAT_20,SPR_STAT_21,SPR_STAT_22,SPR_STAT_23,\r
+\r
+               SPR_STAT_24,SPR_STAT_25,SPR_STAT_26,SPR_STAT_27,\r
+               SPR_STAT_28,SPR_STAT_29,SPR_STAT_30,SPR_STAT_31,\r
+\r
+               SPR_STAT_32,SPR_STAT_33,SPR_STAT_34,SPR_STAT_35,\r
+               SPR_STAT_36,SPR_STAT_37,SPR_STAT_38,SPR_STAT_39,\r
+\r
+               SPR_STAT_40,SPR_STAT_41,SPR_STAT_42,SPR_STAT_43,\r
+               SPR_STAT_44,SPR_STAT_45,SPR_STAT_46,SPR_STAT_47,\r
+\r
+#ifdef SPEAR\r
+               SPR_STAT_48,SPR_STAT_49,SPR_STAT_50,SPR_STAT_51,\r
+#endif\r
+\r
+//\r
+// guard\r
+//\r
+               SPR_GRD_S_1,SPR_GRD_S_2,SPR_GRD_S_3,SPR_GRD_S_4,\r
+               SPR_GRD_S_5,SPR_GRD_S_6,SPR_GRD_S_7,SPR_GRD_S_8,\r
+\r
+               SPR_GRD_W1_1,SPR_GRD_W1_2,SPR_GRD_W1_3,SPR_GRD_W1_4,\r
+               SPR_GRD_W1_5,SPR_GRD_W1_6,SPR_GRD_W1_7,SPR_GRD_W1_8,\r
+\r
+               SPR_GRD_W2_1,SPR_GRD_W2_2,SPR_GRD_W2_3,SPR_GRD_W2_4,\r
+               SPR_GRD_W2_5,SPR_GRD_W2_6,SPR_GRD_W2_7,SPR_GRD_W2_8,\r
+\r
+               SPR_GRD_W3_1,SPR_GRD_W3_2,SPR_GRD_W3_3,SPR_GRD_W3_4,\r
+               SPR_GRD_W3_5,SPR_GRD_W3_6,SPR_GRD_W3_7,SPR_GRD_W3_8,\r
+\r
+               SPR_GRD_W4_1,SPR_GRD_W4_2,SPR_GRD_W4_3,SPR_GRD_W4_4,\r
+               SPR_GRD_W4_5,SPR_GRD_W4_6,SPR_GRD_W4_7,SPR_GRD_W4_8,\r
+\r
+               SPR_GRD_PAIN_1,SPR_GRD_DIE_1,SPR_GRD_DIE_2,SPR_GRD_DIE_3,\r
+               SPR_GRD_PAIN_2,SPR_GRD_DEAD,\r
+\r
+               SPR_GRD_SHOOT1,SPR_GRD_SHOOT2,SPR_GRD_SHOOT3,\r
+\r
+//\r
+// dogs\r
+//\r
+               SPR_DOG_W1_1,SPR_DOG_W1_2,SPR_DOG_W1_3,SPR_DOG_W1_4,\r
+               SPR_DOG_W1_5,SPR_DOG_W1_6,SPR_DOG_W1_7,SPR_DOG_W1_8,\r
+\r
+               SPR_DOG_W2_1,SPR_DOG_W2_2,SPR_DOG_W2_3,SPR_DOG_W2_4,\r
+               SPR_DOG_W2_5,SPR_DOG_W2_6,SPR_DOG_W2_7,SPR_DOG_W2_8,\r
+\r
+               SPR_DOG_W3_1,SPR_DOG_W3_2,SPR_DOG_W3_3,SPR_DOG_W3_4,\r
+               SPR_DOG_W3_5,SPR_DOG_W3_6,SPR_DOG_W3_7,SPR_DOG_W3_8,\r
+\r
+               SPR_DOG_W4_1,SPR_DOG_W4_2,SPR_DOG_W4_3,SPR_DOG_W4_4,\r
+               SPR_DOG_W4_5,SPR_DOG_W4_6,SPR_DOG_W4_7,SPR_DOG_W4_8,\r
+\r
+               SPR_DOG_DIE_1,SPR_DOG_DIE_2,SPR_DOG_DIE_3,SPR_DOG_DEAD,\r
+               SPR_DOG_JUMP1,SPR_DOG_JUMP2,SPR_DOG_JUMP3,\r
+\r
+\r
+\r
+//\r
+// ss\r
+//\r
+               SPR_SS_S_1,SPR_SS_S_2,SPR_SS_S_3,SPR_SS_S_4,\r
+               SPR_SS_S_5,SPR_SS_S_6,SPR_SS_S_7,SPR_SS_S_8,\r
+\r
+               SPR_SS_W1_1,SPR_SS_W1_2,SPR_SS_W1_3,SPR_SS_W1_4,\r
+               SPR_SS_W1_5,SPR_SS_W1_6,SPR_SS_W1_7,SPR_SS_W1_8,\r
+\r
+               SPR_SS_W2_1,SPR_SS_W2_2,SPR_SS_W2_3,SPR_SS_W2_4,\r
+               SPR_SS_W2_5,SPR_SS_W2_6,SPR_SS_W2_7,SPR_SS_W2_8,\r
+\r
+               SPR_SS_W3_1,SPR_SS_W3_2,SPR_SS_W3_3,SPR_SS_W3_4,\r
+               SPR_SS_W3_5,SPR_SS_W3_6,SPR_SS_W3_7,SPR_SS_W3_8,\r
+\r
+               SPR_SS_W4_1,SPR_SS_W4_2,SPR_SS_W4_3,SPR_SS_W4_4,\r
+               SPR_SS_W4_5,SPR_SS_W4_6,SPR_SS_W4_7,SPR_SS_W4_8,\r
+\r
+               SPR_SS_PAIN_1,SPR_SS_DIE_1,SPR_SS_DIE_2,SPR_SS_DIE_3,\r
+               SPR_SS_PAIN_2,SPR_SS_DEAD,\r
+\r
+               SPR_SS_SHOOT1,SPR_SS_SHOOT2,SPR_SS_SHOOT3,\r
+\r
+//\r
+// mutant\r
+//\r
+               SPR_MUT_S_1,SPR_MUT_S_2,SPR_MUT_S_3,SPR_MUT_S_4,\r
+               SPR_MUT_S_5,SPR_MUT_S_6,SPR_MUT_S_7,SPR_MUT_S_8,\r
+\r
+               SPR_MUT_W1_1,SPR_MUT_W1_2,SPR_MUT_W1_3,SPR_MUT_W1_4,\r
+               SPR_MUT_W1_5,SPR_MUT_W1_6,SPR_MUT_W1_7,SPR_MUT_W1_8,\r
+\r
+               SPR_MUT_W2_1,SPR_MUT_W2_2,SPR_MUT_W2_3,SPR_MUT_W2_4,\r
+               SPR_MUT_W2_5,SPR_MUT_W2_6,SPR_MUT_W2_7,SPR_MUT_W2_8,\r
+\r
+               SPR_MUT_W3_1,SPR_MUT_W3_2,SPR_MUT_W3_3,SPR_MUT_W3_4,\r
+               SPR_MUT_W3_5,SPR_MUT_W3_6,SPR_MUT_W3_7,SPR_MUT_W3_8,\r
+\r
+               SPR_MUT_W4_1,SPR_MUT_W4_2,SPR_MUT_W4_3,SPR_MUT_W4_4,\r
+               SPR_MUT_W4_5,SPR_MUT_W4_6,SPR_MUT_W4_7,SPR_MUT_W4_8,\r
+\r
+               SPR_MUT_PAIN_1,SPR_MUT_DIE_1,SPR_MUT_DIE_2,SPR_MUT_DIE_3,\r
+               SPR_MUT_PAIN_2,SPR_MUT_DIE_4,SPR_MUT_DEAD,\r
+\r
+               SPR_MUT_SHOOT1,SPR_MUT_SHOOT2,SPR_MUT_SHOOT3,SPR_MUT_SHOOT4,\r
+\r
+//\r
+// officer\r
+//\r
+               SPR_OFC_S_1,SPR_OFC_S_2,SPR_OFC_S_3,SPR_OFC_S_4,\r
+               SPR_OFC_S_5,SPR_OFC_S_6,SPR_OFC_S_7,SPR_OFC_S_8,\r
+\r
+               SPR_OFC_W1_1,SPR_OFC_W1_2,SPR_OFC_W1_3,SPR_OFC_W1_4,\r
+               SPR_OFC_W1_5,SPR_OFC_W1_6,SPR_OFC_W1_7,SPR_OFC_W1_8,\r
+\r
+               SPR_OFC_W2_1,SPR_OFC_W2_2,SPR_OFC_W2_3,SPR_OFC_W2_4,\r
+               SPR_OFC_W2_5,SPR_OFC_W2_6,SPR_OFC_W2_7,SPR_OFC_W2_8,\r
+\r
+               SPR_OFC_W3_1,SPR_OFC_W3_2,SPR_OFC_W3_3,SPR_OFC_W3_4,\r
+               SPR_OFC_W3_5,SPR_OFC_W3_6,SPR_OFC_W3_7,SPR_OFC_W3_8,\r
+\r
+               SPR_OFC_W4_1,SPR_OFC_W4_2,SPR_OFC_W4_3,SPR_OFC_W4_4,\r
+               SPR_OFC_W4_5,SPR_OFC_W4_6,SPR_OFC_W4_7,SPR_OFC_W4_8,\r
+\r
+               SPR_OFC_PAIN_1,SPR_OFC_DIE_1,SPR_OFC_DIE_2,SPR_OFC_DIE_3,\r
+               SPR_OFC_PAIN_2,SPR_OFC_DIE_4,SPR_OFC_DEAD,\r
+\r
+               SPR_OFC_SHOOT1,SPR_OFC_SHOOT2,SPR_OFC_SHOOT3,\r
+\r
+#ifndef SPEAR\r
+//\r
+// ghosts\r
+//\r
+               SPR_BLINKY_W1,SPR_BLINKY_W2,SPR_PINKY_W1,SPR_PINKY_W2,\r
+               SPR_CLYDE_W1,SPR_CLYDE_W2,SPR_INKY_W1,SPR_INKY_W2,\r
+\r
+//\r
+// hans\r
+//\r
+               SPR_BOSS_W1,SPR_BOSS_W2,SPR_BOSS_W3,SPR_BOSS_W4,\r
+               SPR_BOSS_SHOOT1,SPR_BOSS_SHOOT2,SPR_BOSS_SHOOT3,SPR_BOSS_DEAD,\r
+\r
+               SPR_BOSS_DIE1,SPR_BOSS_DIE2,SPR_BOSS_DIE3,\r
+\r
+//\r
+// schabbs\r
+//\r
+               SPR_SCHABB_W1,SPR_SCHABB_W2,SPR_SCHABB_W3,SPR_SCHABB_W4,\r
+               SPR_SCHABB_SHOOT1,SPR_SCHABB_SHOOT2,\r
+\r
+               SPR_SCHABB_DIE1,SPR_SCHABB_DIE2,SPR_SCHABB_DIE3,SPR_SCHABB_DEAD,\r
+               SPR_HYPO1,SPR_HYPO2,SPR_HYPO3,SPR_HYPO4,\r
+\r
+//\r
+// fake\r
+//\r
+               SPR_FAKE_W1,SPR_FAKE_W2,SPR_FAKE_W3,SPR_FAKE_W4,\r
+               SPR_FAKE_SHOOT,SPR_FIRE1,SPR_FIRE2,\r
+\r
+               SPR_FAKE_DIE1,SPR_FAKE_DIE2,SPR_FAKE_DIE3,SPR_FAKE_DIE4,\r
+               SPR_FAKE_DIE5,SPR_FAKE_DEAD,\r
+\r
+//\r
+// hitler\r
+//\r
+               SPR_MECHA_W1,SPR_MECHA_W2,SPR_MECHA_W3,SPR_MECHA_W4,\r
+               SPR_MECHA_SHOOT1,SPR_MECHA_SHOOT2,SPR_MECHA_SHOOT3,SPR_MECHA_DEAD,\r
+\r
+               SPR_MECHA_DIE1,SPR_MECHA_DIE2,SPR_MECHA_DIE3,\r
+\r
+               SPR_HITLER_W1,SPR_HITLER_W2,SPR_HITLER_W3,SPR_HITLER_W4,\r
+               SPR_HITLER_SHOOT1,SPR_HITLER_SHOOT2,SPR_HITLER_SHOOT3,SPR_HITLER_DEAD,\r
+\r
+               SPR_HITLER_DIE1,SPR_HITLER_DIE2,SPR_HITLER_DIE3,SPR_HITLER_DIE4,\r
+               SPR_HITLER_DIE5,SPR_HITLER_DIE6,SPR_HITLER_DIE7,\r
+\r
+//\r
+// giftmacher\r
+//\r
+               SPR_GIFT_W1,SPR_GIFT_W2,SPR_GIFT_W3,SPR_GIFT_W4,\r
+               SPR_GIFT_SHOOT1,SPR_GIFT_SHOOT2,\r
+\r
+               SPR_GIFT_DIE1,SPR_GIFT_DIE2,SPR_GIFT_DIE3,SPR_GIFT_DEAD,\r
+#endif\r
+//\r
+// Rocket, smoke and small explosion\r
+//\r
+               SPR_ROCKET_1,SPR_ROCKET_2,SPR_ROCKET_3,SPR_ROCKET_4,\r
+               SPR_ROCKET_5,SPR_ROCKET_6,SPR_ROCKET_7,SPR_ROCKET_8,\r
+\r
+               SPR_SMOKE_1,SPR_SMOKE_2,SPR_SMOKE_3,SPR_SMOKE_4,\r
+               SPR_BOOM_1,SPR_BOOM_2,SPR_BOOM_3,\r
+\r
+//\r
+// Angel of Death's DeathSparks(tm)\r
+//\r
+#ifdef SPEAR\r
+               SPR_HROCKET_1,SPR_HROCKET_2,SPR_HROCKET_3,SPR_HROCKET_4,\r
+               SPR_HROCKET_5,SPR_HROCKET_6,SPR_HROCKET_7,SPR_HROCKET_8,\r
+\r
+               SPR_HSMOKE_1,SPR_HSMOKE_2,SPR_HSMOKE_3,SPR_HSMOKE_4,\r
+               SPR_HBOOM_1,SPR_HBOOM_2,SPR_HBOOM_3,\r
+\r
+               SPR_SPARK1,SPR_SPARK2,SPR_SPARK3,SPR_SPARK4,\r
+#endif\r
+\r
+#ifndef SPEAR\r
+//\r
+// gretel\r
+//\r
+               SPR_GRETEL_W1,SPR_GRETEL_W2,SPR_GRETEL_W3,SPR_GRETEL_W4,\r
+               SPR_GRETEL_SHOOT1,SPR_GRETEL_SHOOT2,SPR_GRETEL_SHOOT3,SPR_GRETEL_DEAD,\r
+\r
+               SPR_GRETEL_DIE1,SPR_GRETEL_DIE2,SPR_GRETEL_DIE3,\r
+\r
+//\r
+// fat face\r
+//\r
+               SPR_FAT_W1,SPR_FAT_W2,SPR_FAT_W3,SPR_FAT_W4,\r
+               SPR_FAT_SHOOT1,SPR_FAT_SHOOT2,SPR_FAT_SHOOT3,SPR_FAT_SHOOT4,\r
+\r
+               SPR_FAT_DIE1,SPR_FAT_DIE2,SPR_FAT_DIE3,SPR_FAT_DEAD,\r
+\r
+//\r
+// bj\r
+//\r
+               SPR_BJ_W1,SPR_BJ_W2,SPR_BJ_W3,SPR_BJ_W4,\r
+               SPR_BJ_JUMP1,SPR_BJ_JUMP2,SPR_BJ_JUMP3,SPR_BJ_JUMP4,\r
+#else\r
+//\r
+// THESE ARE FOR 'SPEAR OF DESTINY'\r
+//\r
+\r
+//\r
+// Trans Grosse\r
+//\r
+               SPR_TRANS_W1,SPR_TRANS_W2,SPR_TRANS_W3,SPR_TRANS_W4,\r
+               SPR_TRANS_SHOOT1,SPR_TRANS_SHOOT2,SPR_TRANS_SHOOT3,SPR_TRANS_DEAD,\r
+\r
+               SPR_TRANS_DIE1,SPR_TRANS_DIE2,SPR_TRANS_DIE3,\r
+\r
+//\r
+// Wilhelm\r
+//\r
+               SPR_WILL_W1,SPR_WILL_W2,SPR_WILL_W3,SPR_WILL_W4,\r
+               SPR_WILL_SHOOT1,SPR_WILL_SHOOT2,SPR_WILL_SHOOT3,SPR_WILL_SHOOT4,\r
+\r
+               SPR_WILL_DIE1,SPR_WILL_DIE2,SPR_WILL_DIE3,SPR_WILL_DEAD,\r
+\r
+//\r
+// UberMutant\r
+//\r
+               SPR_UBER_W1,SPR_UBER_W2,SPR_UBER_W3,SPR_UBER_W4,\r
+               SPR_UBER_SHOOT1,SPR_UBER_SHOOT2,SPR_UBER_SHOOT3,SPR_UBER_SHOOT4,\r
+\r
+               SPR_UBER_DIE1,SPR_UBER_DIE2,SPR_UBER_DIE3,SPR_UBER_DIE4,\r
+               SPR_UBER_DEAD,\r
+\r
+//\r
+// Death Knight\r
+//\r
+               SPR_DEATH_W1,SPR_DEATH_W2,SPR_DEATH_W3,SPR_DEATH_W4,\r
+               SPR_DEATH_SHOOT1,SPR_DEATH_SHOOT2,SPR_DEATH_SHOOT3,SPR_DEATH_SHOOT4,\r
+\r
+               SPR_DEATH_DIE1,SPR_DEATH_DIE2,SPR_DEATH_DIE3,SPR_DEATH_DIE4,\r
+               SPR_DEATH_DIE5,SPR_DEATH_DIE6,SPR_DEATH_DEAD,\r
+\r
+//\r
+// Ghost\r
+//\r
+               SPR_SPECTRE_W1,SPR_SPECTRE_W2,SPR_SPECTRE_W3,SPR_SPECTRE_W4,\r
+               SPR_SPECTRE_F1,SPR_SPECTRE_F2,SPR_SPECTRE_F3,SPR_SPECTRE_F4,\r
+\r
+//\r
+// Angel of Death\r
+//\r
+               SPR_ANGEL_W1,SPR_ANGEL_W2,SPR_ANGEL_W3,SPR_ANGEL_W4,\r
+               SPR_ANGEL_SHOOT1,SPR_ANGEL_SHOOT2,SPR_ANGEL_TIRED1,SPR_ANGEL_TIRED2,\r
+\r
+               SPR_ANGEL_DIE1,SPR_ANGEL_DIE2,SPR_ANGEL_DIE3,SPR_ANGEL_DIE4,\r
+               SPR_ANGEL_DIE5,SPR_ANGEL_DIE6,SPR_ANGEL_DIE7,SPR_ANGEL_DEAD,\r
+\r
+#endif\r
+\r
+//\r
+// player attack frames\r
+//\r
+               SPR_KNIFEREADY,SPR_KNIFEATK1,SPR_KNIFEATK2,SPR_KNIFEATK3,\r
+               SPR_KNIFEATK4,\r
+\r
+               SPR_PISTOLREADY,SPR_PISTOLATK1,SPR_PISTOLATK2,SPR_PISTOLATK3,\r
+               SPR_PISTOLATK4,\r
+\r
+               SPR_MACHINEGUNREADY,SPR_MACHINEGUNATK1,SPR_MACHINEGUNATK2,MACHINEGUNATK3,\r
+               SPR_MACHINEGUNATK4,\r
+\r
+               SPR_CHAINREADY,SPR_CHAINATK1,SPR_CHAINATK2,SPR_CHAINATK3,\r
+               SPR_CHAINATK4,\r
+\r
+               };\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                  GLOBAL TYPES\r
+\r
+=============================================================================\r
+*/\r
+\r
+typedef long fixed;\r
+\r
+typedef enum {\r
+       di_north,\r
+       di_east,\r
+       di_south,\r
+       di_west\r
+} controldir_t;\r
+\r
+typedef enum {\r
+       dr_normal,\r
+       dr_lock1,\r
+       dr_lock2,\r
+       dr_lock3,\r
+       dr_lock4,\r
+       dr_elevator\r
+} door_t;\r
+\r
+typedef enum {\r
+       ac_badobject = -1,\r
+       ac_no,\r
+       ac_yes,\r
+       ac_allways\r
+} activetype;\r
+\r
+typedef enum {\r
+       nothing,\r
+       playerobj,\r
+       inertobj,\r
+       guardobj,\r
+       officerobj,\r
+       ssobj,\r
+       dogobj,\r
+       bossobj,\r
+       schabbobj,\r
+       fakeobj,\r
+       mechahitlerobj,\r
+       mutantobj,\r
+       needleobj,\r
+       fireobj,\r
+       bjobj,\r
+       ghostobj,\r
+       realhitlerobj,\r
+       gretelobj,\r
+       giftobj,\r
+       fatobj,\r
+       rocketobj,\r
+\r
+       spectreobj,\r
+       angelobj,\r
+       transobj,\r
+       uberobj,\r
+       willobj,\r
+       deathobj,\r
+       hrocketobj,\r
+       sparkobj\r
+} classtype;\r
+\r
+typedef enum {\r
+       dressing,\r
+       block,\r
+       bo_gibs,\r
+       bo_alpo,\r
+       bo_firstaid,\r
+       bo_key1,\r
+       bo_key2,\r
+       bo_key3,\r
+       bo_key4,\r
+       bo_cross,\r
+       bo_chalice,\r
+       bo_bible,\r
+       bo_crown,\r
+       bo_clip,\r
+       bo_clip2,\r
+       bo_machinegun,\r
+       bo_chaingun,\r
+       bo_food,\r
+       bo_fullheal,\r
+       bo_25clip,\r
+       bo_spear\r
+} stat_t;\r
+\r
+typedef enum {\r
+       east,\r
+       northeast,\r
+       north,\r
+       northwest,\r
+       west,\r
+       southwest,\r
+       south,\r
+       southeast,\r
+       nodir\r
+} dirtype;\r
+\r
+\r
+#define NUMENEMIES             22\r
+typedef enum {\r
+       en_guard,\r
+       en_officer,\r
+       en_ss,\r
+       en_dog,\r
+       en_boss,\r
+       en_schabbs,\r
+       en_fake,\r
+       en_hitler,\r
+       en_mutant,\r
+       en_blinky,\r
+       en_clyde,\r
+       en_pinky,\r
+       en_inky,\r
+       en_gretel,\r
+       en_gift,\r
+       en_fat,\r
+       en_spectre,\r
+       en_angel,\r
+       en_trans,\r
+       en_uber,\r
+       en_will,\r
+       en_death\r
+} enemy_t;\r
+\r
+\r
+typedef struct statestruct\r
+{\r
+       boolean rotate;\r
+       int             shapenum;                       // a shapenum of -1 means get from ob->temp1\r
+       int             tictime;\r
+       void    (*think) (),(*action) ();\r
+       struct  statestruct     *next;\r
+} statetype;\r
+\r
+\r
+//---------------------\r
+//\r
+// trivial actor structure\r
+//\r
+//---------------------\r
+\r
+typedef struct statstruct\r
+{\r
+       byte    tilex,tiley;\r
+       byte    *visspot;\r
+       int             shapenum;                       // if shapenum == -1 the obj has been removed\r
+       byte    flags;\r
+       byte    itemnumber;\r
+} statobj_t;\r
+\r
+\r
+//---------------------\r
+//\r
+// door actor structure\r
+//\r
+//---------------------\r
+\r
+typedef struct doorstruct\r
+{\r
+       byte    tilex,tiley;\r
+       boolean vertical;\r
+       byte    lock;\r
+       enum    {dr_open,dr_closed,dr_opening,dr_closing}       action;\r
+       int             ticcount;\r
+} doorobj_t;\r
+\r
+\r
+//--------------------\r
+//\r
+// thinking actor structure\r
+//\r
+//--------------------\r
+\r
+typedef struct objstruct\r
+{\r
+       activetype      active;\r
+       int                     ticcount;\r
+       classtype       obclass;\r
+       statetype       *state;\r
+\r
+       byte            flags;                          //      FL_SHOOTABLE, etc\r
+\r
+       long            distance;                       // if negative, wait for that door to open\r
+       dirtype         dir;\r
+\r
+       fixed           x,y;\r
+       unsigned        tilex,tiley;\r
+       byte            areanumber;\r
+\r
+       int                     viewx;\r
+       unsigned        viewheight;\r
+       fixed           transx,transy;          // in global coord\r
+\r
+       int             angle;\r
+       int                     hitpoints;\r
+       long            speed;\r
+\r
+       int                     temp1,temp2,temp3;\r
+       struct          objstruct       *next,*prev;\r
+} objtype;\r
+\r
+\r
+#define NUMBUTTONS     8\r
+enum   {\r
+       bt_nobutton=-1,\r
+       bt_attack=0,\r
+       bt_strafe,\r
+       bt_run,\r
+       bt_use,\r
+       bt_readyknife,\r
+       bt_readypistol,\r
+       bt_readymachinegun,\r
+       bt_readychaingun\r
+};\r
+\r
+\r
+#define NUMWEAPONS     5\r
+typedef enum   {\r
+       wp_knife,\r
+       wp_pistol,\r
+       wp_machinegun,\r
+       wp_chaingun\r
+} weapontype;\r
+\r
+\r
+typedef enum   {\r
+       gd_baby,\r
+       gd_easy,\r
+       gd_medium,\r
+       gd_hard\r
+};\r
+\r
+//---------------\r
+//\r
+// gamestate structure\r
+//\r
+//---------------\r
+\r
+typedef        struct\r
+{\r
+       int                     difficulty;\r
+       int                     mapon;\r
+       long            oldscore,score,nextextra;\r
+       int                     lives;\r
+       int                     health;\r
+       int                     ammo;\r
+       int                     keys;\r
+       weapontype              bestweapon,weapon,chosenweapon;\r
+\r
+       int                     faceframe;\r
+       int                     attackframe,attackcount,weaponframe;\r
+\r
+       int                     episode,secretcount,treasurecount,killcount,\r
+                               secrettotal,treasuretotal,killtotal;\r
+       long            TimeCount;\r
+       long            killx,killy;\r
+       boolean         victoryflag;            // set during victory animations\r
+} gametype;\r
+\r
+\r
+typedef        enum    {\r
+       ex_stillplaying,\r
+       ex_completed,\r
+       ex_died,\r
+       ex_warped,\r
+       ex_resetgame,\r
+       ex_loadedgame,\r
+       ex_victorious,\r
+       ex_abort,\r
+       ex_demodone,\r
+       ex_secretlevel\r
+} exit_t;\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                WL_MAIN DEFINITIONS\r
+\r
+=============================================================================\r
+*/\r
+\r
+extern boolean         MS_CheckParm (char far *string);\r
+\r
+extern char            str[80],str2[20];\r
+extern int                     tedlevelnum;\r
+extern boolean         tedlevel;\r
+extern boolean         nospr;\r
+extern boolean         IsA386;\r
+\r
+extern byte far        *scalermemory;\r
+\r
+extern fixed           focallength;\r
+extern unsigned        viewangles;\r
+extern unsigned        screenofs;\r
+extern int                 viewwidth;\r
+extern int                     viewheight;\r
+extern int                     centerx;\r
+extern int                     shootdelta;\r
+\r
+extern int                     dirangle[9];\r
+\r
+extern boolean         startgame,loadedgame,virtualreality;\r
+extern int             mouseadjustment;\r
+//\r
+// math tables\r
+//\r
+extern int                     pixelangle[MAXVIEWWIDTH];\r
+extern long            far finetangent[FINEANGLES/4];\r
+extern fixed           far sintable[],far *costable;\r
+\r
+//\r
+// derived constants\r
+//\r
+extern fixed   scale,maxslope;\r
+extern long    heightnumerator;\r
+extern int             minheightdiv;\r
+\r
+extern char    configname[13];\r
+\r
+\r
+\r
+void           HelpScreens (void);\r
+void           OrderingInfo (void);\r
+void           TEDDeath(void);\r
+void           Quit (char *error);\r
+void           CalcProjection (long focal);\r
+boolean                SetViewSize (unsigned width, unsigned height);\r
+void           NewGame (int difficulty,int episode);\r
+void           NewViewSize (int width);\r
+boolean        LoadTheGame(int file,int x,int y);\r
+boolean                SaveTheGame(int file,int x,int y);\r
+void           ShowViewSize (int width);\r
+void           ShutdownId (void);\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                WL_GAME DEFINITIONS\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+extern boolean         ingame,fizzlein;\r
+extern unsigned        latchpics[NUMLATCHPICS];\r
+extern gametype        gamestate;\r
+extern int                     doornum;\r
+\r
+extern char            demoname[13];\r
+\r
+extern long            spearx,speary;\r
+extern unsigned        spearangle;\r
+extern boolean         spearflag;\r
+\r
+\r
+void   DrawPlayBorder (void);\r
+void   ScanInfoPlane (void);\r
+void   SetupGameLevel (void);\r
+void   NormalScreen (void);\r
+void   DrawPlayScreen (void);\r
+void   FizzleOut (void);\r
+void   GameLoop (void);\r
+void ClearMemory (void);\r
+void PlayDemo (int demonumber);\r
+void RecordDemo (void);\r
+void DrawAllPlayBorder (void);\r
+void   DrawHighScores(void);\r
+void DrawAllPlayBorderSides (void);\r
+\r
+\r
+// JAB\r
+#define        PlaySoundLocTile(s,tx,ty)       PlaySoundLocGlobal(s,(((long)(tx) << TILESHIFT) + (1L << (TILESHIFT - 1))),(((long)ty << TILESHIFT) + (1L << (TILESHIFT - 1))))\r
+#define        PlaySoundLocActor(s,ob)         PlaySoundLocGlobal(s,(ob)->x,(ob)->y)\r
+void   PlaySoundLocGlobal(word s,fixed gx,fixed gy);\r
+void UpdateSoundLoc(void);\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                WL_PLAY DEFINITIONS\r
+\r
+=============================================================================\r
+*/\r
+\r
+#ifdef SPEAR\r
+extern long            funnyticount;           // FOR FUNNY BJ FACE\r
+#endif\r
+\r
+extern exit_t          playstate;\r
+\r
+extern boolean         madenoise;\r
+\r
+extern objtype         objlist[MAXACTORS],*new,*obj,*player,*lastobj,\r
+                                       *objfreelist,*killerobj;\r
+extern statobj_t       statobjlist[MAXSTATS],*laststatobj;\r
+extern doorobj_t       doorobjlist[MAXDOORS],*lastdoorobj;\r
+\r
+extern unsigned        farmapylookup[MAPSIZE];\r
+extern byte            *nearmapylookup[MAPSIZE];\r
+\r
+extern byte            tilemap[MAPSIZE][MAPSIZE];      // wall values only\r
+extern byte            spotvis[MAPSIZE][MAPSIZE];\r
+extern objtype         *actorat[MAPSIZE][MAPSIZE];\r
+\r
+#define UPDATESIZE                     (UPDATEWIDE*UPDATEHIGH)\r
+extern byte            update[UPDATESIZE];\r
+\r
+extern boolean         singlestep,godmode,noclip;\r
+extern int                     extravbls;\r
+\r
+//\r
+// control info\r
+//\r
+extern boolean         mouseenabled,joystickenabled,joypadenabled,joystickprogressive;\r
+extern int                     joystickport;\r
+extern int                     dirscan[4];\r
+extern int                     buttonscan[NUMBUTTONS];\r
+extern int                     buttonmouse[4];\r
+extern int                     buttonjoy[4];\r
+\r
+extern boolean         buttonheld[NUMBUTTONS];\r
+\r
+extern int                     viewsize;\r
+\r
+//\r
+// curent user input\r
+//\r
+extern int                     controlx,controly;              // range from -100 to 100\r
+extern boolean         buttonstate[NUMBUTTONS];\r
+\r
+extern boolean         demorecord,demoplayback;\r
+extern char            far *demoptr, far *lastdemoptr;\r
+extern memptr          demobuffer;\r
+\r
+\r
+\r
+void   InitRedShifts (void);\r
+void   FinishPaletteShifts (void);\r
+\r
+void   CenterWindow(word w,word h);\r
+void   InitActorList (void);\r
+void   GetNewActor (void);\r
+void   RemoveObj (objtype *gone);\r
+void   PollControls (void);\r
+void   StopMusic(void);\r
+void   StartMusic(void);\r
+void   PlayLoop (void);\r
+void StartDamageFlash (int damage);\r
+void StartBonusFlash (void);\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                       WL_INTER\r
+\r
+=============================================================================\r
+*/\r
+\r
+void IntroScreen (void);\r
+void PreloadGraphics(void);\r
+void LevelCompleted (void);\r
+void   CheckHighScore (long score,word other);\r
+void Victory (void);\r
+void ClearSplitVWB (void);\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                       WL_DEBUG\r
+\r
+=============================================================================\r
+*/\r
+\r
+int DebugKeys (void);\r
+void PicturePause (void);\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                WL_DRAW DEFINITIONS\r
+\r
+=============================================================================\r
+*/\r
+\r
+extern unsigned screenloc[3];\r
+extern unsigned freelatch;\r
+\r
+extern long    lasttimecount;\r
+extern long    frameon;\r
+extern boolean fizzlein;\r
+\r
+extern unsigned        wallheight[MAXVIEWWIDTH];\r
+\r
+extern fixed   tileglobal;\r
+extern fixed   focallength;\r
+extern fixed   mindist;\r
+\r
+//\r
+// math tables\r
+//\r
+extern int                     pixelangle[MAXVIEWWIDTH];\r
+extern long            far finetangent[FINEANGLES/4];\r
+extern fixed           far sintable[],far *costable;\r
+\r
+//\r
+// derived constants\r
+//\r
+extern fixed   scale;\r
+extern long    heightnumerator,mindist;\r
+\r
+//\r
+// refresh variables\r
+//\r
+extern fixed   viewx,viewy;                    // the focal point\r
+extern int             viewangle;\r
+extern fixed   viewsin,viewcos;\r
+\r
+extern long            postsource;\r
+extern unsigned        postx;\r
+extern unsigned        postwidth;\r
+\r
+\r
+extern int             horizwall[],vertwall[];\r
+\r
+extern unsigned        pwallpos;\r
+\r
+\r
+fixed  FixedByFrac (fixed a, fixed b);\r
+void   TransformActor (objtype *ob);\r
+void   BuildTables (void);\r
+void   ClearScreen (void);\r
+int            CalcRotate (objtype *ob);\r
+void   DrawScaleds (void);\r
+void   CalcTics (void);\r
+void   FixOfs (void);\r
+void   ThreeDRefresh (void);\r
+void  FarScalePost (void);\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                WL_STATE DEFINITIONS\r
+\r
+=============================================================================\r
+*/\r
+#define TURNTICS       10\r
+#define SPDPATROL      512\r
+#define SPDDOG         1500\r
+\r
+\r
+extern dirtype opposite[9];\r
+extern dirtype diagonal[9][9];\r
+\r
+\r
+void   InitHitRect (objtype *ob, unsigned radius);\r
+void   SpawnNewObj (unsigned tilex, unsigned tiley, statetype *state);\r
+void   NewState (objtype *ob, statetype *state);\r
+\r
+boolean TryWalk (objtype *ob);\r
+void   SelectChaseDir (objtype *ob);\r
+void   SelectDodgeDir (objtype *ob);\r
+void   SelectRunDir (objtype *ob);\r
+void   MoveObj (objtype *ob, long move);\r
+boolean SightPlayer (objtype *ob);\r
+\r
+void   KillActor (objtype *ob);\r
+void   DamageActor (objtype *ob, unsigned damage);\r
+\r
+boolean CheckLine (objtype *ob);\r
+boolean        CheckSight (objtype *ob);\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                WL_SCALE DEFINITIONS\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+#define COMPSCALECODESTART     (65*4)          // offset to start of code in comp scaler\r
+\r
+typedef struct\r
+{\r
+       unsigned        codeofs[65];\r
+       unsigned        width[65];\r
+       byte            code[];\r
+}      t_compscale;\r
+\r
+typedef struct\r
+{\r
+       unsigned        leftpix,rightpix;\r
+       unsigned        dataofs[64];\r
+// table data after dataofs[rightpix-leftpix+1]\r
+}      t_compshape;\r
+\r
+\r
+extern t_compscale _seg *scaledirectory[MAXSCALEHEIGHT+1];\r
+extern long                    fullscalefarcall[MAXSCALEHEIGHT+1];\r
+\r
+extern byte            bitmasks1[8][8];\r
+extern byte            bitmasks2[8][8];\r
+extern unsigned        wordmasks[8][8];\r
+\r
+extern byte            mapmasks1[4][8];\r
+extern byte            mapmasks2[4][8];\r
+extern byte            mapmasks3[4][8];\r
+\r
+extern int                     maxscale,maxscaleshl2;\r
+\r
+extern boolean insetupscaling;\r
+\r
+void SetupScaling (int maxscaleheight);\r
+void ScaleShape (int xcenter, int shapenum, unsigned height);\r
+void SimpleScaleShape (int xcenter, int shapenum, unsigned height);\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                WL_AGENT DEFINITIONS\r
+\r
+=============================================================================\r
+*/\r
+\r
+//\r
+// player state info\r
+//\r
+extern boolean         running;\r
+extern long            thrustspeed;\r
+extern unsigned        plux,pluy;              // player coordinates scaled to unsigned\r
+\r
+extern int                     anglefrac;\r
+extern int                     facecount;\r
+\r
+void   SpawnPlayer (int tilex, int tiley, int dir);\r
+void   DrawFace (void);\r
+void   DrawHealth (void);\r
+void   TakeDamage (int points,objtype *attacker);\r
+void   HealSelf (int points);\r
+void   DrawLevel (void);\r
+void   DrawLives (void);\r
+void   GiveExtraMan (void);\r
+void   DrawScore (void);\r
+void   GivePoints (long points);\r
+void   DrawWeapon (void);\r
+void   DrawKeys (void);\r
+void   GiveWeapon (int weapon);\r
+void   DrawAmmo (void);\r
+void   GiveAmmo (int ammo);\r
+void   GiveKey (int key);\r
+void   GetBonus (statobj_t *check);\r
+\r
+void   Thrust (int angle, long speed);\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                WL_ACT1 DEFINITIONS\r
+\r
+=============================================================================\r
+*/\r
+\r
+extern doorobj_t       doorobjlist[MAXDOORS],*lastdoorobj;\r
+extern int                     doornum;\r
+\r
+extern unsigned        doorposition[MAXDOORS],pwallstate;\r
+\r
+extern byte            far areaconnect[NUMAREAS][NUMAREAS];\r
+\r
+extern boolean         areabyplayer[NUMAREAS];\r
+\r
+extern unsigned        pwallstate;\r
+extern unsigned        pwallpos;                       // amount a pushable wall has been moved (0-63)\r
+extern unsigned        pwallx,pwally;\r
+extern int                     pwalldir;\r
+\r
+\r
+void InitDoorList (void);\r
+void InitStaticList (void);\r
+void SpawnStatic (int tilex, int tiley, int type);\r
+void SpawnDoor (int tilex, int tiley, boolean vertical, int lock);\r
+void MoveDoors (void);\r
+void MovePWalls (void);\r
+void OpenDoor (int door);\r
+void PlaceItemType (int itemtype, int tilex, int tiley);\r
+void PushWall (int checkx, int checky, int dir);\r
+void OperateDoor (int door);\r
+void InitAreas (void);\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                WL_ACT2 DEFINITIONS\r
+\r
+=============================================================================\r
+*/\r
+\r
+#define s_nakedbody s_static10\r
+\r
+extern statetype s_grddie1;\r
+extern statetype s_dogdie1;\r
+extern statetype s_ofcdie1;\r
+extern statetype s_mutdie1;\r
+extern statetype s_ssdie1;\r
+extern statetype s_bossdie1;\r
+extern statetype s_schabbdie1;\r
+extern statetype s_fakedie1;\r
+extern statetype s_mechadie1;\r
+extern statetype s_hitlerdie1;\r
+extern statetype s_greteldie1;\r
+extern statetype s_giftdie1;\r
+extern statetype s_fatdie1;\r
+\r
+extern statetype s_spectredie1;\r
+extern statetype s_angeldie1;\r
+extern statetype s_transdie0;\r
+extern statetype s_uberdie0;\r
+extern statetype s_willdie1;\r
+extern statetype s_deathdie1;\r
+\r
+\r
+extern statetype s_grdchase1;\r
+extern statetype s_dogchase1;\r
+extern statetype s_ofcchase1;\r
+extern statetype s_sschase1;\r
+extern statetype s_mutchase1;\r
+extern statetype s_bosschase1;\r
+extern statetype s_schabbchase1;\r
+extern statetype s_fakechase1;\r
+extern statetype s_mechachase1;\r
+extern statetype s_gretelchase1;\r
+extern statetype s_giftchase1;\r
+extern statetype s_fatchase1;\r
+\r
+extern statetype s_spectrechase1;\r
+extern statetype s_angelchase1;\r
+extern statetype s_transchase1;\r
+extern statetype s_uberchase1;\r
+extern statetype s_willchase1;\r
+extern statetype s_deathchase1;\r
+\r
+extern statetype s_blinkychase1;\r
+extern statetype s_hitlerchase1;\r
+\r
+extern statetype s_grdpain;\r
+extern statetype s_grdpain1;\r
+extern statetype s_ofcpain;\r
+extern statetype s_ofcpain1;\r
+extern statetype s_sspain;\r
+extern statetype s_sspain1;\r
+extern statetype s_mutpain;\r
+extern statetype s_mutpain1;\r
+\r
+extern statetype s_deathcam;\r
+\r
+extern statetype s_schabbdeathcam2;\r
+extern statetype s_hitlerdeathcam2;\r
+extern statetype s_giftdeathcam2;\r
+extern statetype s_fatdeathcam2;\r
+\r
+void SpawnStand (enemy_t which, int tilex, int tiley, int dir);\r
+void SpawnPatrol (enemy_t which, int tilex, int tiley, int dir);\r
+void KillActor (objtype *ob);\r
+\r
+void   US_ControlPanel(byte);\r
+\r
+void SpawnDeadGuard (int tilex, int tiley);\r
+void SpawnBoss (int tilex, int tiley);\r
+void SpawnGretel (int tilex, int tiley);\r
+void SpawnTrans (int tilex, int tiley);\r
+void SpawnUber (int tilex, int tiley);\r
+void SpawnWill (int tilex, int tiley);\r
+void SpawnDeath (int tilex, int tiley);\r
+void SpawnAngel (int tilex, int tiley);\r
+void SpawnSpectre (int tilex, int tiley);\r
+void SpawnGhosts (int which, int tilex, int tiley);\r
+void SpawnSchabbs (int tilex, int tiley);\r
+void SpawnGift (int tilex, int tiley);\r
+void SpawnFat (int tilex, int tiley);\r
+void SpawnFakeHitler (int tilex, int tiley);\r
+void SpawnHitler (int tilex, int tiley);\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                WL_TEXT DEFINITIONS\r
+\r
+=============================================================================\r
+*/\r
+\r
+extern char    helpfilename[],endfilename[];\r
+\r
+extern void    HelpScreens(void);\r
+extern void    EndText(void);\r
diff --git a/src/lib/hb/wl_dr_a.asm b/src/lib/hb/wl_dr_a.asm
new file mode 100755 (executable)
index 0000000..aec139a
--- /dev/null
@@ -0,0 +1,795 @@
+       IDEAL\r
+       MODEL   MEDIUM,C\r
+       P286\r
+\r
+SCREENSEG      =       0a000h\r
+\r
+FINEANGLES     =       3600\r
+DEG90          =       900\r
+DEG180         =       1800\r
+DEG270         =       2700\r
+DEG360         =       3600\r
+\r
+OP_JLE         =       07eh\r
+OP_JGE         =       07dh\r
+\r
+EXTRN  finetangent:DWORD       ; far array, starts at offset 0\r
+\r
+EXTRN  HitHorizWall:FAR\r
+EXTRN  HitVertWall:FAR\r
+EXTRN  HitHorizDoor:FAR\r
+EXTRN  HitVertDoor:FAR\r
+EXTRN  HitHorizPWall:FAR\r
+EXTRN  HitVertPWall:FAR\r
+\r
+\r
+DATASEG\r
+\r
+EXTRN  viewwidth:WORD\r
+\r
+EXTRN  tilemap:BYTE\r
+EXTRN  spotvis:BYTE\r
+EXTRN  pixelangle:WORD\r
+\r
+\r
+EXTRN  midangle:WORD\r
+EXTRN  angle:WORD\r
+\r
+EXTRN  focaltx:WORD\r
+EXTRN  focalty:WORD\r
+EXTRN  viewtx:WORD\r
+EXTRN  viewty:WORD\r
+EXTRN  viewx:DWORD\r
+EXTRN  viewy:DWORD\r
+\r
+EXTRN  xpartialup:WORD\r
+EXTRN  ypartialup:WORD\r
+EXTRN  xpartialdown:WORD\r
+EXTRN  ypartialdown:WORD\r
+\r
+EXTRN  tilehit:WORD\r
+EXTRN  pixx:WORD\r
+EXTRN  wallheight:WORD                 ; array of VIEWWIDTH entries\r
+\r
+EXTRN  xtile:WORD\r
+EXTRN  ytile:WORD\r
+EXTRN  xtilestep:WORD\r
+EXTRN  ytilestep:WORD\r
+EXTRN  xintercept:DWORD\r
+EXTRN  yintercept:DWORD\r
+EXTRN  xstep:DWORD\r
+EXTRN  ystep:DWORD\r
+\r
+EXTRN  doorposition:WORD               ; table of door position values\r
+\r
+\r
+EXTRN  pwallpos:WORD                   ; amound a pushable wall has been moved\r
+\r
+CODESEG\r
+\r
+;-------------------\r
+;\r
+; xpartialbyystep\r
+;\r
+; multiplies long [ystep] (possibly negative), by word [xpartial] (in BX)\r
+;\r
+; returns dx:ax\r
+; trashes bx,cx,di\r
+;\r
+;-------------------\r
+\r
+PROC xpartialbyystep NEAR\r
+;\r
+; setup\r
+;\r
+       mov     ax,[WORD ystep]\r
+       mov     cx,[WORD ystep+2]\r
+       or      cx,cx               ; is ystep negatice?\r
+       jns     @@multpos\r
+;\r
+; multiply negative cx:ax by bx\r
+;\r
+       neg     cx\r
+       neg     ax\r
+       sbb     cx,0\r
+\r
+       mul     bx                                      ; fraction*fraction\r
+       mov     di,dx                           ; di is low word of result\r
+       mov     ax,cx                           ;\r
+       mul     bx                                      ; units*fraction\r
+       add     ax,di\r
+       adc     dx,0\r
+\r
+       neg     dx\r
+       neg     ax\r
+       sbb     dx,0\r
+       ret\r
+;\r
+; multiply positive cx:ax by bx\r
+;\r
+EVEN\r
+@@multpos:\r
+       mul     bx                                      ; fraction*fraction\r
+       mov     di,dx                           ; di is low word of result\r
+       mov     ax,cx                           ;\r
+       mul     bx                                      ; units*fraction\r
+       add     ax,di\r
+       adc     dx,0\r
+\r
+       ret\r
+\r
+ENDP\r
+\r
+\r
+\r
+;-------------------\r
+;\r
+; ypartialbyxstep\r
+;\r
+; multiplies long [xstep] (possibly negative), by word [ypartial] (in BP)\r
+;\r
+; returns dx:ax\r
+; trashes cx,di,bp\r
+;\r
+;-------------------\r
+\r
+PROC ypartialbyxstep NEAR\r
+;\r
+; setup\r
+;\r
+       mov     ax,[WORD xstep]\r
+       mov     cx,[WORD xstep+2]\r
+       or      cx,cx               ; is ystep negatice?\r
+       jns     @@multpos\r
+;\r
+; multiply negative cx:ax by bx\r
+;\r
+       neg     cx\r
+       neg     ax\r
+       sbb     cx,0\r
+\r
+       mul     bp                                      ; fraction*fraction\r
+       mov     di,dx                           ; di is low word of result\r
+       mov     ax,cx                           ;\r
+       mul     bp                                      ; units*fraction\r
+       add     ax,di\r
+       adc     dx,0\r
+\r
+       neg     dx\r
+       neg     ax\r
+       sbb     dx,0\r
+       ret\r
+;\r
+; multiply positive cx:ax by bx\r
+;\r
+EVEN\r
+@@multpos:\r
+       mul     bp                                      ; fraction*fraction\r
+       mov     di,dx                           ; di is low word of result\r
+       mov     ax,cx                           ;\r
+       mul     bp                                      ; units*fraction\r
+       add     ax,di\r
+       adc     dx,0\r
+       ret\r
+\r
+ENDP\r
+\r
+\r
+;============================\r
+;\r
+; AsmRefresh\r
+;\r
+;\r
+;============================\r
+\r
+PROC   AsmRefresh\r
+PUBLIC AsmRefresh\r
+\r
+       push    si\r
+       push    di\r
+       push    bp\r
+\r
+       mov     [pixx],0\r
+;---------------------------------------------------------------------------\r
+;\r
+; Setup to trace a ray through pixx view pixel\r
+;\r
+; CX : angle of the ray through pixx\r
+; ES : points to segment of finetangent array for this block of code\r
+;\r
+; Upon entrance to initialize block\r
+;\r
+; BX : xpartial\r
+; BP : ypartial\r
+;\r
+;---------------------------------------------------------------------------\r
+       EVEN\r
+pixxloop:\r
+       mov     ax,SEG finetangent\r
+       mov     es,ax\r
+       mov     cx,[midangle]                   ; center of view area\r
+       mov     bx,[pixx]\r
+       shl     bx,1\r
+       add     cx,[pixelangle+bx]              ; delta for this pixel\r
+       cmp     cx,0\r
+       jge     not0\r
+;----------\r
+;\r
+; -90 - -1 degree arc\r
+;\r
+;----------\r
+       add     cx,FINEANGLES                   ; -90 is the same as 270\r
+       jmp     entry360\r
+\r
+not0:\r
+       cmp     cx,DEG90\r
+       jge     not90\r
+;----------\r
+;\r
+; 0-89 degree arc\r
+;\r
+;----------\r
+entry90:\r
+       mov     [xtilestep],1                   ; xtilestep = 1\r
+       mov     [ytilestep],-1                  ; ytilestep = -1\r
+       mov     [BYTE cs:horizop],OP_JGE        ; patch a jge in\r
+       mov     [BYTE cs:vertop],OP_JLE         ; patch a jle in\r
+       mov     bx,DEG90-1\r
+       sub     bx,cx\r
+       ;begin 8086 hack\r
+       ;shl    bx,2\r
+       shl bx,1\r
+       shl bx,1\r
+       ;end 8086 hack\r
+       mov     ax,[es:bx]\r
+       mov     dx,[es:bx+2]\r
+       mov     [WORD xstep],ax\r
+       mov     [WORD xstep+2],dx               ; xstep = finetangent[DEG90-1-angle]\r
+       mov     bx,cx\r
+       ;begin 8086 hack\r
+       ;shl    bx,2\r
+       shl bx,1\r
+       shl bx,1\r
+       ;end 8086 hack\r
+       mov     ax,[es:bx]\r
+       mov     dx,[es:bx+2]\r
+       neg     dx\r
+       neg     ax\r
+       sbb     dx,0\r
+       mov     [WORD ystep],ax\r
+       mov     [WORD ystep+2],dx               ; ystep = -finetangent[angle]\r
+\r
+       mov     bx,[xpartialup]                 ; xpartial = xpartialup\r
+       mov     bp,[ypartialdown]               ; ypartial = ypartialdown\r
+       jmp     initvars\r
+\r
+not90:\r
+       cmp     cx,DEG180\r
+       jge     not180\r
+;----------\r
+;\r
+; 90-179 degree arc\r
+;\r
+;----------\r
+       mov     ax,-1\r
+       mov     [xtilestep],ax                  ; xtilestep = -1\r
+       mov     [ytilestep],ax                  ; ytilestep = -1\r
+       mov     [BYTE cs:horizop],OP_JLE        ; patch a jle in\r
+       mov     [BYTE cs:vertop],OP_JLE         ; patch a jle in\r
+\r
+       mov     bx,cx\r
+       ;begin 8086 hack\r
+       ;shl    bx,2\r
+       shl bx,1\r
+       shl bx,1\r
+       ;end 8086 hack\r
+       mov     ax,[es:bx-DEG90*4]\r
+       mov     dx,[es:bx+2-DEG90*4]\r
+       neg     dx\r
+       neg     ax\r
+       sbb     dx,0\r
+       mov     [WORD xstep],ax\r
+       mov     [WORD xstep+2],dx               ; xstep = -finetangent[angle-DEG90]\r
+       mov     bx,DEG180-1\r
+       sub     bx,cx\r
+       ;begin 8086 hack\r
+       ;shl    bx,2\r
+       shl bx,1\r
+       shl bx,1\r
+       ;end 8086 hack\r
+       mov     ax,[es:bx]\r
+       mov     dx,[es:bx+2]\r
+       neg     dx\r
+       neg     ax\r
+       sbb     dx,0\r
+       mov     [WORD ystep],ax\r
+       mov     [WORD ystep+2],dx               ; ystep = -finetangent[DEG180-1-angle]\r
+\r
+       mov     bx,[xpartialdown]               ; xpartial = xpartialdown\r
+       mov     bp,[ypartialdown]               ; ypartial = ypartialdown\r
+       jmp     initvars\r
+\r
+not180:\r
+       cmp     cx,DEG270\r
+       jge     not270\r
+;----------\r
+;\r
+; 180-269 degree arc\r
+;\r
+;----------\r
+       mov     [xtilestep],-1                  ; xtilestep = -1\r
+       mov     [ytilestep],1                   ; ytilestep = 1\r
+       mov     [BYTE cs:horizop],OP_JLE        ; patch a jle in\r
+       mov     [BYTE cs:vertop],OP_JGE         ; patch a jge in\r
+\r
+       mov     bx,DEG270-1\r
+       sub     bx,cx\r
+       ;begin 8086 hack\r
+       ;shl    bx,2\r
+       shl bx,1\r
+       shl bx,1\r
+       ;end 8086 hack\r
+       mov     ax,[es:bx]\r
+       mov     dx,[es:bx+2]\r
+       neg     dx\r
+       neg     ax\r
+       sbb     dx,0\r
+       mov     [WORD xstep],ax\r
+       mov     [WORD xstep+2],dx               ; xstep = -finetangent[DEG270-1-angle]\r
+       mov     bx,cx\r
+       ;begin 8086 hack\r
+       ;shl    bx,2\r
+       shl bx,1\r
+       shl bx,1\r
+       ;end 8086 hack\r
+       mov     ax,[es:bx-DEG180*4]\r
+       mov     dx,[es:bx+2-DEG180*4]\r
+       mov     [WORD ystep],ax\r
+       mov     [WORD ystep+2],dx               ; ystep = finetangent[angle-DEG180]\r
+\r
+       mov     bx,[xpartialdown]               ; xpartial = xpartialdown\r
+       mov     bp,[ypartialup]                 ; ypartial = ypartialup\r
+       jmp     initvars\r
+\r
+\r
+not270:\r
+       cmp     cx,DEG360\r
+       jge     not360\r
+;----------\r
+;\r
+; 270-359 degree arc\r
+;\r
+;----------\r
+entry360:\r
+       mov     ax,1\r
+       mov     [xtilestep],ax                  ; xtilestep = 1\r
+       mov     [ytilestep],ax                  ; ytilestep = 1\r
+       mov     [BYTE cs:horizop],OP_JGE        ; patch a jge in\r
+       mov     [BYTE cs:vertop],OP_JGE         ; patch a jge in\r
+\r
+       mov     bx,cx\r
+       ;begin 8086 hack\r
+       ;shl    bx,2\r
+       shl bx,1\r
+       shl bx,1\r
+       ;end 8086 hack\r
+       mov     ax,[es:bx-DEG270*4]\r
+       mov     dx,[es:bx+2-DEG270*4]\r
+       mov     [WORD xstep],ax\r
+       mov     [WORD xstep+2],dx               ; xstep = finetangent[angle-DEG270]\r
+       mov     bx,DEG360-1\r
+       sub     bx,cx\r
+       ;begin 8086 hack\r
+       ;shl    bx,2\r
+       shl bx,1\r
+       shl bx,1\r
+       ;end 8086 hack\r
+       mov     ax,[es:bx]\r
+       mov     dx,[es:bx+2]\r
+       mov     [WORD ystep],ax\r
+       mov     [WORD ystep+2],dx               ; ystep = finetangent[DEG360-1-angle]\r
+\r
+       mov     bx,[xpartialup]                 ; xpartial = xpartialup\r
+       mov     bp,[ypartialup]                 ; ypartial = ypartialup\r
+       jmp     initvars\r
+\r
+\r
+not360:\r
+;----------\r
+;\r
+; 360-449 degree arc\r
+;\r
+;----------\r
+       sub     cx,FINEANGLES                   ; -449 is the same as 89\r
+       jmp     entry90\r
+\r
+;---------------------------------------------------------------------------\r
+;\r
+; initialise variables for intersection testing\r
+;\r
+;---------------------------------------------------------------------------\r
+initvars:\r
+       call    NEAR xpartialbyystep    ; xpartial is in BX\r
+       add     ax,[WORD viewy]\r
+       adc     dx,[WORD viewy+2]\r
+       mov     [WORD yintercept],ax\r
+       mov     [WORD yintercept+2],dx\r
+\r
+       mov     si,[focaltx]\r
+       add     si,[xtilestep]\r
+       mov     [xtile],si                                      ; xtile = focaltx+xtilestep\r
+       ;begin 8086 hack\r
+       ;shl    si,6\r
+       push cx\r
+       mov cl,6\r
+       shl si,cl\r
+       pop cx\r
+       ;end 8086 hack\r
+       add     si,dx                                           ; xspot = (xtile<<6) + yinttile\r
+\r
+\r
+       call    NEAR ypartialbyxstep    ; ypartial is in BP\r
+       add     ax,[WORD viewx]\r
+       adc     dx,[WORD viewx+2]\r
+       mov     [WORD xintercept],ax\r
+       mov     cx,dx\r
+\r
+       mov     bx,[focalty]\r
+       add     bx,[ytilestep]\r
+       mov     bp,bx                                           ; ytile = focalty+ytilestep\r
+       mov     di,dx\r
+       ;begin 8086 hack\r
+       ;shl    di,6\r
+       push cx\r
+       mov cl,6\r
+       shl di,cl\r
+       pop cx\r
+       ;end 8086 hack\r
+       add     di,bx                                           ; yspot = (xinttile<<6) + ytile\r
+\r
+       mov     bx,[xtile]\r
+       mov     dx,[WORD yintercept+2]\r
+       mov     ax,SCREENSEG\r
+       mov     es,ax                                           ; faster than mov es,[screenseg]\r
+\r
+\r
+;---------------------------------------------------------------------------\r
+;\r
+; trace along this angle until we hit a wall\r
+;\r
+; CORE LOOP!\r
+;\r
+; All variables are killed when a wall is hit\r
+;\r
+; AX : scratch\r
+; BX : xtile\r
+; CX : high word of xintercept\r
+; DX : high word of yintercept\r
+; SI : xspot (yinttile<<6)+xtile (index into tilemap and spotvis)\r
+; DI : yspot (xinttile<<6)+ytile (index into tilemap and spotvis)\r
+; BP : ytile\r
+; ES : screenseg\r
+;\r
+;---------------------------------------------------------------------------\r
+\r
+;-----------\r
+;\r
+; check intersections with vertical walls\r
+;\r
+;-----------\r
+\r
+       EVEN\r
+vertcheck:\r
+       cmp     dx,bp\r
+vertop:                                                                ; 0x7e = jle (ytilestep==-1)\r
+       jle     horizentry                                      ; 0x7d = jge (ytilestep==1)\r
+vertentry:\r
+       test [BYTE tilemap+si],0ffh             ; tilehit = *((byte *)tilemap+xspot);\r
+       jnz     hitvert\r
+passvert:\r
+       mov     [BYTE spotvis+si],1                     ; *((byte *)spotvis+xspot) = true;\r
+       add     bx,[xtilestep]                          ; xtile+=xtilestep\r
+       mov     ax,[WORD ystep]\r
+       add     [WORD yintercept],ax            ; yintercept += ystep\r
+       adc     dx,[WORD ystep+2]\r
+       mov     si,bx\r
+       ;begin 8086 hack\r
+       ;shl    si,6\r
+       push cx\r
+       mov cl,6\r
+       shl si,cl\r
+       pop cx\r
+       ;end 8086 hack\r
+       add     si,dx                                           ; xspot = (xtile<<6)+yinttile\r
+       jmp     vertcheck\r
+\r
+       EVEN\r
+hitvert:\r
+       mov     al,[BYTE tilemap+si]            ; tilehit = *((byte *)tilemap+xspot);\r
+       mov     [BYTE tilehit],al\r
+       or      al,al                                           ; set flags\r
+       jns     notvertdoor\r
+       jmp     vertdoor\r
+notvertdoor:\r
+       mov     [WORD xintercept],0\r
+       mov     [WORD xintercept+2],bx\r
+       mov     [xtile],bx\r
+       mov     [WORD yintercept+2],dx\r
+       mov     [ytile],dx\r
+       call FAR HitVertWall\r
+       jmp nextpix\r
+\r
+\r
+;-----------\r
+;\r
+; check intersections with horizontal walls\r
+;\r
+;-----------\r
+       EVEN\r
+horizcheck:\r
+       cmp     cx,bx\r
+horizop:                                                       ; 0x7e = jle (xtilestep==-1)\r
+       jle     vertentry                                       ; 0x7d = jge (xtilestep==1)\r
+horizentry:\r
+       test [BYTE tilemap+di],0ffh             ; tilehit = *((byte *)tilemap+yspot);\r
+       jnz     hithoriz\r
+passhoriz:\r
+       mov     [BYTE spotvis+di],1                     ; *((byte *)spotvis+yspot) = true;\r
+       add     bp,[ytilestep]                          ; ytile+=ytilestep\r
+       mov     ax,[WORD xstep]\r
+       add     [WORD xintercept],ax            ; xintercept += xstep\r
+       adc     cx,[WORD xstep+2]\r
+       mov     di,cx\r
+       ;begin 8086 hack\r
+       ;shl    di,6\r
+       push cx\r
+       mov cl,6\r
+       shl di,cl\r
+       pop cx\r
+       ;end 8086 hack\r
+       add     di,bp                                           ; yspot = (xinttile<<6)+ytile\r
+       jmp     horizcheck\r
+\r
+       EVEN\r
+hithoriz:\r
+       mov     al,[BYTE tilemap+di]            ; tilehit = *((byte *)tilemap+yspot);\r
+       mov     [BYTE tilehit],al\r
+       or      al,al                                           ; set flags\r
+       js      horizdoor\r
+       mov     [WORD xintercept+2],cx\r
+       mov     [xtile],cx\r
+       mov     [WORD yintercept],0\r
+       mov     [WORD yintercept+2],bp\r
+       mov     [ytile],bp\r
+       call FAR HitHorizWall\r
+       jmp nextpix\r
+\r
+;---------------------------------------------------------------------------\r
+;\r
+; next pixel over\r
+;\r
+;---------------------------------------------------------------------------\r
+\r
+nextpix:\r
+       mov     ax,[pixx]\r
+       inc     ax\r
+       mov     [pixx],ax\r
+       cmp     ax,[viewwidth]\r
+       jge     done\r
+       jmp     pixxloop\r
+done:\r
+       pop     bp\r
+       pop     di\r
+       pop     si\r
+       retf\r
+\r
+;===========================================================================\r
+\r
+;=============\r
+;\r
+; hit a special horizontal wall, so find which coordinate a door would be\r
+; intersected at, and check to see if the door is open past that point\r
+;\r
+;=============\r
+horizdoor:\r
+       mov     [xtile],bx                                      ; save off live register variables\r
+       mov     [WORD yintercept+2],dx\r
+\r
+       test al,040h                                    ; both high bits set == pushable wall\r
+       jnz     horizpushwall\r
+\r
+       mov     bx,ax\r
+       and     bx,7fh                                          ; strip high bit\r
+       shl     bx,1                        ; index into word width door table\r
+\r
+       mov     ax,[WORD xstep]\r
+       mov     dx,[WORD xstep+2]\r
+       sar     dx,1\r
+       rcr ax,1                                                ; half a step gets to door position\r
+\r
+       add     ax,[WORD xintercept]            ; add half step to current intercept pos\r
+       adc     dx,cx                                           ; CX hold high word of xintercept\r
+\r
+       cmp     cx,dx                                           ; is it still in the same tile?\r
+       je      hithmid\r
+;\r
+; midpoint is outside tile, so it hit the side of the wall before a door\r
+;\r
+continuehoriz:\r
+       mov     bx,[xtile]                                      ; reload register variables\r
+       mov     dx,[WORD yintercept+2]\r
+       jmp     passhoriz                                       ; continue tracing\r
+;\r
+; the trace hit the door plane at pixel position AX, see if the door is\r
+; closed that much\r
+;\r
+hithmid:\r
+       cmp     ax,[doorposition+bx]            ; position of leading edge of door\r
+       jb      continuehoriz\r
+;\r
+; draw the door\r
+;\r
+       mov     [WORD xintercept],ax            ; save pixel intercept position\r
+       mov     [WORD xintercept+2],cx\r
+\r
+       mov     [WORD yintercept],8000h         ; intercept in middle of tile\r
+       mov     [WORD yintercept+2],bp\r
+\r
+       call    FAR HitHorizDoor\r
+       jmp     nextpix\r
+\r
+;============\r
+;\r
+; hit a sliding horizontal wall\r
+;\r
+;============\r
+\r
+horizpushwall:\r
+       mov     ax,[WORD xstep+2]                       ; multiply xstep by pwallmove (0-63)\r
+       mul     [pwallpos]\r
+       mov     bx,ax\r
+       mov     ax,[WORD xstep]\r
+       mul     [pwallpos]\r
+       add     dx,bx\r
+\r
+       sar     dx,1                                            ; then divide by 64 to accomplish a\r
+       rcr ax,1                                                ; fixed point multiplication\r
+       sar     dx,1\r
+       rcr ax,1\r
+       sar     dx,1\r
+       rcr ax,1\r
+       sar     dx,1\r
+       rcr ax,1\r
+       sar     dx,1\r
+       rcr ax,1\r
+       sar     dx,1\r
+       rcr ax,1\r
+\r
+       add     ax,[WORD xintercept]            ; add partial step to current intercept\r
+       adc     dx,cx                                           ; CX hold high word of xintercept\r
+\r
+       cmp     cx,dx                                           ; is it still in the same tile?\r
+       jne     continuehoriz                           ; no, it hit the side\r
+\r
+;\r
+; draw the pushable wall at the new height\r
+;\r
+       mov     [WORD xintercept],ax            ; save pixel intercept position\r
+       mov     [WORD xintercept+2],dx\r
+\r
+       mov     [WORD yintercept+2],bp\r
+       mov     [WORD yintercept],0\r
+\r
+       call    FAR HitHorizPWall\r
+       jmp     nextpix\r
+\r
+\r
+\r
+;===========================================================================\r
+\r
+;=============\r
+;\r
+; hit a special vertical wall, so find which coordinate a door would be\r
+; intersected at, and check to see if the door is open past that point\r
+;\r
+;=============\r
+vertdoor:\r
+       mov     [xtile],bx                                      ; save off live register variables\r
+       mov     [WORD yintercept+2],dx\r
+\r
+       test al,040h                                    ; both high bits set == pushable wall\r
+       jnz     vertpushwall\r
+\r
+       mov     bx,ax\r
+       and     bx,7fh                                          ; strip high bit\r
+       shl     bx,1                        ; index into word width doorposition\r
+\r
+       mov     ax,[WORD ystep]\r
+       mov     dx,[WORD ystep+2]\r
+       sar     dx,1\r
+       rcr ax,1                                                ; half a step gets to door position\r
+\r
+       add     ax,[WORD yintercept]            ; add half step to current intercept pos\r
+       adc     dx,[WORD yintercept+2]\r
+\r
+       cmp     [WORD yintercept+2],dx          ; is it still in the same tile?\r
+       je      hitvmid\r
+;\r
+; midpoint is outside tile, so it hit the side of the wall before a door\r
+;\r
+continuevert:\r
+       mov     bx,[xtile]                                      ; reload register variables\r
+       mov     dx,[WORD yintercept+2]\r
+       jmp     passvert                                        ; continue tracing\r
+;\r
+; the trace hit the door plane at pixel position AX, see if the door is\r
+; closed that much\r
+;\r
+hitvmid:\r
+       cmp     ax,[doorposition+bx]            ; position of leading edge of door\r
+       jb      continuevert\r
+;\r
+; draw the door\r
+;\r
+       mov     [WORD yintercept],ax            ; save pixel intercept position\r
+       mov     [WORD xintercept],8000h         ; intercept in middle of tile\r
+       mov     ax,[xtile]\r
+       mov     [WORD xintercept+2],ax\r
+\r
+       call    FAR HitVertDoor\r
+       jmp     nextpix\r
+\r
+;============\r
+;\r
+; hit a sliding vertical wall\r
+;\r
+;============\r
+\r
+vertpushwall:\r
+       mov     ax,[WORD ystep+2]                       ; multiply ystep by pwallmove (0-63)\r
+       mul     [pwallpos]\r
+       mov     bx,ax\r
+       mov     ax,[WORD ystep]\r
+       mul     [pwallpos]\r
+       add     dx,bx\r
+\r
+       sar     dx,1                                            ; then divide by 64 to accomplish a\r
+       rcr ax,1                                                ; fixed point multiplication\r
+       sar     dx,1\r
+       rcr ax,1\r
+       sar     dx,1\r
+       rcr ax,1\r
+       sar     dx,1\r
+       rcr ax,1\r
+       sar     dx,1\r
+       rcr ax,1\r
+       sar     dx,1\r
+       rcr ax,1\r
+\r
+       add     ax,[WORD yintercept]            ; add partial step to current intercept\r
+       adc     dx,[WORD yintercept+2]\r
+\r
+       cmp     [WORD yintercept+2],dx          ; is it still in the same tile?\r
+       jne     continuevert                            ; no, it hit the side\r
+\r
+;\r
+; draw the pushable wall at the new height\r
+;\r
+       mov     [WORD yintercept],ax            ; save pixel intercept position\r
+       mov     [WORD yintercept+2],dx\r
+\r
+       mov     bx,[xtile]\r
+       mov     [WORD xintercept+2],bx\r
+       mov     [WORD xintercept],0\r
+\r
+       call    FAR HitVertPWall\r
+       jmp     nextpix\r
+\r
+\r
+\r
+ENDP\r
+\r
+\r
+END\r
+\r
+\r
diff --git a/src/lib/hb/wl_draw.c b/src/lib/hb/wl_draw.c
new file mode 100755 (executable)
index 0000000..3c32e39
--- /dev/null
@@ -0,0 +1,1419 @@
+// WL_DRAW.C\r
+\r
+#include "WL_DEF.H"\r
+#include <DOS.H>\r
+#pragma hdrstop\r
+\r
+//#define DEBUGWALLS\r
+//#define DEBUGTICS\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+// the door is the last picture before the sprites\r
+#define DOORWALL       (PMSpriteStart-8)\r
+\r
+#define ACTORSIZE      0x4000\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                GLOBAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+#ifdef DEBUGWALLS\r
+unsigned screenloc[3]= {0,0,0};\r
+#else\r
+unsigned screenloc[3]= {PAGE1START,PAGE2START,PAGE3START};\r
+#endif\r
+unsigned freelatch = FREESTART;\r
+\r
+long   lasttimecount;\r
+long   frameon;\r
+\r
+unsigned       wallheight[MAXVIEWWIDTH];\r
+\r
+fixed  tileglobal      = TILEGLOBAL;\r
+fixed  mindist         = MINDIST;\r
+\r
+\r
+//\r
+// math tables\r
+//\r
+int                    pixelangle[MAXVIEWWIDTH];\r
+long           far finetangent[FINEANGLES/4];\r
+fixed          far sintable[ANGLES+ANGLES/4],far *costable = sintable+(ANGLES/4);\r
+\r
+//\r
+// refresh variables\r
+//\r
+fixed  viewx,viewy;                    // the focal point\r
+int            viewangle;\r
+fixed  viewsin,viewcos;\r
+\r
+\r
+\r
+fixed  FixedByFrac (fixed a, fixed b);\r
+void   TransformActor (objtype *ob);\r
+void   BuildTables (void);\r
+void   ClearScreen (void);\r
+int            CalcRotate (objtype *ob);\r
+void   DrawScaleds (void);\r
+void   CalcTics (void);\r
+void   FixOfs (void);\r
+void   ThreeDRefresh (void);\r
+\r
+\r
+\r
+//\r
+// wall optimization variables\r
+//\r
+int            lastside;               // true for vertical\r
+long   lastintercept;\r
+int            lasttilehit;\r
+\r
+\r
+//\r
+// ray tracing variables\r
+//\r
+int                    focaltx,focalty,viewtx,viewty;\r
+\r
+int                    midangle,angle;\r
+unsigned       xpartial,ypartial;\r
+unsigned       xpartialup,xpartialdown,ypartialup,ypartialdown;\r
+unsigned       xinttile,yinttile;\r
+\r
+unsigned       tilehit;\r
+unsigned       pixx;\r
+\r
+int            xtile,ytile;\r
+int            xtilestep,ytilestep;\r
+long   xintercept,yintercept;\r
+long   xstep,ystep;\r
+\r
+int            horizwall[MAXWALLTILES],vertwall[MAXWALLTILES];\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+void AsmRefresh (void);                        // in WL_DR_A.ASM\r
+\r
+/*\r
+============================================================================\r
+\r
+                          3 - D  DEFINITIONS\r
+\r
+============================================================================\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
+//\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    neg     cx\r
+asm    neg     ax\r
+asm    sbb     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    neg     dx\r
+asm    neg     ax\r
+asm    sbb     dx,0\r
+\r
+ansok:;\r
+\r
+}\r
+\r
+#pragma warn +rvl\r
+\r
+//==========================================================================\r
+\r
+/*\r
+========================\r
+=\r
+= TransformActor\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
+=   scale              : conversion from global value to screen value\r
+=\r
+= sets:\r
+=   screenx,transx,transy,screenheight: projected edge location and size\r
+=\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
+       long    temp;\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-ACTORSIZE;         // fudge the shape forward a bit, because\r
+                                                               // the midpoint could put parts of the shape\r
+                                                               // into an adjacent wall\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
+       ob->transx = nx;\r
+       ob->transy = ny;\r
+\r
+       if (nx<mindist)                 // too close, don't overflow the divide\r
+       {\r
+         ob->viewheight = 0;\r
+         return;\r
+       }\r
+\r
+       ob->viewx = centerx + ny*scale/nx;      // DEBUG: use assembly divide\r
+\r
+//\r
+// calculate height (heightnumerator/(nx>>8))\r
+//\r
+       asm     mov     ax,[WORD PTR heightnumerator]\r
+       asm     mov     dx,[WORD PTR heightnumerator+2]\r
+       asm     idiv    [WORD PTR nx+1]                 // nx>>8\r
+       asm     mov     [WORD PTR temp],ax\r
+       asm     mov     [WORD PTR temp+2],dx\r
+\r
+       ob->viewheight = temp;\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+========================\r
+=\r
+= TransformTile\r
+=\r
+= Takes paramaters:\r
+=   tx,ty              : tile the object is centered in\r
+=\r
+= globals:\r
+=   viewx,viewy                : point of view\r
+=   viewcos,viewsin    : sin/cos of viewangle\r
+=   scale              : conversion from global value to screen value\r
+=\r
+= sets:\r
+=   screenx,transx,transy,screenheight: projected edge location and size\r
+=\r
+= Returns true if the tile is withing getting distance\r
+=\r
+========================\r
+*/\r
+\r
+boolean TransformTile (int tx, int ty, int *dispx, int *dispheight)\r
+{\r
+       int ratio;\r
+       fixed gx,gy,gxt,gyt,nx,ny;\r
+       long    temp;\r
+\r
+//\r
+// translate point to view centered coordinates\r
+//\r
+       gx = ((long)tx<<TILESHIFT)+0x8000-viewx;\r
+       gy = ((long)ty<<TILESHIFT)+0x8000-viewy;\r
+\r
+//\r
+// calculate newx\r
+//\r
+       gxt = FixedByFrac(gx,viewcos);\r
+       gyt = FixedByFrac(gy,viewsin);\r
+       nx = gxt-gyt-0x2000;            // 0x2000 is size of object\r
+\r
+//\r
+// calculate newy\r
+//\r
+       gxt = FixedByFrac(gx,viewsin);\r
+       gyt = FixedByFrac(gy,viewcos);\r
+       ny = gyt+gxt;\r
+\r
+\r
+//\r
+// calculate perspective ratio\r
+//\r
+       if (nx<mindist)                 // too close, don't overflow the divide\r
+       {\r
+               *dispheight = 0;\r
+               return false;\r
+       }\r
+\r
+       *dispx = centerx + ny*scale/nx; // DEBUG: use assembly divide\r
+\r
+//\r
+// calculate height (heightnumerator/(nx>>8))\r
+//\r
+       asm     mov     ax,[WORD PTR heightnumerator]\r
+       asm     mov     dx,[WORD PTR heightnumerator+2]\r
+       asm     idiv    [WORD PTR nx+1]                 // nx>>8\r
+       asm     mov     [WORD PTR temp],ax\r
+       asm     mov     [WORD PTR temp+2],dx\r
+\r
+       *dispheight = temp;\r
+\r
+//\r
+// see if it should be grabbed\r
+//\r
+       if (nx<TILEGLOBAL && ny>-TILEGLOBAL/2 && ny<TILEGLOBAL/2)\r
+               return true;\r
+       else\r
+               return false;\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+====================\r
+=\r
+= CalcHeight\r
+=\r
+= Calculates the height of xintercept,yintercept from viewx,viewy\r
+=\r
+====================\r
+*/\r
+\r
+#pragma warn -rvl                      // I stick the return value in with ASMs\r
+\r
+int    CalcHeight (void)\r
+{\r
+       int     transheight;\r
+       int ratio;\r
+       fixed gxt,gyt,nx,ny;\r
+       long    gx,gy;\r
+\r
+       gx = xintercept-viewx;\r
+       gxt = FixedByFrac(gx,viewcos);\r
+\r
+       gy = yintercept-viewy;\r
+       gyt = FixedByFrac(gy,viewsin);\r
+\r
+       nx = gxt-gyt;\r
+\r
+  //\r
+  // calculate perspective ratio (heightnumerator/(nx>>8))\r
+  //\r
+       if (nx<mindist)\r
+               nx=mindist;                     // don't let divide overflow\r
+\r
+       asm     mov     ax,[WORD PTR heightnumerator]\r
+       asm     mov     dx,[WORD PTR heightnumerator+2]\r
+       asm     idiv    [WORD PTR nx+1]                 // nx>>8\r
+}\r
+\r
+\r
+//==========================================================================\r
+\r
+/*\r
+===================\r
+=\r
+= ScalePost\r
+=\r
+===================\r
+*/\r
+\r
+long           postsource;\r
+unsigned       postx;\r
+unsigned       postwidth;\r
+\r
+void   near ScalePost (void)           // VGA version\r
+{\r
+       asm     mov     ax,SCREENSEG\r
+       asm     mov     es,ax\r
+\r
+       asm     mov     bx,[postx]\r
+       asm     shl     bx,1\r
+       asm     mov     bp,WORD PTR [wallheight+bx]             // fractional height (low 3 bits frac)\r
+       asm     and     bp,0xfff8                               // bp = heightscaler*4\r
+       asm     shr     bp,1\r
+       asm     cmp     bp,[maxscaleshl2]\r
+       asm     jle     heightok\r
+       asm     mov     bp,[maxscaleshl2]\r
+heightok:\r
+       asm     add     bp,OFFSET fullscalefarcall\r
+       //\r
+       // scale a byte wide strip of wall\r
+       //\r
+       asm     mov     bx,[postx]\r
+       asm     mov     di,bx\r
+       asm     shr     di,1                                            // X in bytes\r
+       asm     shr     di,1\r
+       asm     add     di,[bufferofs]\r
+\r
+       asm     and     bx,3\r
+       /* begin 8086 hack\r
+       asm     shl     bx,3\r
+       */\r
+       asm push cx\r
+       asm mov cl,3\r
+       asm shl bx,cl\r
+       asm pop cx\r
+       /* end 8086 hack */\r
+       asm     add     bx,[postwidth]\r
+\r
+       asm     mov     al,BYTE PTR [mapmasks1-1+bx]    // -1 because no widths of 0\r
+       asm     mov     dx,SC_INDEX+1\r
+       asm     out     dx,al                                           // set bit mask register\r
+       asm     lds     si,DWORD PTR [postsource]\r
+       asm     call DWORD PTR [bp]                             // scale the line of pixels\r
+\r
+       asm     mov     al,BYTE PTR [ss:mapmasks2-1+bx]   // -1 because no widths of 0\r
+       asm     or      al,al\r
+       asm     jz      nomore\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 [bp]                             // scale the line of pixels\r
+\r
+       asm     mov     al,BYTE PTR [ss:mapmasks3-1+bx] // -1 because no widths of 0\r
+       asm     or      al,al\r
+       asm     jz      nomore\r
+       //\r
+       // draw a third byte for vertical strips that cross three bytes\r
+       //\r
+       asm     inc     di\r
+       asm     out     dx,al                                           // set bit mask register\r
+       asm     call DWORD PTR [bp]                             // scale the line of pixels\r
+\r
+\r
+nomore:\r
+       asm     mov     ax,ss\r
+       asm     mov     ds,ax\r
+}\r
+\r
+void  FarScalePost (void)                              // just so other files can call\r
+{\r
+       ScalePost ();\r
+}\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= HitVertWall\r
+=\r
+= tilehit bit 7 is 0, because it's not a door tile\r
+= if bit 6 is 1 and the adjacent tile is a door tile, use door side pic\r
+=\r
+====================\r
+*/\r
+\r
+void HitVertWall (void)\r
+{\r
+       int                     wallpic;\r
+       unsigned        texture;\r
+\r
+       texture = (yintercept>>4)&0xfc0;\r
+       if (xtilestep == -1)\r
+       {\r
+               texture = 0xfc0-texture;\r
+               xintercept += TILEGLOBAL;\r
+       }\r
+       wallheight[pixx] = CalcHeight();\r
+\r
+       if (lastside==1 && lastintercept == xtile && lasttilehit == tilehit)\r
+       {\r
+               // in the same wall type as last time, so check for optimized draw\r
+               if (texture == (unsigned)postsource)\r
+               {\r
+               // wide scale\r
+                       postwidth++;\r
+                       wallheight[pixx] = wallheight[pixx-1];\r
+                       return;\r
+               }\r
+               else\r
+               {\r
+                       ScalePost ();\r
+                       (unsigned)postsource = texture;\r
+                       postwidth = 1;\r
+                       postx = pixx;\r
+               }\r
+       }\r
+       else\r
+       {\r
+       // new wall\r
+               if (lastside != -1)                             // if not the first scaled post\r
+                       ScalePost ();\r
+\r
+               lastside = true;\r
+               lastintercept = xtile;\r
+\r
+               lasttilehit = tilehit;\r
+               postx = pixx;\r
+               postwidth = 1;\r
+\r
+               if (tilehit & 0x40)\r
+               {                                                               // check for adjacent doors\r
+                       ytile = yintercept>>TILESHIFT;\r
+                       if ( tilemap[xtile-xtilestep][ytile]&0x80 )\r
+                               wallpic = DOORWALL+3;\r
+                       else\r
+                               wallpic = vertwall[tilehit & ~0x40];\r
+               }\r
+               else\r
+                       wallpic = vertwall[tilehit];\r
+\r
+               *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(wallpic);\r
+               (unsigned)postsource = texture;\r
+\r
+       }\r
+}\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= HitHorizWall\r
+=\r
+= tilehit bit 7 is 0, because it's not a door tile\r
+= if bit 6 is 1 and the adjacent tile is a door tile, use door side pic\r
+=\r
+====================\r
+*/\r
+\r
+void HitHorizWall (void)\r
+{\r
+       int                     wallpic;\r
+       unsigned        texture;\r
+\r
+       texture = (xintercept>>4)&0xfc0;\r
+       if (ytilestep == -1)\r
+               yintercept += TILEGLOBAL;\r
+       else\r
+               texture = 0xfc0-texture;\r
+       wallheight[pixx] = CalcHeight();\r
+\r
+       if (lastside==0 && lastintercept == ytile && lasttilehit == tilehit)\r
+       {\r
+               // in the same wall type as last time, so check for optimized draw\r
+               if (texture == (unsigned)postsource)\r
+               {\r
+               // wide scale\r
+                       postwidth++;\r
+                       wallheight[pixx] = wallheight[pixx-1];\r
+                       return;\r
+               }\r
+               else\r
+               {\r
+                       ScalePost ();\r
+                       (unsigned)postsource = texture;\r
+                       postwidth = 1;\r
+                       postx = pixx;\r
+               }\r
+       }\r
+       else\r
+       {\r
+       // new wall\r
+               if (lastside != -1)                             // if not the first scaled post\r
+                       ScalePost ();\r
+\r
+               lastside = 0;\r
+               lastintercept = ytile;\r
+\r
+               lasttilehit = tilehit;\r
+               postx = pixx;\r
+               postwidth = 1;\r
+\r
+               if (tilehit & 0x40)\r
+               {                                                               // check for adjacent doors\r
+                       xtile = xintercept>>TILESHIFT;\r
+                       if ( tilemap[xtile][ytile-ytilestep]&0x80 )\r
+                               wallpic = DOORWALL+2;\r
+                       else\r
+                               wallpic = horizwall[tilehit & ~0x40];\r
+               }\r
+               else\r
+                       wallpic = horizwall[tilehit];\r
+\r
+               *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(wallpic);\r
+               (unsigned)postsource = texture;\r
+       }\r
+\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+====================\r
+=\r
+= HitHorizDoor\r
+=\r
+====================\r
+*/\r
+\r
+void HitHorizDoor (void)\r
+{\r
+       unsigned        texture,doorpage,doornum;\r
+\r
+       doornum = tilehit&0x7f;\r
+       texture = ( (xintercept-doorposition[doornum]) >> 4) &0xfc0;\r
+\r
+       wallheight[pixx] = CalcHeight();\r
+\r
+       if (lasttilehit == tilehit)\r
+       {\r
+       // in the same door as last time, so check for optimized draw\r
+               if (texture == (unsigned)postsource)\r
+               {\r
+               // wide scale\r
+                       postwidth++;\r
+                       wallheight[pixx] = wallheight[pixx-1];\r
+                       return;\r
+               }\r
+               else\r
+               {\r
+                       ScalePost ();\r
+                       (unsigned)postsource = texture;\r
+                       postwidth = 1;\r
+                       postx = pixx;\r
+               }\r
+       }\r
+       else\r
+       {\r
+               if (lastside != -1)                             // if not the first scaled post\r
+                       ScalePost ();                   // draw last post\r
+       // first pixel in this door\r
+               lastside = 2;\r
+               lasttilehit = tilehit;\r
+               postx = pixx;\r
+               postwidth = 1;\r
+\r
+               switch (doorobjlist[doornum].lock)\r
+               {\r
+               case dr_normal:\r
+                       doorpage = DOORWALL;\r
+                       break;\r
+               case dr_lock1:\r
+               case dr_lock2:\r
+               case dr_lock3:\r
+               case dr_lock4:\r
+                       doorpage = DOORWALL+6;\r
+                       break;\r
+               case dr_elevator:\r
+                       doorpage = DOORWALL+4;\r
+                       break;\r
+               }\r
+\r
+               *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(doorpage);\r
+               (unsigned)postsource = texture;\r
+       }\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+====================\r
+=\r
+= HitVertDoor\r
+=\r
+====================\r
+*/\r
+\r
+void HitVertDoor (void)\r
+{\r
+       unsigned        texture,doorpage,doornum;\r
+\r
+       doornum = tilehit&0x7f;\r
+       texture = ( (yintercept-doorposition[doornum]) >> 4) &0xfc0;\r
+\r
+       wallheight[pixx] = CalcHeight();\r
+\r
+       if (lasttilehit == tilehit)\r
+       {\r
+       // in the same door as last time, so check for optimized draw\r
+               if (texture == (unsigned)postsource)\r
+               {\r
+               // wide scale\r
+                       postwidth++;\r
+                       wallheight[pixx] = wallheight[pixx-1];\r
+                       return;\r
+               }\r
+               else\r
+               {\r
+                       ScalePost ();\r
+                       (unsigned)postsource = texture;\r
+                       postwidth = 1;\r
+                       postx = pixx;\r
+               }\r
+       }\r
+       else\r
+       {\r
+               if (lastside != -1)                             // if not the first scaled post\r
+                       ScalePost ();                   // draw last post\r
+       // first pixel in this door\r
+               lastside = 2;\r
+               lasttilehit = tilehit;\r
+               postx = pixx;\r
+               postwidth = 1;\r
+\r
+               switch (doorobjlist[doornum].lock)\r
+               {\r
+               case dr_normal:\r
+                       doorpage = DOORWALL;\r
+                       break;\r
+               case dr_lock1:\r
+               case dr_lock2:\r
+               case dr_lock3:\r
+               case dr_lock4:\r
+                       doorpage = DOORWALL+6;\r
+                       break;\r
+               case dr_elevator:\r
+                       doorpage = DOORWALL+4;\r
+                       break;\r
+               }\r
+\r
+               *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(doorpage+1);\r
+               (unsigned)postsource = texture;\r
+       }\r
+}\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= HitHorizPWall\r
+=\r
+= A pushable wall in action has been hit\r
+=\r
+====================\r
+*/\r
+\r
+void HitHorizPWall (void)\r
+{\r
+       int                     wallpic;\r
+       unsigned        texture,offset;\r
+\r
+       texture = (xintercept>>4)&0xfc0;\r
+       offset = pwallpos<<10;\r
+       if (ytilestep == -1)\r
+               yintercept += TILEGLOBAL-offset;\r
+       else\r
+       {\r
+               texture = 0xfc0-texture;\r
+               yintercept += offset;\r
+       }\r
+\r
+       wallheight[pixx] = CalcHeight();\r
+\r
+       if (lasttilehit == tilehit)\r
+       {\r
+               // in the same wall type as last time, so check for optimized draw\r
+               if (texture == (unsigned)postsource)\r
+               {\r
+               // wide scale\r
+                       postwidth++;\r
+                       wallheight[pixx] = wallheight[pixx-1];\r
+                       return;\r
+               }\r
+               else\r
+               {\r
+                       ScalePost ();\r
+                       (unsigned)postsource = texture;\r
+                       postwidth = 1;\r
+                       postx = pixx;\r
+               }\r
+       }\r
+       else\r
+       {\r
+       // new wall\r
+               if (lastside != -1)                             // if not the first scaled post\r
+                       ScalePost ();\r
+\r
+               lasttilehit = tilehit;\r
+               postx = pixx;\r
+               postwidth = 1;\r
+\r
+               wallpic = horizwall[tilehit&63];\r
+\r
+               *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(wallpic);\r
+               (unsigned)postsource = texture;\r
+       }\r
+\r
+}\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= HitVertPWall\r
+=\r
+= A pushable wall in action has been hit\r
+=\r
+====================\r
+*/\r
+\r
+void HitVertPWall (void)\r
+{\r
+       int                     wallpic;\r
+       unsigned        texture,offset;\r
+\r
+       texture = (yintercept>>4)&0xfc0;\r
+       offset = pwallpos<<10;\r
+       if (xtilestep == -1)\r
+       {\r
+               xintercept += TILEGLOBAL-offset;\r
+               texture = 0xfc0-texture;\r
+       }\r
+       else\r
+               xintercept += offset;\r
+\r
+       wallheight[pixx] = CalcHeight();\r
+\r
+       if (lasttilehit == tilehit)\r
+       {\r
+               // in the same wall type as last time, so check for optimized draw\r
+               if (texture == (unsigned)postsource)\r
+               {\r
+               // wide scale\r
+                       postwidth++;\r
+                       wallheight[pixx] = wallheight[pixx-1];\r
+                       return;\r
+               }\r
+               else\r
+               {\r
+                       ScalePost ();\r
+                       (unsigned)postsource = texture;\r
+                       postwidth = 1;\r
+                       postx = pixx;\r
+               }\r
+       }\r
+       else\r
+       {\r
+       // new wall\r
+               if (lastside != -1)                             // if not the first scaled post\r
+                       ScalePost ();\r
+\r
+               lasttilehit = tilehit;\r
+               postx = pixx;\r
+               postwidth = 1;\r
+\r
+               wallpic = vertwall[tilehit&63];\r
+\r
+               *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(wallpic);\r
+               (unsigned)postsource = texture;\r
+       }\r
+\r
+}\r
+\r
+//==========================================================================\r
+\r
+//==========================================================================\r
+\r
+#if 0\r
+/*\r
+=====================\r
+=\r
+= ClearScreen\r
+=\r
+=====================\r
+*/\r
+\r
+void ClearScreen (void)\r
+{\r
+ unsigned floor=egaFloor[gamestate.episode*10+mapon],\r
+         ceiling=egaCeiling[gamestate.episode*10+mapon];\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\r
+asm    mov     ax,[viewwidth]\r
+asm    shr     ax,1\r
+asm    shr     ax,1\r
+asm    shr     ax,1\r
+asm    sub     dx,ax                                   // dx = 40-viewwidth/8\r
+\r
+asm    mov     bx,[viewwidth]\r
+asm    shr     bx,1                                    // bl = viewwidth/16\r
+asm    shr     bx,1\r
+asm    shr     bx,1\r
+asm    shr     bx,1\r
+asm    mov     bh,BYTE PTR [viewheight]\r
+asm    shr     bh,1                                    // half height\r
+\r
+asm    mov     ax,[ceiling]\r
+asm    mov     es,[screenseg]\r
+asm    mov     di,[bufferofs]\r
+\r
+toploop:\r
+asm    mov     cl,bl\r
+asm    rep     stosw\r
+asm    add     di,dx\r
+asm    dec     bh\r
+asm    jnz     toploop\r
+\r
+asm    mov     bh,BYTE PTR [viewheight]\r
+asm    shr     bh,1                                    // half height\r
+asm    mov     ax,[floor]\r
+\r
+bottomloop:\r
+asm    mov     cl,bl\r
+asm    rep     stosw\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
+#endif\r
+//==========================================================================\r
+\r
+unsigned vgaCeiling[]=\r
+{\r
+#ifndef SPEAR\r
+ 0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0xbfbf,\r
+ 0x4e4e,0x4e4e,0x4e4e,0x1d1d,0x8d8d,0x4e4e,0x1d1d,0x2d2d,0x1d1d,0x8d8d,\r
+ 0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x2d2d,0xdddd,0x1d1d,0x1d1d,0x9898,\r
+\r
+ 0x1d1d,0x9d9d,0x2d2d,0xdddd,0xdddd,0x9d9d,0x2d2d,0x4d4d,0x1d1d,0xdddd,\r
+ 0x7d7d,0x1d1d,0x2d2d,0x2d2d,0xdddd,0xd7d7,0x1d1d,0x1d1d,0x1d1d,0x2d2d,\r
+ 0x1d1d,0x1d1d,0x1d1d,0x1d1d,0xdddd,0xdddd,0x7d7d,0xdddd,0xdddd,0xdddd\r
+#else\r
+ 0x6f6f,0x4f4f,0x1d1d,0xdede,0xdfdf,0x2e2e,0x7f7f,0x9e9e,0xaeae,0x7f7f,\r
+ 0x1d1d,0xdede,0xdfdf,0xdede,0xdfdf,0xdede,0xe1e1,0xdcdc,0x2e2e,0x1d1d,0xdcdc\r
+#endif\r
+};\r
+\r
+/*\r
+=====================\r
+=\r
+= VGAClearScreen\r
+=\r
+=====================\r
+*/\r
+\r
+void VGAClearScreen (void)\r
+{\r
+ unsigned ceiling=vgaCeiling[gamestate.episode*10+mapon];\r
+\r
+  //\r
+  // clear the screen\r
+  //\r
+asm    mov     dx,SC_INDEX\r
+asm    mov     ax,SC_MAPMASK+15*256    // write through all planes\r
+asm    out     dx,ax\r
+\r
+asm    mov     dx,80\r
+asm    mov     ax,[viewwidth]\r
+asm    shr     ax,1\r
+asm    shr     ax,1\r
+asm    sub     dx,ax                                   // dx = 40-viewwidth/2\r
+\r
+asm    mov     bx,[viewwidth]\r
+asm    shr     bx,1                                    // bl = viewwidth/8\r
+asm    shr     bx,1\r
+asm    shr     bx,1\r
+asm    mov     bh,BYTE PTR [viewheight]\r
+asm    shr     bh,1                                    // half height\r
+\r
+asm    mov     es,[screenseg]\r
+asm    mov     di,[bufferofs]\r
+asm    mov     ax,[ceiling]\r
+\r
+toploop:\r
+asm    mov     cl,bl\r
+asm    rep     stosw\r
+asm    add     di,dx\r
+asm    dec     bh\r
+asm    jnz     toploop\r
+\r
+asm    mov     bh,BYTE PTR [viewheight]\r
+asm    shr     bh,1                                    // half height\r
+asm    mov     ax,0x1919\r
+\r
+bottomloop:\r
+asm    mov     cl,bl\r
+asm    rep     stosw\r
+asm    add     di,dx\r
+asm    dec     bh\r
+asm    jnz     bottomloop\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+=====================\r
+=\r
+= CalcRotate\r
+=\r
+=====================\r
+*/\r
+\r
+int    CalcRotate (objtype *ob)\r
+{\r
+       int     angle,viewangle;\r
+\r
+       // this isn't exactly correct, as it should vary by a trig value,\r
+       // but it is close enough with only eight rotations\r
+\r
+       viewangle = player->angle + (centerx - ob->viewx)/8;\r
+\r
+       if (ob->obclass == rocketobj || ob->obclass == hrocketobj)\r
+               angle =  (viewangle-180)- ob->angle;\r
+       else\r
+               angle =  (viewangle-180)- dirangle[ob->dir];\r
+\r
+       angle+=ANGLES/16;\r
+       while (angle>=ANGLES)\r
+               angle-=ANGLES;\r
+       while (angle<0)\r
+               angle+=ANGLES;\r
+\r
+       if (ob->state->rotate == 2)             // 2 rotation pain frame\r
+               return 4*(angle/(ANGLES/2));        // seperated by 3 (art layout...)\r
+\r
+       return angle/(ANGLES/8);\r
+}\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= DrawScaleds\r
+=\r
+= Draws all objects that are visable\r
+=\r
+=====================\r
+*/\r
+\r
+#define MAXVISABLE     50\r
+\r
+typedef struct\r
+{\r
+       int     viewx,\r
+               viewheight,\r
+               shapenum;\r
+} visobj_t;\r
+\r
+visobj_t       vislist[MAXVISABLE],*visptr,*visstep,*farthest;\r
+\r
+void DrawScaleds (void)\r
+{\r
+       int             i,j,least,numvisable,height;\r
+       memptr          shape;\r
+       byte            *tilespot,*visspot;\r
+       int                     shapenum;\r
+       unsigned        spotloc;\r
+\r
+       statobj_t       *statptr;\r
+       objtype         *obj;\r
+\r
+       visptr = &vislist[0];\r
+\r
+//\r
+// place static objects\r
+//\r
+       for (statptr = &statobjlist[0] ; statptr !=laststatobj ; statptr++)\r
+       {\r
+               if ((visptr->shapenum = statptr->shapenum) == -1)\r
+                       continue;                                               // object has been deleted\r
+\r
+               if (!*statptr->visspot)\r
+                       continue;                                               // not visable\r
+\r
+               if (TransformTile (statptr->tilex,statptr->tiley\r
+                       ,&visptr->viewx,&visptr->viewheight) && statptr->flags & FL_BONUS)\r
+               {\r
+                       GetBonus (statptr);\r
+                       continue;\r
+               }\r
+\r
+               if (!visptr->viewheight)\r
+                       continue;                                               // to close to the object\r
+\r
+               if (visptr < &vislist[MAXVISABLE-1])    // don't let it overflow\r
+                       visptr++;\r
+       }\r
+\r
+//\r
+// place active objects\r
+//\r
+       for (obj = player->next;obj;obj=obj->next)\r
+       {\r
+               if (!(visptr->shapenum = obj->state->shapenum))\r
+                       continue;                                               // no shape\r
+\r
+               spotloc = (obj->tilex<<6)+obj->tiley;   // optimize: keep in struct?\r
+               visspot = &spotvis[0][0]+spotloc;\r
+               tilespot = &tilemap[0][0]+spotloc;\r
+\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)\r
+                               continue;                                               // too close or far away\r
+\r
+                       visptr->viewx = obj->viewx;\r
+                       visptr->viewheight = obj->viewheight;\r
+                       if (visptr->shapenum == -1)\r
+                               visptr->shapenum = obj->temp1;  // special shape\r
+\r
+                       if (obj->state->rotate)\r
+                               visptr->shapenum += CalcRotate (obj);\r
+\r
+                       if (visptr < &vislist[MAXVISABLE-1])    // don't let it overflow\r
+                               visptr++;\r
+                       obj->flags |= FL_VISABLE;\r
+               }\r
+               else\r
+                       obj->flags &= ~FL_VISABLE;\r
+       }\r
+\r
+//\r
+// draw from back to front\r
+//\r
+       numvisable = visptr-&vislist[0];\r
+\r
+       if (!numvisable)\r
+               return;                                                                 // no visable objects\r
+\r
+       for (i = 0; i<numvisable; i++)\r
+       {\r
+               least = 32000;\r
+               for (visstep=&vislist[0] ; visstep<visptr ; visstep++)\r
+               {\r
+                       height = visstep->viewheight;\r
+                       if (height < least)\r
+                       {\r
+                               least = height;\r
+                               farthest = visstep;\r
+                       }\r
+               }\r
+               //\r
+               // draw farthest\r
+               //\r
+               ScaleShape(farthest->viewx,farthest->shapenum,farthest->viewheight);\r
+\r
+               farthest->viewheight = 32000;\r
+       }\r
+\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+==============\r
+=\r
+= DrawPlayerWeapon\r
+=\r
+= Draw the player's hands\r
+=\r
+==============\r
+*/\r
+\r
+int    weaponscale[NUMWEAPONS] = {SPR_KNIFEREADY,SPR_PISTOLREADY\r
+       ,SPR_MACHINEGUNREADY,SPR_CHAINREADY};\r
+\r
+void DrawPlayerWeapon (void)\r
+{\r
+       int     shapenum;\r
+\r
+#ifndef SPEAR\r
+       if (gamestate.victoryflag)\r
+       {\r
+               if (player->state == &s_deathcam && (TimeCount&32) )\r
+                       SimpleScaleShape(viewwidth/2,SPR_DEATHCAM,viewheight+1);\r
+               return;\r
+       }\r
+#endif\r
+\r
+       if (gamestate.weapon != -1)\r
+       {\r
+               shapenum = weaponscale[gamestate.weapon]+gamestate.weaponframe;\r
+               SimpleScaleShape(viewwidth/2,shapenum,viewheight+1);\r
+       }\r
+\r
+       if (demorecord || demoplayback)\r
+               SimpleScaleShape(viewwidth/2,SPR_DEMO,viewheight+1);\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
+// 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
+       do\r
+       {\r
+               newtime = TimeCount;\r
+               tics = newtime-lasttimecount;\r
+       } while (!tics);                        // make sure at least one tic passes\r
+\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
+= FixOfs\r
+=\r
+========================\r
+*/\r
+\r
+void   FixOfs (void)\r
+{\r
+       VW_ScreenToScreen (displayofs,bufferofs,viewwidth/8,viewheight);\r
+}\r
+\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= WallRefresh\r
+=\r
+====================\r
+*/\r
+\r
+void WallRefresh (void)\r
+{\r
+//\r
+// set up variables for this view\r
+//\r
+       viewangle = player->angle;\r
+       midangle = 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
+\r
+       focaltx = viewx>>TILESHIFT;\r
+       focalty = viewy>>TILESHIFT;\r
+\r
+       viewtx = player->x >> TILESHIFT;\r
+       viewty = player->y >> TILESHIFT;\r
+\r
+       xpartialdown = viewx&(TILEGLOBAL-1);\r
+       xpartialup = TILEGLOBAL-xpartialdown;\r
+       ypartialdown = viewy&(TILEGLOBAL-1);\r
+       ypartialup = TILEGLOBAL-ypartialdown;\r
+\r
+       lastside = -1;                  // the first pixel is on a new wall\r
+       AsmRefresh ();\r
+       ScalePost ();                   // no more optimization on last post\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+========================\r
+=\r
+= ThreeDRefresh\r
+=\r
+========================\r
+*/\r
+\r
+void   ThreeDRefresh (void)\r
+{\r
+       int tracedir;\r
+\r
+// this wouldn't need to be done except for my debugger/video wierdness\r
+       outportb (SC_INDEX,SC_MAPMASK);\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,2048                                                 // 64*64 / 2\r
+asm    rep stosw\r
+\r
+       bufferofs += screenofs;\r
+\r
+//\r
+// follow the walls from there to the right, drawwing as we go\r
+//\r
+       VGAClearScreen ();\r
+\r
+       WallRefresh ();\r
+\r
+//\r
+// draw all the scaled images\r
+//\r
+       DrawScaleds();                  // draw scaled stuff\r
+       DrawPlayerWeapon ();    // draw player's hands\r
+\r
+//\r
+// show screen and time last cycle\r
+//\r
+       if (fizzlein)\r
+       {\r
+               FizzleFade(bufferofs,displayofs+screenofs,viewwidth,viewheight,20,false);\r
+               fizzlein = false;\r
+\r
+               lasttimecount = TimeCount = 0;          // don't make a big tic count\r
+\r
+       }\r
+\r
+       bufferofs -= screenofs;\r
+       displayofs = bufferofs;\r
+\r
+       asm     cli\r
+       asm     mov     cx,[displayofs]\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     sti\r
+\r
+       bufferofs += SCREENSIZE;\r
+       if (bufferofs > PAGE3START)\r
+               bufferofs = PAGE1START;\r
+\r
+       frameon++;\r
+       PM_NextFrame();\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
diff --git a/src/lib/hb/wl_game.c b/src/lib/hb/wl_game.c
new file mode 100755 (executable)
index 0000000..9f63d9f
--- /dev/null
@@ -0,0 +1,1484 @@
+// WL_GAME.C\r
+\r
+#include "WL_DEF.H"\r
+#pragma hdrstop\r
+\r
+#ifdef MYPROFILE\r
+#include <TIME.H>\r
+#endif\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                GLOBAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+boolean                ingame,fizzlein;\r
+unsigned       latchpics[NUMLATCHPICS];\r
+gametype       gamestate;\r
+\r
+long           spearx,speary;\r
+unsigned       spearangle;\r
+boolean                spearflag;\r
+\r
+//\r
+// ELEVATOR BACK MAPS - REMEMBER (-1)!!\r
+//\r
+int ElevatorBackTo[]={1,1,7,3,5,3};\r
+\r
+void ScanInfoPlane (void);\r
+void SetupGameLevel (void);\r
+void DrawPlayScreen (void);\r
+void LoadLatchMem (void);\r
+void GameLoop (void);\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+\r
+//===========================================================================\r
+//===========================================================================\r
+\r
+\r
+/*\r
+==========================\r
+=\r
+= SetSoundLoc - Given the location of an object (in terms of global\r
+=      coordinates, held in globalsoundx and globalsoundy), munges the values\r
+=      for an approximate distance from the left and right ear, and puts\r
+=      those values into leftchannel and rightchannel.\r
+=\r
+= JAB\r
+=\r
+==========================\r
+*/\r
+\r
+       fixed   globalsoundx,globalsoundy;\r
+       int             leftchannel,rightchannel;\r
+#define ATABLEMAX 15\r
+byte righttable[ATABLEMAX][ATABLEMAX * 2] = {\r
+{ 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 6, 0, 0, 0, 0, 0, 1, 3, 5, 8, 8, 8, 8, 8, 8, 8, 8},\r
+{ 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 6, 4, 0, 0, 0, 0, 0, 2, 4, 6, 8, 8, 8, 8, 8, 8, 8, 8},\r
+{ 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 4, 1, 0, 0, 0, 1, 2, 4, 6, 8, 8, 8, 8, 8, 8, 8, 8},\r
+{ 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 6, 5, 4, 2, 1, 0, 1, 2, 3, 5, 7, 8, 8, 8, 8, 8, 8, 8, 8},\r
+{ 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 6, 5, 4, 3, 2, 2, 3, 3, 5, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8},\r
+{ 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 6, 6, 5, 4, 4, 4, 4, 5, 6, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8},\r
+{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 6, 6, 5, 5, 5, 6, 6, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},\r
+{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},\r
+{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},\r
+{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},\r
+{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},\r
+{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},\r
+{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},\r
+{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},\r
+{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}\r
+};\r
+byte lefttable[ATABLEMAX][ATABLEMAX * 2] = {\r
+{ 8, 8, 8, 8, 8, 8, 8, 8, 5, 3, 1, 0, 0, 0, 0, 0, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8},\r
+{ 8, 8, 8, 8, 8, 8, 8, 8, 6, 4, 2, 0, 0, 0, 0, 0, 4, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8},\r
+{ 8, 8, 8, 8, 8, 8, 8, 8, 6, 4, 2, 1, 0, 0, 0, 1, 4, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8},\r
+{ 8, 8, 8, 8, 8, 8, 8, 8, 7, 5, 3, 2, 1, 0, 1, 2, 4, 5, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8},\r
+{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 6, 5, 3, 3, 2, 2, 3, 4, 5, 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8},\r
+{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 6, 5, 4, 4, 4, 4, 5, 6, 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8},\r
+{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 6, 6, 5, 5, 5, 6, 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8},\r
+{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 6, 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},\r
+{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},\r
+{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},\r
+{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},\r
+{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},\r
+{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},\r
+{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},\r
+{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}\r
+};\r
+\r
+void\r
+SetSoundLoc(fixed gx,fixed gy)\r
+{\r
+       fixed   xt,yt;\r
+       int             x,y;\r
+\r
+//\r
+// translate point to view centered coordinates\r
+//\r
+       gx -= viewx;\r
+       gy -= viewy;\r
+\r
+//\r
+// calculate newx\r
+//\r
+       xt = FixedByFrac(gx,viewcos);\r
+       yt = FixedByFrac(gy,viewsin);\r
+       x = (xt - yt) >> TILESHIFT;\r
+\r
+//\r
+// calculate newy\r
+//\r
+       xt = FixedByFrac(gx,viewsin);\r
+       yt = FixedByFrac(gy,viewcos);\r
+       y = (yt + xt) >> TILESHIFT;\r
+\r
+       if (y >= ATABLEMAX)\r
+               y = ATABLEMAX - 1;\r
+       else if (y <= -ATABLEMAX)\r
+               y = -ATABLEMAX;\r
+       if (x < 0)\r
+               x = -x;\r
+       if (x >= ATABLEMAX)\r
+               x = ATABLEMAX - 1;\r
+       leftchannel  =  lefttable[x][y + ATABLEMAX];\r
+       rightchannel = righttable[x][y + ATABLEMAX];\r
+\r
+#if 0\r
+       CenterWindow(8,1);\r
+       US_PrintSigned(leftchannel);\r
+       US_Print(",");\r
+       US_PrintSigned(rightchannel);\r
+       VW_UpdateScreen();\r
+#endif\r
+}\r
+\r
+/*\r
+==========================\r
+=\r
+= SetSoundLocGlobal - Sets up globalsoundx & globalsoundy and then calls\r
+=      UpdateSoundLoc() to transform that into relative channel volumes. Those\r
+=      values are then passed to the Sound Manager so that they'll be used for\r
+=      the next sound played (if possible).\r
+=\r
+= JAB\r
+=\r
+==========================\r
+*/\r
+void PlaySoundLocGlobal(word s,fixed gx,fixed gy)\r
+{\r
+       SetSoundLoc(gx,gy);\r
+       SD_PositionSound(leftchannel,rightchannel);\r
+       if (SD_PlaySound(s))\r
+       {\r
+               globalsoundx = gx;\r
+               globalsoundy = gy;\r
+       }\r
+}\r
+\r
+void UpdateSoundLoc(void)\r
+{\r
+       if (SoundPositioned)\r
+       {\r
+               SetSoundLoc(globalsoundx,globalsoundy);\r
+               SD_SetPosition(leftchannel,rightchannel);\r
+       }\r
+}\r
+\r
+/*\r
+**     JAB End\r
+*/\r
+\r
+\r
+/*\r
+==========================\r
+=\r
+= ClearMemory\r
+=\r
+==========================\r
+*/\r
+\r
+void ClearMemory (void)\r
+{\r
+       PM_UnlockMainMem();\r
+       SD_StopDigitized();\r
+       MM_SortMem ();\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
+       start = mapsegs[1];\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 19:\r
+                       case 20:\r
+                       case 21:\r
+                       case 22:\r
+                               SpawnPlayer(x,y,NORTH+tile-19);\r
+                               break;\r
+\r
+                       case 23:\r
+                       case 24:\r
+                       case 25:\r
+                       case 26:\r
+                       case 27:\r
+                       case 28:\r
+                       case 29:\r
+                       case 30:\r
+\r
+                       case 31:\r
+                       case 32:\r
+                       case 33:\r
+                       case 34:\r
+                       case 35:\r
+                       case 36:\r
+                       case 37:\r
+                       case 38:\r
+\r
+                       case 39:\r
+                       case 40:\r
+                       case 41:\r
+                       case 42:\r
+                       case 43:\r
+                       case 44:\r
+                       case 45:\r
+                       case 46:\r
+\r
+                       case 47:\r
+                       case 48:\r
+                       case 49:\r
+                       case 50:\r
+                       case 51:\r
+                       case 52:\r
+                       case 53:\r
+                       case 54:\r
+\r
+                       case 55:\r
+                       case 56:\r
+                       case 57:\r
+                       case 58:\r
+                       case 59:\r
+                       case 60:\r
+                       case 61:\r
+                       case 62:\r
+\r
+                       case 63:\r
+                       case 64:\r
+                       case 65:\r
+                       case 66:\r
+                       case 67:\r
+                       case 68:\r
+                       case 69:\r
+                       case 70:\r
+                       case 71:\r
+                       case 72:\r
+                       case 73:                                                // TRUCK AND SPEAR!\r
+                       case 74:\r
+\r
+                               SpawnStatic(x,y,tile-23);\r
+                               break;\r
+\r
+//\r
+// P wall\r
+//\r
+                       case 98:\r
+                               if (!loadedgame)\r
+                                 gamestate.secrettotal++;\r
+                               break;\r
+\r
+//\r
+// guard\r
+//\r
+                       case 180:\r
+                       case 181:\r
+                       case 182:\r
+                       case 183:\r
+                               if (gamestate.difficulty<gd_hard)\r
+                                       break;\r
+                               tile -= 36;\r
+                       case 144:\r
+                       case 145:\r
+                       case 146:\r
+                       case 147:\r
+                               if (gamestate.difficulty<gd_medium)\r
+                                       break;\r
+                               tile -= 36;\r
+                       case 108:\r
+                       case 109:\r
+                       case 110:\r
+                       case 111:\r
+                               SpawnStand(en_guard,x,y,tile-108);\r
+                               break;\r
+\r
+\r
+                       case 184:\r
+                       case 185:\r
+                       case 186:\r
+                       case 187:\r
+                               if (gamestate.difficulty<gd_hard)\r
+                                       break;\r
+                               tile -= 36;\r
+                       case 148:\r
+                       case 149:\r
+                       case 150:\r
+                       case 151:\r
+                               if (gamestate.difficulty<gd_medium)\r
+                                       break;\r
+                               tile -= 36;\r
+                       case 112:\r
+                       case 113:\r
+                       case 114:\r
+                       case 115:\r
+                               SpawnPatrol(en_guard,x,y,tile-112);\r
+                               break;\r
+\r
+                       case 124:\r
+                               SpawnDeadGuard (x,y);\r
+                               break;\r
+//\r
+// officer\r
+//\r
+                       case 188:\r
+                       case 189:\r
+                       case 190:\r
+                       case 191:\r
+                               if (gamestate.difficulty<gd_hard)\r
+                                       break;\r
+                               tile -= 36;\r
+                       case 152:\r
+                       case 153:\r
+                       case 154:\r
+                       case 155:\r
+                               if (gamestate.difficulty<gd_medium)\r
+                                       break;\r
+                               tile -= 36;\r
+                       case 116:\r
+                       case 117:\r
+                       case 118:\r
+                       case 119:\r
+                               SpawnStand(en_officer,x,y,tile-116);\r
+                               break;\r
+\r
+\r
+                       case 192:\r
+                       case 193:\r
+                       case 194:\r
+                       case 195:\r
+                               if (gamestate.difficulty<gd_hard)\r
+                                       break;\r
+                               tile -= 36;\r
+                       case 156:\r
+                       case 157:\r
+                       case 158:\r
+                       case 159:\r
+                               if (gamestate.difficulty<gd_medium)\r
+                                       break;\r
+                               tile -= 36;\r
+                       case 120:\r
+                       case 121:\r
+                       case 122:\r
+                       case 123:\r
+                               SpawnPatrol(en_officer,x,y,tile-120);\r
+                               break;\r
+\r
+\r
+//\r
+// ss\r
+//\r
+                       case 198:\r
+                       case 199:\r
+                       case 200:\r
+                       case 201:\r
+                               if (gamestate.difficulty<gd_hard)\r
+                                       break;\r
+                               tile -= 36;\r
+                       case 162:\r
+                       case 163:\r
+                       case 164:\r
+                       case 165:\r
+                               if (gamestate.difficulty<gd_medium)\r
+                                       break;\r
+                               tile -= 36;\r
+                       case 126:\r
+                       case 127:\r
+                       case 128:\r
+                       case 129:\r
+                               SpawnStand(en_ss,x,y,tile-126);\r
+                               break;\r
+\r
+\r
+                       case 202:\r
+                       case 203:\r
+                       case 204:\r
+                       case 205:\r
+                               if (gamestate.difficulty<gd_hard)\r
+                                       break;\r
+                               tile -= 36;\r
+                       case 166:\r
+                       case 167:\r
+                       case 168:\r
+                       case 169:\r
+                               if (gamestate.difficulty<gd_medium)\r
+                                       break;\r
+                               tile -= 36;\r
+                       case 130:\r
+                       case 131:\r
+                       case 132:\r
+                       case 133:\r
+                               SpawnPatrol(en_ss,x,y,tile-130);\r
+                               break;\r
+\r
+//\r
+// dogs\r
+//\r
+                       case 206:\r
+                       case 207:\r
+                       case 208:\r
+                       case 209:\r
+                               if (gamestate.difficulty<gd_hard)\r
+                                       break;\r
+                               tile -= 36;\r
+                       case 170:\r
+                       case 171:\r
+                       case 172:\r
+                       case 173:\r
+                               if (gamestate.difficulty<gd_medium)\r
+                                       break;\r
+                               tile -= 36;\r
+                       case 134:\r
+                       case 135:\r
+                       case 136:\r
+                       case 137:\r
+                               SpawnStand(en_dog,x,y,tile-134);\r
+                               break;\r
+\r
+\r
+                       case 210:\r
+                       case 211:\r
+                       case 212:\r
+                       case 213:\r
+                               if (gamestate.difficulty<gd_hard)\r
+                                       break;\r
+                               tile -= 36;\r
+                       case 174:\r
+                       case 175:\r
+                       case 176:\r
+                       case 177:\r
+                               if (gamestate.difficulty<gd_medium)\r
+                                       break;\r
+                               tile -= 36;\r
+                       case 138:\r
+                       case 139:\r
+                       case 140:\r
+                       case 141:\r
+                               SpawnPatrol(en_dog,x,y,tile-138);\r
+                               break;\r
+\r
+//\r
+// boss\r
+//\r
+#ifndef SPEAR\r
+                       case 214:\r
+                               SpawnBoss (x,y);\r
+                               break;\r
+                       case 197:\r
+                               SpawnGretel (x,y);\r
+                               break;\r
+                       case 215:\r
+                               SpawnGift (x,y);\r
+                               break;\r
+                       case 179:\r
+                               SpawnFat (x,y);\r
+                               break;\r
+                       case 196:\r
+                               SpawnSchabbs (x,y);\r
+                               break;\r
+                       case 160:\r
+                               SpawnFakeHitler (x,y);\r
+                               break;\r
+                       case 178:\r
+                               SpawnHitler (x,y);\r
+                               break;\r
+#else\r
+                       case 106:\r
+                               SpawnSpectre (x,y);\r
+                               break;\r
+                       case 107:\r
+                               SpawnAngel (x,y);\r
+                               break;\r
+                       case 125:\r
+                               SpawnTrans (x,y);\r
+                               break;\r
+                       case 142:\r
+                               SpawnUber (x,y);\r
+                               break;\r
+                       case 143:\r
+                               SpawnWill (x,y);\r
+                               break;\r
+                       case 161:\r
+                               SpawnDeath (x,y);\r
+                               break;\r
+\r
+#endif\r
+\r
+//\r
+// mutants\r
+//\r
+                       case 252:\r
+                       case 253:\r
+                       case 254:\r
+                       case 255:\r
+                               if (gamestate.difficulty<gd_hard)\r
+                                       break;\r
+                               tile -= 18;\r
+                       case 234:\r
+                       case 235:\r
+                       case 236:\r
+                       case 237:\r
+                               if (gamestate.difficulty<gd_medium)\r
+                                       break;\r
+                               tile -= 18;\r
+                       case 216:\r
+                       case 217:\r
+                       case 218:\r
+                       case 219:\r
+                               SpawnStand(en_mutant,x,y,tile-216);\r
+                               break;\r
+\r
+                       case 256:\r
+                       case 257:\r
+                       case 258:\r
+                       case 259:\r
+                               if (gamestate.difficulty<gd_hard)\r
+                                       break;\r
+                               tile -= 18;\r
+                       case 238:\r
+                       case 239:\r
+                       case 240:\r
+                       case 241:\r
+                               if (gamestate.difficulty<gd_medium)\r
+                                       break;\r
+                               tile -= 18;\r
+                       case 220:\r
+                       case 221:\r
+                       case 222:\r
+                       case 223:\r
+                               SpawnPatrol(en_mutant,x,y,tile-220);\r
+                               break;\r
+\r
+//\r
+// ghosts\r
+//\r
+#ifndef SPEAR\r
+                       case 224:\r
+                               SpawnGhosts (en_blinky,x,y);\r
+                               break;\r
+                       case 225:\r
+                               SpawnGhosts (en_clyde,x,y);\r
+                               break;\r
+                       case 226:\r
+                               SpawnGhosts (en_pinky,x,y);\r
+                               break;\r
+                       case 227:\r
+                               SpawnGhosts (en_inky,x,y);\r
+                               break;\r
+#endif\r
+                       }\r
+\r
+               }\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
+\r
+       if (!loadedgame)\r
+       {\r
+        gamestate.TimeCount=\r
+        gamestate.secrettotal=\r
+        gamestate.killtotal=\r
+        gamestate.treasuretotal=\r
+        gamestate.secretcount=\r
+        gamestate.killcount=\r
+        gamestate.treasurecount=0;\r
+       }\r
+\r
+       if (demoplayback || demorecord)\r
+               US_InitRndT (false);\r
+       else\r
+               US_InitRndT (true);\r
+\r
+//\r
+// load the level\r
+//\r
+       CA_CacheMap (gamestate.mapon+10*gamestate.episode);\r
+       mapon-=gamestate.episode*10;\r
+\r
+       mapwidth = mapheaderseg[mapon]->width;\r
+       mapheight = mapheaderseg[mapon]->height;\r
+\r
+       if (mapwidth != 64 || mapheight != 64)\r
+               Quit ("Map not 64*64!");\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<AREATILE)\r
+                       {\r
+                       // solid wall\r
+                               tilemap[x][y] = tile;\r
+                               (unsigned)actorat[x][y] = tile;\r
+                       }\r
+                       else\r
+                       {\r
+                       // area floor\r
+                               tilemap[x][y] = 0;\r
+                               (unsigned)actorat[x][y] = 0;\r
+                       }\r
+               }\r
+\r
+//\r
+// spawn doors\r
+//\r
+       InitActorList ();                       // start spawning things with a clean slate\r
+       InitDoorList ();\r
+       InitStaticList ();\r
+\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 >= 90 && tile <= 101)\r
+                       {\r
+                       // door\r
+                               switch (tile)\r
+                               {\r
+                               case 90:\r
+                               case 92:\r
+                               case 94:\r
+                               case 96:\r
+                               case 98:\r
+                               case 100:\r
+                                       SpawnDoor (x,y,1,(tile-90)/2);\r
+                                       break;\r
+                               case 91:\r
+                               case 93:\r
+                               case 95:\r
+                               case 97:\r
+                               case 99:\r
+                               case 101:\r
+                                       SpawnDoor (x,y,0,(tile-91)/2);\r
+                                       break;\r
+                               }\r
+                       }\r
+               }\r
+\r
+//\r
+// spawn actors\r
+//\r
+       ScanInfoPlane ();\r
+\r
+//\r
+// take out the ambush markers\r
+//\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 == AMBUSHTILE)\r
+                       {\r
+                               tilemap[x][y] = 0;\r
+                               if ( (unsigned)actorat[x][y] == AMBUSHTILE)\r
+                                       actorat[x][y] = NULL;\r
+\r
+                               if (*map >= AREATILE)\r
+                                       tile = *map;\r
+                               if (*(map-1-mapwidth) >= AREATILE)\r
+                                       tile = *(map-1-mapwidth);\r
+                               if (*(map-1+mapwidth) >= AREATILE)\r
+                                       tile = *(map-1+mapwidth);\r
+                               if ( *(map-2) >= AREATILE)\r
+                                       tile = *(map-2);\r
+\r
+                               *(map-1) = tile;\r
+                       }\r
+               }\r
+\r
+\r
+\r
+//\r
+// have the caching manager load and purge stuff to make sure all marks\r
+// are in memory\r
+//\r
+       CA_LoadAllSounds ();\r
+\r
+}\r
+\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= DrawPlayBorderSides\r
+=\r
+= To fix window overwrites\r
+=\r
+===================\r
+*/\r
+\r
+void DrawPlayBorderSides (void)\r
+{\r
+       int     xl,yl;\r
+\r
+       xl = 160-viewwidth/2;\r
+       yl = (200-STATUSLINES-viewheight)/2;\r
+\r
+       VWB_Bar (0,0,xl-1,200-STATUSLINES,127);\r
+       VWB_Bar (xl+viewwidth+1,0,xl-2,200-STATUSLINES,127);\r
+\r
+       VWB_Vlin (yl-1,yl+viewheight,xl-1,0);\r
+       VWB_Vlin (yl-1,yl+viewheight,xl+viewwidth,125);\r
+}\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= DrawAllPlayBorderSides\r
+=\r
+===================\r
+*/\r
+\r
+void DrawAllPlayBorderSides (void)\r
+{\r
+       unsigned        i,temp;\r
+\r
+       temp = bufferofs;\r
+       for (i=0;i<3;i++)\r
+       {\r
+               bufferofs = screenloc[i];\r
+               DrawPlayBorderSides ();\r
+       }\r
+       bufferofs = temp;\r
+}\r
+\r
+/*\r
+===================\r
+=\r
+= DrawPlayBorder\r
+=\r
+===================\r
+*/\r
+void DrawAllPlayBorder (void)\r
+{\r
+       unsigned        i,temp;\r
+\r
+       temp = bufferofs;\r
+       for (i=0;i<3;i++)\r
+       {\r
+               bufferofs = screenloc[i];\r
+               DrawPlayBorder ();\r
+       }\r
+       bufferofs = temp;\r
+}\r
+\r
+/*\r
+===================\r
+=\r
+= DrawPlayBorder\r
+=\r
+===================\r
+*/\r
+\r
+void DrawPlayBorder (void)\r
+{\r
+       int     xl,yl;\r
+\r
+       VWB_Bar (0,0,320,200-STATUSLINES,127);\r
+\r
+       xl = 160-viewwidth/2;\r
+       yl = (200-STATUSLINES-viewheight)/2;\r
+       VWB_Bar (xl,yl,viewwidth,viewheight,0);\r
+\r
+       VWB_Hlin (xl-1,xl+viewwidth,yl-1,0);\r
+       VWB_Hlin (xl-1,xl+viewwidth,yl+viewheight,125);\r
+       VWB_Vlin (yl-1,yl+viewheight,xl-1,0);\r
+       VWB_Vlin (yl-1,yl+viewheight,xl+viewwidth,125);\r
+       VWB_Plot (xl-1,yl+viewheight,124);\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
+       unsigned        temp;\r
+\r
+       VW_FadeOut ();\r
+\r
+       temp = bufferofs;\r
+\r
+       CA_CacheGrChunk (STATUSBARPIC);\r
+\r
+       for (i=0;i<3;i++)\r
+       {\r
+               bufferofs = screenloc[i];\r
+               DrawPlayBorder ();\r
+               VWB_DrawPic (0,200-STATUSLINES,STATUSBARPIC);\r
+       }\r
+\r
+       bufferofs = temp;\r
+\r
+       UNCACHEGRCHUNK (STATUSBARPIC);\r
+\r
+       DrawFace ();\r
+       DrawHealth ();\r
+       DrawLives ();\r
+       DrawLevel ();\r
+       DrawAmmo ();\r
+       DrawKeys ();\r
+       DrawWeapon ();\r
+       DrawScore ();\r
+}\r
+\r
+\r
+\r
+//==========================================================================\r
+\r
+/*\r
+==================\r
+=\r
+= StartDemoRecord\r
+=\r
+==================\r
+*/\r
+\r
+#define MAXDEMOSIZE    8192\r
+\r
+void StartDemoRecord (int levelnumber)\r
+{\r
+       MM_GetPtr (&demobuffer,MAXDEMOSIZE);\r
+       MM_SetLock (&demobuffer,true);\r
+       demoptr = (char far *)demobuffer;\r
+       lastdemoptr = demoptr+MAXDEMOSIZE;\r
+\r
+       *demoptr = levelnumber;\r
+       demoptr += 4;                           // leave space for length\r
+       demorecord = true;\r
+}\r
+\r
+\r
+/*\r
+==================\r
+=\r
+= FinishDemoRecord\r
+=\r
+==================\r
+*/\r
+\r
+char   demoname[13] = "DEMO?.";\r
+\r
+void FinishDemoRecord (void)\r
+{\r
+       long    length,level;\r
+\r
+       demorecord = false;\r
+\r
+       length = demoptr - (char far *)demobuffer;\r
+\r
+       demoptr = ((char far *)demobuffer)+1;\r
+       *(unsigned far *)demoptr = length;\r
+\r
+       CenterWindow(24,3);\r
+       PrintY+=6;\r
+       US_Print(" Demo number (0-9):");\r
+       VW_UpdateScreen();\r
+\r
+       if (US_LineInput (px,py,str,NULL,true,2,0))\r
+       {\r
+               level = atoi (str);\r
+               if (level>=0 && level<=9)\r
+               {\r
+                       demoname[4] = '0'+level;\r
+                       CA_WriteFile (demoname,(void far *)demobuffer,length);\r
+               }\r
+       }\r
+\r
+\r
+       MM_FreePtr (&demobuffer);\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+==================\r
+=\r
+= RecordDemo\r
+=\r
+= Fades the screen out, then starts a demo.  Exits with the screen faded\r
+=\r
+==================\r
+*/\r
+\r
+void RecordDemo (void)\r
+{\r
+       int level,esc;\r
+\r
+       CenterWindow(26,3);\r
+       PrintY+=6;\r
+       CA_CacheGrChunk(STARTFONT);\r
+       fontnumber=0;\r
+       US_Print("  Demo which level(1-10):");\r
+       VW_UpdateScreen();\r
+       VW_FadeIn ();\r
+       esc = !US_LineInput (px,py,str,NULL,true,2,0);\r
+       if (esc)\r
+               return;\r
+\r
+       level = atoi (str);\r
+       level--;\r
+\r
+       SETFONTCOLOR(0,15);\r
+       VW_FadeOut ();\r
+\r
+#ifndef SPEAR\r
+       NewGame (gd_hard,level/10);\r
+       gamestate.mapon = level%10;\r
+#else\r
+       NewGame (gd_hard,0);\r
+       gamestate.mapon = level;\r
+#endif\r
+\r
+       StartDemoRecord (level);\r
+\r
+       DrawPlayScreen ();\r
+       VW_FadeIn ();\r
+\r
+       startgame = false;\r
+       demorecord = true;\r
+\r
+       SetupGameLevel ();\r
+       StartMusic ();\r
+       PM_CheckMainMem ();\r
+       fizzlein = true;\r
+\r
+       PlayLoop ();\r
+\r
+       demoplayback = false;\r
+\r
+       StopMusic ();\r
+       VW_FadeOut ();\r
+       ClearMemory ();\r
+\r
+       FinishDemoRecord ();\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+==================\r
+=\r
+= PlayDemo\r
+=\r
+= Fades the screen out, then starts a demo.  Exits with the screen faded\r
+=\r
+==================\r
+*/\r
+\r
+void PlayDemo (int demonumber)\r
+{\r
+       int length;\r
+\r
+#ifdef DEMOSEXTERN\r
+// debug: load chunk\r
+#ifndef SPEARDEMO\r
+       int dems[4]={T_DEMO0,T_DEMO1,T_DEMO2,T_DEMO3};\r
+#else\r
+       int dems[1]={T_DEMO0};\r
+#endif\r
+\r
+       CA_CacheGrChunk(dems[demonumber]);\r
+       demoptr = grsegs[dems[demonumber]];\r
+       MM_SetLock (&grsegs[dems[demonumber]],true);\r
+#else\r
+       demoname[4] = '0'+demonumber;\r
+       CA_LoadFile (demoname,&demobuffer);\r
+       MM_SetLock (&demobuffer,true);\r
+       demoptr = (char far *)demobuffer;\r
+#endif\r
+\r
+       NewGame (1,0);\r
+       gamestate.mapon = *demoptr++;\r
+       gamestate.difficulty = gd_hard;\r
+       length = *((unsigned far *)demoptr)++;\r
+       demoptr++;\r
+       lastdemoptr = demoptr-4+length;\r
+\r
+       VW_FadeOut ();\r
+\r
+       SETFONTCOLOR(0,15);\r
+       DrawPlayScreen ();\r
+       VW_FadeIn ();\r
+\r
+       startgame = false;\r
+       demoplayback = true;\r
+\r
+       SetupGameLevel ();\r
+       StartMusic ();\r
+       PM_CheckMainMem ();\r
+       fizzlein = true;\r
+\r
+       PlayLoop ();\r
+\r
+#ifdef DEMOSEXTERN\r
+       UNCACHEGRCHUNK(dems[demonumber]);\r
+#else\r
+       MM_FreePtr (&demobuffer);\r
+#endif\r
+\r
+       demoplayback = false;\r
+\r
+       StopMusic ();\r
+       VW_FadeOut ();\r
+       ClearMemory ();\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+==================\r
+=\r
+= Died\r
+=\r
+==================\r
+*/\r
+\r
+#define DEATHROTATE 2\r
+\r
+void Died (void)\r
+{\r
+       float   fangle;\r
+       long    dx,dy;\r
+       int             iangle,curangle,clockwise,counter,change;\r
+\r
+       gamestate.weapon = -1;                  // take away weapon\r
+       SD_PlaySound (PLAYERDEATHSND);\r
+//\r
+// swing around to face attacker\r
+//\r
+       dx = killerobj->x - player->x;\r
+       dy = player->y - killerobj->y;\r
+\r
+       fangle = atan2(dy,dx);                  // returns -pi to pi\r
+       if (fangle<0)\r
+               fangle = M_PI*2+fangle;\r
+\r
+       iangle = fangle/(M_PI*2)*ANGLES;\r
+\r
+       if (player->angle > iangle)\r
+       {\r
+               counter = player->angle - iangle;\r
+               clockwise = ANGLES-player->angle + iangle;\r
+       }\r
+       else\r
+       {\r
+               clockwise = iangle - player->angle;\r
+               counter = player->angle + ANGLES-iangle;\r
+       }\r
+\r
+       curangle = player->angle;\r
+\r
+       if (clockwise<counter)\r
+       {\r
+       //\r
+       // rotate clockwise\r
+       //\r
+               if (curangle>iangle)\r
+                       curangle -= ANGLES;\r
+               do\r
+               {\r
+                       change = tics*DEATHROTATE;\r
+                       if (curangle + change > iangle)\r
+                               change = iangle-curangle;\r
+\r
+                       curangle += change;\r
+                       player->angle += change;\r
+                       if (player->angle >= ANGLES)\r
+                               player->angle -= ANGLES;\r
+\r
+                       ThreeDRefresh ();\r
+                       CalcTics ();\r
+               } while (curangle != iangle);\r
+       }\r
+       else\r
+       {\r
+       //\r
+       // rotate counterclockwise\r
+       //\r
+               if (curangle<iangle)\r
+                       curangle += ANGLES;\r
+               do\r
+               {\r
+                       change = -tics*DEATHROTATE;\r
+                       if (curangle + change < iangle)\r
+                               change = iangle-curangle;\r
+\r
+                       curangle += change;\r
+                       player->angle += change;\r
+                       if (player->angle < 0)\r
+                               player->angle += ANGLES;\r
+\r
+                       ThreeDRefresh ();\r
+                       CalcTics ();\r
+               } while (curangle != iangle);\r
+       }\r
+\r
+//\r
+// fade to red\r
+//\r
+       FinishPaletteShifts ();\r
+\r
+       bufferofs += screenofs;\r
+       VW_Bar (0,0,viewwidth,viewheight,4);\r
+       IN_ClearKeysDown ();\r
+       FizzleFade(bufferofs,displayofs+screenofs,viewwidth,viewheight,70,false);\r
+       bufferofs -= screenofs;\r
+       IN_UserInput(100);\r
+       SD_WaitSoundDone ();\r
+\r
+       if (tedlevel == false)  // SO'S YA DON'T GET KILLED WHILE LAUNCHING!\r
+         gamestate.lives--;\r
+\r
+       if (gamestate.lives > -1)\r
+       {\r
+               gamestate.health = 100;\r
+               gamestate.weapon = gamestate.bestweapon\r
+                       = gamestate.chosenweapon = wp_pistol;\r
+               gamestate.ammo = STARTAMMO;\r
+               gamestate.keys = 0;\r
+               gamestate.attackframe = gamestate.attackcount =\r
+               gamestate.weaponframe = 0;\r
+\r
+               DrawKeys ();\r
+               DrawWeapon ();\r
+               DrawAmmo ();\r
+               DrawHealth ();\r
+               DrawFace ();\r
+               DrawLives ();\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
+       boolean died;\r
+#ifdef MYPROFILE\r
+       clock_t start,end;\r
+#endif\r
+\r
+restartgame:\r
+       ClearMemory ();\r
+       SETFONTCOLOR(0,15);\r
+       DrawPlayScreen ();\r
+       died = false;\r
+restart:\r
+       do\r
+       {\r
+               if (!loadedgame)\r
+                 gamestate.score = gamestate.oldscore;\r
+               DrawScore();\r
+\r
+               startgame = false;\r
+               if (loadedgame)\r
+                       loadedgame = false;\r
+               else\r
+                       SetupGameLevel ();\r
+\r
+#ifdef SPEAR\r
+               if (gamestate.mapon == 20)      // give them the key allways\r
+               {\r
+                       gamestate.keys |= 1;\r
+                       DrawKeys ();\r
+               }\r
+#endif\r
+\r
+               ingame = true;\r
+               StartMusic ();\r
+               PM_CheckMainMem ();\r
+               if (!died)\r
+                       PreloadGraphics ();\r
+               else\r
+                       died = false;\r
+\r
+               fizzlein = true;\r
+               DrawLevel ();\r
+\r
+startplayloop:\r
+               PlayLoop ();\r
+\r
+#ifdef SPEAR\r
+               if (spearflag)\r
+               {\r
+                       SD_StopSound();\r
+                       SD_PlaySound(GETSPEARSND);\r
+                       if (DigiMode != sds_Off)\r
+                       {\r
+                               long lasttimecount = TimeCount;\r
+\r
+                               while(TimeCount < lasttimecount+150)\r
+                               //while(DigiPlaying!=false)\r
+                                       SD_Poll();\r
+                       }\r
+                       else\r
+                               SD_WaitSoundDone();\r
+\r
+                       ClearMemory ();\r
+                       gamestate.oldscore = gamestate.score;\r
+                       gamestate.mapon = 20;\r
+                       SetupGameLevel ();\r
+                       StartMusic ();\r
+                       PM_CheckMainMem ();\r
+                       player->x = spearx;\r
+                       player->y = speary;\r
+                       player->angle = spearangle;\r
+                       spearflag = false;\r
+                       Thrust (0,0);\r
+                       goto startplayloop;\r
+               }\r
+#endif\r
+\r
+               StopMusic ();\r
+               ingame = false;\r
+\r
+               if (demorecord && playstate != ex_warped)\r
+                       FinishDemoRecord ();\r
+\r
+               if (startgame || loadedgame)\r
+                       goto restartgame;\r
+\r
+               switch (playstate)\r
+               {\r
+               case ex_completed:\r
+               case ex_secretlevel:\r
+                       gamestate.keys = 0;\r
+                       DrawKeys ();\r
+                       VW_FadeOut ();\r
+\r
+                       ClearMemory ();\r
+\r
+                       LevelCompleted ();              // do the intermission\r
+#ifdef SPEARDEMO\r
+                       if (gamestate.mapon == 1)\r
+                       {\r
+                               died = true;                    // don't "get psyched!"\r
+\r
+                               VW_FadeOut ();\r
+\r
+                               ClearMemory ();\r
+\r
+                               CheckHighScore (gamestate.score,gamestate.mapon+1);\r
+\r
+                               #pragma warn -sus\r
+                               #ifndef JAPAN\r
+                               _fstrcpy(MainMenu[viewscores].string,STR_VS);\r
+                               #endif\r
+                               MainMenu[viewscores].routine = CP_ViewScores;\r
+                               #pragma warn +sus\r
+\r
+                               return;\r
+                       }\r
+#endif\r
+\r
+#ifdef JAPDEMO\r
+                       if (gamestate.mapon == 3)\r
+                       {\r
+                               died = true;                    // don't "get psyched!"\r
+\r
+                               VW_FadeOut ();\r
+\r
+                               ClearMemory ();\r
+\r
+                               CheckHighScore (gamestate.score,gamestate.mapon+1);\r
+\r
+                               #pragma warn -sus\r
+                               #ifndef JAPAN\r
+                               _fstrcpy(MainMenu[viewscores].string,STR_VS);\r
+                               #endif\r
+                               MainMenu[viewscores].routine = CP_ViewScores;\r
+                               #pragma warn +sus\r
+\r
+                               return;\r
+                       }\r
+#endif\r
+\r
+                       gamestate.oldscore = gamestate.score;\r
+\r
+#ifndef SPEAR\r
+                       //\r
+                       // COMING BACK FROM SECRET LEVEL\r
+                       //\r
+                       if (gamestate.mapon == 9)\r
+                               gamestate.mapon = ElevatorBackTo[gamestate.episode];    // back from secret\r
+                       else\r
+                       //\r
+                       // GOING TO SECRET LEVEL\r
+                       //\r
+                       if (playstate == ex_secretlevel)\r
+                               gamestate.mapon = 9;\r
+#else\r
+\r
+#define FROMSECRET1            3\r
+#define FROMSECRET2            11\r
+\r
+                       //\r
+                       // GOING TO SECRET LEVEL\r
+                       //\r
+                       if (playstate == ex_secretlevel)\r
+                               switch(gamestate.mapon)\r
+                               {\r
+                                case FROMSECRET1: gamestate.mapon = 18; break;\r
+                                case FROMSECRET2: gamestate.mapon = 19; break;\r
+                               }\r
+                       else\r
+                       //\r
+                       // COMING BACK FROM SECRET LEVEL\r
+                       //\r
+                       if (gamestate.mapon == 18 || gamestate.mapon == 19)\r
+                               switch(gamestate.mapon)\r
+                               {\r
+                                case 18: gamestate.mapon = FROMSECRET1+1; break;\r
+                                case 19: gamestate.mapon = FROMSECRET2+1; break;\r
+                               }\r
+#endif\r
+                       else\r
+                       //\r
+                       // GOING TO NEXT LEVEL\r
+                       //\r
+                               gamestate.mapon++;\r
+\r
+\r
+                       break;\r
+\r
+               case ex_died:\r
+                       Died ();\r
+                       died = true;                    // don't "get psyched!"\r
+\r
+                       if (gamestate.lives > -1)\r
+                               break;                          // more lives left\r
+\r
+                       VW_FadeOut ();\r
+\r
+                       ClearMemory ();\r
+\r
+                       CheckHighScore (gamestate.score,gamestate.mapon+1);\r
+\r
+                       #pragma warn -sus\r
+                       #ifndef JAPAN\r
+                       _fstrcpy(MainMenu[viewscores].string,STR_VS);\r
+                       #endif\r
+                       MainMenu[viewscores].routine = CP_ViewScores;\r
+                       #pragma warn +sus\r
+\r
+                       return;\r
+\r
+               case ex_victorious:\r
+\r
+#ifndef SPEAR\r
+                       VW_FadeOut ();\r
+#else\r
+                       VL_FadeOut (0,255,0,17,17,300);\r
+#endif\r
+                       ClearMemory ();\r
+\r
+                       Victory ();\r
+\r
+                       ClearMemory ();\r
+\r
+                       CheckHighScore (gamestate.score,gamestate.mapon+1);\r
+\r
+                       #pragma warn -sus\r
+                       #ifndef JAPAN\r
+                       _fstrcpy(MainMenu[viewscores].string,STR_VS);\r
+                       #endif\r
+                       MainMenu[viewscores].routine = CP_ViewScores;\r
+                       #pragma warn +sus\r
+\r
+                       return;\r
+\r
+               default:\r
+                       ClearMemory ();\r
+                       break;\r
+               }\r
+\r
+       } while (1);\r
+\r
+}\r
+\r
diff --git a/src/lib/hb/wl_inter.c b/src/lib/hb/wl_inter.c
new file mode 100755 (executable)
index 0000000..c74cc9e
--- /dev/null
@@ -0,0 +1,1718 @@
+// WL_INTER.C\r
+\r
+#include "WL_DEF.H"\r
+#pragma hdrstop\r
+\r
+\r
+//==========================================================================\r
+\r
+/*\r
+==================\r
+=\r
+= CLearSplitVWB\r
+=\r
+==================\r
+*/\r
+\r
+void ClearSplitVWB (void)\r
+{\r
+       memset (update,0,sizeof(update));\r
+       WindowX = 0;\r
+       WindowY = 0;\r
+       WindowW = 320;\r
+       WindowH = 160;\r
+}\r
+\r
+\r
+//==========================================================================\r
+\r
+#ifdef SPEAR\r
+#ifndef SPEARDEMO\r
+////////////////////////////////////////////////////////\r
+//\r
+// End of Spear of Destiny\r
+//\r
+////////////////////////////////////////////////////////\r
+\r
+void EndScreen (int palette, int screen)\r
+{\r
+       CA_CacheScreen (screen);\r
+       VW_UpdateScreen ();\r
+       CA_CacheGrChunk (palette);\r
+       VL_FadeIn(0,255,grsegs[palette],30);\r
+       UNCACHEGRCHUNK (palette);\r
+       IN_ClearKeysDown ();\r
+       IN_Ack ();\r
+       VW_FadeOut ();\r
+}\r
+\r
+\r
+void EndSpear(void)\r
+{\r
+       EndScreen (END1PALETTE, ENDSCREEN11PIC);\r
+\r
+       CA_CacheScreen (ENDSCREEN3PIC);\r
+       VW_UpdateScreen ();\r
+       CA_CacheGrChunk (END3PALETTE);\r
+       VL_FadeIn(0,255,grsegs[END3PALETTE],30);\r
+       UNCACHEGRCHUNK (END3PALETTE);\r
+       fontnumber = 0;\r
+       fontcolor = 0xd0;\r
+       WindowX = 0;\r
+       WindowW = 320;\r
+       PrintX = 0;\r
+       PrintY = 180;\r
+       US_CPrint (STR_ENDGAME1"\n");\r
+       US_CPrint (STR_ENDGAME2);\r
+       VW_UpdateScreen ();\r
+       IN_StartAck ();\r
+       TimeCount = 0;\r
+       while (!IN_CheckAck () && TimeCount < 700);\r
+\r
+       PrintX = 0;\r
+       PrintY = 180;\r
+       VWB_Bar(0,180,320,20,0);\r
+       US_CPrint (STR_ENDGAME3"\n");\r
+       US_CPrint (STR_ENDGAME4);\r
+       VW_UpdateScreen ();\r
+       IN_StartAck ();\r
+       TimeCount = 0;\r
+       while (!IN_CheckAck () && TimeCount < 700);\r
+\r
+       VW_FadeOut ();\r
+\r
+       EndScreen (END4PALETTE, ENDSCREEN4PIC);\r
+       EndScreen (END5PALETTE, ENDSCREEN5PIC);\r
+       EndScreen (END6PALETTE, ENDSCREEN6PIC);\r
+       EndScreen (END7PALETTE, ENDSCREEN7PIC);\r
+       EndScreen (END8PALETTE, ENDSCREEN8PIC);\r
+       EndScreen (END9PALETTE, ENDSCREEN9PIC);\r
+\r
+       EndScreen (END2PALETTE, ENDSCREEN12PIC);\r
+\r
+       MainMenu[savegame].active = 0;\r
+}\r
+#endif\r
+#endif\r
+\r
+//==========================================================================\r
+\r
+/*\r
+==================\r
+=\r
+= Victory\r
+=\r
+==================\r
+*/\r
+\r
+void Victory (void)\r
+{\r
+#ifndef SPEARDEMO\r
+       long    sec;\r
+       int i,min,kr,sr,tr,x;\r
+       char tempstr[8];\r
+\r
+#define RATIOX 6\r
+#define RATIOY 14\r
+#define TIMEX  14\r
+#define TIMEY  8\r
+\r
+\r
+#ifdef SPEAR\r
+       StartCPMusic (XTHEEND_MUS);\r
+\r
+       CA_CacheGrChunk(BJCOLLAPSE1PIC);\r
+       CA_CacheGrChunk(BJCOLLAPSE2PIC);\r
+       CA_CacheGrChunk(BJCOLLAPSE3PIC);\r
+       CA_CacheGrChunk(BJCOLLAPSE4PIC);\r
+\r
+       VWB_Bar(0,0,320,200,VIEWCOLOR);\r
+       VWB_DrawPic (124,44,BJCOLLAPSE1PIC);\r
+       VW_UpdateScreen ();\r
+       VW_FadeIn ();\r
+       VW_WaitVBL(2*70);\r
+       VWB_DrawPic (124,44,BJCOLLAPSE2PIC);\r
+       VW_UpdateScreen ();\r
+       VW_WaitVBL(105);\r
+       VWB_DrawPic (124,44,BJCOLLAPSE3PIC);\r
+       VW_UpdateScreen ();\r
+       VW_WaitVBL(105);\r
+       VWB_DrawPic (124,44,BJCOLLAPSE4PIC);\r
+       VW_UpdateScreen ();\r
+       VW_WaitVBL(3*70);\r
+\r
+       UNCACHEGRCHUNK(BJCOLLAPSE1PIC);\r
+       UNCACHEGRCHUNK(BJCOLLAPSE2PIC);\r
+       UNCACHEGRCHUNK(BJCOLLAPSE3PIC);\r
+       UNCACHEGRCHUNK(BJCOLLAPSE4PIC);\r
+       VL_FadeOut (0,255,0,17,17,5);\r
+#endif\r
+\r
+       StartCPMusic (URAHERO_MUS);\r
+       ClearSplitVWB ();\r
+       CacheLump(LEVELEND_LUMP_START,LEVELEND_LUMP_END);\r
+       CA_CacheGrChunk(STARTFONT);\r
+\r
+#ifndef SPEAR\r
+       CA_CacheGrChunk(C_TIMECODEPIC);\r
+#endif\r
+\r
+\r
+       VWB_Bar (0,0,320,200-STATUSLINES,127);\r
+#ifdef JAPAN\r
+#ifndef JAPDEMO\r
+       CA_CacheGrChunk(C_ENDRATIOSPIC);\r
+       VWB_DrawPic(0,0,C_ENDRATIOSPIC);\r
+       UNCACHEGRCHUNK(C_ENDRATIOSPIC);\r
+#endif\r
+#else\r
+       Write(18,2,STR_YOUWIN);\r
+\r
+       Write(TIMEX,TIMEY-2,STR_TOTALTIME);\r
+\r
+       Write(12,RATIOY-2,"averages");\r
+\r
+       #ifdef SPANISH\r
+       Write(RATIOX+2,  RATIOY,      STR_RATKILL);\r
+       Write(RATIOX+2,  RATIOY+2,  STR_RATSECRET);\r
+       Write(RATIOX+2,  RATIOY+4,STR_RATTREASURE);\r
+       #else\r
+       Write(RATIOX+8,RATIOY,      STR_RATKILL);\r
+       Write(RATIOX+4,RATIOY+2,  STR_RATSECRET);\r
+       Write(RATIOX,  RATIOY+4,STR_RATTREASURE);\r
+       #endif\r
+\r
+#endif\r
+\r
+#ifndef JAPDEMO\r
+       VWB_DrawPic (8,4,L_BJWINSPIC);\r
+#endif\r
+\r
+\r
+#ifndef SPEAR\r
+       for (kr = sr = tr = sec = i = 0;i < 8;i++)\r
+#else\r
+       for (kr = sr = tr = sec = i = 0;i < 20;i++)\r
+#endif\r
+       {\r
+               sec += LevelRatios[i].time;\r
+               kr += LevelRatios[i].kill;\r
+               sr += LevelRatios[i].secret;\r
+               tr += LevelRatios[i].treasure;\r
+       }\r
+\r
+#ifndef SPEAR\r
+       kr /= 8;\r
+       sr /= 8;\r
+       tr /= 8;\r
+#else\r
+       kr /= 14;\r
+       sr /= 14;\r
+       tr /= 14;\r
+#endif\r
+\r
+       min = sec/60;\r
+       sec %= 60;\r
+\r
+       if (min > 99)\r
+               min = sec = 99;\r
+\r
+       i = TIMEX*8+1;\r
+       VWB_DrawPic(i,TIMEY*8,L_NUM0PIC+(min/10));\r
+       i += 2*8;\r
+       VWB_DrawPic(i,TIMEY*8,L_NUM0PIC+(min%10));\r
+       i += 2*8;\r
+       Write(i/8,TIMEY,":");\r
+       i += 1*8;\r
+       VWB_DrawPic(i,TIMEY*8,L_NUM0PIC+(sec/10));\r
+       i += 2*8;\r
+       VWB_DrawPic(i,TIMEY*8,L_NUM0PIC+(sec%10));\r
+       VW_UpdateScreen ();\r
+\r
+       itoa(kr,tempstr,10);\r
+       x=RATIOX+24-strlen(tempstr)*2;\r
+       Write(x,RATIOY,tempstr);\r
+\r
+       itoa(sr,tempstr,10);\r
+       x=RATIOX+24-strlen(tempstr)*2;\r
+       Write(x,RATIOY+2,tempstr);\r
+\r
+       itoa(tr,tempstr,10);\r
+       x=RATIOX+24-strlen(tempstr)*2;\r
+       Write(x,RATIOY+4,tempstr);\r
+\r
+\r
+#ifndef SPANISH\r
+#ifndef UPLOAD\r
+#ifndef SPEAR\r
+       //\r
+       // TOTAL TIME VERIFICATION CODE\r
+       //\r
+       if (gamestate.difficulty>=gd_medium)\r
+       {\r
+               VWB_DrawPic (30*8,TIMEY*8,C_TIMECODEPIC);\r
+               fontnumber = 0;\r
+               fontcolor = READHCOLOR;\r
+               PrintX = 30*8-3;\r
+               PrintY = TIMEY*8+8;\r
+               PrintX+=4;\r
+               tempstr[0] = (((min/10)^(min%10))^0xa)+'A';\r
+               tempstr[1] = (((sec/10)^(sec%10))^0xa)+'A';\r
+               tempstr[2] = (tempstr[0]^tempstr[1])+'A';\r
+               tempstr[3] = 0;\r
+               US_Print(tempstr);\r
+       }\r
+#endif\r
+#endif\r
+#endif\r
+\r
+\r
+       fontnumber = 1;\r
+\r
+       VW_UpdateScreen ();\r
+       VW_FadeIn ();\r
+\r
+       IN_Ack();\r
+\r
+       #ifndef SPEAR\r
+       if (Keyboard[sc_P] && MS_CheckParm("goobers"))\r
+               PicturePause();\r
+       #endif\r
+\r
+       VW_FadeOut ();\r
+\r
+#ifndef SPEAR\r
+       UNCACHEGRCHUNK(C_TIMECODEPIC);\r
+#endif\r
+       UnCacheLump(LEVELEND_LUMP_START,LEVELEND_LUMP_END);\r
+\r
+#ifndef SPEAR\r
+       EndText();\r
+#else\r
+       EndSpear();\r
+#endif\r
+\r
+#endif // SPEARDEMO\r
+}\r
+\r
+\r
+//==========================================================================\r
+\r
+#ifndef JAPAN\r
+/*\r
+==================\r
+=\r
+= PG13\r
+=\r
+==================\r
+*/\r
+\r
+void PG13 (void)\r
+{\r
+       VW_FadeOut();\r
+       VWB_Bar(0,0,320,200,0x82);                      // background\r
+\r
+       CA_CacheGrChunk (PG13PIC);\r
+       VWB_DrawPic (216,110,PG13PIC);\r
+       VW_UpdateScreen ();\r
+\r
+       UNCACHEGRCHUNK (PG13PIC);\r
+\r
+       VW_FadeIn();\r
+       IN_UserInput(TickBase*7);\r
+\r
+       VW_FadeOut ();\r
+}\r
+#endif\r
+\r
+\r
+//==========================================================================\r
+\r
+void Write(int x,int y,char *string)\r
+{\r
+ int alpha[]={L_NUM0PIC,L_NUM1PIC,L_NUM2PIC,L_NUM3PIC,L_NUM4PIC,L_NUM5PIC,\r
+       L_NUM6PIC,L_NUM7PIC,L_NUM8PIC,L_NUM9PIC,L_COLONPIC,0,0,0,0,0,0,L_APIC,L_BPIC,\r
+       L_CPIC,L_DPIC,L_EPIC,L_FPIC,L_GPIC,L_HPIC,L_IPIC,L_JPIC,L_KPIC,\r
+       L_LPIC,L_MPIC,L_NPIC,L_OPIC,L_PPIC,L_QPIC,L_RPIC,L_SPIC,L_TPIC,\r
+       L_UPIC,L_VPIC,L_WPIC,L_XPIC,L_YPIC,L_ZPIC};\r
+\r
+ int i,ox,nx,ny;\r
+ char ch;\r
+\r
+\r
+ ox=nx=x*8;\r
+ ny=y*8;\r
+ for (i=0;i<strlen(string);i++)\r
+   if (string[i]=='\n')\r
+   {\r
+       nx=ox;\r
+       ny+=16;\r
+   }\r
+   else\r
+   {\r
+       ch=string[i];\r
+       if (ch>='a')\r
+         ch-=('a'-'A');\r
+       ch-='0';\r
+\r
+       switch(string[i])\r
+       {\r
+        case '!':\r
+          VWB_DrawPic(nx,ny,L_EXPOINTPIC);\r
+          nx+=8;\r
+          continue;\r
+\r
+        case '\'':\r
+          VWB_DrawPic(nx,ny,L_APOSTROPHEPIC);\r
+          nx+=8;\r
+          continue;\r
+\r
+        case ' ': break;\r
+        case 0x3a:     // ':'\r
+\r
+          VWB_DrawPic(nx,ny,L_COLONPIC);\r
+          nx+=8;\r
+          continue;\r
+\r
+        case '%':\r
+          VWB_DrawPic(nx,ny,L_PERCENTPIC);\r
+          break;\r
+\r
+        default:\r
+          VWB_DrawPic(nx,ny,alpha[ch]);\r
+       }\r
+       nx+=16;\r
+   }\r
+}\r
+\r
+\r
+//\r
+// Breathe Mr. BJ!!!\r
+//\r
+void BJ_Breathe(void)\r
+{\r
+       static int which=0,max=10;\r
+       int pics[2]={L_GUYPIC,L_GUY2PIC};\r
+\r
+\r
+       if (TimeCount>max)\r
+       {\r
+               which^=1;\r
+               VWB_DrawPic(0,16,pics[which]);\r
+               VW_UpdateScreen();\r
+               TimeCount=0;\r
+               max=35;\r
+       }\r
+}\r
+\r
+\r
+\r
+/*\r
+==================\r
+=\r
+= LevelCompleted\r
+=\r
+= Entered with the screen faded out\r
+= Still in split screen mode with the status bar\r
+=\r
+= Exit with the screen faded out\r
+=\r
+==================\r
+*/\r
+\r
+#ifndef SPEAR\r
+LRstruct LevelRatios[8];\r
+#else\r
+LRstruct LevelRatios[20];\r
+#endif\r
+\r
+void LevelCompleted (void)\r
+{\r
+       #define VBLWAIT 30\r
+       #define PAR_AMOUNT      500\r
+       #define PERCENT100AMT   10000\r
+       typedef struct {\r
+                       float time;\r
+                       char timestr[6];\r
+                       } times;\r
+\r
+       int     x,i,min,sec,ratio,kr,sr,tr;\r
+       unsigned        temp;\r
+       char tempstr[10];\r
+       long bonus,timeleft=0;\r
+       times parTimes[]=\r
+       {\r
+#ifndef SPEAR\r
+        //\r
+        // Episode One Par Times\r
+        //\r
+        {1.5,  "01:30"},\r
+        {2,    "02:00"},\r
+        {2,    "02:00"},\r
+        {3.5,  "03:30"},\r
+        {3,    "03:00"},\r
+        {3,    "03:00"},\r
+        {2.5,  "02:30"},\r
+        {2.5,  "02:30"},\r
+        {0,    "??:??"},       // Boss level\r
+        {0,    "??:??"},       // Secret level\r
+\r
+        //\r
+        // Episode Two Par Times\r
+        //\r
+        {1.5,  "01:30"},\r
+        {3.5,  "03:30"},\r
+        {3,    "03:00"},\r
+        {2,    "02:00"},\r
+        {4,    "04:00"},\r
+        {6,    "06:00"},\r
+        {1,    "01:00"},\r
+        {3,    "03:00"},\r
+        {0,    "??:??"},\r
+        {0,    "??:??"},\r
+\r
+        //\r
+        // Episode Three Par Times\r
+        //\r
+        {1.5,  "01:30"},\r
+        {1.5,  "01:30"},\r
+        {2.5,  "02:30"},\r
+        {2.5,  "02:30"},\r
+        {3.5,  "03:30"},\r
+        {2.5,  "02:30"},\r
+        {2,    "02:00"},\r
+        {6,    "06:00"},\r
+        {0,    "??:??"},\r
+        {0,    "??:??"},\r
+\r
+        //\r
+        // Episode Four Par Times\r
+        //\r
+        {2,    "02:00"},\r
+        {2,    "02:00"},\r
+        {1.5,  "01:30"},\r
+        {1,    "01:00"},\r
+        {4.5,  "04:30"},\r
+        {3.5,  "03:30"},\r
+        {2,    "02:00"},\r
+        {4.5,  "04:30"},\r
+        {0,    "??:??"},\r
+        {0,    "??:??"},\r
+\r
+        //\r
+        // Episode Five Par Times\r
+        //\r
+        {2.5,  "02:30"},\r
+        {1.5,  "01:30"},\r
+        {2.5,  "02:30"},\r
+        {2.5,  "02:30"},\r
+        {4,    "04:00"},\r
+        {3,    "03:00"},\r
+        {4.5,  "04:30"},\r
+        {3.5,  "03:30"},\r
+        {0,    "??:??"},\r
+        {0,    "??:??"},\r
+\r
+        //\r
+        // Episode Six Par Times\r
+        //\r
+        {6.5,  "06:30"},\r
+        {4,    "04:00"},\r
+        {4.5,  "04:30"},\r
+        {6,    "06:00"},\r
+        {5,    "05:00"},\r
+        {5.5,  "05:30"},\r
+        {5.5,  "05:30"},\r
+        {8.5,  "08:30"},\r
+        {0,    "??:??"},\r
+        {0,    "??:??"}\r
+#else\r
+        //\r
+        // SPEAR OF DESTINY TIMES\r
+        //\r
+        {1.5,  "01:30"},\r
+        {3.5,  "03:30"},\r
+        {2.75, "02:45"},\r
+        {3.5,  "03:30"},\r
+        {0,    "??:??"},       // Boss 1\r
+        {4.5,  "04:30"},\r
+        {3.25, "03:15"},\r
+        {2.75, "02:45"},\r
+        {4.75, "04:45"},\r
+        {0,    "??:??"},       // Boss 2\r
+        {6.5,  "06:30"},\r
+        {4.5,  "04:30"},\r
+        {2.75, "02:45"},\r
+        {4.5,  "04:30"},\r
+        {6,    "06:00"},\r
+        {0,    "??:??"},       // Boss 3\r
+        {6,    "06:00"},\r
+        {0,    "??:??"},       // Boss 4\r
+        {0,    "??:??"},       // Secret level 1\r
+        {0,    "??:??"},       // Secret level 2\r
+#endif\r
+       };\r
+\r
+\r
+\r
+       CacheLump(LEVELEND_LUMP_START,LEVELEND_LUMP_END);\r
+       ClearSplitVWB ();                       // set up for double buffering in split screen\r
+       VWB_Bar (0,0,320,200-STATUSLINES,127);\r
+       StartCPMusic(ENDLEVEL_MUS);\r
+\r
+//\r
+// do the intermission\r
+//\r
+       IN_ClearKeysDown();\r
+       IN_StartAck();\r
+\r
+#ifdef JAPAN\r
+       CA_CacheGrChunk(C_INTERMISSIONPIC);\r
+       VWB_DrawPic(0,0,C_INTERMISSIONPIC);\r
+       UNCACHEGRCHUNK(C_INTERMISSIONPIC);\r
+#endif\r
+       VWB_DrawPic(0,16,L_GUYPIC);\r
+\r
+#ifndef SPEAR\r
+       if (mapon<8)\r
+#else\r
+       if (mapon != 4 &&\r
+               mapon != 9 &&\r
+               mapon != 15 &&\r
+               mapon < 17)\r
+#endif\r
+       {\r
+#ifndef JAPAN\r
+        #ifdef SPANISH\r
+        Write(14,2,"piso\ncompletado");\r
+        #else\r
+        Write(14,2,"floor\ncompleted");\r
+        #endif\r
+\r
+        Write(14,7,STR_BONUS"     0");\r
+        Write(16,10,STR_TIME);\r
+        Write(16,12,STR_PAR);\r
+\r
+        #ifdef SPANISH\r
+        Write(11,14,    STR_RAT2KILL);\r
+        Write(11,16,  STR_RAT2SECRET);\r
+        Write(11,18,STR_RAT2TREASURE);\r
+        #else\r
+        Write(9,14,    STR_RAT2KILL);\r
+        Write(5,16,  STR_RAT2SECRET);\r
+        Write(1,18,STR_RAT2TREASURE);\r
+        #endif\r
+\r
+        Write(26,2,itoa(gamestate.mapon+1,tempstr,10));\r
+#endif\r
+\r
+        #ifdef SPANISH\r
+        Write(30,12,parTimes[gamestate.episode*10+mapon].timestr);\r
+        #else\r
+        Write(26,12,parTimes[gamestate.episode*10+mapon].timestr);\r
+        #endif\r
+\r
+        //\r
+        // PRINT TIME\r
+        //\r
+        sec=gamestate.TimeCount/70;\r
+\r
+        if (sec > 99*60)               // 99 minutes max\r
+          sec = 99*60;\r
+\r
+        if (gamestate.TimeCount<parTimes[gamestate.episode*10+mapon].time*4200)\r
+               timeleft=(parTimes[gamestate.episode*10+mapon].time*4200)/70-sec;\r
+\r
+        min=sec/60;\r
+        sec%=60;\r
+\r
+        #ifdef SPANISH\r
+        i=30*8;\r
+        #else\r
+        i=26*8;\r
+        #endif\r
+        VWB_DrawPic(i,10*8,L_NUM0PIC+(min/10));\r
+        i+=2*8;\r
+        VWB_DrawPic(i,10*8,L_NUM0PIC+(min%10));\r
+        i+=2*8;\r
+        Write(i/8,10,":");\r
+        i+=1*8;\r
+        VWB_DrawPic(i,10*8,L_NUM0PIC+(sec/10));\r
+        i+=2*8;\r
+        VWB_DrawPic(i,10*8,L_NUM0PIC+(sec%10));\r
+\r
+        VW_UpdateScreen ();\r
+        VW_FadeIn ();\r
+\r
+\r
+        //\r
+        // FIGURE RATIOS OUT BEFOREHAND\r
+        //\r
+        kr = sr = tr = 0;\r
+        if (gamestate.killtotal)\r
+               kr=(gamestate.killcount*100)/gamestate.killtotal;\r
+        if (gamestate.secrettotal)\r
+               sr=(gamestate.secretcount*100)/gamestate.secrettotal;\r
+        if (gamestate.treasuretotal)\r
+               tr=(gamestate.treasurecount*100)/gamestate.treasuretotal;\r
+\r
+\r
+        //\r
+        // PRINT TIME BONUS\r
+        //\r
+        bonus=timeleft*PAR_AMOUNT;\r
+        if (bonus)\r
+        {\r
+         for (i=0;i<=timeleft;i++)\r
+         {\r
+          ltoa((long)i*PAR_AMOUNT,tempstr,10);\r
+          x=36-strlen(tempstr)*2;\r
+          Write(x,7,tempstr);\r
+          if (!(i%(PAR_AMOUNT/10)))\r
+                SD_PlaySound(ENDBONUS1SND);\r
+          VW_UpdateScreen();\r
+          while(SD_SoundPlaying())\r
+                BJ_Breathe();\r
+          if (IN_CheckAck())\r
+                goto done;\r
+         }\r
+\r
+         VW_UpdateScreen();\r
+         SD_PlaySound(ENDBONUS2SND);\r
+         while(SD_SoundPlaying())\r
+               BJ_Breathe();\r
+        }\r
+\r
+\r
+        #ifdef SPANISH\r
+        #define RATIOXX                33\r
+        #else\r
+        #define RATIOXX                37\r
+        #endif\r
+        //\r
+        // KILL RATIO\r
+        //\r
+        ratio=kr;\r
+        for (i=0;i<=ratio;i++)\r
+        {\r
+         itoa(i,tempstr,10);\r
+         x=RATIOXX-strlen(tempstr)*2;\r
+         Write(x,14,tempstr);\r
+         if (!(i%10))\r
+               SD_PlaySound(ENDBONUS1SND);\r
+         VW_UpdateScreen ();\r
+         while(SD_SoundPlaying())\r
+               BJ_Breathe();\r
+\r
+         if (IN_CheckAck())\r
+               goto done;\r
+        }\r
+        if (ratio==100)\r
+        {\r
+          VW_WaitVBL(VBLWAIT);\r
+          SD_StopSound();\r
+          bonus+=PERCENT100AMT;\r
+          ltoa(bonus,tempstr,10);\r
+          x=(RATIOXX-1)-strlen(tempstr)*2;\r
+          Write(x,7,tempstr);\r
+          VW_UpdateScreen();\r
+          SD_PlaySound(PERCENT100SND);\r
+        }\r
+        else\r
+        if (!ratio)\r
+        {\r
+          VW_WaitVBL(VBLWAIT);\r
+          SD_StopSound();\r
+          SD_PlaySound(NOBONUSSND);\r
+        }\r
+        else\r
+        SD_PlaySound(ENDBONUS2SND);\r
+\r
+        VW_UpdateScreen();\r
+        while(SD_SoundPlaying())\r
+          BJ_Breathe();\r
+\r
+\r
+        //\r
+        // SECRET RATIO\r
+        //\r
+        ratio=sr;\r
+        for (i=0;i<=ratio;i++)\r
+        {\r
+         itoa(i,tempstr,10);\r
+         x=RATIOXX-strlen(tempstr)*2;\r
+         Write(x,16,tempstr);\r
+         if (!(i%10))\r
+               SD_PlaySound(ENDBONUS1SND);\r
+         VW_UpdateScreen ();\r
+         while(SD_SoundPlaying())\r
+               BJ_Breathe();\r
+         BJ_Breathe();\r
+\r
+         if (IN_CheckAck())\r
+               goto done;\r
+        }\r
+        if (ratio==100)\r
+        {\r
+          VW_WaitVBL(VBLWAIT);\r
+          SD_StopSound();\r
+          bonus+=PERCENT100AMT;\r
+          ltoa(bonus,tempstr,10);\r
+          x=(RATIOXX-1)-strlen(tempstr)*2;\r
+          Write(x,7,tempstr);\r
+          VW_UpdateScreen();\r
+          SD_PlaySound(PERCENT100SND);\r
+        }\r
+        else\r
+        if (!ratio)\r
+        {\r
+          VW_WaitVBL(VBLWAIT);\r
+          SD_StopSound();\r
+          SD_PlaySound(NOBONUSSND);\r
+        }\r
+        else\r
+          SD_PlaySound(ENDBONUS2SND);\r
+        VW_UpdateScreen();\r
+        while(SD_SoundPlaying())\r
+          BJ_Breathe();\r
+\r
+\r
+        //\r
+        // TREASURE RATIO\r
+        //\r
+        ratio=tr;\r
+        for (i=0;i<=ratio;i++)\r
+        {\r
+         itoa(i,tempstr,10);\r
+         x=RATIOXX-strlen(tempstr)*2;\r
+         Write(x,18,tempstr);\r
+         if (!(i%10))\r
+               SD_PlaySound(ENDBONUS1SND);\r
+         VW_UpdateScreen ();\r
+         while(SD_SoundPlaying())\r
+               BJ_Breathe();\r
+         if (IN_CheckAck())\r
+               goto done;\r
+        }\r
+        if (ratio==100)\r
+        {\r
+          VW_WaitVBL(VBLWAIT);\r
+          SD_StopSound();\r
+          bonus+=PERCENT100AMT;\r
+          ltoa(bonus,tempstr,10);\r
+          x=(RATIOXX-1)-strlen(tempstr)*2;\r
+          Write(x,7,tempstr);\r
+          VW_UpdateScreen();\r
+          SD_PlaySound(PERCENT100SND);\r
+        }\r
+        else\r
+        if (!ratio)\r
+        {\r
+          VW_WaitVBL(VBLWAIT);\r
+          SD_StopSound();\r
+          SD_PlaySound(NOBONUSSND);\r
+        }\r
+        else\r
+        SD_PlaySound(ENDBONUS2SND);\r
+        VW_UpdateScreen();\r
+        while(SD_SoundPlaying())\r
+          BJ_Breathe();\r
+\r
+\r
+        //\r
+        // JUMP STRAIGHT HERE IF KEY PRESSED\r
+        //\r
+        done:\r
+\r
+        itoa(kr,tempstr,10);\r
+        x=RATIOXX-strlen(tempstr)*2;\r
+        Write(x,14,tempstr);\r
+\r
+        itoa(sr,tempstr,10);\r
+        x=RATIOXX-strlen(tempstr)*2;\r
+        Write(x,16,tempstr);\r
+\r
+        itoa(tr,tempstr,10);\r
+        x=RATIOXX-strlen(tempstr)*2;\r
+        Write(x,18,tempstr);\r
+\r
+        bonus=(long)timeleft*PAR_AMOUNT+\r
+                  (PERCENT100AMT*(kr==100))+\r
+                  (PERCENT100AMT*(sr==100))+\r
+                  (PERCENT100AMT*(tr==100));\r
+\r
+        GivePoints(bonus);\r
+        ltoa(bonus,tempstr,10);\r
+        x=36-strlen(tempstr)*2;\r
+        Write(x,7,tempstr);\r
+\r
+        //\r
+        // SAVE RATIO INFORMATION FOR ENDGAME\r
+        //\r
+        LevelRatios[mapon].kill=kr;\r
+        LevelRatios[mapon].secret=sr;\r
+        LevelRatios[mapon].treasure=tr;\r
+        LevelRatios[mapon].time=min*60+sec;\r
+       }\r
+       else\r
+       {\r
+#ifdef SPEAR\r
+#ifndef SPEARDEMO\r
+         switch(mapon)\r
+         {\r
+          case 4: Write(14,4," trans\n"\r
+                                                 " grosse\n"\r
+                                                 STR_DEFEATED); break;\r
+          case 9: Write(14,4,"barnacle\n"\r
+                                                 "wilhelm\n"\r
+                                                 STR_DEFEATED); break;\r
+          case 15: Write(14,4,"ubermutant\n"\r
+                                                  STR_DEFEATED); break;\r
+          case 17: Write(14,4," death\n"\r
+                                                  " knight\n"\r
+                                                  STR_DEFEATED); break;\r
+          case 18: Write(13,4,"secret tunnel\n"\r
+                                                  "    area\n"\r
+                                                  "  completed!"); break;\r
+          case 19: Write(13,4,"secret castle\n"\r
+                                                  "    area\n"\r
+                                                  "  completed!"); break;\r
+         }\r
+#endif\r
+#else\r
+         Write(14,4,"secret floor\n completed!");\r
+#endif\r
+\r
+         Write(10,16,"15000 bonus!");\r
+\r
+         VW_UpdateScreen();\r
+         VW_FadeIn();\r
+\r
+         GivePoints(15000);\r
+       }\r
+\r
+\r
+       DrawScore();\r
+       VW_UpdateScreen();\r
+\r
+       TimeCount=0;\r
+       IN_StartAck();\r
+       while(!IN_CheckAck())\r
+         BJ_Breathe();\r
+\r
+//\r
+// done\r
+//\r
+#ifdef SPEARDEMO\r
+       if (gamestate.mapon == 1)\r
+       {\r
+               SD_PlaySound (BONUS1UPSND);\r
+\r
+               CA_CacheGrChunk (STARTFONT+1);\r
+               Message ("This concludes your demo\n"\r
+                                "of Spear of Destiny! Now,\n"\r
+                                "go to your local software\n"\r
+                                "store and buy it!");\r
+               UNCACHEGRCHUNK (STARTFONT+1);\r
+\r
+               IN_ClearKeysDown();\r
+               IN_Ack();\r
+       }\r
+#endif\r
+\r
+#ifdef JAPDEMO\r
+       if (gamestate.mapon == 3)\r
+       {\r
+               SD_PlaySound (BONUS1UPSND);\r
+\r
+               CA_CacheGrChunk (STARTFONT+1);\r
+               Message ("This concludes your demo\n"\r
+                                "of Wolfenstein 3-D! Now,\n"\r
+                                "go to your local software\n"\r
+                                "store and buy it!");\r
+               UNCACHEGRCHUNK (STARTFONT+1);\r
+\r
+               IN_ClearKeysDown();\r
+               IN_Ack();\r
+       }\r
+#endif\r
+\r
+       #ifndef SPEAR\r
+       if (Keyboard[sc_P] && MS_CheckParm("goobers"))\r
+               PicturePause();\r
+       #endif\r
+\r
+       VW_FadeOut ();\r
+       temp = bufferofs;\r
+       for (i=0;i<3;i++)\r
+       {\r
+               bufferofs = screenloc[i];\r
+               DrawPlayBorder ();\r
+       }\r
+       bufferofs = temp;\r
+\r
+       UnCacheLump(LEVELEND_LUMP_START,LEVELEND_LUMP_END);\r
+}\r
+\r
+\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= PreloadGraphics\r
+=\r
+= Fill the cache up\r
+=\r
+=================\r
+*/\r
+\r
+boolean PreloadUpdate(unsigned current, unsigned total)\r
+{\r
+       unsigned w = WindowW - 10;\r
+\r
+\r
+       VWB_Bar(WindowX + 5,WindowY + WindowH - 3,w,2,BLACK);\r
+       w = ((long)w * current) / total;\r
+       if (w)\r
+       {\r
+        VWB_Bar(WindowX + 5,WindowY + WindowH - 3,w,2,0x37); //SECONDCOLOR);\r
+        VWB_Bar(WindowX + 5,WindowY + WindowH - 3,w-1,1,0x32);\r
+\r
+       }\r
+       VW_UpdateScreen();\r
+//     if (LastScan == sc_Escape)\r
+//     {\r
+//             IN_ClearKeysDown();\r
+//             return(true);\r
+//     }\r
+//     else\r
+               return(false);\r
+}\r
+\r
+void PreloadGraphics(void)\r
+{\r
+       DrawLevel ();\r
+       ClearSplitVWB ();                       // set up for double buffering in split screen\r
+\r
+       VWB_Bar (0,0,320,200-STATUSLINES,127);\r
+\r
+       LatchDrawPic (20-14,80-3*8,GETPSYCHEDPIC);\r
+\r
+       WindowX = 160-14*8;\r
+       WindowY = 80-3*8;\r
+       WindowW = 28*8;\r
+       WindowH = 48;\r
+       VW_UpdateScreen();\r
+       VW_FadeIn ();\r
+\r
+       PM_Preload (PreloadUpdate);\r
+       IN_UserInput (70);\r
+       VW_FadeOut ();\r
+\r
+       DrawPlayBorder ();\r
+       VW_UpdateScreen ();\r
+}\r
+\r
+\r
+//==========================================================================\r
+\r
+/*\r
+==================\r
+=\r
+= DrawHighScores\r
+=\r
+==================\r
+*/\r
+\r
+void   DrawHighScores(void)\r
+{\r
+       char            buffer[16],*str,buffer1[5];\r
+       byte            temp,temp1,temp2,temp3;\r
+       word            i,j,\r
+                               w,h,\r
+                               x,y;\r
+       HighScore       *s;\r
+\r
+\r
+       MM_SortMem ();\r
+\r
+#ifndef SPEAR\r
+//     CA_CacheGrChunk (C_CODEPIC);\r
+       CA_CacheGrChunk (HIGHSCORESPIC);\r
+       CA_CacheGrChunk (STARTFONT);\r
+       CA_CacheGrChunk (C_LEVELPIC);\r
+       CA_CacheGrChunk (C_SCOREPIC);\r
+       CA_CacheGrChunk (C_NAMEPIC);\r
+\r
+       ClearMScreen();\r
+       DrawStripes(10);\r
+\r
+       VWB_DrawPic(48,0,HIGHSCORESPIC);\r
+       UNCACHEGRCHUNK (HIGHSCORESPIC);\r
+\r
+       VWB_DrawPic(4*8,68,C_NAMEPIC);\r
+       VWB_DrawPic(20*8,68,C_LEVELPIC);\r
+       VWB_DrawPic(28*8,68,C_SCOREPIC);\r
+#ifndef UPLOAD\r
+//     VWB_DrawPic(35*8,68,C_CODEPIC);\r
+#endif\r
+       fontnumber=0;\r
+\r
+#else\r
+       CacheLump (BACKDROP_LUMP_START,BACKDROP_LUMP_END);\r
+       ClearMScreen();\r
+       DrawStripes(10);\r
+       UnCacheLump (BACKDROP_LUMP_START,BACKDROP_LUMP_END);\r
+\r
+       CacheLump (HIGHSCORES_LUMP_START,HIGHSCORES_LUMP_END);\r
+       CA_CacheGrChunk (STARTFONT+1);\r
+       VWB_DrawPic (0,0,HIGHSCORESPIC);\r
+\r
+       fontnumber = 1;\r
+#endif\r
+\r
+\r
+#ifndef SPEAR\r
+       SETFONTCOLOR(15,0x29);\r
+#else\r
+       SETFONTCOLOR(HIGHLIGHT,0x29);\r
+#endif\r
+\r
+       for (i = 0,s = Scores;i < MaxScores;i++,s++)\r
+       {\r
+               PrintY = 76 + (16 * i);\r
+\r
+               //\r
+               // name\r
+               //\r
+#ifndef SPEAR\r
+               PrintX = 4*8;\r
+#else\r
+               PrintX = 16;\r
+#endif\r
+               US_Print(s->name);\r
+\r
+               //\r
+               // level\r
+               //\r
+               ultoa(s->completed,buffer,10);\r
+#ifndef SPEAR\r
+               for (str = buffer;*str;str++)\r
+                       *str = *str + (129 - '0');      // Used fixed-width numbers (129...)\r
+               USL_MeasureString(buffer,&w,&h);\r
+               PrintX = (22 * 8)-w;\r
+#else\r
+               USL_MeasureString(buffer,&w,&h);\r
+               PrintX = 194 - w;\r
+#endif\r
+\r
+#ifndef UPLOAD\r
+#ifndef SPEAR\r
+               PrintX -= 6;\r
+               itoa(s->episode+1,buffer1,10);\r
+               US_Print("E");\r
+               US_Print(buffer1);\r
+               US_Print("/L");\r
+#endif\r
+#endif\r
+\r
+#ifdef SPEAR\r
+               if (s->completed == 21)\r
+                       VWB_DrawPic (PrintX+8,PrintY-1,C_WONSPEARPIC);\r
+               else\r
+#endif\r
+               US_Print(buffer);\r
+\r
+               //\r
+               // score\r
+               //\r
+               ultoa(s->score,buffer,10);\r
+#ifndef SPEAR\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
+#else\r
+               USL_MeasureString(buffer,&w,&h);\r
+               PrintX = 292 - w;\r
+#endif\r
+               US_Print(buffer);\r
+\r
+               #if 0\r
+#ifndef UPLOAD\r
+#ifndef SPEAR\r
+               //\r
+               // verification #\r
+               //\r
+               if (!i)\r
+               {\r
+                temp=(((s->score >> 28)& 0xf)^\r
+                         ((s->score >> 24)& 0xf))+'A';\r
+                temp1=(((s->score >> 20)& 0xf)^\r
+                          ((s->score >> 16)& 0xf))+'A';\r
+                temp2=(((s->score >> 12)& 0xf)^\r
+                          ((s->score >> 8)& 0xf))+'A';\r
+                temp3=(((s->score >> 4)& 0xf)^\r
+                          ((s->score >> 0)& 0xf))+'A';\r
+\r
+                SETFONTCOLOR(0x49,0x29);\r
+                PrintX = 35*8;\r
+                buffer[0]=temp;\r
+                buffer[1]=temp1;\r
+                buffer[2]=temp2;\r
+                buffer[3]=temp3;\r
+                buffer[4]=0;\r
+                US_Print(buffer);\r
+                SETFONTCOLOR(15,0x29);\r
+               }\r
+#endif\r
+#endif\r
+               #endif\r
+       }\r
+\r
+       VW_UpdateScreen ();\r
+\r
+#ifdef SPEAR\r
+       UnCacheLump (HIGHSCORES_LUMP_START,HIGHSCORES_LUMP_END);\r
+       fontnumber = 0;\r
+#endif\r
+}\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.episode = gamestate.episode;\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
+                       break;\r
+               }\r
+       }\r
+\r
+#ifdef SPEAR\r
+       StartCPMusic (XAWARD_MUS);\r
+#else\r
+       StartCPMusic (ROSTER_MUS);\r
+#endif\r
+       DrawHighScores ();\r
+\r
+       VW_FadeIn ();\r
+\r
+       if (n != -1)\r
+       {\r
+       //\r
+       // got a high score\r
+       //\r
+               PrintY = 76 + (16 * n);\r
+#ifndef SPEAR\r
+               PrintX = 4*8;\r
+               backcolor = BORDCOLOR;\r
+               fontcolor = 15;\r
+               US_LineInput(PrintX,PrintY,Scores[n].name,nil,true,MaxHighName,100);\r
+#else\r
+               PrintX = 16;\r
+               fontnumber = 1;\r
+               VWB_Bar (PrintX-2,PrintY-2,145,15,0x9c);\r
+               VW_UpdateScreen ();\r
+               backcolor = 0x9c;\r
+               fontcolor = 15;\r
+               US_LineInput(PrintX,PrintY,Scores[n].name,nil,true,MaxHighName,130);\r
+#endif\r
+       }\r
+       else\r
+       {\r
+               IN_ClearKeysDown ();\r
+               IN_UserInput(500);\r
+       }\r
+\r
+}\r
+\r
+\r
+#ifndef UPLOAD\r
+#ifndef SPEAR\r
+#ifndef JAPAN\r
+////////////////////////////////////////////////////////\r
+//\r
+// NON-SHAREWARE NOTICE\r
+//\r
+////////////////////////////////////////////////////////\r
+void NonShareware(void)\r
+{\r
+       VW_FadeOut();\r
+\r
+       ClearMScreen();\r
+       DrawStripes(10);\r
+\r
+       CA_CacheGrChunk(STARTFONT+1);\r
+       fontnumber = 1;\r
+\r
+       SETFONTCOLOR(READHCOLOR,BKGDCOLOR);\r
+       PrintX=110;\r
+       PrintY=15;\r
+\r
+       #ifdef SPANISH\r
+       US_Print("Atencion");\r
+       #else\r
+       US_Print("Attention");\r
+       #endif\r
+\r
+       SETFONTCOLOR(HIGHLIGHT,BKGDCOLOR);\r
+       WindowX=PrintX=40;\r
+       PrintY=60;\r
+       #ifdef SPANISH\r
+       US_Print("Este juego NO es gratis y\n");\r
+       US_Print("NO es Shareware; favor de\n");\r
+       US_Print("no distribuirlo.\n\n");\r
+       #else\r
+       US_Print("This game is NOT shareware.\n");\r
+       US_Print("Please do not distribute it.\n");\r
+       US_Print("Thanks.\n\n");\r
+       #endif\r
+       US_Print("        Id Software\n");\r
+\r
+       VW_UpdateScreen ();\r
+       VW_FadeIn();\r
+       IN_Ack();\r
+}\r
+#endif\r
+#endif\r
+#endif\r
+\r
+#ifdef SPEAR\r
+#ifndef SPEARDEMO\r
+////////////////////////////////////////////////////////\r
+//\r
+// COPY PROTECTION FOR FormGen\r
+//\r
+////////////////////////////////////////////////////////\r
+char   far CopyProFailedStrs[][100] = {\r
+                       STR_COPY1,\r
+                       STR_COPY2,\r
+\r
+                       STR_COPY3,\r
+                       STR_COPY4,\r
+\r
+                       STR_COPY5,\r
+                       STR_COPY6,\r
+\r
+                       STR_COPY7,\r
+                       STR_COPY8,\r
+\r
+                       STR_COPY9,\r
+                       "",\r
+\r
+                       STR_COPY10,\r
+                       STR_COPY11,\r
+\r
+                       STR_COPY12,\r
+                       "",\r
+\r
+                       STR_COPY13,\r
+                       "",\r
+\r
+                       STR_COPY14,\r
+                       ""\r
+                       },\r
+\r
+               far BackDoorStrs[5][16] = {\r
+                       "a spoon?",\r
+                       "bite me!",\r
+                       "joshua",\r
+                       "pelt",\r
+#ifdef BETA\r
+                       "beta"\r
+#else\r
+                       "snoops"\r
+#endif\r
+                       },\r
+\r
+               far GoodBoyStrs[10][40] = {\r
+                       "...is the CORRECT ANSWER!",\r
+                       "",\r
+\r
+                       "Consider yourself bitten, sir.",\r
+                       "",\r
+\r
+                       "Greetings Professor Falken, would you",\r
+                       "like to play Spear of Destiny?",\r
+\r
+                       "Do you have any gold spray paint?",\r
+                       "",\r
+\r
+#ifdef BETA\r
+                       "Beta testing approved.",\r
+#else\r
+                       "I wish I had a 21\" monitor...",\r
+#endif\r
+                       ""\r
+                       },\r
+\r
+               far bossstrs[4][24] = {\r
+                       "DEATH KNIGHT",\r
+                       "BARNACLE WILHELM",\r
+                       "UBERMUTANTUBER MUTANT",\r
+                       "TRANS GROSSE"\r
+                       },\r
+\r
+               far WordStr[5][20] = {\r
+                       "New Game",\r
+                       "Sound...F4",\r
+                       "Control...F6",\r
+                       "Change View...F5",\r
+                       "Quit...F10"},\r
+\r
+               far     WordCorrect[5][2] = {"3","4","4","5","5"},\r
+\r
+               far MemberStr[10][40] = {\r
+                       STR_COPY15,\r
+                       "",\r
+\r
+                       STR_COPY16,\r
+                       "",\r
+\r
+                       STR_COPY17,\r
+                       STR_COPY18,\r
+\r
+                       STR_COPY19,\r
+                       STR_COPY20,\r
+\r
+                       STR_COPY21,\r
+                       STR_COPY22},\r
+\r
+               far MemberCorrect[5][24] = {\r
+                       "adrian carmack",\r
+                       "john carmackjohn romero",\r
+                       "tom hall",\r
+                       "jay wilbur",\r
+                       "kevin cloud"},\r
+\r
+               far DosMessages[9][80] = {\r
+                       STR_NOPE1,\r
+                       STR_NOPE2,\r
+                       STR_NOPE3,\r
+                       STR_NOPE4,\r
+                       STR_NOPE5,\r
+                       STR_NOPE6,\r
+                       STR_NOPE7,\r
+                       STR_NOPE8,\r
+                       STR_NOPE9},\r
+\r
+               far MiscTitle[4][20] = {\r
+                       "BLOOD TEST",\r
+                       "STRAIGHT-LACED",\r
+                       "QUITE SHAPELY",\r
+                       "I AM WHAT I AMMO"\r
+                       },\r
+\r
+               far MiscStr[12][40] = {\r
+                       STR_MISC1,\r
+                       STR_MISC2,\r
+                       "",\r
+\r
+                       STR_MISC3,\r
+                       STR_MISC4,\r
+                       "",\r
+\r
+                       STR_MISC5,\r
+                       STR_MISC6,\r
+                       "",\r
+\r
+                       STR_MISC7,\r
+                       STR_MISC8,\r
+                       STR_MISC9\r
+                       },\r
+\r
+               far MiscCorrect[4][5] = {"ss","8",STR_STAR,"45"};\r
+\r
+\r
+int  BackDoor(char *s)\r
+{\r
+       int i;\r
+\r
+\r
+       strlwr(s);\r
+\r
+       for (i=0;i<5;i++)\r
+               if (!_fstrcmp(s,BackDoorStrs[i]))\r
+               {\r
+                       SETFONTCOLOR(14,15);\r
+                       fontnumber = 0;\r
+                       PrintY = 175;\r
+                       VWB_DrawPic (0,20*8,COPYPROTBOXPIC);\r
+                       US_CPrint(GoodBoyStrs[i*2]);\r
+                       US_CPrint(GoodBoyStrs[i*2+1]);\r
+                       VW_UpdateScreen();\r
+                       return 1;\r
+               }\r
+\r
+       return 0;\r
+}\r
+\r
+\r
+void CopyProtection(void)\r
+{\r
+#define TYPEBOX_Y              177\r
+#define TYPEBOX_BKGD   0x9c\r
+#define PRINTCOLOR             HIGHLIGHT\r
+\r
+       int     i,match,whichboss,bossnum,try,whichline,enemypicked[4]={0,0,0,0},\r
+               bosses[4] = { BOSSPIC1PIC,BOSSPIC2PIC,BOSSPIC3PIC,BOSSPIC4PIC },\r
+               whichone,whichpicked[4]={0,0,0,0},quiztype,whichmem,\r
+               memberpicked[5]={0,0,0,0,0},wordpicked[5]={0,0,0,0,0},whichword;\r
+\r
+       char    inputbuffer[20],\r
+                       message[80];\r
+\r
+       enum\r
+       {\r
+               debriefing,\r
+               checkmanual,\r
+               staffquiz,\r
+               miscquiz,\r
+\r
+               totaltypes\r
+       };\r
+\r
+\r
+\r
+       try = 0;\r
+       VW_FadeOut();\r
+       CA_CacheGrChunk(C_BACKDROPPIC);\r
+       CacheLump(COPYPROT_LUMP_START,COPYPROT_LUMP_END);\r
+       CA_CacheGrChunk(STARTFONT+1);\r
+       CA_LoadAllSounds();\r
+       StartCPMusic(COPYPRO_MUS);\r
+       US_InitRndT(true);\r
+\r
+       while (try<3)\r
+       {\r
+               fontnumber = 1;\r
+               SETFONTCOLOR(PRINTCOLOR-2,15);\r
+               VWB_DrawPic (0,0,C_BACKDROPPIC);\r
+               VWB_DrawPic (0,0,COPYPROTTOPPIC);\r
+               VWB_DrawPic (0,20*8,COPYPROTBOXPIC);\r
+               WindowX = WindowY = 0;\r
+               WindowW = 320;\r
+               WindowH = 200;\r
+               PrintY = 65;\r
+\r
+               quiztype = US_RndT()%totaltypes;\r
+               switch(quiztype)\r
+               {\r
+                       //\r
+                       // BOSSES QUIZ\r
+                       //\r
+                       case debriefing:\r
+                               PrintX = 0;\r
+                               US_Print(STR_DEBRIEF);\r
+                               SETFONTCOLOR(PRINTCOLOR,15);\r
+\r
+                               while (enemypicked[whichboss = US_RndT()&3]);\r
+                               enemypicked[whichboss] = 1;\r
+                               bossnum = bosses[whichboss];\r
+                               VWB_DrawPic(128,60,bossnum);\r
+                               fontnumber = 0;\r
+                               PrintY = 130;\r
+                               US_CPrint(STR_ENEMY1"\n");\r
+                               US_CPrint(STR_ENEMY2"\n\n");\r
+\r
+                               VW_UpdateScreen();\r
+                               VW_FadeIn();\r
+\r
+                               PrintX = 100;\r
+                               fontcolor = 15;\r
+                               backcolor = TYPEBOX_BKGD;\r
+                               inputbuffer[0] = 0;\r
+                               PrintY = TYPEBOX_Y;\r
+                               fontnumber = 1;\r
+                               US_LineInput(PrintX,PrintY,inputbuffer,nil,true,20,100);\r
+\r
+                               match = 0;\r
+                               for (i=0;i<_fstrlen(bossstrs[whichboss]);i++)\r
+                                       if (!_fstrnicmp(inputbuffer,bossstrs[whichboss]+i,strlen(inputbuffer)) &&\r
+                                               strlen(inputbuffer)>3)\r
+                                               match = 1;\r
+\r
+                               match += BackDoor(inputbuffer);\r
+                               break;\r
+\r
+                       //\r
+                       // MANUAL CHECK\r
+                       //\r
+                       case checkmanual:\r
+                               while (wordpicked[whichword = US_RndT()%5]);\r
+                               wordpicked[whichword] = 1;\r
+                               US_CPrint(STR_CHECKMAN);\r
+                               SETFONTCOLOR(PRINTCOLOR,15);\r
+                               PrintY += 25;\r
+                               US_CPrint(STR_MAN1);\r
+                               US_CPrint(STR_MAN2);\r
+                               _fstrcpy(message,STR_MAN3" \"");\r
+                               _fstrcat(message,WordStr[whichword]);\r
+                               _fstrcat(message,"\" "STR_MAN4);\r
+                               US_CPrint(message);\r
+                               VW_UpdateScreen();\r
+                               VW_FadeIn();\r
+\r
+                               PrintX = 146;\r
+                               fontcolor = 15;\r
+                               backcolor = TYPEBOX_BKGD;\r
+                               inputbuffer[0] = 0;\r
+                               PrintY = TYPEBOX_Y;\r
+                               US_LineInput(PrintX,PrintY,inputbuffer,nil,true,6,100);\r
+\r
+                               strlwr(inputbuffer);\r
+                               match = 1-(_fstrcmp(inputbuffer,WordCorrect[whichword])!=0);\r
+                               match += BackDoor(inputbuffer);\r
+                               break;\r
+\r
+                       //\r
+                       // STAFF QUIZ\r
+                       //\r
+                       case staffquiz:\r
+                               while (memberpicked[whichmem = US_RndT()%5]);\r
+                               memberpicked[whichmem] = 1;\r
+                               US_CPrint(STR_ID1);\r
+                               SETFONTCOLOR(PRINTCOLOR,15);\r
+                               PrintY += 25;\r
+                               US_CPrint(MemberStr[whichmem*2]);\r
+                               US_CPrint(MemberStr[whichmem*2+1]);\r
+                               VW_UpdateScreen();\r
+                               VW_FadeIn();\r
+\r
+                               PrintX = 100;\r
+                               fontcolor = 15;\r
+                               backcolor = TYPEBOX_BKGD;\r
+                               inputbuffer[0] = 0;\r
+                               PrintY = TYPEBOX_Y;\r
+                               US_LineInput(PrintX,PrintY,inputbuffer,nil,true,20,120);\r
+\r
+                               strlwr(inputbuffer);\r
+                               match = 0;\r
+                               for (i=0;i<_fstrlen(MemberCorrect[whichmem]);i++)\r
+                                       if (!_fstrnicmp(inputbuffer,MemberCorrect[whichmem]+i,strlen(inputbuffer)) &&\r
+                                               strlen(inputbuffer)>2)\r
+                                                       match = 1;\r
+                               match += BackDoor(inputbuffer);\r
+                               break;\r
+\r
+                       //\r
+                       // MISCELLANEOUS QUESTIONS\r
+                       //\r
+                       case miscquiz:\r
+                               while (whichpicked[whichone = US_RndT()&3]);\r
+                               whichpicked[whichone] = 1;\r
+                               US_CPrint(MiscTitle[whichone]);\r
+                               SETFONTCOLOR(PRINTCOLOR,15);\r
+                               PrintY += 25;\r
+                               US_CPrint(MiscStr[whichone*3]);\r
+                               US_CPrint(MiscStr[whichone*3+1]);\r
+                               US_CPrint(MiscStr[whichone*3+2]);\r
+                               VW_UpdateScreen();\r
+                               VW_FadeIn();\r
+\r
+                               PrintX = 146;\r
+                               fontcolor = 15;\r
+                               backcolor = TYPEBOX_BKGD;\r
+                               inputbuffer[0] = 0;\r
+                               PrintY = TYPEBOX_Y;\r
+                               US_LineInput(PrintX,PrintY,inputbuffer,nil,true,6,100);\r
+\r
+                               strlwr(inputbuffer);\r
+                               match = 1-(_fstrcmp(inputbuffer,MiscCorrect[whichone])!=0);\r
+                               match += BackDoor(inputbuffer);\r
+                               break;\r
+                       }\r
+\r
+               //\r
+               // IF NO MATCH, WE'VE GOT A (MINOR) PROBLEM!\r
+               //\r
+\r
+               if (!match)\r
+               {\r
+                       whichline = 2*(US_RndT()%9);\r
+                       SETFONTCOLOR(14,15);\r
+                       fontnumber = 0;\r
+                       PrintY = 175;\r
+                       VWB_DrawPic (0,20*8,COPYPROTBOXPIC);\r
+                       US_CPrint(CopyProFailedStrs[whichline]);\r
+                       US_CPrint(CopyProFailedStrs[whichline+1]);\r
+\r
+                       VW_UpdateScreen();\r
+                       SD_PlaySound(NOWAYSND);\r
+                       IN_UserInput(TickBase*3);\r
+                       VW_FadeOut();\r
+                       try++;\r
+               }\r
+               else\r
+               {\r
+                       int start;\r
+\r
+\r
+                       SD_PlaySound(BONUS1UPSND);\r
+                       SD_WaitSoundDone();\r
+                       UNCACHEGRCHUNK (STARTFONT+1);\r
+                       UNCACHEGRCHUNK (C_BACKDROPPIC);\r
+                       UnCacheLump (COPYPROT_LUMP_START,COPYPROT_LUMP_END);\r
+\r
+                       switch(SoundMode)\r
+                       {\r
+                               case sdm_Off: return;\r
+                               case sdm_PC: start = STARTPCSOUNDS; break;\r
+                               case sdm_AdLib: start = STARTADLIBSOUNDS;\r
+                       }\r
+\r
+                       for (i=0;i<NUMSOUNDS;i++,start++)\r
+                               MM_FreePtr ((memptr *)&audiosegs[start]);\r
+                       return;\r
+               }\r
+       }\r
+\r
+       ClearMemory();\r
+       ShutdownId();\r
+\r
+       _fstrcpy(message,DosMessages[US_RndT()%9]);\r
+\r
+       _AX = 3;\r
+       geninterrupt(0x10);\r
+\r
+       printf("%s\n",message);\r
+       exit(1);\r
+}\r
+\r
+#endif // SPEARDEMO\r
+#endif // SPEAR\r
+//===========================================================================\r
diff --git a/src/lib/hb/wl_main.c b/src/lib/hb/wl_main.c
new file mode 100755 (executable)
index 0000000..7fec729
--- /dev/null
@@ -0,0 +1,1616 @@
+// WL_MAIN.C\r
+\r
+#include <conio.h>\r
+#include "WL_DEF.H"\r
+#pragma hdrstop\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                  WOLFENSTEIN 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
+#define FOCALLENGTH     (0x5700l)               // in global coordinates\r
+#define VIEWGLOBAL      0x10000                 // globals visable flush to wall\r
+\r
+#define VIEWWIDTH       256                     // size of view window\r
+#define VIEWHEIGHT      144\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                GLOBAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+char            str[80],str2[20];\r
+int                            tedlevelnum;\r
+boolean         tedlevel;\r
+boolean         nospr;\r
+boolean         IsA386;\r
+int                     dirangle[9] = {0,ANGLES/8,2*ANGLES/8,3*ANGLES/8,4*ANGLES/8,\r
+       5*ANGLES/8,6*ANGLES/8,7*ANGLES/8,ANGLES};\r
+\r
+//\r
+// proejection variables\r
+//\r
+fixed           focallength;\r
+unsigned        screenofs;\r
+int             viewwidth;\r
+int             viewheight;\r
+int             centerx;\r
+int             shootdelta;                     // pixels away from centerx a target can be\r
+fixed           scale,maxslope;\r
+long            heightnumerator;\r
+int                     minheightdiv;\r
+\r
+\r
+void            Quit (char *error);\r
+\r
+boolean         startgame,loadedgame,virtualreality;\r
+int             mouseadjustment;\r
+\r
+char   configname[13]="CONFIG.";\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= ReadConfig\r
+=\r
+====================\r
+*/\r
+\r
+void ReadConfig(void)\r
+{\r
+       int                     file;\r
+       SDMode          sd;\r
+       SMMode          sm;\r
+       SDSMode         sds;\r
+\r
+\r
+       if ( (file = open(configname,O_BINARY | O_RDONLY)) != -1)\r
+       {\r
+       //\r
+       // valid config file\r
+       //\r
+               read(file,Scores,sizeof(HighScore) * MaxScores);\r
+\r
+               read(file,&sd,sizeof(sd));\r
+               read(file,&sm,sizeof(sm));\r
+               read(file,&sds,sizeof(sds));\r
+\r
+               read(file,&mouseenabled,sizeof(mouseenabled));\r
+               read(file,&joystickenabled,sizeof(joystickenabled));\r
+               read(file,&joypadenabled,sizeof(joypadenabled));\r
+               read(file,&joystickprogressive,sizeof(joystickprogressive));\r
+               read(file,&joystickport,sizeof(joystickport));\r
+\r
+               read(file,&dirscan,sizeof(dirscan));\r
+               read(file,&buttonscan,sizeof(buttonscan));\r
+               read(file,&buttonmouse,sizeof(buttonmouse));\r
+               read(file,&buttonjoy,sizeof(buttonjoy));\r
+\r
+               read(file,&viewsize,sizeof(viewsize));\r
+               read(file,&mouseadjustment,sizeof(mouseadjustment));\r
+\r
+               close(file);\r
+\r
+               if (sd == sdm_AdLib && !AdLibPresent && !SoundBlasterPresent)\r
+               {\r
+                       sd = sdm_PC;\r
+                       sd = smm_Off;\r
+               }\r
+\r
+               if ((sds == sds_SoundBlaster && !SoundBlasterPresent) ||\r
+                       (sds == sds_SoundSource && !SoundSourcePresent))\r
+                       sds = sds_Off;\r
+\r
+               if (!MousePresent)\r
+                       mouseenabled = false;\r
+               if (!JoysPresent[joystickport])\r
+                       joystickenabled = false;\r
+\r
+               MainMenu[6].active=1;\r
+               MainItems.curpos=0;\r
+       }\r
+       else\r
+       {\r
+       //\r
+       // no config file, so select by hardware\r
+       //\r
+               if (SoundBlasterPresent || AdLibPresent)\r
+               {\r
+                       sd = sdm_AdLib;\r
+                       sm = smm_AdLib;\r
+               }\r
+               else\r
+               {\r
+                       sd = sdm_PC;\r
+                       sm = smm_Off;\r
+               }\r
+\r
+               if (SoundBlasterPresent)\r
+                       sds = sds_SoundBlaster;\r
+               else if (SoundSourcePresent)\r
+                       sds = sds_SoundSource;\r
+               else\r
+                       sds = sds_Off;\r
+\r
+               if (MousePresent)\r
+                       mouseenabled = true;\r
+\r
+               joystickenabled = false;\r
+               joypadenabled = false;\r
+               joystickport = 0;\r
+               joystickprogressive = false;\r
+\r
+               viewsize = 15;\r
+               mouseadjustment=5;\r
+       }\r
+\r
+       SD_SetMusicMode (sm);\r
+       SD_SetSoundMode (sd);\r
+       SD_SetDigiDevice (sds);\r
+\r
+}\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= WriteConfig\r
+=\r
+====================\r
+*/\r
+\r
+void WriteConfig(void)\r
+{\r
+       int                     file;\r
+\r
+       file = open(configname,O_CREAT | O_BINARY | O_WRONLY,\r
+                               S_IREAD | S_IWRITE | S_IFREG);\r
+\r
+       if (file != -1)\r
+       {\r
+               write(file,Scores,sizeof(HighScore) * MaxScores);\r
+\r
+               write(file,&SoundMode,sizeof(SoundMode));\r
+               write(file,&MusicMode,sizeof(MusicMode));\r
+               write(file,&DigiMode,sizeof(DigiMode));\r
+\r
+               write(file,&mouseenabled,sizeof(mouseenabled));\r
+               write(file,&joystickenabled,sizeof(joystickenabled));\r
+               write(file,&joypadenabled,sizeof(joypadenabled));\r
+               write(file,&joystickprogressive,sizeof(joystickprogressive));\r
+               write(file,&joystickport,sizeof(joystickport));\r
+\r
+               write(file,&dirscan,sizeof(dirscan));\r
+               write(file,&buttonscan,sizeof(buttonscan));\r
+               write(file,&buttonmouse,sizeof(buttonmouse));\r
+               write(file,&buttonjoy,sizeof(buttonjoy));\r
+\r
+               write(file,&viewsize,sizeof(viewsize));\r
+               write(file,&mouseadjustment,sizeof(mouseadjustment));\r
+\r
+               close(file);\r
+       }\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+========================\r
+=\r
+= Patch386\r
+=\r
+= Patch ldiv to use 32 bit instructions\r
+=\r
+========================\r
+*/\r
+\r
+char    *JHParmStrings[] = {"no386",nil};\r
+void Patch386 (void)\r
+{\r
+extern void far jabhack2(void);\r
+extern int far  CheckIs386(void);\r
+\r
+       int     i;\r
+\r
+       for (i = 1;i < _argc;i++)\r
+               if (US_CheckParm(_argv[i],JHParmStrings) == 0)\r
+               {\r
+                       IsA386 = false;\r
+                       return;\r
+               }\r
+\r
+       if (CheckIs386())\r
+       {\r
+               IsA386 = true;\r
+               jabhack2();\r
+       }\r
+       else\r
+               IsA386 = false;\r
+}\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 (int difficulty,int episode)\r
+{\r
+       memset (&gamestate,0,sizeof(gamestate));\r
+       gamestate.difficulty = difficulty;\r
+       gamestate.weapon = gamestate.bestweapon\r
+               = gamestate.chosenweapon = wp_pistol;\r
+       gamestate.health = 100;\r
+       gamestate.ammo = STARTAMMO;\r
+       gamestate.lives = 3;\r
+       gamestate.nextextra = EXTRAPOINTS;\r
+       gamestate.episode=episode;\r
+\r
+       startgame = true;\r
+}\r
+\r
+//===========================================================================\r
+\r
+void DiskFlopAnim(int x,int y)\r
+{\r
+ static char which=0;\r
+ if (!x && !y)\r
+   return;\r
+ VWB_DrawPic(x,y,C_DISKLOADING1PIC+which);\r
+ VW_UpdateScreen();\r
+ which^=1;\r
+}\r
+\r
+\r
+long DoChecksum(byte far *source,unsigned size,long checksum)\r
+{\r
+ unsigned i;\r
+\r
+ for (i=0;i<size-1;i++)\r
+   checksum += source[i]^source[i+1];\r
+\r
+ return checksum;\r
+}\r
+\r
+\r
+/*\r
+==================\r
+=\r
+= SaveTheGame\r
+=\r
+==================\r
+*/\r
+\r
+boolean SaveTheGame(int file,int x,int y)\r
+{\r
+       struct diskfree_t dfree;\r
+       long avail,size,checksum;\r
+       objtype *ob,nullobj;\r
+\r
+\r
+       if (_dos_getdiskfree(0,&dfree))\r
+         Quit("Error in _dos_getdiskfree call");\r
+\r
+       avail = (long)dfree.avail_clusters *\r
+                       dfree.bytes_per_sector *\r
+                       dfree.sectors_per_cluster;\r
+\r
+       size = 0;\r
+       for (ob = player; ob ; ob=ob->next)\r
+         size += sizeof(*ob);\r
+       size += sizeof(nullobj);\r
+\r
+       size += sizeof(gamestate) +\r
+                       sizeof(LRstruct)*8 +\r
+                       sizeof(tilemap) +\r
+                       sizeof(actorat) +\r
+                       sizeof(laststatobj) +\r
+                       sizeof(statobjlist) +\r
+                       sizeof(doorposition) +\r
+                       sizeof(pwallstate) +\r
+                       sizeof(pwallx) +\r
+                       sizeof(pwally) +\r
+                       sizeof(pwalldir) +\r
+                       sizeof(pwallpos);\r
+\r
+       if (avail < size)\r
+       {\r
+        Message(STR_NOSPACE1"\n"\r
+                        STR_NOSPACE2);\r
+        return false;\r
+       }\r
+\r
+       checksum = 0;\r
+\r
+\r
+       DiskFlopAnim(x,y);\r
+       CA_FarWrite (file,(void far *)&gamestate,sizeof(gamestate));\r
+       checksum = DoChecksum((byte far *)&gamestate,sizeof(gamestate),checksum);\r
+\r
+       DiskFlopAnim(x,y);\r
+#ifdef SPEAR\r
+       CA_FarWrite (file,(void far *)&LevelRatios[0],sizeof(LRstruct)*20);\r
+       checksum = DoChecksum((byte far *)&LevelRatios[0],sizeof(LRstruct)*20,checksum);\r
+#else\r
+       CA_FarWrite (file,(void far *)&LevelRatios[0],sizeof(LRstruct)*8);\r
+       checksum = DoChecksum((byte far *)&LevelRatios[0],sizeof(LRstruct)*8,checksum);\r
+#endif\r
+\r
+       DiskFlopAnim(x,y);\r
+       CA_FarWrite (file,(void far *)tilemap,sizeof(tilemap));\r
+       checksum = DoChecksum((byte far *)tilemap,sizeof(tilemap),checksum);\r
+       DiskFlopAnim(x,y);\r
+       CA_FarWrite (file,(void far *)actorat,sizeof(actorat));\r
+       checksum = DoChecksum((byte far *)actorat,sizeof(actorat),checksum);\r
+\r
+       CA_FarWrite (file,(void far *)areaconnect,sizeof(areaconnect));\r
+       CA_FarWrite (file,(void far *)areabyplayer,sizeof(areabyplayer));\r
+\r
+       for (ob = player ; ob ; ob=ob->next)\r
+       {\r
+        DiskFlopAnim(x,y);\r
+        CA_FarWrite (file,(void far *)ob,sizeof(*ob));\r
+       }\r
+       nullobj.active = ac_badobject;          // end of file marker\r
+       DiskFlopAnim(x,y);\r
+       CA_FarWrite (file,(void far *)&nullobj,sizeof(nullobj));\r
+\r
+\r
+\r
+       DiskFlopAnim(x,y);\r
+       CA_FarWrite (file,(void far *)&laststatobj,sizeof(laststatobj));\r
+       checksum = DoChecksum((byte far *)&laststatobj,sizeof(laststatobj),checksum);\r
+       DiskFlopAnim(x,y);\r
+       CA_FarWrite (file,(void far *)statobjlist,sizeof(statobjlist));\r
+       checksum = DoChecksum((byte far *)statobjlist,sizeof(statobjlist),checksum);\r
+\r
+       DiskFlopAnim(x,y);\r
+       CA_FarWrite (file,(void far *)doorposition,sizeof(doorposition));\r
+       checksum = DoChecksum((byte far *)doorposition,sizeof(doorposition),checksum);\r
+       DiskFlopAnim(x,y);\r
+       CA_FarWrite (file,(void far *)doorobjlist,sizeof(doorobjlist));\r
+       checksum = DoChecksum((byte far *)doorobjlist,sizeof(doorobjlist),checksum);\r
+\r
+       DiskFlopAnim(x,y);\r
+       CA_FarWrite (file,(void far *)&pwallstate,sizeof(pwallstate));\r
+       checksum = DoChecksum((byte far *)&pwallstate,sizeof(pwallstate),checksum);\r
+       CA_FarWrite (file,(void far *)&pwallx,sizeof(pwallx));\r
+       checksum = DoChecksum((byte far *)&pwallx,sizeof(pwallx),checksum);\r
+       CA_FarWrite (file,(void far *)&pwally,sizeof(pwally));\r
+       checksum = DoChecksum((byte far *)&pwally,sizeof(pwally),checksum);\r
+       CA_FarWrite (file,(void far *)&pwalldir,sizeof(pwalldir));\r
+       checksum = DoChecksum((byte far *)&pwalldir,sizeof(pwalldir),checksum);\r
+       CA_FarWrite (file,(void far *)&pwallpos,sizeof(pwallpos));\r
+       checksum = DoChecksum((byte far *)&pwallpos,sizeof(pwallpos),checksum);\r
+\r
+       //\r
+       // WRITE OUT CHECKSUM\r
+       //\r
+       CA_FarWrite (file,(void far *)&checksum,sizeof(checksum));\r
+\r
+       return(true);\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+==================\r
+=\r
+= LoadTheGame\r
+=\r
+==================\r
+*/\r
+\r
+boolean LoadTheGame(int file,int x,int y)\r
+{\r
+       long checksum,oldchecksum;\r
+       objtype *ob,nullobj;\r
+\r
+\r
+       checksum = 0;\r
+\r
+       DiskFlopAnim(x,y);\r
+       CA_FarRead (file,(void far *)&gamestate,sizeof(gamestate));\r
+       checksum = DoChecksum((byte far *)&gamestate,sizeof(gamestate),checksum);\r
+\r
+       DiskFlopAnim(x,y);\r
+#ifdef SPEAR\r
+       CA_FarRead (file,(void far *)&LevelRatios[0],sizeof(LRstruct)*20);\r
+       checksum = DoChecksum((byte far *)&LevelRatios[0],sizeof(LRstruct)*20,checksum);\r
+#else\r
+       CA_FarRead (file,(void far *)&LevelRatios[0],sizeof(LRstruct)*8);\r
+       checksum = DoChecksum((byte far *)&LevelRatios[0],sizeof(LRstruct)*8,checksum);\r
+#endif\r
+\r
+       DiskFlopAnim(x,y);\r
+       SetupGameLevel ();\r
+\r
+       DiskFlopAnim(x,y);\r
+       CA_FarRead (file,(void far *)tilemap,sizeof(tilemap));\r
+       checksum = DoChecksum((byte far *)tilemap,sizeof(tilemap),checksum);\r
+       DiskFlopAnim(x,y);\r
+       CA_FarRead (file,(void far *)actorat,sizeof(actorat));\r
+       checksum = DoChecksum((byte far *)actorat,sizeof(actorat),checksum);\r
+\r
+       CA_FarRead (file,(void far *)areaconnect,sizeof(areaconnect));\r
+       CA_FarRead (file,(void far *)areabyplayer,sizeof(areabyplayer));\r
+\r
+\r
+\r
+       InitActorList ();\r
+       DiskFlopAnim(x,y);\r
+       CA_FarRead (file,(void far *)player,sizeof(*player));\r
+\r
+       while (1)\r
+       {\r
+        DiskFlopAnim(x,y);\r
+               CA_FarRead (file,(void far *)&nullobj,sizeof(nullobj));\r
+               if (nullobj.active == ac_badobject)\r
+                       break;\r
+               GetNewActor ();\r
+        // don't copy over the links\r
+               memcpy (new,&nullobj,sizeof(nullobj)-4);\r
+       }\r
+\r
+\r
+\r
+       DiskFlopAnim(x,y);\r
+       CA_FarRead (file,(void far *)&laststatobj,sizeof(laststatobj));\r
+       checksum = DoChecksum((byte far *)&laststatobj,sizeof(laststatobj),checksum);\r
+       DiskFlopAnim(x,y);\r
+       CA_FarRead (file,(void far *)statobjlist,sizeof(statobjlist));\r
+       checksum = DoChecksum((byte far *)statobjlist,sizeof(statobjlist),checksum);\r
+\r
+       DiskFlopAnim(x,y);\r
+       CA_FarRead (file,(void far *)doorposition,sizeof(doorposition));\r
+       checksum = DoChecksum((byte far *)doorposition,sizeof(doorposition),checksum);\r
+       DiskFlopAnim(x,y);\r
+       CA_FarRead (file,(void far *)doorobjlist,sizeof(doorobjlist));\r
+       checksum = DoChecksum((byte far *)doorobjlist,sizeof(doorobjlist),checksum);\r
+\r
+       DiskFlopAnim(x,y);\r
+       CA_FarRead (file,(void far *)&pwallstate,sizeof(pwallstate));\r
+       checksum = DoChecksum((byte far *)&pwallstate,sizeof(pwallstate),checksum);\r
+       CA_FarRead (file,(void far *)&pwallx,sizeof(pwallx));\r
+       checksum = DoChecksum((byte far *)&pwallx,sizeof(pwallx),checksum);\r
+       CA_FarRead (file,(void far *)&pwally,sizeof(pwally));\r
+       checksum = DoChecksum((byte far *)&pwally,sizeof(pwally),checksum);\r
+       CA_FarRead (file,(void far *)&pwalldir,sizeof(pwalldir));\r
+       checksum = DoChecksum((byte far *)&pwalldir,sizeof(pwalldir),checksum);\r
+       CA_FarRead (file,(void far *)&pwallpos,sizeof(pwallpos));\r
+       checksum = DoChecksum((byte far *)&pwallpos,sizeof(pwallpos),checksum);\r
+\r
+       CA_FarRead (file,(void far *)&oldchecksum,sizeof(oldchecksum));\r
+\r
+       if (oldchecksum != checksum)\r
+       {\r
+        Message(STR_SAVECHT1"\n"\r
+                        STR_SAVECHT2"\n"\r
+                        STR_SAVECHT3"\n"\r
+                        STR_SAVECHT4);\r
+\r
+        IN_ClearKeysDown();\r
+        IN_Ack();\r
+\r
+        gamestate.score = 0;\r
+        gamestate.lives = 1;\r
+        gamestate.weapon =\r
+          gamestate.chosenweapon =\r
+          gamestate.bestweapon = wp_pistol;\r
+        gamestate.ammo = 8;\r
+       }\r
+\r
+       return true;\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
+       SD_Shutdown ();\r
+       PM_Shutdown ();\r
+       IN_Shutdown ();\r
+       VW_Shutdown ();\r
+       CA_Shutdown ();\r
+       MM_Shutdown ();\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+==================\r
+=\r
+= BuildTables\r
+=\r
+= Calculates:\r
+=\r
+= scale                 projection constant\r
+= sintable/costable     overlapping fractional tables\r
+=\r
+==================\r
+*/\r
+\r
+const   float   radtoint = (float)FINEANGLES/2/PI;\r
+\r
+void BuildTables (void)\r
+{\r
+  int           i;\r
+  float         angle,anglestep;\r
+  double        tang;\r
+  fixed         value;\r
+\r
+\r
+//\r
+// calculate fine tangents\r
+//\r
+\r
+       for (i=0;i<FINEANGLES/8;i++)\r
+       {\r
+               tang = tan( (i+0.5)/radtoint);\r
+               finetangent[i] = tang*TILEGLOBAL;\r
+               finetangent[FINEANGLES/4-1-i] = 1/tang*TILEGLOBAL;\r
+       }\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
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= CalcProjection\r
+=\r
+= Uses focallength\r
+=\r
+====================\r
+*/\r
+\r
+void CalcProjection (long focal)\r
+{\r
+       int             i;\r
+       long            intang;\r
+       float   angle;\r
+       double  tang;\r
+       double  planedist;\r
+       double  globinhalf;\r
+       int             halfview;\r
+       double  halfangle,facedist;\r
+\r
+\r
+       focallength = focal;\r
+       facedist = focal+MINDIST;\r
+       halfview = viewwidth/2;                                 // half view in pixels\r
+\r
+//\r
+// calculate scale value for vertical height calculations\r
+// and sprite x calculations\r
+//\r
+       scale = halfview*facedist/(VIEWGLOBAL/2);\r
+\r
+//\r
+// divide heightnumerator by a posts distance to get the posts height for\r
+// the heightbuffer.  The pixel height is height>>2\r
+//\r
+       heightnumerator = (TILEGLOBAL*scale)>>6;\r
+       minheightdiv = heightnumerator/0x7fff +1;\r
+\r
+//\r
+// calculate the angle offset from view angle of each pixel's ray\r
+//\r
+\r
+       for (i=0;i<halfview;i++)\r
+       {\r
+       // start 1/2 pixel over, so viewangle bisects two middle pixels\r
+               tang = (long)i*VIEWGLOBAL/viewwidth/facedist;\r
+               angle = atan(tang);\r
+               intang = angle*radtoint;\r
+               pixelangle[halfview-1-i] = intang;\r
+               pixelangle[halfview+i] = -intang;\r
+       }\r
+\r
+//\r
+// if a point's abs(y/x) is greater than maxslope, the point is outside\r
+// the view area\r
+//\r
+       maxslope = finetangent[pixelangle[0]];\r
+       maxslope >>= 8;\r
+}\r
+\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===================\r
+=\r
+= SetupWalls\r
+=\r
+= Map tile values to scaled pics\r
+=\r
+===================\r
+*/\r
+\r
+void SetupWalls (void)\r
+{\r
+       int     i;\r
+\r
+       for (i=1;i<MAXWALLTILES;i++)\r
+       {\r
+               horizwall[i]=(i-1)*2;\r
+               vertwall[i]=(i-1)*2+1;\r
+       }\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+==========================\r
+=\r
+= SignonScreen\r
+=\r
+==========================\r
+*/\r
+\r
+void SignonScreen (void)                        // VGA version\r
+{\r
+       unsigned        segstart,seglength;\r
+\r
+       VL_SetVGAPlaneMode ();\r
+       VL_TestPaletteSet ();\r
+       VL_SetPalette (&gamepal);\r
+\r
+       if (!virtualreality)\r
+       {\r
+               VW_SetScreen(0x8000,0);\r
+               VL_MungePic (&introscn,320,200);\r
+               VL_MemToScreen (&introscn,320,200,0,0);\r
+               VW_SetScreen(0,0);\r
+       }\r
+\r
+//\r
+// reclaim the memory from the linked in signon screen\r
+//\r
+       segstart = FP_SEG(&introscn);\r
+       seglength = 64000/16;\r
+       if (FP_OFF(&introscn))\r
+       {\r
+               segstart++;\r
+               seglength--;\r
+       }\r
+       MML_UseSpace (segstart,seglength);\r
+}\r
+\r
+\r
+/*\r
+==========================\r
+=\r
+= FinishSignon\r
+=\r
+==========================\r
+*/\r
+\r
+void FinishSignon (void)\r
+{\r
+\r
+#ifndef SPEAR\r
+       VW_Bar (0,189,300,11,peekb(0xa000,0));\r
+       WindowX = 0;\r
+       WindowW = 320;\r
+       PrintY = 190;\r
+\r
+       #ifndef JAPAN\r
+       SETFONTCOLOR(14,4);\r
+\r
+       #ifdef SPANISH\r
+       US_CPrint ("Oprima una tecla");\r
+       #else\r
+       US_CPrint ("Press a key");\r
+       #endif\r
+\r
+       #endif\r
+\r
+       if (!NoWait)\r
+               IN_Ack ();\r
+\r
+       #ifndef JAPAN\r
+       VW_Bar (0,189,300,11,peekb(0xa000,0));\r
+\r
+       PrintY = 190;\r
+       SETFONTCOLOR(10,4);\r
+\r
+       #ifdef SPANISH\r
+       US_CPrint ("pensando...");\r
+       #else\r
+       US_CPrint ("Working...");\r
+       #endif\r
+\r
+       #endif\r
+\r
+       SETFONTCOLOR(0,15);\r
+#else\r
+       if (!NoWait)\r
+               VW_WaitVBL(3*70);\r
+#endif\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+=================\r
+=\r
+= MS_CheckParm\r
+=\r
+=================\r
+*/\r
+\r
+boolean MS_CheckParm (char far *check)\r
+{\r
+       int             i;\r
+       char    *parm;\r
+\r
+       for (i = 1;i<_argc;i++)\r
+       {\r
+               parm = _argv[i];\r
+\r
+               while ( !isalpha(*parm) )       // skip - / \ etc.. in front of parm\r
+                       if (!*parm++)\r
+                               break;                          // hit end of string without an alphanum\r
+\r
+               if ( !_fstricmp(check,parm) )\r
+                       return true;\r
+       }\r
+\r
+       return false;\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+=====================\r
+=\r
+= InitDigiMap\r
+=\r
+=====================\r
+*/\r
+\r
+static  int     wolfdigimap[] =\r
+               {\r
+                       // These first sounds are in the upload version\r
+#ifndef SPEAR\r
+                       HALTSND,                0,\r
+                       DOGBARKSND,             1,\r
+                       CLOSEDOORSND,           2,\r
+                       OPENDOORSND,            3,\r
+                       ATKMACHINEGUNSND,       4,\r
+                       ATKPISTOLSND,           5,\r
+                       ATKGATLINGSND,          6,\r
+                       SCHUTZADSND,            7,\r
+                       GUTENTAGSND,            8,\r
+                       MUTTISND,               9,\r
+                       BOSSFIRESND,            10,\r
+                       SSFIRESND,              11,\r
+                       DEATHSCREAM1SND,        12,\r
+                       DEATHSCREAM2SND,        13,\r
+                       DEATHSCREAM3SND,        13,\r
+                       TAKEDAMAGESND,          14,\r
+                       PUSHWALLSND,            15,\r
+\r
+                       LEBENSND,               20,\r
+                       NAZIFIRESND,            21,\r
+                       SLURPIESND,             22,\r
+\r
+                       YEAHSND,                                32,\r
+\r
+#ifndef UPLOAD\r
+                       // These are in all other episodes\r
+                       DOGDEATHSND,            16,\r
+                       AHHHGSND,               17,\r
+                       DIESND,                 18,\r
+                       EVASND,                 19,\r
+\r
+                       TOT_HUNDSND,            23,\r
+                       MEINGOTTSND,            24,\r
+                       SCHABBSHASND,           25,\r
+                       HITLERHASND,            26,\r
+                       SPIONSND,               27,\r
+                       NEINSOVASSND,           28,\r
+                       DOGATTACKSND,           29,\r
+                       LEVELDONESND,           30,\r
+                       MECHSTEPSND,                    31,\r
+\r
+                       SCHEISTSND,                             33,\r
+                       DEATHSCREAM4SND,                34,             // AIIEEE\r
+                       DEATHSCREAM5SND,                35,             // DEE-DEE\r
+                       DONNERSND,                              36,             // EPISODE 4 BOSS DIE\r
+                       EINESND,                                37,             // EPISODE 4 BOSS SIGHTING\r
+                       ERLAUBENSND,                    38,             // EPISODE 6 BOSS SIGHTING\r
+                       DEATHSCREAM6SND,                39,             // FART\r
+                       DEATHSCREAM7SND,                40,             // GASP\r
+                       DEATHSCREAM8SND,                41,             // GUH-BOY!\r
+                       DEATHSCREAM9SND,                42,             // AH GEEZ!\r
+                       KEINSND,                                43,             // EPISODE 5 BOSS SIGHTING\r
+                       MEINSND,                                44,             // EPISODE 6 BOSS DIE\r
+                       ROSESND,                                45,             // EPISODE 5 BOSS DIE\r
+\r
+#endif\r
+#else\r
+//\r
+// SPEAR OF DESTINY DIGISOUNDS\r
+//\r
+                       HALTSND,                0,\r
+                       CLOSEDOORSND,           2,\r
+                       OPENDOORSND,            3,\r
+                       ATKMACHINEGUNSND,       4,\r
+                       ATKPISTOLSND,           5,\r
+                       ATKGATLINGSND,          6,\r
+                       SCHUTZADSND,            7,\r
+                       BOSSFIRESND,            8,\r
+                       SSFIRESND,              9,\r
+                       DEATHSCREAM1SND,        10,\r
+                       DEATHSCREAM2SND,        11,\r
+                       TAKEDAMAGESND,          12,\r
+                       PUSHWALLSND,            13,\r
+                       AHHHGSND,               15,\r
+                       LEBENSND,               16,\r
+                       NAZIFIRESND,            17,\r
+                       SLURPIESND,             18,\r
+                       LEVELDONESND,           22,\r
+                       DEATHSCREAM4SND,                23,             // AIIEEE\r
+                       DEATHSCREAM3SND,        23,             // DOUBLY-MAPPED!!!\r
+                       DEATHSCREAM5SND,                24,             // DEE-DEE\r
+                       DEATHSCREAM6SND,                25,             // FART\r
+                       DEATHSCREAM7SND,                26,             // GASP\r
+                       DEATHSCREAM8SND,                27,             // GUH-BOY!\r
+                       DEATHSCREAM9SND,                28,             // AH GEEZ!\r
+                       GETGATLINGSND,                  38,             // Got Gat replacement\r
+\r
+#ifndef SPEARDEMO\r
+                       DOGBARKSND,             1,\r
+                       DOGDEATHSND,            14,\r
+                       SPIONSND,               19,\r
+                       NEINSOVASSND,           20,\r
+                       DOGATTACKSND,           21,\r
+                       TRANSSIGHTSND,                  29,             // Trans Sight\r
+                       TRANSDEATHSND,                  30,             // Trans Death\r
+                       WILHELMSIGHTSND,                31,             // Wilhelm Sight\r
+                       WILHELMDEATHSND,                32,             // Wilhelm Death\r
+                       UBERDEATHSND,                   33,             // Uber Death\r
+                       KNIGHTSIGHTSND,                 34,             // Death Knight Sight\r
+                       KNIGHTDEATHSND,                 35,             // Death Knight Death\r
+                       ANGELSIGHTSND,                  36,             // Angel Sight\r
+                       ANGELDEATHSND,                  37,             // Angel Death\r
+                       GETSPEARSND,                    39,             // Got Spear replacement\r
+#endif\r
+#endif\r
+                       LASTSOUND\r
+               };\r
+\r
+\r
+void InitDigiMap (void)\r
+{\r
+       int                     *map;\r
+\r
+       for (map = wolfdigimap;*map != LASTSOUND;map += 2)\r
+               DigiMap[map[0]] = map[1];\r
+\r
+\r
+}\r
+\r
+\r
+#ifndef SPEAR\r
+CP_iteminfo    MusicItems={CTL_X,CTL_Y,6,0,32};\r
+CP_itemtype far MusicMenu[]=\r
+       {\r
+               {1,"Get Them!",0},\r
+               {1,"Searching",0},\r
+               {1,"P.O.W.",0},\r
+               {1,"Suspense",0},\r
+               {1,"War March",0},\r
+               {1,"Around The Corner!",0},\r
+\r
+               {1,"Nazi Anthem",0},\r
+               {1,"Lurking...",0},\r
+               {1,"Going After Hitler",0},\r
+               {1,"Pounding Headache",0},\r
+               {1,"Into the Dungeons",0},\r
+               {1,"Ultimate Conquest",0},\r
+\r
+               {1,"Kill the S.O.B.",0},\r
+               {1,"The Nazi Rap",0},\r
+               {1,"Twelfth Hour",0},\r
+               {1,"Zero Hour",0},\r
+               {1,"Ultimate Conquest",0},\r
+               {1,"Wolfpack",0}\r
+       };\r
+#else\r
+CP_iteminfo MusicItems={CTL_X,CTL_Y-20,9,0,32};\r
+CP_itemtype far MusicMenu[]=\r
+   {\r
+               {1,"Funky Colonel Bill",0},\r
+               {1,"Death To The Nazis",0},\r
+               {1,"Tiptoeing Around",0},\r
+               {1,"Is This THE END?",0},\r
+               {1,"Evil Incarnate",0},\r
+               {1,"Jazzin' Them Nazis",0},\r
+               {1,"Puttin' It To The Enemy",0},\r
+               {1,"The SS Gonna Get You",0},\r
+               {1,"Towering Above",0}\r
+       };\r
+#endif\r
+\r
+#ifndef SPEARDEMO\r
+void DoJukebox(void)\r
+{\r
+       int which,lastsong=-1;\r
+       unsigned start,songs[]=\r
+               {\r
+#ifndef SPEAR\r
+                       GETTHEM_MUS,\r
+                       SEARCHN_MUS,\r
+                       POW_MUS,\r
+                       SUSPENSE_MUS,\r
+                       WARMARCH_MUS,\r
+                       CORNER_MUS,\r
+\r
+                       NAZI_OMI_MUS,\r
+                       PREGNANT_MUS,\r
+                       GOINGAFT_MUS,\r
+                       HEADACHE_MUS,\r
+                       DUNGEON_MUS,\r
+                       ULTIMATE_MUS,\r
+\r
+                       INTROCW3_MUS,\r
+                       NAZI_RAP_MUS,\r
+                       TWELFTH_MUS,\r
+                       ZEROHOUR_MUS,\r
+                       ULTIMATE_MUS,\r
+                       PACMAN_MUS\r
+#else\r
+                       XFUNKIE_MUS,             // 0\r
+                       XDEATH_MUS,              // 2\r
+                       XTIPTOE_MUS,             // 4\r
+                       XTHEEND_MUS,             // 7\r
+                       XEVIL_MUS,               // 17\r
+                       XJAZNAZI_MUS,            // 18\r
+                       XPUTIT_MUS,              // 21\r
+                       XGETYOU_MUS,             // 22\r
+                       XTOWER2_MUS              // 23\r
+#endif\r
+               };\r
+       struct dostime_t time;\r
+\r
+\r
+\r
+       IN_ClearKeysDown();\r
+       if (!AdLibPresent && !SoundBlasterPresent)\r
+               return;\r
+\r
+\r
+       MenuFadeOut();\r
+\r
+#ifndef SPEAR\r
+#ifndef UPLOAD\r
+       _dos_gettime(&time);\r
+       start = (time.hsecond%3)*6;\r
+#else\r
+       start = 0;\r
+#endif\r
+#else\r
+       start = 0;\r
+#endif\r
+\r
+\r
+       CA_CacheGrChunk (STARTFONT+1);\r
+#ifdef SPEAR\r
+       CacheLump (BACKDROP_LUMP_START,BACKDROP_LUMP_END);\r
+#else\r
+       CacheLump (CONTROLS_LUMP_START,CONTROLS_LUMP_END);\r
+#endif\r
+       CA_LoadAllSounds ();\r
+\r
+       fontnumber=1;\r
+       ClearMScreen ();\r
+       VWB_DrawPic(112,184,C_MOUSELBACKPIC);\r
+       DrawStripes (10);\r
+       SETFONTCOLOR (TEXTCOLOR,BKGDCOLOR);\r
+\r
+#ifndef SPEAR\r
+       DrawWindow (CTL_X-2,CTL_Y-6,280,13*7,BKGDCOLOR);\r
+#else\r
+       DrawWindow (CTL_X-2,CTL_Y-26,280,13*10,BKGDCOLOR);\r
+#endif\r
+\r
+       DrawMenu (&MusicItems,&MusicMenu[start]);\r
+\r
+       SETFONTCOLOR (READHCOLOR,BKGDCOLOR);\r
+       PrintY=15;\r
+       WindowX = 0;\r
+       WindowY = 320;\r
+       US_CPrint ("Robert's Jukebox");\r
+\r
+       SETFONTCOLOR (TEXTCOLOR,BKGDCOLOR);\r
+       VW_UpdateScreen();\r
+       MenuFadeIn();\r
+\r
+       do\r
+       {\r
+               which = HandleMenu(&MusicItems,&MusicMenu[start],NULL);\r
+               if (which>=0)\r
+               {\r
+                       if (lastsong >= 0)\r
+                               MusicMenu[start+lastsong].active = 1;\r
+\r
+                       StartCPMusic(songs[start + which]);\r
+                       MusicMenu[start+which].active = 2;\r
+                       DrawMenu (&MusicItems,&MusicMenu[start]);\r
+                       VW_UpdateScreen();\r
+                       lastsong = which;\r
+               }\r
+       } while(which>=0);\r
+\r
+       MenuFadeOut();\r
+       IN_ClearKeysDown();\r
+#ifdef SPEAR\r
+       UnCacheLump (BACKDROP_LUMP_START,BACKDROP_LUMP_END);\r
+#else\r
+       UnCacheLump (CONTROLS_LUMP_START,CONTROLS_LUMP_END);\r
+#endif\r
+}\r
+#endif\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
+       int                     i,x,y;\r
+       unsigned        *blockstart;\r
+\r
+       if (MS_CheckParm ("virtual"))\r
+               virtualreality = true;\r
+       else\r
+               virtualreality = false;\r
+\r
+       MM_Startup ();                  // so the signon screen can be freed\r
+\r
+       SignonScreen ();\r
+\r
+       VW_Startup ();\r
+       IN_Startup ();\r
+       PM_Startup ();\r
+       PM_UnlockMainMem ();\r
+       SD_Startup ();\r
+       CA_Startup ();\r
+       US_Startup ();\r
+\r
+\r
+#ifndef SPEAR\r
+       if (mminfo.mainmem < 235000L)\r
+#else\r
+       if (mminfo.mainmem < 257000L && !MS_CheckParm("debugmode"))\r
+#endif\r
+       {\r
+               memptr screen;\r
+\r
+               CA_CacheGrChunk (ERRORSCREEN);\r
+               screen = grsegs[ERRORSCREEN];\r
+               ShutdownId();\r
+               movedata ((unsigned)screen,7+7*160,0xb800,0,17*160);\r
+               gotoxy (1,23);\r
+               exit(1);\r
+       }\r
+\r
+\r
+//\r
+// build some tables\r
+//\r
+       InitDigiMap ();\r
+\r
+       for (i=0;i<MAPSIZE;i++)\r
+       {\r
+               nearmapylookup[i] = &tilemap[0][0]+MAPSIZE*i;\r
+               farmapylookup[i] = i*64;\r
+       }\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
+       updateptr = &update[0];\r
+\r
+       bufferofs = 0;\r
+       displayofs = 0;\r
+       ReadConfig ();\r
+\r
+\r
+//\r
+// HOLDING DOWN 'M' KEY?\r
+//\r
+#ifndef SPEARDEMO\r
+       if (Keyboard[sc_M])\r
+         DoJukebox();\r
+       else\r
+#endif\r
+//\r
+// draw intro screen stuff\r
+//\r
+       if (!virtualreality)\r
+               IntroScreen ();\r
+\r
+//\r
+// load in and lock down some basic chunks\r
+//\r
+\r
+       CA_CacheGrChunk(STARTFONT);\r
+       MM_SetLock (&grsegs[STARTFONT],true);\r
+\r
+       LoadLatchMem ();\r
+       BuildTables ();          // trig tables\r
+       SetupWalls ();\r
+\r
+#if 0\r
+{\r
+int temp,i;\r
+temp = viewsize;\r
+       profilehandle = open("SCALERS.TXT", O_CREAT | O_WRONLY | O_TEXT);\r
+for (i=1;i<20;i++)\r
+       NewViewSize(i);\r
+viewsize = temp;\r
+close(profilehandle);\r
+}\r
+#endif\r
+\r
+       NewViewSize (viewsize);\r
+\r
+\r
+//\r
+// initialize variables\r
+//\r
+       InitRedShifts ();\r
+       if (!virtualreality)\r
+               FinishSignon();\r
+\r
+       displayofs = PAGE1START;\r
+       bufferofs = PAGE2START;\r
+\r
+       if (virtualreality)\r
+       {\r
+               NoWait = true;\r
+               geninterrupt(0x60);\r
+       }\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+==========================\r
+=\r
+= SetViewSize\r
+=\r
+==========================\r
+*/\r
+\r
+boolean SetViewSize (unsigned width, unsigned height)\r
+{\r
+       viewwidth = width&~15;                  // must be divisable by 16\r
+       viewheight = height&~1;                 // must be even\r
+       centerx = viewwidth/2-1;\r
+       shootdelta = viewwidth/10;\r
+       screenofs = ((200-STATUSLINES-viewheight)/2*SCREENWIDTH+(320-viewwidth)/8);\r
+\r
+//\r
+// calculate trace angles and projection constants\r
+//\r
+       CalcProjection (FOCALLENGTH);\r
+\r
+//\r
+// build all needed compiled scalers\r
+//\r
+//     MM_BombOnError (false);\r
+       SetupScaling (viewwidth*1.5);\r
+#if 0\r
+       MM_BombOnError (true);\r
+       if (mmerror)\r
+       {\r
+               Quit ("Can't build scalers!");\r
+               mmerror = false;\r
+               return false;\r
+       }\r
+#endif\r
+       return true;\r
+}\r
+\r
+\r
+void ShowViewSize (int width)\r
+{\r
+       int     oldwidth,oldheight;\r
+\r
+       oldwidth = viewwidth;\r
+       oldheight = viewheight;\r
+\r
+       viewwidth = width*16;\r
+       viewheight = width*16*HEIGHTRATIO;\r
+       DrawPlayBorder ();\r
+\r
+       viewheight = oldheight;\r
+       viewwidth = oldwidth;\r
+}\r
+\r
+\r
+void NewViewSize (int width)\r
+{\r
+       CA_UpLevel ();\r
+       MM_SortMem ();\r
+       viewsize = width;\r
+       SetViewSize (width*16,width*16*HEIGHTRATIO);\r
+       CA_DownLevel ();\r
+}\r
+\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+==========================\r
+=\r
+= Quit\r
+=\r
+==========================\r
+*/\r
+\r
+void Quit (char *error)\r
+{\r
+       unsigned        finscreen;\r
+       memptr  screen;\r
+\r
+       if (virtualreality)\r
+               geninterrupt(0x61);\r
+\r
+       ClearMemory ();\r
+       if (!*error)\r
+       {\r
+        #ifndef JAPAN\r
+        CA_CacheGrChunk (ORDERSCREEN);\r
+        screen = grsegs[ORDERSCREEN];\r
+        #endif\r
+        WriteConfig ();\r
+       }\r
+       else\r
+       {\r
+        CA_CacheGrChunk (ERRORSCREEN);\r
+        screen = grsegs[ERRORSCREEN];\r
+       }\r
+\r
+       ShutdownId ();\r
+\r
+       if (error && *error)\r
+       {\r
+         movedata ((unsigned)screen,7,0xb800,0,7*160);\r
+         gotoxy (10,4);\r
+         puts(error);\r
+         gotoxy (1,8);\r
+         exit(1);\r
+       }\r
+       else\r
+       if (!error || !(*error))\r
+       {\r
+               clrscr();\r
+               #ifndef JAPAN\r
+               movedata ((unsigned)screen,7,0xb800,0,4000);\r
+               gotoxy(1,24);\r
+               #endif\r
+//asm  mov     bh,0\r
+//asm  mov     dh,23   // row\r
+//asm  mov     dl,0    // collumn\r
+//asm  mov ah,2\r
+//asm  int     0x10\r
+       }\r
+\r
+       exit(0);\r
+}\r
+\r
+//===========================================================================\r
+\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= DemoLoop\r
+=\r
+=====================\r
+*/\r
+\r
+static  char *ParmStrings[] = {"baby","easy","normal","hard",""};\r
+\r
+void    DemoLoop (void)\r
+{\r
+       static int LastDemo;\r
+       int     i,level;\r
+       long nsize;\r
+       memptr  nullblock;\r
+\r
+//\r
+// check for launch from ted\r
+//\r
+       if (tedlevel)\r
+       {\r
+               NoWait = true;\r
+               NewGame(1,0);\r
+\r
+               for (i = 1;i < _argc;i++)\r
+               {\r
+                       if ( (level = US_CheckParm(_argv[i],ParmStrings)) != -1)\r
+                       {\r
+                        gamestate.difficulty=level;\r
+                        break;\r
+                       }\r
+               }\r
+\r
+#ifndef SPEAR\r
+               gamestate.episode = tedlevelnum/10;\r
+               gamestate.mapon = tedlevelnum%10;\r
+#else\r
+               gamestate.episode = 0;\r
+               gamestate.mapon = tedlevelnum;\r
+#endif\r
+               GameLoop();\r
+               Quit (NULL);\r
+       }\r
+\r
+\r
+//\r
+// main game cycle\r
+//\r
+\r
+\r
+//     nsize = (long)40*1024;\r
+//     MM_GetPtr(&nullblock,nsize);\r
+\r
+#ifndef DEMOTEST\r
+\r
+       #ifndef UPLOAD\r
+\r
+               #ifndef GOODTIMES\r
+               #ifndef SPEAR\r
+               #ifndef JAPAN\r
+               if (!NoWait)\r
+                       NonShareware();\r
+               #endif\r
+               #else\r
+\r
+                       #ifndef GOODTIMES\r
+                       #ifndef SPEARDEMO\r
+                       CopyProtection();\r
+                       #endif\r
+                       #endif\r
+\r
+               #endif\r
+               #endif\r
+       #endif\r
+\r
+       StartCPMusic(INTROSONG);\r
+\r
+#ifndef JAPAN\r
+       if (!NoWait)\r
+               PG13 ();\r
+#endif\r
+\r
+#endif\r
+\r
+       while (1)\r
+       {\r
+               while (!NoWait)\r
+               {\r
+//\r
+// title page\r
+//\r
+                       MM_SortMem ();\r
+#ifndef DEMOTEST\r
+\r
+#ifdef SPEAR\r
+                       CA_CacheGrChunk (TITLEPALETTE);\r
+\r
+                       CA_CacheGrChunk (TITLE1PIC);\r
+                       VWB_DrawPic (0,0,TITLE1PIC);\r
+                       UNCACHEGRCHUNK (TITLE1PIC);\r
+\r
+                       CA_CacheGrChunk (TITLE2PIC);\r
+                       VWB_DrawPic (0,80,TITLE2PIC);\r
+                       UNCACHEGRCHUNK (TITLE2PIC);\r
+                       VW_UpdateScreen ();\r
+                       VL_FadeIn(0,255,grsegs[TITLEPALETTE],30);\r
+\r
+                       UNCACHEGRCHUNK (TITLEPALETTE);\r
+#else\r
+                       CA_CacheScreen (TITLEPIC);\r
+                       VW_UpdateScreen ();\r
+                       VW_FadeIn();\r
+#endif\r
+                       if (IN_UserInput(TickBase*15))\r
+                               break;\r
+                       VW_FadeOut();\r
+//\r
+// credits page\r
+//\r
+                       CA_CacheScreen (CREDITSPIC);\r
+                       VW_UpdateScreen();\r
+                       VW_FadeIn ();\r
+                       if (IN_UserInput(TickBase*10))\r
+                               break;\r
+                       VW_FadeOut ();\r
+//\r
+// high scores\r
+//\r
+                       DrawHighScores ();\r
+                       VW_UpdateScreen ();\r
+                       VW_FadeIn ();\r
+\r
+                       if (IN_UserInput(TickBase*10))\r
+                               break;\r
+#endif\r
+//\r
+// demo\r
+//\r
+\r
+                       #ifndef SPEARDEMO\r
+                       PlayDemo (LastDemo++%4);\r
+                       #else\r
+                       PlayDemo (0);\r
+                       #endif\r
+\r
+                       if (playstate == ex_abort)\r
+                               break;\r
+                       StartCPMusic(INTROSONG);\r
+               }\r
+\r
+               VW_FadeOut ();\r
+\r
+#ifndef SPEAR\r
+               if (Keyboard[sc_Tab] && MS_CheckParm("goobers"))\r
+#else\r
+               if (Keyboard[sc_Tab] && MS_CheckParm("debugmode"))\r
+#endif\r
+                       RecordDemo ();\r
+               else\r
+                       US_ControlPanel (0);\r
+\r
+               if (startgame || loadedgame)\r
+               {\r
+                       GameLoop ();\r
+                       VW_FadeOut();\r
+                       StartCPMusic(INTROSONG);\r
+               }\r
+       }\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+==========================\r
+=\r
+= main\r
+=\r
+==========================\r
+*/\r
+\r
+char    *nosprtxt[] = {"nospr",nil};\r
+\r
+void main (void)\r
+{\r
+       int     i;\r
+\r
+\r
+#ifdef BETA\r
+       //\r
+       // THIS IS FOR BETA ONLY!\r
+       //\r
+       struct dosdate_t d;\r
+\r
+       _dos_getdate(&d);\r
+       if (d.year > YEAR ||\r
+               (d.month >= MONTH && d.day >= DAY))\r
+       {\r
+        printf("Sorry, BETA-TESTING is over. Thanks for you help.\n");\r
+        exit(1);\r
+       }\r
+#endif\r
+\r
+       CheckForEpisodes();\r
+\r
+       Patch386 ();\r
+\r
+       InitGame ();\r
+\r
+       DemoLoop();\r
+\r
+       Quit("Demo loop exited???");\r
+}\r
+\r
diff --git a/src/lib/hb/wl_menu.c b/src/lib/hb/wl_menu.c
new file mode 100755 (executable)
index 0000000..7d1521c
--- /dev/null
@@ -0,0 +1,3986 @@
+////////////////////////////////////////////////////////////////////\r
+//\r
+// WL_MENU.C\r
+// by John Romero (C) 1992 Id Software, Inc.\r
+//\r
+////////////////////////////////////////////////////////////////////\r
+#include "wl_def.h"\r
+#pragma hdrstop\r
+\r
+//\r
+// PRIVATE PROTOTYPES\r
+//\r
+void CP_ReadThis(void);\r
+\r
+#ifdef SPEAR\r
+#define STARTITEM      newgame\r
+\r
+#else\r
+#ifdef GOODTIMES\r
+#define STARTITEM      newgame\r
+\r
+#else\r
+#define STARTITEM      readthis\r
+#endif\r
+#endif\r
+\r
+char far endStrings[9][80]=\r
+{\r
+#ifndef SPEAR\r
+       {"Dost thou wish to\nleave with such hasty\nabandon?"},\r
+       {"Chickening out...\nalready?"},\r
+       {"Press N for more carnage.\nPress Y to be a weenie."},\r
+       {"So, you think you can\nquit this easily, huh?"},\r
+       {"Press N to save the world.\nPress Y to abandon it in\nits hour of need."},\r
+       {"Press N if you are brave.\nPress Y to cower in shame."},\r
+       {"Heroes, press N.\nWimps, press Y."},\r
+       {"You are at an intersection.\nA sign says, 'Press Y to quit.'\n>"},\r
+       {"For guns and glory, press N.\nFor work and worry, press Y."}\r
+#else\r
+       ENDSTR1,\r
+       ENDSTR2,\r
+       ENDSTR3,\r
+       ENDSTR4,\r
+       ENDSTR5,\r
+       ENDSTR6,\r
+       ENDSTR7,\r
+       ENDSTR8,\r
+       ENDSTR9\r
+#endif\r
+};\r
+\r
+CP_iteminfo\r
+       MainItems={MENU_X,MENU_Y,10,STARTITEM,24},\r
+       SndItems={SM_X,SM_Y1,12,0,52},\r
+       LSItems={LSM_X,LSM_Y,10,0,24},\r
+       CtlItems={CTL_X,CTL_Y,6,-1,56},\r
+       CusItems={8,CST_Y+13*2,9,-1,0},\r
+       NewEitems={NE_X,NE_Y,11,0,88},\r
+       NewItems={NM_X,NM_Y,4,2,24};\r
+\r
+#pragma warn -sus\r
+CP_itemtype far\r
+MainMenu[]=\r
+{\r
+#ifdef JAPAN\r
+       {1,"",CP_NewGame},\r
+       {1,"",CP_Sound},\r
+       {1,"",CP_Control},\r
+       {1,"",CP_LoadGame},\r
+       {0,"",CP_SaveGame},\r
+       {1,"",CP_ChangeView},\r
+       {2,"",CP_ReadThis},\r
+       {1,"",CP_ViewScores},\r
+       {1,"",0},\r
+       {1,"",0}\r
+#else\r
+\r
+       {1,STR_NG,CP_NewGame},\r
+       {1,STR_SD,CP_Sound},\r
+       {1,STR_CL,CP_Control},\r
+       {1,STR_LG,CP_LoadGame},\r
+       {0,STR_SG,CP_SaveGame},\r
+       {1,STR_CV,CP_ChangeView},\r
+\r
+#ifndef GOODTIMES\r
+#ifndef SPEAR\r
+\r
+       #ifdef SPANISH\r
+       {2,"Ve esto!",CP_ReadThis},\r
+       #else\r
+       {2,"Read This!",CP_ReadThis},\r
+       #endif\r
+\r
+#endif\r
+#endif\r
+\r
+       {1,STR_VS,CP_ViewScores},\r
+       {1,STR_BD,0},\r
+       {1,STR_QT,0}\r
+#endif\r
+},\r
+\r
+far SndMenu[]=\r
+{\r
+#ifdef JAPAN\r
+       {1,"",0},\r
+       {1,"",0},\r
+       {1,"",0},\r
+       {0,"",0},\r
+       {0,"",0},\r
+       {1,"",0},\r
+       {1,"",0},\r
+       {1,"",0},\r
+       {0,"",0},\r
+       {0,"",0},\r
+       {1,"",0},\r
+       {1,"",0},\r
+#else\r
+       {1,STR_NONE,0},\r
+       {1,STR_PC,0},\r
+       {1,STR_ALSB,0},\r
+       {0,"",0},\r
+       {0,"",0},\r
+       {1,STR_NONE,0},\r
+       {1,STR_DISNEY,0},\r
+       {1,STR_SB,0},\r
+       {0,"",0},\r
+       {0,"",0},\r
+       {1,STR_NONE,0},\r
+       {1,STR_ALSB,0}\r
+#endif\r
+},\r
+\r
+far CtlMenu[]=\r
+{\r
+#ifdef JAPAN\r
+       {0,"",0},\r
+       {0,"",0},\r
+       {0,"",0},\r
+       {0,"",0},\r
+       {0,"",MouseSensitivity},\r
+       {1,"",CustomControls}\r
+#else\r
+       {0,STR_MOUSEEN,0},\r
+       {0,STR_JOYEN,0},\r
+       {0,STR_PORT2,0},\r
+       {0,STR_GAMEPAD,0},\r
+       {0,STR_SENS,MouseSensitivity},\r
+       {1,STR_CUSTOM,CustomControls}\r
+#endif\r
+},\r
+\r
+#pragma warn +sus\r
+\r
+#ifndef SPEAR\r
+far NewEmenu[]=\r
+{\r
+#ifdef JAPAN\r
+#ifdef JAPDEMO\r
+       {1,"",0},\r
+       {0,"",0},\r
+       {0,"",0},\r
+       {0,"",0},\r
+       {0,"",0},\r
+       {0,"",0},\r
+       {0,"",0},\r
+       {0,"",0},\r
+       {0,"",0},\r
+       {0,"",0},\r
+       {0,"",0},\r
+       {0,"",0},\r
+#else\r
+       {1,"",0},\r
+       {0,"",0},\r
+       {1,"",0},\r
+       {0,"",0},\r
+       {1,"",0},\r
+       {0,"",0},\r
+       {1,"",0},\r
+       {0,"",0},\r
+       {1,"",0},\r
+       {0,"",0},\r
+       {1,"",0},\r
+       {0,"",0}\r
+#endif\r
+#else\r
+       #ifdef SPANISH\r
+       {1,"Episodio 1\n"\r
+          "Fuga desde Wolfenstein",0},\r
+       {0,"",0},\r
+       {3,"Episodio 2\n"\r
+                  "Operacion Eisenfaust",0},\r
+       {0,"",0},\r
+       {3,"Episodio 3\n"\r
+                  "Muere, Fuhrer, Muere!",0},\r
+       {0,"",0},\r
+       {3,"Episodio 4\n"\r
+                 "Un Negro Secreto",0},\r
+       {0,"",0},\r
+       {3,"Episodio 5\n"\r
+                 "Huellas del Loco",0},\r
+       {0,"",0},\r
+       {3,"Episodio 6\n"\r
+                 "Confrontacion",0}\r
+       #else\r
+       {1,"Episode 1\n"\r
+          "Escape from Wolfenstein",0},\r
+       {0,"",0},\r
+       {3,"Episode 2\n"\r
+                  "Operation: Eisenfaust",0},\r
+       {0,"",0},\r
+       {3,"Episode 3\n"\r
+                  "Die, Fuhrer, Die!",0},\r
+       {0,"",0},\r
+       {3,"Episode 4\n"\r
+                 "A Dark Secret",0},\r
+       {0,"",0},\r
+       {3,"Episode 5\n"\r
+                 "Trail of the Madman",0},\r
+       {0,"",0},\r
+       {3,"Episode 6\n"\r
+                 "Confrontation",0}\r
+       #endif\r
+#endif\r
+},\r
+#endif\r
+\r
+\r
+far NewMenu[]=\r
+{\r
+#ifdef JAPAN\r
+       {1,"",0},\r
+       {1,"",0},\r
+       {1,"",0},\r
+       {1,"",0}\r
+#else\r
+       {1,STR_DADDY,0},\r
+       {1,STR_HURTME,0},\r
+       {1,STR_BRINGEM,0},\r
+       {1,STR_DEATH,0}\r
+#endif\r
+},\r
+\r
+far LSMenu[]=\r
+{\r
+       {1,"",0},\r
+       {1,"",0},\r
+       {1,"",0},\r
+       {1,"",0},\r
+       {1,"",0},\r
+       {1,"",0},\r
+       {1,"",0},\r
+       {1,"",0},\r
+       {1,"",0},\r
+       {1,"",0}\r
+},\r
+\r
+far CusMenu[]=\r
+{\r
+       {1,"",0},\r
+       {0,"",0},\r
+       {0,"",0},\r
+       {1,"",0},\r
+       {0,"",0},\r
+       {0,"",0},\r
+       {1,"",0},\r
+       {0,"",0},\r
+       {1,"",0}\r
+}\r
+;\r
+\r
+\r
+int color_hlite[]={\r
+   DEACTIVE,\r
+   HIGHLIGHT,\r
+   READHCOLOR,\r
+   0x67\r
+   },\r
+\r
+   color_norml[]={\r
+   DEACTIVE,\r
+   TEXTCOLOR,\r
+   READCOLOR,\r
+   0x6b\r
+   };\r
+\r
+int EpisodeSelect[6]={1};\r
+\r
+\r
+int SaveGamesAvail[10],StartGame,SoundStatus=1,pickquick;\r
+char SaveGameNames[10][32],SaveName[13]="SAVEGAM?.";\r
+\r
+\r
+////////////////////////////////////////////////////////////////////\r
+//\r
+// INPUT MANAGER SCANCODE TABLES\r
+//\r
+////////////////////////////////////////////////////////////////////\r
+static byte\r
+                                       *ScanNames[] =          // Scan code names with single chars\r
+                                       {\r
+       "?","?","1","2","3","4","5","6","7","8","9","0","-","+","?","?",\r
+       "Q","W","E","R","T","Y","U","I","O","P","[","]","|","?","A","S",\r
+       "D","F","G","H","J","K","L",";","\"","?","?","?","Z","X","C","V",\r
+       "B","N","M",",",".","/","?","?","?","?","?","?","?","?","?","?",\r
+       "?","?","?","?","?","?","?","?","\xf","?","-","\x15","5","\x11","+","?",\r
+       "\x13","?","?","?","?","?","?","?","?","?","?","?","?","?","?","?",\r
+       "?","?","?","?","?","?","?","?","?","?","?","?","?","?","?","?",\r
+       "?","?","?","?","?","?","?","?","?","?","?","?","?","?","?","?"\r
+                                       },      // DEBUG - consolidate these\r
+                                       far ExtScanCodes[] =    // Scan codes with >1 char names\r
+                                       {\r
+       1,0xe,0xf,0x1d,0x2a,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,\r
+       0x3f,0x40,0x41,0x42,0x43,0x44,0x57,0x59,0x46,0x1c,0x36,\r
+       0x37,0x38,0x47,0x49,0x4f,0x51,0x52,0x53,0x45,0x48,\r
+       0x50,0x4b,0x4d,0x00\r
+                                       },\r
+                                       *ExtScanNames[] =       // Names corresponding to ExtScanCodes\r
+                                       {\r
+       "Esc","BkSp","Tab","Ctrl","LShft","Space","CapsLk","F1","F2","F3","F4",\r
+       "F5","F6","F7","F8","F9","F10","F11","F12","ScrlLk","Enter","RShft",\r
+       "PrtSc","Alt","Home","PgUp","End","PgDn","Ins","Del","NumLk","Up",\r
+       "Down","Left","Right",""\r
+                                       };\r
+\r
+\r
+////////////////////////////////////////////////////////////////////\r
+//\r
+// Wolfenstein Control Panel!  Ta Da!\r
+//\r
+////////////////////////////////////////////////////////////////////\r
+void US_ControlPanel(byte scancode)\r
+{\r
+       int which,i,start;\r
+\r
+\r
+       if (ingame)\r
+               if (CP_CheckQuick(scancode))\r
+                       return;\r
+\r
+       StartCPMusic(MENUSONG);\r
+       SetupControlPanel();\r
+\r
+       //\r
+       // F-KEYS FROM WITHIN GAME\r
+       //\r
+       switch(scancode)\r
+       {\r
+               case sc_F1:\r
+                       #ifdef SPEAR\r
+                       BossKey();\r
+                       #else\r
+                       #ifdef GOODTIMES\r
+                       BossKey();\r
+                       #else\r
+                       HelpScreens();\r
+                       #endif\r
+                       #endif\r
+                       goto finishup;\r
+\r
+               case sc_F2:\r
+                       CP_SaveGame(0);\r
+                       goto finishup;\r
+\r
+               case sc_F3:\r
+                       CP_LoadGame(0);\r
+                       goto finishup;\r
+\r
+               case sc_F4:\r
+                       CP_Sound();\r
+                       goto finishup;\r
+\r
+               case sc_F5:\r
+                       CP_ChangeView();\r
+                       goto finishup;\r
+\r
+               case sc_F6:\r
+                       CP_Control();\r
+                       goto finishup;\r
+\r
+               finishup:\r
+                       CleanupControlPanel();\r
+                       #ifdef SPEAR\r
+                       UnCacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END);\r
+                       #endif\r
+                       return;\r
+       }\r
+\r
+#ifdef SPEAR\r
+       CacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END);\r
+#endif\r
+\r
+       DrawMainMenu();\r
+       MenuFadeIn();\r
+       StartGame=0;\r
+\r
+       //\r
+       // MAIN MENU LOOP\r
+       //\r
+       do\r
+       {\r
+               which=HandleMenu(&MainItems,&MainMenu[0],NULL);\r
+\r
+               #ifdef SPEAR\r
+               #ifndef SPEARDEMO\r
+               //\r
+               // EASTER EGG FOR SPEAR OF DESTINY!\r
+               //\r
+               if (Keyboard[sc_I] && Keyboard[sc_D])\r
+               {\r
+                       VW_FadeOut();\r
+                       StartCPMusic (XJAZNAZI_MUS);\r
+                       UnCacheLump(OPTIONS_LUMP_START,OPTIONS_LUMP_END);\r
+                       UnCacheLump(BACKDROP_LUMP_START,BACKDROP_LUMP_END);\r
+                       MM_SortMem ();\r
+                       ClearMemory ();\r
+\r
+\r
+                       CA_CacheGrChunk (IDGUYS1PIC);\r
+                       VWB_DrawPic(0,0,IDGUYS1PIC);\r
+                       UNCACHEGRCHUNK(IDGUYS1PIC);\r
+\r
+                       CA_CacheGrChunk (IDGUYS2PIC);\r
+                       VWB_DrawPic(0,80,IDGUYS2PIC);\r
+                       UNCACHEGRCHUNK(IDGUYS2PIC);\r
+\r
+                       VW_UpdateScreen();\r
+\r
+                       CA_CacheGrChunk (IDGUYSPALETTE);\r
+                       VL_FadeIn(0,255,grsegs[IDGUYSPALETTE],30);\r
+                       UNCACHEGRCHUNK(IDGUYSPALETTE);\r
+\r
+                       while (Keyboard[sc_I] || Keyboard[sc_D]);\r
+                       IN_ClearKeysDown();\r
+                       IN_Ack();\r
+\r
+                       VW_FadeOut();\r
+\r
+                       CacheLump(BACKDROP_LUMP_START,BACKDROP_LUMP_END);\r
+                       CacheLump(OPTIONS_LUMP_START,OPTIONS_LUMP_END);\r
+                       DrawMainMenu();\r
+                       StartCPMusic (MENUSONG);\r
+                       MenuFadeIn();\r
+               }\r
+               #endif\r
+               #endif\r
+\r
+               switch(which)\r
+               {\r
+                       case viewscores:\r
+                               if (MainMenu[viewscores].routine == NULL)\r
+                                       if (CP_EndGame())\r
+                                               StartGame=1;\r
+\r
+                               DrawMainMenu();\r
+                               MenuFadeIn();\r
+                               break;\r
+\r
+                       case backtodemo:\r
+                               #ifdef SPEAR\r
+                               if (!ingame)\r
+                               {\r
+                                       //\r
+                                       // DEALLOCATE ALL SOUNDS!\r
+                                       //\r
+                                       switch (SoundMode)\r
+                                       {\r
+                                               case sdm_PC:\r
+                                                       start = STARTPCSOUNDS;\r
+                                                       break;\r
+                                               case sdm_AdLib:\r
+                                                       start = STARTADLIBSOUNDS;\r
+                                                       break;\r
+                                       }\r
+\r
+                                       if (SoundMode != sdm_Off)\r
+                                               for (i=0;i<NUMSOUNDS;i++,start++)\r
+                                                       if (audiosegs[start])\r
+                                                               MM_SetPurge (&(memptr)audiosegs[start],3);              // make purgable\r
+                               }\r
+                               #endif\r
+\r
+                               MM_SortMem();\r
+                               StartGame=1;\r
+                               if (!ingame)\r
+                                       StartCPMusic(INTROSONG);\r
+                               VL_FadeOut(0,255,0,0,0,10);\r
+                               break;\r
+\r
+                       case -1:\r
+                       case quit:\r
+                               CP_Quit();\r
+                               break;\r
+\r
+                       default:\r
+                               if (!StartGame)\r
+                               {\r
+                                       DrawMainMenu();\r
+                                       MenuFadeIn();\r
+                               }\r
+               }\r
+\r
+       //\r
+       // "EXIT OPTIONS" OR "NEW GAME" EXITS\r
+       //\r
+       } while(!StartGame);\r
+\r
+       //\r
+       // DEALLOCATE EVERYTHING\r
+       //\r
+       CleanupControlPanel();\r
+\r
+       //\r
+       // CHANGE MAINMENU ITEM\r
+       //\r
+       if (startgame || loadedgame)\r
+       {\r
+               #pragma warn -sus\r
+               MainMenu[viewscores].routine = NULL;\r
+               #ifndef JAPAN\r
+               _fstrcpy(MainMenu[viewscores].string,STR_EG);\r
+               #endif\r
+               #pragma warn +sus\r
+       }\r
+\r
+       // RETURN/START GAME EXECUTION\r
+\r
+#ifdef SPEAR\r
+       UnCacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END);\r
+       MM_SortMem ();\r
+#endif\r
+}\r
+\r
+\r
+////////////////////////\r
+//\r
+// DRAW MAIN MENU SCREEN\r
+//\r
+void DrawMainMenu(void)\r
+{\r
+#ifdef JAPAN\r
+       CA_CacheScreen(S_OPTIONSPIC);\r
+#else\r
+       ClearMScreen();\r
+\r
+       VWB_DrawPic(112,184,C_MOUSELBACKPIC);\r
+       DrawStripes(10);\r
+       VWB_DrawPic(84,0,C_OPTIONSPIC);\r
+\r
+       #ifdef SPANISH\r
+       DrawWindow(MENU_X-8,MENU_Y-3,MENU_W+8,MENU_H,BKGDCOLOR);\r
+       #else\r
+       DrawWindow(MENU_X-8,MENU_Y-3,MENU_W,MENU_H,BKGDCOLOR);\r
+       #endif\r
+#endif\r
+\r
+       //\r
+       // CHANGE "GAME" AND "DEMO"\r
+       //\r
+       if (ingame)\r
+       {\r
+               #ifndef JAPAN\r
+\r
+               #ifdef SPANISH\r
+               _fstrcpy(&MainMenu[backtodemo].string,STR_GAME);\r
+               #else\r
+               _fstrcpy(&MainMenu[backtodemo].string[8],STR_GAME);\r
+               #endif\r
+\r
+               #else\r
+               CA_CacheGrChunk(C_MRETGAMEPIC);\r
+               VWB_DrawPic(12*8,20*8,C_MRETGAMEPIC);\r
+               UNCACHEGRCHUNK(C_MRETGAMEPIC);\r
+               CA_CacheGrChunk(C_MENDGAMEPIC);\r
+               VWB_DrawPic(12*8,18*8,C_MENDGAMEPIC);\r
+               UNCACHEGRCHUNK(C_MENDGAMEPIC);\r
+               #endif\r
+               MainMenu[backtodemo].active=2;\r
+       }\r
+       else\r
+       {\r
+               #ifndef JAPAN\r
+               #ifdef SPANISH\r
+               _fstrcpy(&MainMenu[backtodemo].string,STR_BD);\r
+               #else\r
+               _fstrcpy(&MainMenu[backtodemo].string[8],STR_DEMO);\r
+               #endif\r
+               #else\r
+               CA_CacheGrChunk(C_MRETDEMOPIC);\r
+               VWB_DrawPic(12*8,20*8,C_MRETDEMOPIC);\r
+               UNCACHEGRCHUNK(C_MRETDEMOPIC);\r
+               CA_CacheGrChunk(C_MSCORESPIC);\r
+               VWB_DrawPic(12*8,18*8,C_MSCORESPIC);\r
+               UNCACHEGRCHUNK(C_MSCORESPIC);\r
+               #endif\r
+               MainMenu[backtodemo].active=1;\r
+       }\r
+\r
+       DrawMenu(&MainItems,&MainMenu[0]);\r
+       VW_UpdateScreen();\r
+}\r
+\r
+#ifndef GOODTIMES\r
+#ifndef SPEAR\r
+////////////////////////////////////////////////////////////////////\r
+//\r
+// READ THIS!\r
+//\r
+////////////////////////////////////////////////////////////////////\r
+void CP_ReadThis(void)\r
+{\r
+       StartCPMusic(CORNER_MUS);\r
+       HelpScreens();\r
+       StartCPMusic(MENUSONG);\r
+}\r
+#endif\r
+#endif\r
+\r
+#ifndef SPEAR\r
+#ifndef GOODTIMES\r
+#else\r
+////////////////////////////////////////////////////////////////////\r
+//\r
+// BOSS KEY\r
+//\r
+////////////////////////////////////////////////////////////////////\r
+void BossKey(void)\r
+{\r
+       SD_MusicOff();\r
+       _AX = 3;\r
+       geninterrupt(0x10);\r
+       printf("C>");\r
+       while (!Keyboard[sc_Escape])\r
+       IN_ClearKeysDown();\r
+\r
+       SD_MusicOn();\r
+       VL_SetVGAPlaneMode ();\r
+       VL_TestPaletteSet ();\r
+       VL_SetPalette (&gamepal);\r
+       LoadLatchMem();\r
+}\r
+#endif\r
+#endif\r
+\r
+////////////////////////////////////////////////////////////////////\r
+//\r
+// CHECK QUICK-KEYS & QUIT (WHILE IN A GAME)\r
+//\r
+////////////////////////////////////////////////////////////////////\r
+int CP_CheckQuick(unsigned scancode)\r
+{\r
+       switch(scancode)\r
+       {\r
+               //\r
+               // END GAME\r
+               //\r
+               case sc_F7:\r
+                       CA_CacheGrChunk(STARTFONT+1);\r
+\r
+                       WindowH=160;\r
+                       #ifdef JAPAN\r
+                       if (GetYorN(7,8,C_JAPQUITPIC))\r
+                       #else\r
+                       if (Confirm(ENDGAMESTR))\r
+                       #endif\r
+                       {\r
+                               playstate = ex_died;\r
+                               pickquick = gamestate.lives = 0;\r
+                       }\r
+\r
+                       DrawAllPlayBorder();\r
+                       WindowH=200;\r
+                       fontnumber=0;\r
+                       MainMenu[savegame].active = 0;\r
+                       return 1;\r
+\r
+               //\r
+               // QUICKSAVE\r
+               //\r
+               case sc_F8:\r
+                       if (SaveGamesAvail[LSItems.curpos] && pickquick)\r
+                       {\r
+                               CA_CacheGrChunk(STARTFONT+1);\r
+                               fontnumber = 1;\r
+                               Message(STR_SAVING"...");\r
+                               CP_SaveGame(1);\r
+                               fontnumber=0;\r
+                       }\r
+                       else\r
+                       {\r
+                               #ifndef SPEAR\r
+                               CA_CacheGrChunk(STARTFONT+1);\r
+                               CA_CacheGrChunk(C_CURSOR1PIC);\r
+                               CA_CacheGrChunk(C_CURSOR2PIC);\r
+                               CA_CacheGrChunk(C_DISKLOADING1PIC);\r
+                               CA_CacheGrChunk(C_DISKLOADING2PIC);\r
+                               CA_CacheGrChunk(C_SAVEGAMEPIC);\r
+                               CA_CacheGrChunk(C_MOUSELBACKPIC);\r
+                               #else\r
+                               CacheLump (BACKDROP_LUMP_START,BACKDROP_LUMP_END);\r
+                               CA_CacheGrChunk(C_CURSOR1PIC);\r
+                               #endif\r
+\r
+                               VW_FadeOut ();\r
+\r
+                               StartCPMusic(MENUSONG);\r
+                               pickquick=CP_SaveGame(0);\r
+\r
+                               SETFONTCOLOR(0,15);\r
+                               IN_ClearKeysDown();\r
+                               DrawPlayScreen ();\r
+\r
+                               if (!startgame && !loadedgame)\r
+                               {\r
+                                       VW_FadeIn ();\r
+                                       StartMusic ();\r
+                               }\r
+\r
+                               if (loadedgame)\r
+                                       playstate = ex_abort;\r
+                               lasttimecount = TimeCount;\r
+\r
+                               if (MousePresent)\r
+                                       Mouse(MDelta);  // Clear accumulated mouse movement\r
+\r
+                               PM_CheckMainMem ();\r
+\r
+                               #ifndef SPEAR\r
+                               UNCACHEGRCHUNK(C_CURSOR1PIC);\r
+                               UNCACHEGRCHUNK(C_CURSOR2PIC);\r
+                               UNCACHEGRCHUNK(C_DISKLOADING1PIC);\r
+                               UNCACHEGRCHUNK(C_DISKLOADING2PIC);\r
+                               UNCACHEGRCHUNK(C_SAVEGAMEPIC);\r
+                               UNCACHEGRCHUNK(C_MOUSELBACKPIC);\r
+                               #else\r
+                               UnCacheLump (BACKDROP_LUMP_START,BACKDROP_LUMP_END);\r
+                               #endif\r
+                       }\r
+                       return 1;\r
+\r
+               //\r
+               // QUICKLOAD\r
+               //\r
+               case sc_F9:\r
+                       if (SaveGamesAvail[LSItems.curpos] && pickquick)\r
+                       {\r
+                               char string[100]=STR_LGC;\r
+\r
+\r
+                               CA_CacheGrChunk(STARTFONT+1);\r
+                               fontnumber = 1;\r
+\r
+                               strcat(string,SaveGameNames[LSItems.curpos]);\r
+                               strcat(string,"\"?");\r
+\r
+                               if (Confirm(string))\r
+                                       CP_LoadGame(1);\r
+\r
+                               DrawAllPlayBorder();\r
+                               fontnumber=0;\r
+                       }\r
+                       else\r
+                       {\r
+                               #ifndef SPEAR\r
+                               CA_CacheGrChunk(STARTFONT+1);\r
+                               CA_CacheGrChunk(C_CURSOR1PIC);\r
+                               CA_CacheGrChunk(C_CURSOR2PIC);\r
+                               CA_CacheGrChunk(C_DISKLOADING1PIC);\r
+                               CA_CacheGrChunk(C_DISKLOADING2PIC);\r
+                               CA_CacheGrChunk(C_LOADGAMEPIC);\r
+                               CA_CacheGrChunk(C_MOUSELBACKPIC);\r
+                               #else\r
+                               CA_CacheGrChunk(C_CURSOR1PIC);\r
+                               CacheLump (BACKDROP_LUMP_START,BACKDROP_LUMP_END);\r
+                               #endif\r
+\r
+                               VW_FadeOut ();\r
+\r
+                               StartCPMusic(MENUSONG);\r
+                               pickquick=CP_LoadGame(0);\r
+\r
+                               SETFONTCOLOR(0,15);\r
+                               IN_ClearKeysDown();\r
+                               DrawPlayScreen ();\r
+\r
+                               if (!startgame && !loadedgame)\r
+                               {\r
+                                       VW_FadeIn ();\r
+                                       StartMusic ();\r
+                               }\r
+\r
+                               if (loadedgame)\r
+                                       playstate = ex_abort;\r
+\r
+                               lasttimecount = TimeCount;\r
+\r
+                               if (MousePresent)\r
+                                       Mouse(MDelta);  // Clear accumulated mouse movement\r
+                               PM_CheckMainMem ();\r
+\r
+                               #ifndef SPEAR\r
+                               UNCACHEGRCHUNK(C_CURSOR1PIC);\r
+                               UNCACHEGRCHUNK(C_CURSOR2PIC);\r
+                               UNCACHEGRCHUNK(C_DISKLOADING1PIC);\r
+                               UNCACHEGRCHUNK(C_DISKLOADING2PIC);\r
+                               UNCACHEGRCHUNK(C_LOADGAMEPIC);\r
+                               UNCACHEGRCHUNK(C_MOUSELBACKPIC);\r
+                               #else\r
+                               UnCacheLump (BACKDROP_LUMP_START,BACKDROP_LUMP_END);\r
+                               #endif\r
+                       }\r
+                       return 1;\r
+\r
+               //\r
+               // QUIT\r
+               //\r
+               case sc_F10:\r
+                       CA_CacheGrChunk(STARTFONT+1);\r
+\r
+                       WindowX=WindowY=0;\r
+                       WindowW=320;\r
+                       WindowH=160;\r
+                       #ifdef JAPAN\r
+                       if (GetYorN(7,8,C_QUITMSGPIC))\r
+                       #else\r
+                               #ifdef SPANISH\r
+                       if (Confirm(ENDGAMESTR))\r
+                               #else\r
+                       if (Confirm(endStrings[US_RndT()&0x7+(US_RndT()&1)]))\r
+                               #endif\r
+                       #endif\r
+                       {\r
+                               int i;\r
+\r
+\r
+                               VW_UpdateScreen();\r
+                               SD_MusicOff();\r
+                               SD_StopSound();\r
+                               MenuFadeOut();\r
+\r
+                               //\r
+                               // SHUT-UP THE ADLIB\r
+                               //\r
+                               for (i=1;i<=0xf5;i++)\r
+                                       alOut(i,0);\r
+                               Quit(NULL);\r
+                       }\r
+\r
+                       DrawAllPlayBorder();\r
+                       WindowH=200;\r
+                       fontnumber=0;\r
+                       return 1;\r
+               }\r
+\r
+       return 0;\r
+}\r
+\r
+\r
+////////////////////////////////////////////////////////////////////\r
+//\r
+// END THE CURRENT GAME\r
+//\r
+////////////////////////////////////////////////////////////////////\r
+int CP_EndGame(void)\r
+{\r
+#ifdef JAPAN\r
+       if (!GetYorN(7,8,C_JAPQUITPIC))\r
+#else\r
+       if (!Confirm(ENDGAMESTR))\r
+#endif\r
+               return 0;\r
+\r
+       pickquick = gamestate.lives = 0;\r
+       playstate = ex_died;\r
+\r
+       #pragma warn -sus\r
+       MainMenu[savegame].active = 0;\r
+       MainMenu[viewscores].routine=CP_ViewScores;\r
+       #ifndef JAPAN\r
+       _fstrcpy(MainMenu[viewscores].string,STR_VS);\r
+       #endif\r
+       #pragma warn +sus\r
+\r
+       return 1;\r
+}\r
+\r
+\r
+////////////////////////////////////////////////////////////////////\r
+//\r
+// VIEW THE HIGH SCORES\r
+//\r
+////////////////////////////////////////////////////////////////////\r
+void CP_ViewScores(void)\r
+{\r
+       fontnumber=0;\r
+\r
+#ifdef SPEAR\r
+       UnCacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END);\r
+       StartCPMusic (XAWARD_MUS);\r
+#else\r
+       StartCPMusic (ROSTER_MUS);\r
+#endif\r
+\r
+       DrawHighScores ();\r
+       VW_UpdateScreen ();\r
+       MenuFadeIn();\r
+       fontnumber=1;\r
+\r
+       IN_Ack();\r
+\r
+       StartCPMusic(MENUSONG);\r
+       MenuFadeOut();\r
+\r
+#ifdef SPEAR\r
+       CacheLump (BACKDROP_LUMP_START,BACKDROP_LUMP_END);\r
+       CacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END);\r
+#endif\r
+}\r
+\r
+\r
+////////////////////////////////////////////////////////////////////\r
+//\r
+// START A NEW GAME\r
+//\r
+////////////////////////////////////////////////////////////////////\r
+void CP_NewGame(void)\r
+{\r
+       int which,episode;\r
+\r
+#ifdef SPEAR\r
+       UnCacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END);\r
+#endif\r
+\r
+\r
+#ifndef SPEAR\r
+firstpart:\r
+\r
+       DrawNewEpisode();\r
+       do\r
+       {\r
+               which=HandleMenu(&NewEitems,&NewEmenu[0],NULL);\r
+               switch(which)\r
+               {\r
+                       case -1:\r
+                               MenuFadeOut();\r
+                               return;\r
+\r
+                       default:\r
+                               if (!EpisodeSelect[which/2])\r
+                               {\r
+                                       SD_PlaySound (NOWAYSND);\r
+                                       Message("Please select \"Read This!\"\n"\r
+                                                       "from the Options menu to\n"\r
+                                                       "find out how to order this\n"\r
+                                                       "episode from Apogee.");\r
+                                       IN_ClearKeysDown();\r
+                                       IN_Ack();\r
+                                       DrawNewEpisode();\r
+                                       which = 0;\r
+                               }\r
+                               else\r
+                               {\r
+                                       episode = which/2;\r
+                                       which = 1;\r
+                               }\r
+                               break;\r
+               }\r
+\r
+       } while (!which);\r
+\r
+       ShootSnd();\r
+\r
+       //\r
+       // ALREADY IN A GAME?\r
+       //\r
+       if (ingame)\r
+               #ifdef JAPAN\r
+               if (!GetYorN(7,8,C_JAPNEWGAMEPIC))\r
+               #else\r
+               if (!Confirm(CURGAME))\r
+               #endif\r
+               {\r
+                       MenuFadeOut();\r
+                       return;\r
+               }\r
+\r
+       MenuFadeOut();\r
+\r
+#else\r
+       episode = 0;\r
+\r
+       //\r
+       // ALREADY IN A GAME?\r
+       //\r
+       CacheLump (NEWGAME_LUMP_START,NEWGAME_LUMP_END);\r
+       DrawNewGame();\r
+       if (ingame)\r
+               if (!Confirm(CURGAME))\r
+               {\r
+                       MenuFadeOut();\r
+                       UnCacheLump (NEWGAME_LUMP_START,NEWGAME_LUMP_END);\r
+                       CacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END);\r
+                       return;\r
+               }\r
+\r
+#endif\r
+\r
+       DrawNewGame();\r
+       which=HandleMenu(&NewItems,&NewMenu[0],DrawNewGameDiff);\r
+       if (which<0)\r
+       {\r
+               MenuFadeOut();\r
+               #ifndef SPEAR\r
+               goto firstpart;\r
+               #else\r
+               UnCacheLump (NEWGAME_LUMP_START,NEWGAME_LUMP_END);\r
+               CacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END);\r
+               return;\r
+               #endif\r
+       }\r
+\r
+       ShootSnd();\r
+       NewGame(which,episode);\r
+       StartGame=1;\r
+       MenuFadeOut();\r
+\r
+       //\r
+       // CHANGE "READ THIS!" TO NORMAL COLOR\r
+       //\r
+       #ifndef SPEAR\r
+       #ifndef GOODTIMES\r
+       MainMenu[readthis].active=1;\r
+       #endif\r
+       #endif\r
+\r
+       pickquick = 0;\r
+\r
+#ifdef SPEAR\r
+       UnCacheLump (NEWGAME_LUMP_START,NEWGAME_LUMP_END);\r
+       CacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END);\r
+#endif\r
+}\r
+\r
+\r
+#ifndef SPEAR\r
+/////////////////////\r
+//\r
+// DRAW NEW EPISODE MENU\r
+//\r
+void DrawNewEpisode(void)\r
+{\r
+       int i;\r
+\r
+#ifdef JAPAN\r
+       CA_CacheScreen(S_EPISODEPIC);\r
+#else\r
+       ClearMScreen();\r
+       VWB_DrawPic(112,184,C_MOUSELBACKPIC);\r
+\r
+       DrawWindow(NE_X-4,NE_Y-4,NE_W+8,NE_H+8,BKGDCOLOR);\r
+       SETFONTCOLOR(READHCOLOR,BKGDCOLOR);\r
+       PrintY=2;\r
+       WindowX=0;\r
+       #ifdef SPANISH\r
+       US_CPrint("Cual episodio jugar?");\r
+       #else\r
+       US_CPrint("Which episode to play?");\r
+       #endif\r
+#endif\r
+\r
+       SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR);\r
+       DrawMenu(&NewEitems,&NewEmenu[0]);\r
+\r
+       for (i=0;i<6;i++)\r
+               VWB_DrawPic(NE_X+32,NE_Y+i*26,C_EPISODE1PIC+i);\r
+\r
+       VW_UpdateScreen();\r
+       MenuFadeIn();\r
+       WaitKeyUp();\r
+}\r
+#endif\r
+\r
+/////////////////////\r
+//\r
+// DRAW NEW GAME MENU\r
+//\r
+void DrawNewGame(void)\r
+{\r
+#ifdef JAPAN\r
+       CA_CacheScreen(S_SKILLPIC);\r
+#else\r
+       ClearMScreen();\r
+       VWB_DrawPic(112,184,C_MOUSELBACKPIC);\r
+\r
+       SETFONTCOLOR(READHCOLOR,BKGDCOLOR);\r
+       PrintX=NM_X+20;\r
+       PrintY=NM_Y-32;\r
+\r
+#ifndef SPEAR\r
+       #ifdef SPANISH\r
+       US_Print("Eres macho?");\r
+       #else\r
+       US_Print("How tough are you?");\r
+       #endif\r
+#else\r
+       VWB_DrawPic (PrintX,PrintY,C_HOWTOUGHPIC);\r
+#endif\r
+\r
+       DrawWindow(NM_X-5,NM_Y-10,NM_W,NM_H,BKGDCOLOR);\r
+#endif\r
+\r
+       DrawMenu(&NewItems,&NewMenu[0]);\r
+       DrawNewGameDiff(NewItems.curpos);\r
+       VW_UpdateScreen();\r
+       MenuFadeIn();\r
+       WaitKeyUp();\r
+}\r
+\r
+\r
+////////////////////////\r
+//\r
+// DRAW NEW GAME GRAPHIC\r
+//\r
+void DrawNewGameDiff(int w)\r
+{\r
+       VWB_DrawPic(NM_X+185,NM_Y+7,w+C_BABYMODEPIC);\r
+}\r
+\r
+\r
+////////////////////////////////////////////////////////////////////\r
+//\r
+// HANDLE SOUND MENU\r
+//\r
+////////////////////////////////////////////////////////////////////\r
+void CP_Sound(void)\r
+{\r
+       int which,i;\r
+\r
+\r
+#ifdef SPEAR\r
+       UnCacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END);\r
+       CacheLump (SOUND_LUMP_START,SOUND_LUMP_END);\r
+#endif\r
+\r
+       DrawSoundMenu();\r
+       MenuFadeIn();\r
+       WaitKeyUp();\r
+\r
+       do\r
+       {\r
+               which=HandleMenu(&SndItems,&SndMenu[0],NULL);\r
+               //\r
+               // HANDLE MENU CHOICES\r
+               //\r
+               switch(which)\r
+               {\r
+                       //\r
+                       // SOUND EFFECTS\r
+                       //\r
+                       case 0:\r
+                               if (SoundMode!=sdm_Off)\r
+                               {\r
+                                       SD_WaitSoundDone();\r
+                                       SD_SetSoundMode(sdm_Off);\r
+                                       DrawSoundMenu();\r
+                               }\r
+                               break;\r
+                       case 1:\r
+                               if (SoundMode!=sdm_PC)\r
+                               {\r
+                                       SD_WaitSoundDone();\r
+                                       SD_SetSoundMode(sdm_PC);\r
+                                       CA_LoadAllSounds();\r
+                                       DrawSoundMenu();\r
+                                       ShootSnd();\r
+                               }\r
+                               break;\r
+                       case 2:\r
+                               if (SoundMode!=sdm_AdLib)\r
+                               {\r
+                                       SD_WaitSoundDone();\r
+                                       SD_SetSoundMode(sdm_AdLib);\r
+                                       CA_LoadAllSounds();\r
+                                       DrawSoundMenu();\r
+                                       ShootSnd();\r
+                               }\r
+                               break;\r
+\r
+                       //\r
+                       // DIGITIZED SOUND\r
+                       //\r
+                       case 5:\r
+                               if (DigiMode!=sds_Off)\r
+                               {\r
+                                       SD_SetDigiDevice(sds_Off);\r
+                                       DrawSoundMenu();\r
+                               }\r
+                               break;\r
+                       case 6:\r
+                               if (DigiMode!=sds_SoundSource)\r
+                               {\r
+                                       SD_SetDigiDevice(sds_SoundSource);\r
+                                       DrawSoundMenu();\r
+                                       ShootSnd();\r
+                               }\r
+                               break;\r
+                       case 7:\r
+                               if (DigiMode!=sds_SoundBlaster)\r
+                               {\r
+                                       SD_SetDigiDevice(sds_SoundBlaster);\r
+                                       DrawSoundMenu();\r
+                                       ShootSnd();\r
+                               }\r
+                               break;\r
+\r
+                       //\r
+                       // MUSIC\r
+                       //\r
+                       case 10:\r
+                               if (MusicMode!=smm_Off)\r
+                               {\r
+                                       SD_SetMusicMode(smm_Off);\r
+                                       DrawSoundMenu();\r
+                                       ShootSnd();\r
+                               }\r
+                               break;\r
+                       case 11:\r
+                               if (MusicMode!=smm_AdLib)\r
+                               {\r
+                                       SD_SetMusicMode(smm_AdLib);\r
+                                       DrawSoundMenu();\r
+                                       ShootSnd();\r
+                                       StartCPMusic(MENUSONG);\r
+                               }\r
+                               break;\r
+               }\r
+       } while(which>=0);\r
+\r
+       MenuFadeOut();\r
+\r
+#ifdef SPEAR\r
+       UnCacheLump (SOUND_LUMP_START,SOUND_LUMP_END);\r
+       CacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END);\r
+#endif\r
+}\r
+\r
+\r
+//////////////////////\r
+//\r
+// DRAW THE SOUND MENU\r
+//\r
+void DrawSoundMenu(void)\r
+{\r
+       int i,on;\r
+\r
+\r
+#ifdef JAPAN\r
+       CA_CacheScreen(S_SOUNDPIC);\r
+#else\r
+       //\r
+       // DRAW SOUND MENU\r
+       //\r
+       ClearMScreen();\r
+       VWB_DrawPic(112,184,C_MOUSELBACKPIC);\r
+\r
+       DrawWindow(SM_X-8,SM_Y1-3,SM_W,SM_H1,BKGDCOLOR);\r
+       DrawWindow(SM_X-8,SM_Y2-3,SM_W,SM_H2,BKGDCOLOR);\r
+       DrawWindow(SM_X-8,SM_Y3-3,SM_W,SM_H3,BKGDCOLOR);\r
+#endif\r
+\r
+       //\r
+       // IF NO ADLIB, NON-CHOOSENESS!\r
+       //\r
+       if (!AdLibPresent && !SoundBlasterPresent)\r
+       {\r
+               SndMenu[2].active=SndMenu[10].active=SndMenu[11].active=0;\r
+       }\r
+\r
+       if (!SoundSourcePresent)\r
+               SndMenu[6].active=0;\r
+\r
+       if (!SoundBlasterPresent)\r
+               SndMenu[7].active=0;\r
+\r
+       if (!SoundSourcePresent && !SoundBlasterPresent)\r
+               SndMenu[5].active=0;\r
+\r
+       DrawMenu(&SndItems,&SndMenu[0]);\r
+#ifndef JAPAN\r
+       VWB_DrawPic(100,SM_Y1-20,C_FXTITLEPIC);\r
+       VWB_DrawPic(100,SM_Y2-20,C_DIGITITLEPIC);\r
+       VWB_DrawPic(100,SM_Y3-20,C_MUSICTITLEPIC);\r
+#endif\r
+\r
+       for (i=0;i<SndItems.amount;i++)\r
+#ifdef JAPAN\r
+               if (i!=3 && i!=4 && i!=8 && i!=9)\r
+#else\r
+               if (SndMenu[i].string[0])\r
+#endif\r
+               {\r
+                       //\r
+                       // DRAW SELECTED/NOT SELECTED GRAPHIC BUTTONS\r
+                       //\r
+                       on=0;\r
+                       switch(i)\r
+                       {\r
+                               //\r
+                               // SOUND EFFECTS\r
+                               //\r
+                               case 0: if (SoundMode==sdm_Off) on=1; break;\r
+                               case 1: if (SoundMode==sdm_PC) on=1; break;\r
+                               case 2: if (SoundMode==sdm_AdLib) on=1; break;\r
+\r
+                               //\r
+                               // DIGITIZED SOUND\r
+                               //\r
+                               case 5: if (DigiMode==sds_Off) on=1; break;\r
+                               case 6: if (DigiMode==sds_SoundSource) on=1; break;\r
+                               case 7: if (DigiMode==sds_SoundBlaster) on=1; break;\r
+\r
+                               //\r
+                               // MUSIC\r
+                               //\r
+                               case 10: if (MusicMode==smm_Off) on=1; break;\r
+                               case 11: if (MusicMode==smm_AdLib) on=1; break;\r
+                       }\r
+\r
+                       if (on)\r
+                               VWB_DrawPic(SM_X+24,SM_Y1+i*13+2,C_SELECTEDPIC);\r
+                       else\r
+                               VWB_DrawPic(SM_X+24,SM_Y1+i*13+2,C_NOTSELECTEDPIC);\r
+               }\r
+\r
+       DrawMenuGun(&SndItems);\r
+       VW_UpdateScreen();\r
+}\r
+\r
+\r
+//\r
+// DRAW LOAD/SAVE IN PROGRESS\r
+//\r
+void DrawLSAction(int which)\r
+{\r
+       #define LSA_X   96\r
+       #define LSA_Y   80\r
+       #define LSA_W   130\r
+       #define LSA_H   42\r
+\r
+       DrawWindow(LSA_X,LSA_Y,LSA_W,LSA_H,TEXTCOLOR);\r
+       DrawOutline(LSA_X,LSA_Y,LSA_W,LSA_H,0,HIGHLIGHT);\r
+       VWB_DrawPic(LSA_X+8,LSA_Y+5,C_DISKLOADING1PIC);\r
+\r
+       fontnumber=1;\r
+       SETFONTCOLOR(0,TEXTCOLOR);\r
+       PrintX=LSA_X+46;\r
+       PrintY=LSA_Y+13;\r
+\r
+       if (!which)\r
+               US_Print(STR_LOADING"...");\r
+       else\r
+               US_Print(STR_SAVING"...");\r
+\r
+       VW_UpdateScreen();\r
+}\r
+\r
+\r
+////////////////////////////////////////////////////////////////////\r
+//\r
+// LOAD SAVED GAMES\r
+//\r
+////////////////////////////////////////////////////////////////////\r
+int CP_LoadGame(int quick)\r
+{\r
+       int handle,which,exit=0;\r
+       char name[13];\r
+\r
+\r
+       strcpy(name,SaveName);\r
+\r
+       //\r
+       // QUICKLOAD?\r
+       //\r
+       if (quick)\r
+       {\r
+               which=LSItems.curpos;\r
+\r
+               if (SaveGamesAvail[which])\r
+               {\r
+                       name[7]=which+'0';\r
+                       handle=open(name,O_BINARY);\r
+                       lseek(handle,32,SEEK_SET);\r
+                       loadedgame=true;\r
+                       LoadTheGame(handle,0,0);\r
+                       loadedgame=false;\r
+                       close(handle);\r
+\r
+                       DrawFace ();\r
+                       DrawHealth ();\r
+                       DrawLives ();\r
+                       DrawLevel ();\r
+                       DrawAmmo ();\r
+                       DrawKeys ();\r
+                       DrawWeapon ();\r
+                       DrawScore ();\r
+                       return 1;\r
+               }\r
+       }\r
+\r
+\r
+#ifdef SPEAR\r
+       UnCacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END);\r
+       CacheLump (LOADSAVE_LUMP_START,LOADSAVE_LUMP_END);\r
+#endif\r
+\r
+       DrawLoadSaveScreen(0);\r
+\r
+       do\r
+       {\r
+               which=HandleMenu(&LSItems,&LSMenu[0],TrackWhichGame);\r
+               if (which>=0 && SaveGamesAvail[which])\r
+               {\r
+                       ShootSnd();\r
+                       name[7]=which+'0';\r
+\r
+                       handle=open(name,O_BINARY);\r
+                       lseek(handle,32,SEEK_SET);\r
+\r
+                       DrawLSAction(0);\r
+                       loadedgame=true;\r
+\r
+                       LoadTheGame(handle,LSA_X+8,LSA_Y+5);\r
+                       close(handle);\r
+\r
+                       StartGame=1;\r
+                       ShootSnd();\r
+                       //\r
+                       // CHANGE "READ THIS!" TO NORMAL COLOR\r
+                       //\r
+\r
+                       #ifndef SPEAR\r
+                       #ifndef GOODTIMES\r
+                       MainMenu[readthis].active=1;\r
+                       #endif\r
+                       #endif\r
+\r
+                       exit=1;\r
+                       break;\r
+               }\r
+\r
+       } while(which>=0);\r
+\r
+       MenuFadeOut();\r
+\r
+#ifdef SPEAR\r
+       UnCacheLump (LOADSAVE_LUMP_START,LOADSAVE_LUMP_END);\r
+       CacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END);\r
+#endif\r
+\r
+       return exit;\r
+}\r
+\r
+\r
+///////////////////////////////////\r
+//\r
+// HIGHLIGHT CURRENT SELECTED ENTRY\r
+//\r
+void TrackWhichGame(int w)\r
+{\r
+       static int lastgameon=0;\r
+\r
+       PrintLSEntry(lastgameon,TEXTCOLOR);\r
+       PrintLSEntry(w,HIGHLIGHT);\r
+\r
+       lastgameon=w;\r
+}\r
+\r
+\r
+////////////////////////////\r
+//\r
+// DRAW THE LOAD/SAVE SCREEN\r
+//\r
+void DrawLoadSaveScreen(int loadsave)\r
+{\r
+       #define DISKX   100\r
+       #define DISKY   0\r
+\r
+       int i;\r
+\r
+\r
+       ClearMScreen();\r
+       fontnumber=1;\r
+       VWB_DrawPic(112,184,C_MOUSELBACKPIC);\r
+       DrawWindow(LSM_X-10,LSM_Y-5,LSM_W,LSM_H,BKGDCOLOR);\r
+       DrawStripes(10);\r
+\r
+       if (!loadsave)\r
+               VWB_DrawPic(60,0,C_LOADGAMEPIC);\r
+       else\r
+               VWB_DrawPic(60,0,C_SAVEGAMEPIC);\r
+\r
+       for (i=0;i<10;i++)\r
+               PrintLSEntry(i,TEXTCOLOR);\r
+\r
+       DrawMenu(&LSItems,&LSMenu[0]);\r
+       VW_UpdateScreen();\r
+       MenuFadeIn();\r
+       WaitKeyUp();\r
+}\r
+\r
+\r
+///////////////////////////////////////////\r
+//\r
+// PRINT LOAD/SAVE GAME ENTRY W/BOX OUTLINE\r
+//\r
+void PrintLSEntry(int w,int color)\r
+{\r
+       SETFONTCOLOR(color,BKGDCOLOR);\r
+       DrawOutline(LSM_X+LSItems.indent,LSM_Y+w*13,LSM_W-LSItems.indent-15,11,color,color);\r
+       PrintX=LSM_X+LSItems.indent+2;\r
+       PrintY=LSM_Y+w*13+1;\r
+       fontnumber=0;\r
+\r
+       if (SaveGamesAvail[w])\r
+               US_Print(SaveGameNames[w]);\r
+       else\r
+               US_Print("      - "STR_EMPTY" -");\r
+\r
+       fontnumber=1;\r
+}\r
+\r
+\r
+////////////////////////////////////////////////////////////////////\r
+//\r
+// SAVE CURRENT GAME\r
+//\r
+////////////////////////////////////////////////////////////////////\r
+int CP_SaveGame(int quick)\r
+{\r
+       int handle,which,exit=0;\r
+       unsigned nwritten;\r
+       char name[13],input[32];\r
+\r
+\r
+       strcpy(name,SaveName);\r
+\r
+       //\r
+       // QUICKSAVE?\r
+       //\r
+       if (quick)\r
+       {\r
+               which=LSItems.curpos;\r
+\r
+               if (SaveGamesAvail[which])\r
+               {\r
+                       name[7]=which+'0';\r
+                       unlink(name);\r
+                       handle=creat(name,S_IREAD|S_IWRITE);\r
+\r
+                       strcpy(input,&SaveGameNames[which][0]);\r
+\r
+                       _dos_write(handle,(void far *)input,32,&nwritten);\r
+                       lseek(handle,32,SEEK_SET);\r
+                       SaveTheGame(handle,0,0);\r
+                       close(handle);\r
+\r
+                       return 1;\r
+               }\r
+       }\r
+\r
+\r
+#ifdef SPEAR\r
+       UnCacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END);\r
+       CacheLump (LOADSAVE_LUMP_START,LOADSAVE_LUMP_END);\r
+#endif\r
+\r
+       DrawLoadSaveScreen(1);\r
+\r
+       do\r
+       {\r
+               which=HandleMenu(&LSItems,&LSMenu[0],TrackWhichGame);\r
+               if (which>=0)\r
+               {\r
+                       //\r
+                       // OVERWRITE EXISTING SAVEGAME?\r
+                       //\r
+                       if (SaveGamesAvail[which])\r
+                               #ifdef JAPAN\r
+                               if (!GetYorN(7,8,C_JAPSAVEOVERPIC))\r
+                               #else\r
+                               if (!Confirm(GAMESVD))\r
+                               #endif\r
+                               {\r
+                                       DrawLoadSaveScreen(1);\r
+                                       continue;\r
+                               }\r
+                               else\r
+                               {\r
+                                       DrawLoadSaveScreen(1);\r
+                                       PrintLSEntry(which,HIGHLIGHT);\r
+                                       VW_UpdateScreen();\r
+                               }\r
+\r
+                       ShootSnd();\r
+\r
+                       strcpy(input,&SaveGameNames[which][0]);\r
+                       name[7]=which+'0';\r
+\r
+                       fontnumber=0;\r
+                       if (!SaveGamesAvail[which])\r
+                               VWB_Bar(LSM_X+LSItems.indent+1,LSM_Y+which*13+1,LSM_W-LSItems.indent-16,10,BKGDCOLOR);\r
+                       VW_UpdateScreen();\r
+\r
+                       if (US_LineInput(LSM_X+LSItems.indent+2,LSM_Y+which*13+1,input,input,true,31,LSM_W-LSItems.indent-30))\r
+                       {\r
+                               SaveGamesAvail[which]=1;\r
+                               strcpy(&SaveGameNames[which][0],input);\r
+\r
+                               unlink(name);\r
+                               handle=creat(name,S_IREAD|S_IWRITE);\r
+                               _dos_write(handle,(void far *)input,32,&nwritten);\r
+                               lseek(handle,32,SEEK_SET);\r
+\r
+                               DrawLSAction(1);\r
+                               SaveTheGame(handle,LSA_X+8,LSA_Y+5);\r
+\r
+                               close(handle);\r
+\r
+                               ShootSnd();\r
+                               exit=1;\r
+                       }\r
+                       else\r
+                       {\r
+                               VWB_Bar(LSM_X+LSItems.indent+1,LSM_Y+which*13+1,LSM_W-LSItems.indent-16,10,BKGDCOLOR);\r
+                               PrintLSEntry(which,HIGHLIGHT);\r
+                               VW_UpdateScreen();\r
+                               SD_PlaySound(ESCPRESSEDSND);\r
+                               continue;\r
+                       }\r
+\r
+                       fontnumber=1;\r
+                       break;\r
+               }\r
+\r
+       } while(which>=0);\r
+\r
+       MenuFadeOut();\r
+\r
+#ifdef SPEAR\r
+       UnCacheLump (LOADSAVE_LUMP_START,LOADSAVE_LUMP_END);\r
+       CacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END);\r
+#endif\r
+\r
+       return exit;\r
+}\r
+\r
+\r
+////////////////////////////////////////////////////////////////////\r
+//\r
+// CALIBRATE JOYSTICK\r
+//\r
+////////////////////////////////////////////////////////////////////\r
+int CalibrateJoystick(void)\r
+{\r
+       #define CALX    85\r
+       #define CALY    40\r
+       #define CALW    158\r
+       #define CALH    140\r
+\r
+       unsigned xmin,ymin,xmax,ymax,jb;\r
+\r
+\r
+\r
+       #ifdef JAPAN\r
+       VWB_DrawPic(CALX,CALY,C_JOY0PIC);\r
+       #else\r
+       DrawWindow(CALX-5,CALY-5,CALW,CALH,TEXTCOLOR);\r
+       DrawOutline(CALX-5,CALY-5,CALW,CALH,0,HIGHLIGHT);\r
+       SETFONTCOLOR(0,TEXTCOLOR);\r
+\r
+       WindowX = PrintX = CALX;\r
+       WindowW = CALW;\r
+       WindowH = CALH;\r
+       WindowY = PrintY = CALY;\r
+       US_Print("    "STR_CALIB"\n    "STR_JOYST"\n");\r
+       VWB_DrawPic(CALX+40,CALY+30,C_JOY1PIC);\r
+       PrintY = CALY+80;\r
+       US_Print(STR_MOVEJOY);\r
+       SETFONTCOLOR(BKGDCOLOR,TEXTCOLOR);\r
+       US_Print("   "STR_ESCEXIT);\r
+       #endif\r
+       VW_UpdateScreen();\r
+\r
+       do\r
+       {\r
+               jb=IN_JoyButtons();\r
+               if (Keyboard[sc_Escape])\r
+                       return 0;\r
+               #ifndef SPEAR\r
+               if (Keyboard[sc_Tab] && Keyboard[sc_P] && MS_CheckParm("goobers"))\r
+                       PicturePause();\r
+               #endif\r
+\r
+       } while(!(jb&1));\r
+\r
+       SD_PlaySound(SHOOTSND);\r
+       IN_GetJoyAbs(joystickport,&xmin,&ymin);\r
+\r
+\r
+       #ifdef JAPAN\r
+       VWB_DrawPic(CALX,CALY,C_JOY1PIC);\r
+       #else\r
+       DrawWindow(CALX-5,CALY-5,CALW,CALH,TEXTCOLOR);\r
+       DrawOutline(CALX-5,CALY-5,CALW,CALH,0,HIGHLIGHT);\r
+       SETFONTCOLOR(0,TEXTCOLOR);\r
+\r
+       PrintX = CALX;\r
+       PrintY = CALY;\r
+       US_Print("    "STR_CALIB"\n    "STR_JOYST"\n");\r
+       VWB_DrawPic(CALX+40,CALY+30,C_JOY2PIC);\r
+       PrintY = CALY+80;\r
+       US_Print(STR_MOVEJOY2);\r
+       SETFONTCOLOR(BKGDCOLOR,TEXTCOLOR);\r
+       US_Print("   "STR_ESCEXIT);\r
+       #endif\r
+       VW_UpdateScreen();\r
+\r
+       do\r
+       {\r
+               jb=IN_JoyButtons();\r
+               if (Keyboard[sc_Escape])\r
+                       return 0;\r
+               #ifndef SPEAR\r
+               if (Keyboard[sc_Tab] && Keyboard[sc_P] && MS_CheckParm("goobers"))\r
+                       PicturePause();\r
+               #endif\r
+       } while(!(jb&2));\r
+\r
+       IN_GetJoyAbs(joystickport,&xmax,&ymax);\r
+       SD_PlaySound(SHOOTSND);\r
+\r
+       while (IN_JoyButtons());\r
+\r
+       //\r
+       // ASSIGN ACTUAL VALUES HERE\r
+       //\r
+       if ((xmin != xmax) && (ymin != ymax))\r
+               IN_SetupJoy(joystickport,xmin,xmax,ymin,ymax);\r
+       else\r
+               return 0;\r
+\r
+       return 1;\r
+}\r
+\r
+\r
+////////////////////////////////////////////////////////////////////\r
+//\r
+// DEFINE CONTROLS\r
+//\r
+////////////////////////////////////////////////////////////////////\r
+void CP_Control(void)\r
+{\r
+       #define CTL_SPC 70\r
+       enum {MOUSEENABLE,JOYENABLE,USEPORT2,PADENABLE,MOUSESENS,CUSTOMIZE};\r
+       int i,which;\r
+\r
+\r
+#ifdef SPEAR\r
+       UnCacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END);\r
+       CacheLump (CONTROL_LUMP_START,CONTROL_LUMP_END);\r
+#endif\r
+\r
+       DrawCtlScreen();\r
+       MenuFadeIn();\r
+       WaitKeyUp();\r
+\r
+       do\r
+       {\r
+               which=HandleMenu(&CtlItems,&CtlMenu[0],NULL);\r
+               switch(which)\r
+               {\r
+                       case MOUSEENABLE:\r
+                               mouseenabled^=1;\r
+                               _CX=_DX=CENTER;\r
+                               Mouse(4);\r
+                               DrawCtlScreen();\r
+                               CusItems.curpos=-1;\r
+                               ShootSnd();\r
+                               break;\r
+\r
+                       case JOYENABLE:\r
+                               joystickenabled^=1;\r
+                               if (joystickenabled)\r
+                                       if (!CalibrateJoystick())\r
+                                               joystickenabled = 0;\r
+                               DrawCtlScreen();\r
+                               CusItems.curpos=-1;\r
+                               ShootSnd();\r
+                               break;\r
+\r
+                       case USEPORT2:\r
+                               joystickport^=1;\r
+                               DrawCtlScreen();\r
+                               ShootSnd();\r
+                               break;\r
+\r
+                       case PADENABLE:\r
+                               joypadenabled^=1;\r
+                               DrawCtlScreen();\r
+                               ShootSnd();\r
+                               break;\r
+\r
+                       case MOUSESENS:\r
+                       case CUSTOMIZE:\r
+                               DrawCtlScreen();\r
+                               MenuFadeIn();\r
+                               WaitKeyUp();\r
+                               break;\r
+               }\r
+       } while(which>=0);\r
+\r
+       MenuFadeOut();\r
+\r
+#ifdef SPEAR\r
+       UnCacheLump (CONTROL_LUMP_START,CONTROL_LUMP_END);\r
+       CacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END);\r
+#endif\r
+}\r
+\r
+\r
+////////////////////////////////\r
+//\r
+// DRAW MOUSE SENSITIVITY SCREEN\r
+//\r
+void DrawMouseSens(void)\r
+{\r
+#ifdef JAPAN\r
+       CA_CacheScreen(S_MOUSESENSPIC);\r
+#else\r
+       ClearMScreen();\r
+       VWB_DrawPic(112,184,C_MOUSELBACKPIC);\r
+       #ifdef SPANISH\r
+       DrawWindow(10,80,300,43,BKGDCOLOR);\r
+       #else\r
+       DrawWindow(10,80,300,30,BKGDCOLOR);\r
+       #endif\r
+\r
+       WindowX=0;\r
+       WindowW=320;\r
+       PrintY=82;\r
+       SETFONTCOLOR(READCOLOR,BKGDCOLOR);\r
+       US_CPrint(STR_MOUSEADJ);\r
+\r
+       SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR);\r
+       #ifdef SPANISH\r
+       PrintX=14;\r
+       PrintY=95+13;\r
+       US_Print(STR_SLOW);\r
+       PrintX=252;\r
+       US_Print(STR_FAST);\r
+       #else\r
+       PrintX=14;\r
+       PrintY=95;\r
+       US_Print(STR_SLOW);\r
+       PrintX=269;\r
+       US_Print(STR_FAST);\r
+       #endif\r
+#endif\r
+\r
+       VWB_Bar(60,97,200,10,TEXTCOLOR);\r
+       DrawOutline(60,97,200,10,0,HIGHLIGHT);\r
+       DrawOutline(60+20*mouseadjustment,97,20,10,0,READCOLOR);\r
+       VWB_Bar(61+20*mouseadjustment,98,19,9,READHCOLOR);\r
+\r
+       VW_UpdateScreen();\r
+       MenuFadeIn();\r
+}\r
+\r
+\r
+///////////////////////////\r
+//\r
+// ADJUST MOUSE SENSITIVITY\r
+//\r
+void MouseSensitivity(void)\r
+{\r
+       ControlInfo ci;\r
+       int exit=0,oldMA;\r
+\r
+\r
+       oldMA=mouseadjustment;\r
+       DrawMouseSens();\r
+       do\r
+       {\r
+               ReadAnyControl(&ci);\r
+               switch(ci.dir)\r
+               {\r
+                       case dir_North:\r
+                       case dir_West:\r
+                               if (mouseadjustment)\r
+                               {\r
+                                       mouseadjustment--;\r
+                                       VWB_Bar(60,97,200,10,TEXTCOLOR);\r
+                                       DrawOutline(60,97,200,10,0,HIGHLIGHT);\r
+                                       DrawOutline(60+20*mouseadjustment,97,20,10,0,READCOLOR);\r
+                                       VWB_Bar(61+20*mouseadjustment,98,19,9,READHCOLOR);\r
+                                       VW_UpdateScreen();\r
+                                       SD_PlaySound(MOVEGUN1SND);\r
+                                       while(Keyboard[sc_LeftArrow]);\r
+                                       WaitKeyUp();\r
+                               }\r
+                               break;\r
+\r
+                       case dir_South:\r
+                       case dir_East:\r
+                               if (mouseadjustment<9)\r
+                               {\r
+                                       mouseadjustment++;\r
+                                       VWB_Bar(60,97,200,10,TEXTCOLOR);\r
+                                       DrawOutline(60,97,200,10,0,HIGHLIGHT);\r
+                                       DrawOutline(60+20*mouseadjustment,97,20,10,0,READCOLOR);\r
+                                       VWB_Bar(61+20*mouseadjustment,98,19,9,READHCOLOR);\r
+                                       VW_UpdateScreen();\r
+                                       SD_PlaySound(MOVEGUN1SND);\r
+                                       while(Keyboard[sc_RightArrow]);\r
+                                       WaitKeyUp();\r
+                               }\r
+                               break;\r
+               }\r
+\r
+               #ifndef SPEAR\r
+               if (Keyboard[sc_Tab] && Keyboard[sc_P] && MS_CheckParm("goobers"))\r
+               #else\r
+               if (Keyboard[sc_Tab] && Keyboard[sc_P] && MS_CheckParm("debugmode"))\r
+               #endif\r
+                       PicturePause();\r
+\r
+               if (ci.button0 || Keyboard[sc_Space] || Keyboard[sc_Enter])\r
+                       exit=1;\r
+               else\r
+               if (ci.button1 || Keyboard[sc_Escape])\r
+                       exit=2;\r
+\r
+       } while(!exit);\r
+\r
+       if (exit==2)\r
+       {\r
+               mouseadjustment=oldMA;\r
+               SD_PlaySound(ESCPRESSEDSND);\r
+       }\r
+       else\r
+               SD_PlaySound(SHOOTSND);\r
+\r
+       WaitKeyUp();\r
+       MenuFadeOut();\r
+}\r
+\r
+\r
+///////////////////////////\r
+//\r
+// DRAW CONTROL MENU SCREEN\r
+//\r
+void DrawCtlScreen(void)\r
+{\r
+ int i,x,y;\r
+\r
+\r
+#ifdef JAPAN\r
+       CA_CacheScreen(S_CONTROLPIC);\r
+#else\r
+ ClearMScreen();\r
+ DrawStripes(10);\r
+ VWB_DrawPic(80,0,C_CONTROLPIC);\r
+ VWB_DrawPic(112,184,C_MOUSELBACKPIC);\r
+ DrawWindow(CTL_X-8,CTL_Y-5,CTL_W,CTL_H,BKGDCOLOR);\r
+#endif\r
+ WindowX=0;\r
+ WindowW=320;\r
+ SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR);\r
+\r
+ if (JoysPresent[0])\r
+   CtlMenu[1].active=\r
+   CtlMenu[2].active=\r
+   CtlMenu[3].active=1;\r
+\r
+ CtlMenu[2].active=CtlMenu[3].active=joystickenabled;\r
+\r
+ if (MousePresent)\r
+ {\r
+  CtlMenu[4].active=\r
+  CtlMenu[0].active=1;\r
+ }\r
+\r
+ CtlMenu[4].active=mouseenabled;\r
+\r
+\r
+ DrawMenu(&CtlItems,&CtlMenu[0]);\r
+\r
+\r
+ x=CTL_X+CtlItems.indent-24;\r
+ y=CTL_Y+3;\r
+ if (mouseenabled)\r
+   VWB_DrawPic(x,y,C_SELECTEDPIC);\r
+ else\r
+   VWB_DrawPic(x,y,C_NOTSELECTEDPIC);\r
+\r
+ y=CTL_Y+16;\r
+ if (joystickenabled)\r
+   VWB_DrawPic(x,y,C_SELECTEDPIC);\r
+ else\r
+   VWB_DrawPic(x,y,C_NOTSELECTEDPIC);\r
+\r
+ y=CTL_Y+29;\r
+ if (joystickport)\r
+   VWB_DrawPic(x,y,C_SELECTEDPIC);\r
+ else\r
+   VWB_DrawPic(x,y,C_NOTSELECTEDPIC);\r
+\r
+ y=CTL_Y+42;\r
+ if (joypadenabled)\r
+   VWB_DrawPic(x,y,C_SELECTEDPIC);\r
+ else\r
+   VWB_DrawPic(x,y,C_NOTSELECTEDPIC);\r
+\r
+ //\r
+ // PICK FIRST AVAILABLE SPOT\r
+ //\r
+ if (CtlItems.curpos<0 || !CtlMenu[CtlItems.curpos].active)\r
+   for (i=0;i<6;i++)\r
+        if (CtlMenu[i].active)\r
+        {\r
+         CtlItems.curpos=i;\r
+         break;\r
+        }\r
+\r
+ DrawMenuGun(&CtlItems);\r
+ VW_UpdateScreen();\r
+}\r
+\r
+\r
+////////////////////////////////////////////////////////////////////\r
+//\r
+// CUSTOMIZE CONTROLS\r
+//\r
+////////////////////////////////////////////////////////////////////\r
+enum {FIRE,STRAFE,RUN,OPEN};\r
+char mbarray[4][3]={"b0","b1","b2","b3"},\r
+          order[4]={RUN,OPEN,FIRE,STRAFE};\r
+\r
+\r
+void CustomControls(void)\r
+{\r
+ int which;\r
+\r
+\r
+ DrawCustomScreen();\r
+ do\r
+ {\r
+  which=HandleMenu(&CusItems,&CusMenu[0],FixupCustom);\r
+  switch(which)\r
+  {\r
+   case 0:\r
+        DefineMouseBtns();\r
+        DrawCustMouse(1);\r
+        break;\r
+   case 3:\r
+        DefineJoyBtns();\r
+        DrawCustJoy(0);\r
+        break;\r
+   case 6:\r
+        DefineKeyBtns();\r
+        DrawCustKeybd(0);\r
+        break;\r
+   case 8:\r
+        DefineKeyMove();\r
+        DrawCustKeys(0);\r
+  }\r
+ } while(which>=0);\r
+\r
+\r
+\r
+ MenuFadeOut();\r
+}\r
+\r
+\r
+////////////////////////\r
+//\r
+// DEFINE THE MOUSE BUTTONS\r
+//\r
+void DefineMouseBtns(void)\r
+{\r
+ CustomCtrls mouseallowed={0,1,1,1};\r
+ EnterCtrlData(2,&mouseallowed,DrawCustMouse,PrintCustMouse,MOUSE);\r
+}\r
+\r
+\r
+////////////////////////\r
+//\r
+// DEFINE THE JOYSTICK BUTTONS\r
+//\r
+void DefineJoyBtns(void)\r
+{\r
+ CustomCtrls joyallowed={1,1,1,1};\r
+ EnterCtrlData(5,&joyallowed,DrawCustJoy,PrintCustJoy,JOYSTICK);\r
+}\r
+\r
+\r
+////////////////////////\r
+//\r
+// DEFINE THE KEYBOARD BUTTONS\r
+//\r
+void DefineKeyBtns(void)\r
+{\r
+ CustomCtrls keyallowed={1,1,1,1};\r
+ EnterCtrlData(8,&keyallowed,DrawCustKeybd,PrintCustKeybd,KEYBOARDBTNS);\r
+}\r
+\r
+\r
+////////////////////////\r
+//\r
+// DEFINE THE KEYBOARD BUTTONS\r
+//\r
+void DefineKeyMove(void)\r
+{\r
+       CustomCtrls keyallowed={1,1,1,1};\r
+       EnterCtrlData(10,&keyallowed,DrawCustKeys,PrintCustKeys,KEYBOARDMOVE);\r
+}\r
+\r
+\r
+////////////////////////\r
+//\r
+// ENTER CONTROL DATA FOR ANY TYPE OF CONTROL\r
+//\r
+enum {FWRD,RIGHT,BKWD,LEFT};\r
+int moveorder[4]={LEFT,RIGHT,FWRD,BKWD};\r
+\r
+void EnterCtrlData(int index,CustomCtrls *cust,void (*DrawRtn)(int),void (*PrintRtn)(int),int type)\r
+{\r
+ int j,exit,tick,redraw,which,x,picked;\r
+ ControlInfo ci;\r
+\r
+\r
+ ShootSnd();\r
+ PrintY=CST_Y+13*index;\r
+ IN_ClearKeysDown();\r
+ exit=0;\r
+ redraw=1;\r
+ //\r
+ // FIND FIRST SPOT IN ALLOWED ARRAY\r
+ //\r
+ for (j=0;j<4;j++)\r
+   if (cust->allowed[j])\r
+   {\r
+       which=j;\r
+       break;\r
+   }\r
+\r
+ do\r
+ {\r
+  if (redraw)\r
+  {\r
+   x=CST_START+CST_SPC*which;\r
+   DrawWindow(5,PrintY-1,310,13,BKGDCOLOR);\r
+\r
+   DrawRtn(1);\r
+   DrawWindow(x-2,PrintY,CST_SPC,11,TEXTCOLOR);\r
+   DrawOutline(x-2,PrintY,CST_SPC,11,0,HIGHLIGHT);\r
+   SETFONTCOLOR(0,TEXTCOLOR);\r
+   PrintRtn(which);\r
+   PrintX=x;\r
+   SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR);\r
+   VW_UpdateScreen();\r
+   WaitKeyUp();\r
+   redraw=0;\r
+  }\r
+\r
+  ReadAnyControl(&ci);\r
+\r
+  if (type==MOUSE || type==JOYSTICK)\r
+       if (IN_KeyDown(sc_Enter)||IN_KeyDown(sc_Control)||IN_KeyDown(sc_Alt))\r
+       {\r
+        IN_ClearKeysDown();\r
+        ci.button0=ci.button1=false;\r
+       }\r
+\r
+  //\r
+  // CHANGE BUTTON VALUE?\r
+  //\r
+  if ((ci.button0|ci.button1|ci.button2|ci.button3)||\r
+         ((type==KEYBOARDBTNS||type==KEYBOARDMOVE) && LastScan==sc_Enter))\r
+  {\r
+   tick=TimeCount=picked=0;\r
+   SETFONTCOLOR(0,TEXTCOLOR);\r
+\r
+   do\r
+   {\r
+       int button,result=0;\r
+\r
+\r
+       if (type==KEYBOARDBTNS||type==KEYBOARDMOVE)\r
+         IN_ClearKeysDown();\r
+\r
+       //\r
+       // FLASH CURSOR\r
+       //\r
+       if (TimeCount>10)\r
+       {\r
+        switch(tick)\r
+        {\r
+         case 0:\r
+       VWB_Bar(x,PrintY+1,CST_SPC-2,10,TEXTCOLOR);\r
+       break;\r
+         case 1:\r
+       PrintX=x;\r
+       US_Print("?");\r
+       SD_PlaySound(HITWALLSND);\r
+        }\r
+        tick^=1;\r
+        TimeCount=0;\r
+        VW_UpdateScreen();\r
+       }\r
+\r
+       //\r
+       // WHICH TYPE OF INPUT DO WE PROCESS?\r
+       //\r
+       switch(type)\r
+       {\r
+        case MOUSE:\r
+          Mouse(3);\r
+          button=_BX;\r
+          switch(button)\r
+          {\r
+       case 1: result=1; break;\r
+       case 2: result=2; break;\r
+       case 4: result=3; break;\r
+          }\r
+\r
+          if (result)\r
+          {\r
+       int z;\r
+\r
+\r
+       for (z=0;z<4;z++)\r
+         if (order[which]==buttonmouse[z])\r
+         {\r
+          buttonmouse[z]=bt_nobutton;\r
+          break;\r
+         }\r
+\r
+       buttonmouse[result-1]=order[which];\r
+       picked=1;\r
+       SD_PlaySound(SHOOTDOORSND);\r
+          }\r
+          break;\r
+\r
+        case JOYSTICK:\r
+          if (ci.button0) result=1;\r
+          else\r
+          if (ci.button1) result=2;\r
+          else\r
+          if (ci.button2) result=3;\r
+          else\r
+          if (ci.button3) result=4;\r
+\r
+          if (result)\r
+          {\r
+       int z;\r
+\r
+\r
+       for (z=0;z<4;z++)\r
+         if (order[which]==buttonjoy[z])\r
+         {\r
+          buttonjoy[z]=bt_nobutton;\r
+          break;\r
+         }\r
+\r
+       buttonjoy[result-1]=order[which];\r
+       picked=1;\r
+       SD_PlaySound(SHOOTDOORSND);\r
+          }\r
+          break;\r
+\r
+        case KEYBOARDBTNS:\r
+          if (LastScan)\r
+          {\r
+       buttonscan[order[which]]=LastScan;\r
+       picked=1;\r
+       ShootSnd();\r
+       IN_ClearKeysDown();\r
+          }\r
+          break;\r
+\r
+        case KEYBOARDMOVE:\r
+          if (LastScan)\r
+          {\r
+       dirscan[moveorder[which]]=LastScan;\r
+       picked=1;\r
+       ShootSnd();\r
+       IN_ClearKeysDown();\r
+          }\r
+          break;\r
+       }\r
+\r
+       //\r
+       // EXIT INPUT?\r
+       //\r
+       if (IN_KeyDown(sc_Escape))\r
+       {\r
+        picked=1;\r
+        continue;\r
+       }\r
+\r
+   } while(!picked);\r
+\r
+   SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR);\r
+   redraw=1;\r
+   WaitKeyUp();\r
+   continue;\r
+  }\r
+\r
+  if (ci.button1 || IN_KeyDown(sc_Escape))\r
+       exit=1;\r
+\r
+  //\r
+  // MOVE TO ANOTHER SPOT?\r
+  //\r
+  switch(ci.dir)\r
+  {\r
+   case dir_West:\r
+        do\r
+        {\r
+         which--;\r
+         if (which<0)\r
+       which=3;\r
+        } while(!cust->allowed[which]);\r
+        redraw=1;\r
+        SD_PlaySound(MOVEGUN1SND);\r
+        while(ReadAnyControl(&ci),ci.dir!=dir_None);\r
+        IN_ClearKeysDown();\r
+        break;\r
+\r
+   case dir_East:\r
+        do\r
+        {\r
+         which++;\r
+         if (which>3)\r
+       which=0;\r
+        } while(!cust->allowed[which]);\r
+        redraw=1;\r
+        SD_PlaySound(MOVEGUN1SND);\r
+        while(ReadAnyControl(&ci),ci.dir!=dir_None);\r
+        IN_ClearKeysDown();\r
+        break;\r
+   case dir_North:\r
+   case dir_South:\r
+        exit=1;\r
+  }\r
+ } while(!exit);\r
+\r
+ SD_PlaySound(ESCPRESSEDSND);\r
+ WaitKeyUp();\r
+ DrawWindow(5,PrintY-1,310,13,BKGDCOLOR);\r
+}\r
+\r
+\r
+////////////////////////\r
+//\r
+// FIXUP GUN CURSOR OVERDRAW SHIT\r
+//\r
+void FixupCustom(int w)\r
+{\r
+       static int lastwhich=-1;\r
+       int y=CST_Y+26+w*13;\r
+\r
+\r
+       VWB_Hlin(7,32,y-1,DEACTIVE);\r
+       VWB_Hlin(7,32,y+12,BORD2COLOR);\r
+#ifndef SPEAR\r
+       VWB_Hlin(7,32,y-2,BORDCOLOR);\r
+       VWB_Hlin(7,32,y+13,BORDCOLOR);\r
+#else\r
+       VWB_Hlin(7,32,y-2,BORD2COLOR);\r
+       VWB_Hlin(7,32,y+13,BORD2COLOR);\r
+#endif\r
+\r
+       switch(w)\r
+       {\r
+               case 0: DrawCustMouse(1); break;\r
+               case 3: DrawCustJoy(1); break;\r
+               case 6: DrawCustKeybd(1); break;\r
+               case 8: DrawCustKeys(1);\r
+       }\r
+\r
+\r
+       if (lastwhich>=0)\r
+       {\r
+               y=CST_Y+26+lastwhich*13;\r
+               VWB_Hlin(7,32,y-1,DEACTIVE);\r
+               VWB_Hlin(7,32,y+12,BORD2COLOR);\r
+#ifndef SPEAR\r
+               VWB_Hlin(7,32,y-2,BORDCOLOR);\r
+               VWB_Hlin(7,32,y+13,BORDCOLOR);\r
+#else\r
+               VWB_Hlin(7,32,y-2,BORD2COLOR);\r
+               VWB_Hlin(7,32,y+13,BORD2COLOR);\r
+#endif\r
+\r
+               if (lastwhich!=w)\r
+                       switch(lastwhich)\r
+                       {\r
+                               case 0: DrawCustMouse(0); break;\r
+                               case 3: DrawCustJoy(0); break;\r
+                               case 6: DrawCustKeybd(0); break;\r
+                               case 8: DrawCustKeys(0);\r
+                       }\r
+       }\r
+\r
+       lastwhich=w;\r
+}\r
+\r
+\r
+////////////////////////\r
+//\r
+// DRAW CUSTOMIZE SCREEN\r
+//\r
+void DrawCustomScreen(void)\r
+{\r
+       int i;\r
+\r
+\r
+#ifdef JAPAN\r
+       CA_CacheScreen(S_CUSTOMPIC);\r
+       fontnumber=1;\r
+\r
+       PrintX=CST_START;\r
+       PrintY = CST_Y+26;\r
+       DrawCustMouse(0);\r
+\r
+       PrintX=CST_START;\r
+       US_Print("\n\n\n");\r
+       DrawCustJoy(0);\r
+\r
+       PrintX=CST_START;\r
+       US_Print("\n\n\n");\r
+       DrawCustKeybd(0);\r
+\r
+       PrintX=CST_START;\r
+       US_Print("\n\n\n");\r
+       DrawCustKeys(0);\r
+#else\r
+       ClearMScreen();\r
+       WindowX=0;\r
+       WindowW=320;\r
+       VWB_DrawPic(112,184,C_MOUSELBACKPIC);\r
+       DrawStripes(10);\r
+       VWB_DrawPic(80,0,C_CUSTOMIZEPIC);\r
+\r
+       //\r
+       // MOUSE\r
+       //\r
+       SETFONTCOLOR(READCOLOR,BKGDCOLOR);\r
+       WindowX=0;\r
+       WindowW=320;\r
+\r
+#ifndef SPEAR\r
+       PrintY=CST_Y;\r
+       US_CPrint("Mouse\n");\r
+#else\r
+       PrintY = CST_Y+13;\r
+       VWB_DrawPic (128,48,C_MOUSEPIC);\r
+#endif\r
+\r
+       SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR);\r
+       #ifdef SPANISH\r
+       PrintX=CST_START-16;\r
+       US_Print(STR_CRUN);\r
+       PrintX=CST_START-16+CST_SPC*1;\r
+       US_Print(STR_COPEN);\r
+       PrintX=CST_START-16+CST_SPC*2;\r
+       US_Print(STR_CFIRE);\r
+       PrintX=CST_START-16+CST_SPC*3;\r
+       US_Print(STR_CSTRAFE"\n");\r
+       #else\r
+       PrintX=CST_START;\r
+       US_Print(STR_CRUN);\r
+       PrintX=CST_START+CST_SPC*1;\r
+       US_Print(STR_COPEN);\r
+       PrintX=CST_START+CST_SPC*2;\r
+       US_Print(STR_CFIRE);\r
+       PrintX=CST_START+CST_SPC*3;\r
+       US_Print(STR_CSTRAFE"\n");\r
+       #endif\r
+\r
+       DrawWindow(5,PrintY-1,310,13,BKGDCOLOR);\r
+       DrawCustMouse(0);\r
+       US_Print("\n");\r
+\r
+\r
+       //\r
+       // JOYSTICK/PAD\r
+       //\r
+#ifndef SPEAR\r
+       SETFONTCOLOR(READCOLOR,BKGDCOLOR);\r
+       US_CPrint("Joystick/Gravis GamePad\n");\r
+#else\r
+       PrintY += 13;\r
+       VWB_DrawPic (40,88,C_JOYSTICKPIC);\r
+#endif\r
+\r
+#ifdef SPEAR\r
+       VWB_DrawPic (112,120,C_KEYBOARDPIC);\r
+#endif\r
+\r
+       SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR);\r
+       #ifdef SPANISH\r
+       PrintX=CST_START-16;\r
+       US_Print(STR_CRUN);\r
+       PrintX=CST_START-16+CST_SPC*1;\r
+       US_Print(STR_COPEN);\r
+       PrintX=CST_START-16+CST_SPC*2;\r
+       US_Print(STR_CFIRE);\r
+       PrintX=CST_START-16+CST_SPC*3;\r
+       US_Print(STR_CSTRAFE"\n");\r
+       #else\r
+       PrintX=CST_START;\r
+       US_Print(STR_CRUN);\r
+       PrintX=CST_START+CST_SPC*1;\r
+       US_Print(STR_COPEN);\r
+       PrintX=CST_START+CST_SPC*2;\r
+       US_Print(STR_CFIRE);\r
+       PrintX=CST_START+CST_SPC*3;\r
+       US_Print(STR_CSTRAFE"\n");\r
+       #endif\r
+       DrawWindow(5,PrintY-1,310,13,BKGDCOLOR);\r
+       DrawCustJoy(0);\r
+       US_Print("\n");\r
+\r
+\r
+       //\r
+       // KEYBOARD\r
+       //\r
+#ifndef SPEAR\r
+       SETFONTCOLOR(READCOLOR,BKGDCOLOR);\r
+       US_CPrint("Keyboard\n");\r
+#else\r
+       PrintY += 13;\r
+#endif\r
+       SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR);\r
+       #ifdef SPANISH\r
+       PrintX=CST_START-16;\r
+       US_Print(STR_CRUN);\r
+       PrintX=CST_START-16+CST_SPC*1;\r
+       US_Print(STR_COPEN);\r
+       PrintX=CST_START-16+CST_SPC*2;\r
+       US_Print(STR_CFIRE);\r
+       PrintX=CST_START-16+CST_SPC*3;\r
+       US_Print(STR_CSTRAFE"\n");\r
+       #else\r
+       PrintX=CST_START;\r
+       US_Print(STR_CRUN);\r
+       PrintX=CST_START+CST_SPC*1;\r
+       US_Print(STR_COPEN);\r
+       PrintX=CST_START+CST_SPC*2;\r
+       US_Print(STR_CFIRE);\r
+       PrintX=CST_START+CST_SPC*3;\r
+       US_Print(STR_CSTRAFE"\n");\r
+       #endif\r
+       DrawWindow(5,PrintY-1,310,13,BKGDCOLOR);\r
+       DrawCustKeybd(0);\r
+       US_Print("\n");\r
+\r
+\r
+       //\r
+       // KEYBOARD MOVE KEYS\r
+       //\r
+       SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR);\r
+       #ifdef SPANISH\r
+       PrintX=4;\r
+       US_Print(STR_LEFT);\r
+       US_Print("/");\r
+       US_Print(STR_RIGHT);\r
+       US_Print("/");\r
+       US_Print(STR_FRWD);\r
+       US_Print("/");\r
+       US_Print(STR_BKWD"\n");\r
+       #else\r
+       PrintX=CST_START;\r
+       US_Print(STR_LEFT);\r
+       PrintX=CST_START+CST_SPC*1;\r
+       US_Print(STR_RIGHT);\r
+       PrintX=CST_START+CST_SPC*2;\r
+       US_Print(STR_FRWD);\r
+       PrintX=CST_START+CST_SPC*3;\r
+       US_Print(STR_BKWD"\n");\r
+       #endif\r
+       DrawWindow(5,PrintY-1,310,13,BKGDCOLOR);\r
+       DrawCustKeys(0);\r
+#endif\r
+       //\r
+       // PICK STARTING POINT IN MENU\r
+       //\r
+       if (CusItems.curpos<0)\r
+               for (i=0;i<CusItems.amount;i++)\r
+                       if (CusMenu[i].active)\r
+                       {\r
+                               CusItems.curpos=i;\r
+                               break;\r
+                       }\r
+\r
+\r
+       VW_UpdateScreen();\r
+       MenuFadeIn();\r
+}\r
+\r
+\r
+void PrintCustMouse(int i)\r
+{\r
+       int j;\r
+\r
+       for (j=0;j<4;j++)\r
+               if (order[i]==buttonmouse[j])\r
+               {\r
+                       PrintX=CST_START+CST_SPC*i;\r
+                       US_Print(mbarray[j]);\r
+                       break;\r
+               }\r
+}\r
+\r
+void DrawCustMouse(int hilight)\r
+{\r
+       int i,color;\r
+\r
+\r
+       color=TEXTCOLOR;\r
+       if (hilight)\r
+               color=HIGHLIGHT;\r
+       SETFONTCOLOR(color,BKGDCOLOR);\r
+\r
+       if (!mouseenabled)\r
+       {\r
+               SETFONTCOLOR(DEACTIVE,BKGDCOLOR);\r
+               CusMenu[0].active=0;\r
+       }\r
+       else\r
+               CusMenu[0].active=1;\r
+\r
+       PrintY=CST_Y+13*2;\r
+       for (i=0;i<4;i++)\r
+               PrintCustMouse(i);\r
+}\r
+\r
+void PrintCustJoy(int i)\r
+{\r
+       int j;\r
+\r
+       for (j=0;j<4;j++)\r
+               if (order[i]==buttonjoy[j])\r
+               {\r
+                       PrintX=CST_START+CST_SPC*i;\r
+                       US_Print(mbarray[j]);\r
+                       break;\r
+               }\r
+}\r
+\r
+void DrawCustJoy(int hilight)\r
+{\r
+       int i,color;\r
+\r
+\r
+       color=TEXTCOLOR;\r
+       if (hilight)\r
+               color=HIGHLIGHT;\r
+       SETFONTCOLOR(color,BKGDCOLOR);\r
+\r
+       if (!joystickenabled)\r
+       {\r
+               SETFONTCOLOR(DEACTIVE,BKGDCOLOR);\r
+               CusMenu[3].active=0;\r
+       }\r
+       else\r
+               CusMenu[3].active=1;\r
+\r
+       PrintY=CST_Y+13*5;\r
+       for (i=0;i<4;i++)\r
+               PrintCustJoy(i);\r
+}\r
+\r
+\r
+void PrintCustKeybd(int i)\r
+{\r
+       PrintX=CST_START+CST_SPC*i;\r
+       US_Print(IN_GetScanName(buttonscan[order[i]]));\r
+}\r
+\r
+void DrawCustKeybd(int hilight)\r
+{\r
+       int i,color;\r
+\r
+\r
+       color=TEXTCOLOR;\r
+       if (hilight)\r
+               color=HIGHLIGHT;\r
+       SETFONTCOLOR(color,BKGDCOLOR);\r
+\r
+       PrintY=CST_Y+13*8;\r
+       for (i=0;i<4;i++)\r
+               PrintCustKeybd(i);\r
+}\r
+\r
+void PrintCustKeys(int i)\r
+{\r
+       PrintX=CST_START+CST_SPC*i;\r
+       US_Print(IN_GetScanName(dirscan[moveorder[i]]));\r
+}\r
+\r
+void DrawCustKeys(int hilight)\r
+{\r
+       int i,color;\r
+\r
+\r
+       color=TEXTCOLOR;\r
+       if (hilight)\r
+               color=HIGHLIGHT;\r
+       SETFONTCOLOR(color,BKGDCOLOR);\r
+\r
+       PrintY=CST_Y+13*10;\r
+       for (i=0;i<4;i++)\r
+               PrintCustKeys(i);\r
+}\r
+\r
+\r
+////////////////////////////////////////////////////////////////////\r
+//\r
+// CHANGE SCREEN VIEWING SIZE\r
+//\r
+////////////////////////////////////////////////////////////////////\r
+void CP_ChangeView(void)\r
+{\r
+       int exit=0,oldview,newview;\r
+       ControlInfo ci;\r
+\r
+\r
+       WindowX=WindowY=0;\r
+       WindowW=320;\r
+       WindowH=200;\r
+       newview=oldview=viewwidth/16;\r
+       DrawChangeView(oldview);\r
+\r
+       do\r
+       {\r
+               CheckPause();\r
+               ReadAnyControl(&ci);\r
+               switch(ci.dir)\r
+               {\r
+               case dir_South:\r
+               case dir_West:\r
+                       newview--;\r
+                       if (newview<4)\r
+                               newview=4;\r
+                       ShowViewSize(newview);\r
+                       VW_UpdateScreen();\r
+                       SD_PlaySound(HITWALLSND);\r
+                       TicDelay(10);\r
+                       break;\r
+\r
+               case dir_North:\r
+               case dir_East:\r
+                       newview++;\r
+                       if (newview>19)\r
+                               newview=19;\r
+                       ShowViewSize(newview);\r
+                       VW_UpdateScreen();\r
+                       SD_PlaySound(HITWALLSND);\r
+                       TicDelay(10);\r
+                       break;\r
+               }\r
+\r
+               #ifndef SPEAR\r
+               if (Keyboard[sc_Tab] && Keyboard[sc_P] && MS_CheckParm("goobers"))\r
+               #else\r
+               if (Keyboard[sc_Tab] && Keyboard[sc_P] && MS_CheckParm("debugmode"))\r
+               #endif\r
+                       PicturePause();\r
+\r
+               if (ci.button0 || Keyboard[sc_Enter])\r
+                       exit=1;\r
+               else\r
+               if (ci.button1 || Keyboard[sc_Escape])\r
+               {\r
+                       viewwidth=oldview*16;\r
+                       SD_PlaySound(ESCPRESSEDSND);\r
+                       MenuFadeOut();\r
+                       return;\r
+               }\r
+\r
+       } while(!exit);\r
+\r
+\r
+       if (oldview!=newview)\r
+       {\r
+               SD_PlaySound (SHOOTSND);\r
+               Message(STR_THINK"...");\r
+               NewViewSize(newview);\r
+       }\r
+\r
+       ShootSnd();\r
+       MenuFadeOut();\r
+}\r
+\r
+\r
+/////////////////////////////\r
+//\r
+// DRAW THE CHANGEVIEW SCREEN\r
+//\r
+void DrawChangeView(int view)\r
+{\r
+#ifdef JAPAN\r
+       CA_CacheScreen(S_CHANGEPIC);\r
+\r
+       ShowViewSize(view);\r
+#else\r
+       VWB_Bar(0,160,320,40,VIEWCOLOR);\r
+       ShowViewSize(view);\r
+\r
+       PrintY=161;\r
+       WindowX=0;\r
+       WindowY=320;\r
+       SETFONTCOLOR(HIGHLIGHT,BKGDCOLOR);\r
+\r
+       US_CPrint(STR_SIZE1"\n");\r
+       US_CPrint(STR_SIZE2"\n");\r
+       US_CPrint(STR_SIZE3);\r
+#endif\r
+       VW_UpdateScreen();\r
+\r
+       MenuFadeIn();\r
+}\r
+\r
+\r
+////////////////////////////////////////////////////////////////////\r
+//\r
+// QUIT THIS INFERNAL GAME!\r
+//\r
+////////////////////////////////////////////////////////////////////\r
+void CP_Quit(void)\r
+{\r
+       int i;\r
+\r
+\r
+       #ifdef JAPAN\r
+       if (GetYorN(7,11,C_QUITMSGPIC))\r
+       #else\r
+\r
+       #ifdef SPANISH\r
+       if (Confirm(ENDGAMESTR))\r
+       #else\r
+       if (Confirm(endStrings[US_RndT()&0x7+(US_RndT()&1)]))\r
+       #endif\r
+\r
+       #endif\r
+       {\r
+               VW_UpdateScreen();\r
+               SD_MusicOff();\r
+               SD_StopSound();\r
+               MenuFadeOut();\r
+               //\r
+               // SHUT-UP THE ADLIB\r
+               //\r
+               for (i=1;i<=0xf5;i++)\r
+                       alOut(i,0);\r
+               Quit(NULL);\r
+       }\r
+\r
+       DrawMainMenu();\r
+}\r
+\r
+\r
+////////////////////////////////////////////////////////////////////\r
+//\r
+// HANDLE INTRO SCREEN (SYSTEM CONFIG)\r
+//\r
+////////////////////////////////////////////////////////////////////\r
+void IntroScreen(void)\r
+{\r
+#ifdef SPEAR\r
+\r
+#define MAINCOLOR      0x4f\r
+#define EMSCOLOR       0x4f\r
+#define XMSCOLOR       0x4f\r
+\r
+#else\r
+\r
+#define MAINCOLOR      0x6c\r
+#define EMSCOLOR       0x6c\r
+#define XMSCOLOR       0x6c\r
+\r
+#endif\r
+#define FILLCOLOR      14\r
+\r
+       long memory,emshere,xmshere;\r
+       int i,num,ems[10]={100,200,300,400,500,600,700,800,900,1000},\r
+               xms[10]={100,200,300,400,500,600,700,800,900,1000},\r
+               main[10]={32,64,96,128,160,192,224,256,288,320};\r
+\r
+\r
+       //\r
+       // DRAW MAIN MEMORY\r
+       //\r
+       memory=(1023l+mminfo.nearheap+mminfo.farheap)/1024l;\r
+       for (i=0;i<10;i++)\r
+               if (memory>=main[i])\r
+                       VWB_Bar(49,163-8*i,6,5,MAINCOLOR-i);\r
+\r
+\r
+       //\r
+       // DRAW EMS MEMORY\r
+       //\r
+       if (EMSPresent)\r
+       {\r
+               emshere=4l*EMSPagesAvail;\r
+               for (i=0;i<10;i++)\r
+                       if (emshere>=ems[i])\r
+                               VWB_Bar(89,163-8*i,6,5,EMSCOLOR-i);\r
+       }\r
+\r
+       //\r
+       // DRAW XMS MEMORY\r
+       //\r
+       if (XMSPresent)\r
+       {\r
+               xmshere=4l*XMSPagesAvail;\r
+               for (i=0;i<10;i++)\r
+                       if (xmshere>=xms[i])\r
+                               VWB_Bar(129,163-8*i,6,5,XMSCOLOR-i);\r
+       }\r
+\r
+       //\r
+       // FILL BOXES\r
+       //\r
+       if (MousePresent)\r
+               VWB_Bar(164,82,12,2,FILLCOLOR);\r
+\r
+       if (JoysPresent[0] || JoysPresent[1])\r
+               VWB_Bar(164,105,12,2,FILLCOLOR);\r
+\r
+       if (AdLibPresent && !SoundBlasterPresent)\r
+               VWB_Bar(164,128,12,2,FILLCOLOR);\r
+\r
+       if (SoundBlasterPresent)\r
+               VWB_Bar(164,151,12,2,FILLCOLOR);\r
+\r
+       if (SoundSourcePresent)\r
+               VWB_Bar(164,174,12,2,FILLCOLOR);\r
+}\r
+\r
+\r
+////////////////////////////////////////////////////////////////////\r
+////////////////////////////////////////////////////////////////////\r
+//\r
+// SUPPORT ROUTINES\r
+//\r
+////////////////////////////////////////////////////////////////////\r
+////////////////////////////////////////////////////////////////////\r
+\r
+////////////////////////////////////////////////////////////////////\r
+//\r
+// Clear Menu screens to dark red\r
+//\r
+////////////////////////////////////////////////////////////////////\r
+void ClearMScreen(void)\r
+{\r
+#ifndef SPEAR\r
+       VWB_Bar(0,0,320,200,BORDCOLOR);\r
+#else\r
+       VWB_DrawPic(0,0,C_BACKDROPPIC);\r
+#endif\r
+}\r
+\r
+\r
+////////////////////////////////////////////////////////////////////\r
+//\r
+// Un/Cache a LUMP of graphics\r
+//\r
+////////////////////////////////////////////////////////////////////\r
+void CacheLump(int lumpstart,int lumpend)\r
+{\r
+ int i;\r
+\r
+ for (i=lumpstart;i<=lumpend;i++)\r
+   CA_CacheGrChunk(i);\r
+}\r
+\r
+\r
+void UnCacheLump(int lumpstart,int lumpend)\r
+{\r
+ int i;\r
+\r
+ for (i=lumpstart;i<=lumpend;i++)\r
+       if (grsegs[i])\r
+               UNCACHEGRCHUNK(i);\r
+}\r
+\r
+\r
+////////////////////////////////////////////////////////////////////\r
+//\r
+// Draw a window for a menu\r
+//\r
+////////////////////////////////////////////////////////////////////\r
+void DrawWindow(int x,int y,int w,int h,int wcolor)\r
+{\r
+       VWB_Bar(x,y,w,h,wcolor);\r
+       DrawOutline(x,y,w,h,BORD2COLOR,DEACTIVE);\r
+}\r
+\r
+\r
+void DrawOutline(int x,int y,int w,int h,int color1,int color2)\r
+{\r
+       VWB_Hlin(x,x+w,y,color2);\r
+       VWB_Vlin(y,y+h,x,color2);\r
+       VWB_Hlin(x,x+w,y+h,color1);\r
+       VWB_Vlin(y,y+h,x+w,color1);\r
+}\r
+\r
+\r
+////////////////////////////////////////////////////////////////////\r
+//\r
+// Setup Control Panel stuff - graphics, etc.\r
+//\r
+////////////////////////////////////////////////////////////////////\r
+void SetupControlPanel(void)\r
+{\r
+       struct ffblk f;\r
+       char name[13];\r
+       int which,i;\r
+\r
+\r
+       //\r
+       // CACHE GRAPHICS & SOUNDS\r
+       //\r
+       CA_CacheGrChunk(STARTFONT+1);\r
+#ifndef SPEAR\r
+       CacheLump(CONTROLS_LUMP_START,CONTROLS_LUMP_END);\r
+#else\r
+       CacheLump(BACKDROP_LUMP_START,BACKDROP_LUMP_END);\r
+#endif\r
+\r
+       SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR);\r
+       fontnumber=1;\r
+       WindowH=200;\r
+\r
+       if (!ingame)\r
+               CA_LoadAllSounds();\r
+       else\r
+               MainMenu[savegame].active=1;\r
+\r
+       //\r
+       // SEE WHICH SAVE GAME FILES ARE AVAILABLE & READ STRING IN\r
+       //\r
+       strcpy(name,SaveName);\r
+       if (!findfirst(name,&f,0))\r
+               do\r
+               {\r
+                       which=f.ff_name[7]-'0';\r
+                       if (which<10)\r
+                       {\r
+                               int handle;\r
+                               char temp[32];\r
+\r
+                               SaveGamesAvail[which]=1;\r
+                               handle=open(f.ff_name,O_BINARY);\r
+                               read(handle,temp,32);\r
+                               close(handle);\r
+                               strcpy(&SaveGameNames[which][0],temp);\r
+                       }\r
+               } while(!findnext(&f));\r
+\r
+       //\r
+       // CENTER MOUSE\r
+       //\r
+       _CX=_DX=CENTER;\r
+       Mouse(4);\r
+}\r
+\r
+\r
+////////////////////////////////////////////////////////////////////\r
+//\r
+// Clean up all the Control Panel stuff\r
+//\r
+////////////////////////////////////////////////////////////////////\r
+void CleanupControlPanel(void)\r
+{\r
+#ifndef SPEAR\r
+       UnCacheLump(CONTROLS_LUMP_START,CONTROLS_LUMP_END);\r
+#else\r
+       UnCacheLump (BACKDROP_LUMP_START,BACKDROP_LUMP_END);\r
+#endif\r
+\r
+       fontnumber = 0;\r
+}\r
+\r
+\r
+////////////////////////////////////////////////////////////////////\r
+//\r
+// Handle moving gun around a menu\r
+//\r
+////////////////////////////////////////////////////////////////////\r
+int HandleMenu(CP_iteminfo *item_i,CP_itemtype far *items,void (*routine)(int w))\r
+{\r
+       char key;\r
+       static int redrawitem=1,lastitem=-1;\r
+       int i,x,y,basey,exit,which,shape,timer;\r
+       ControlInfo ci;\r
+\r
+\r
+       which=item_i->curpos;\r
+       x=item_i->x&-8;\r
+       basey=item_i->y-2;\r
+       y=basey+which*13;\r
+\r
+       VWB_DrawPic(x,y,C_CURSOR1PIC);\r
+       SetTextColor(items+which,1);\r
+       if (redrawitem)\r
+       {\r
+               PrintX=item_i->x+item_i->indent;\r
+               PrintY=item_i->y+which*13;\r
+               US_Print((items+which)->string);\r
+       }\r
+       //\r
+       // CALL CUSTOM ROUTINE IF IT IS NEEDED\r
+       //\r
+       if (routine)\r
+               routine(which);\r
+       VW_UpdateScreen();\r
+\r
+       shape=C_CURSOR1PIC;\r
+       timer=8;\r
+       exit=0;\r
+       TimeCount=0;\r
+       IN_ClearKeysDown();\r
+\r
+\r
+       do\r
+       {\r
+               //\r
+               // CHANGE GUN SHAPE\r
+               //\r
+               if (TimeCount>timer)\r
+               {\r
+                       TimeCount=0;\r
+                       if (shape==C_CURSOR1PIC)\r
+                       {\r
+                               shape=C_CURSOR2PIC;\r
+                               timer=8;\r
+                       }\r
+                       else\r
+                       {\r
+                               shape=C_CURSOR1PIC;\r
+                               timer=70;\r
+                       }\r
+                       VWB_DrawPic(x,y,shape);\r
+                       if (routine)\r
+                               routine(which);\r
+                       VW_UpdateScreen();\r
+               }\r
+\r
+               CheckPause();\r
+\r
+               //\r
+               // SEE IF ANY KEYS ARE PRESSED FOR INITIAL CHAR FINDING\r
+               //\r
+               key=LastASCII;\r
+               if (key)\r
+               {\r
+                       int ok=0;\r
+\r
+                       //\r
+                       // CHECK FOR SCREEN CAPTURE\r
+                       //\r
+                       #ifndef SPEAR\r
+                       if (Keyboard[sc_Tab] && Keyboard[sc_P] && MS_CheckParm("goobers"))\r
+                       #else\r
+                       if (Keyboard[sc_Tab] && Keyboard[sc_P] && MS_CheckParm("debugmode"))\r
+                       #endif\r
+                               PicturePause();\r
+\r
+\r
+                       if (key>='a')\r
+                               key-='a'-'A';\r
+\r
+                       for (i=which+1;i<item_i->amount;i++)\r
+                               if ((items+i)->active && (items+i)->string[0]==key)\r
+                               {\r
+                                       EraseGun(item_i,items,x,y,which);\r
+                                       which=i;\r
+                                       DrawGun(item_i,items,x,&y,which,basey,routine);\r
+                                       ok=1;\r
+                                       IN_ClearKeysDown();\r
+                                       break;\r
+                               }\r
+\r
+                       //\r
+                       // DIDN'T FIND A MATCH FIRST TIME THRU. CHECK AGAIN.\r
+                       //\r
+                       if (!ok)\r
+                       {\r
+                               for (i=0;i<which;i++)\r
+                                       if ((items+i)->active && (items+i)->string[0]==key)\r
+                                       {\r
+                                               EraseGun(item_i,items,x,y,which);\r
+                                               which=i;\r
+                                               DrawGun(item_i,items,x,&y,which,basey,routine);\r
+                                               IN_ClearKeysDown();\r
+                                               break;\r
+                                       }\r
+                       }\r
+               }\r
+\r
+               //\r
+               // GET INPUT\r
+               //\r
+               ReadAnyControl(&ci);\r
+               switch(ci.dir)\r
+               {\r
+                       ////////////////////////////////////////////////\r
+                       //\r
+                       // MOVE UP\r
+                       //\r
+                       case dir_North:\r
+\r
+                       EraseGun(item_i,items,x,y,which);\r
+\r
+                       //\r
+                       // ANIMATE HALF-STEP\r
+                       //\r
+                       if (which && (items+which-1)->active)\r
+                       {\r
+                               y-=6;\r
+                               DrawHalfStep(x,y);\r
+                       }\r
+\r
+                       //\r
+                       // MOVE TO NEXT AVAILABLE SPOT\r
+                       //\r
+                       do\r
+                       {\r
+                               if (!which)\r
+                                       which=item_i->amount-1;\r
+                               else\r
+                                       which--;\r
+                       } while(!(items+which)->active);\r
+\r
+                       DrawGun(item_i,items,x,&y,which,basey,routine);\r
+                       //\r
+                       // WAIT FOR BUTTON-UP OR DELAY NEXT MOVE\r
+                       //\r
+                       TicDelay(20);\r
+                       break;\r
+\r
+                       ////////////////////////////////////////////////\r
+                       //\r
+                       // MOVE DOWN\r
+                       //\r
+                       case dir_South:\r
+\r
+                       EraseGun(item_i,items,x,y,which);\r
+                       //\r
+                       // ANIMATE HALF-STEP\r
+                       //\r
+                       if (which!=item_i->amount-1 && (items+which+1)->active)\r
+                       {\r
+                               y+=6;\r
+                               DrawHalfStep(x,y);\r
+                       }\r
+\r
+                       do\r
+                       {\r
+                               if (which==item_i->amount-1)\r
+                                       which=0;\r
+                               else\r
+                                       which++;\r
+                       } while(!(items+which)->active);\r
+\r
+                       DrawGun(item_i,items,x,&y,which,basey,routine);\r
+\r
+                       //\r
+                       // WAIT FOR BUTTON-UP OR DELAY NEXT MOVE\r
+                       //\r
+                       TicDelay(20);\r
+                       break;\r
+               }\r
+\r
+               if (ci.button0 ||\r
+                       Keyboard[sc_Space] ||\r
+                       Keyboard[sc_Enter])\r
+                               exit=1;\r
+\r
+               if (ci.button1 ||\r
+                       Keyboard[sc_Escape])\r
+                               exit=2;\r
+\r
+       } while(!exit);\r
+\r
+\r
+       IN_ClearKeysDown();\r
+\r
+       //\r
+       // ERASE EVERYTHING\r
+       //\r
+       if (lastitem!=which)\r
+       {\r
+               VWB_Bar(x-1,y,25,16,BKGDCOLOR);\r
+               PrintX=item_i->x+item_i->indent;\r
+               PrintY=item_i->y+which*13;\r
+               US_Print((items+which)->string);\r
+               redrawitem=1;\r
+       }\r
+       else\r
+               redrawitem=0;\r
+\r
+       if (routine)\r
+               routine(which);\r
+       VW_UpdateScreen();\r
+\r
+       item_i->curpos=which;\r
+\r
+       lastitem=which;\r
+       switch(exit)\r
+       {\r
+               case 1:\r
+                       //\r
+                       // CALL THE ROUTINE\r
+                       //\r
+                       if ((items+which)->routine!=NULL)\r
+                       {\r
+                               ShootSnd();\r
+                               MenuFadeOut();\r
+                               (items+which)->routine(0);\r
+                       }\r
+                       return which;\r
+\r
+               case 2:\r
+                       SD_PlaySound(ESCPRESSEDSND);\r
+                       return -1;\r
+       }\r
+\r
+       return 0; // JUST TO SHUT UP THE ERROR MESSAGES!\r
+}\r
+\r
+\r
+//\r
+// ERASE GUN & DE-HIGHLIGHT STRING\r
+//\r
+void EraseGun(CP_iteminfo *item_i,CP_itemtype far *items,int x,int y,int which)\r
+{\r
+       VWB_Bar(x-1,y,25,16,BKGDCOLOR);\r
+       SetTextColor(items+which,0);\r
+\r
+       PrintX=item_i->x+item_i->indent;\r
+       PrintY=item_i->y+which*13;\r
+       US_Print((items+which)->string);\r
+       VW_UpdateScreen();\r
+}\r
+\r
+\r
+//\r
+// DRAW HALF STEP OF GUN TO NEXT POSITION\r
+//\r
+void DrawHalfStep(int x,int y)\r
+{\r
+       VWB_DrawPic(x,y,C_CURSOR1PIC);\r
+       VW_UpdateScreen();\r
+       SD_PlaySound(MOVEGUN1SND);\r
+       TimeCount=0;\r
+       while(TimeCount<8);\r
+}\r
+\r
+\r
+//\r
+// DRAW GUN AT NEW POSITION\r
+//\r
+void DrawGun(CP_iteminfo *item_i,CP_itemtype far *items,int x,int *y,int which,int basey,void (*routine)(int w))\r
+{\r
+       VWB_Bar(x-1,*y,25,16,BKGDCOLOR);\r
+       *y=basey+which*13;\r
+       VWB_DrawPic(x,*y,C_CURSOR1PIC);\r
+       SetTextColor(items+which,1);\r
+\r
+       PrintX=item_i->x+item_i->indent;\r
+       PrintY=item_i->y+which*13;\r
+       US_Print((items+which)->string);\r
+\r
+       //\r
+       // CALL CUSTOM ROUTINE IF IT IS NEEDED\r
+       //\r
+       if (routine)\r
+               routine(which);\r
+       VW_UpdateScreen();\r
+       SD_PlaySound(MOVEGUN2SND);\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////\r
+//\r
+// DELAY FOR AN AMOUNT OF TICS OR UNTIL CONTROLS ARE INACTIVE\r
+//\r
+////////////////////////////////////////////////////////////////////\r
+void TicDelay(int count)\r
+{\r
+       ControlInfo ci;\r
+\r
+\r
+       TimeCount=0;\r
+       do\r
+       {\r
+               ReadAnyControl(&ci);\r
+       } while(TimeCount<count && ci.dir!=dir_None);\r
+}\r
+\r
+\r
+////////////////////////////////////////////////////////////////////\r
+//\r
+// Draw a menu\r
+//\r
+////////////////////////////////////////////////////////////////////\r
+void DrawMenu(CP_iteminfo *item_i,CP_itemtype far *items)\r
+{\r
+       int i,which=item_i->curpos;\r
+\r
+\r
+       WindowX=PrintX=item_i->x+item_i->indent;\r
+       WindowY=PrintY=item_i->y;\r
+       WindowW=320;\r
+       WindowH=200;\r
+\r
+       for (i=0;i<item_i->amount;i++)\r
+       {\r
+               SetTextColor(items+i,which==i);\r
+\r
+               PrintY=item_i->y+i*13;\r
+               if ((items+i)->active)\r
+                       US_Print((items+i)->string);\r
+               else\r
+               {\r
+                       SETFONTCOLOR(DEACTIVE,BKGDCOLOR);\r
+                       US_Print((items+i)->string);\r
+                       SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR);\r
+               }\r
+\r
+               US_Print("\n");\r
+       }\r
+}\r
+\r
+\r
+////////////////////////////////////////////////////////////////////\r
+//\r
+// SET TEXT COLOR (HIGHLIGHT OR NO)\r
+//\r
+////////////////////////////////////////////////////////////////////\r
+void SetTextColor(CP_itemtype far *items,int hlight)\r
+{\r
+       if (hlight)\r
+               {SETFONTCOLOR(color_hlite[items->active],BKGDCOLOR);}\r
+       else\r
+               {SETFONTCOLOR(color_norml[items->active],BKGDCOLOR);}\r
+}\r
+\r
+\r
+////////////////////////////////////////////////////////////////////\r
+//\r
+// WAIT FOR CTRLKEY-UP OR BUTTON-UP\r
+//\r
+////////////////////////////////////////////////////////////////////\r
+void WaitKeyUp(void)\r
+{\r
+       ControlInfo ci;\r
+       while(ReadAnyControl(&ci),      ci.button0|\r
+                                                               ci.button1|\r
+                                                               ci.button2|\r
+                                                               ci.button3|\r
+                                                               Keyboard[sc_Space]|\r
+                                                               Keyboard[sc_Enter]|\r
+                                                               Keyboard[sc_Escape]);\r
+}\r
+\r
+\r
+////////////////////////////////////////////////////////////////////\r
+//\r
+// READ KEYBOARD, JOYSTICK AND MOUSE FOR INPUT\r
+//\r
+////////////////////////////////////////////////////////////////////\r
+void ReadAnyControl(ControlInfo *ci)\r
+{\r
+       int mouseactive=0;\r
+\r
+\r
+       IN_ReadControl(0,ci);\r
+\r
+       if (mouseenabled)\r
+       {\r
+               int mousey,mousex;\r
+\r
+\r
+               // READ MOUSE MOTION COUNTERS\r
+               // RETURN DIRECTION\r
+               // HOME MOUSE\r
+               // CHECK MOUSE BUTTONS\r
+\r
+               Mouse(3);\r
+               mousex=_CX;\r
+               mousey=_DX;\r
+\r
+               if (mousey<CENTER-SENSITIVE)\r
+               {\r
+                       ci->dir=dir_North;\r
+                       _CX=_DX=CENTER;\r
+                       Mouse(4);\r
+                       mouseactive=1;\r
+               }\r
+               else\r
+               if (mousey>CENTER+SENSITIVE)\r
+               {\r
+                       ci->dir=dir_South;\r
+                       _CX=_DX=CENTER;\r
+                       Mouse(4);\r
+                       mouseactive=1;\r
+               }\r
+\r
+               if (mousex<CENTER-SENSITIVE)\r
+               {\r
+                       ci->dir=dir_West;\r
+                       _CX=_DX=CENTER;\r
+                       Mouse(4);\r
+                       mouseactive=1;\r
+               }\r
+               else\r
+               if (mousex>CENTER+SENSITIVE)\r
+               {\r
+                       ci->dir=dir_East;\r
+                       _CX=_DX=CENTER;\r
+                       Mouse(4);\r
+                       mouseactive=1;\r
+               }\r
+\r
+               if (IN_MouseButtons())\r
+               {\r
+                       ci->button0=IN_MouseButtons()&1;\r
+                       ci->button1=IN_MouseButtons()&2;\r
+                       ci->button2=IN_MouseButtons()&4;\r
+                       ci->button3=false;\r
+                       mouseactive=1;\r
+               }\r
+       }\r
+\r
+       if (joystickenabled && !mouseactive)\r
+       {\r
+               int jx,jy,jb;\r
+\r
+\r
+               INL_GetJoyDelta(joystickport,&jx,&jy);\r
+               if (jy<-SENSITIVE)\r
+                       ci->dir=dir_North;\r
+               else\r
+               if (jy>SENSITIVE)\r
+                       ci->dir=dir_South;\r
+\r
+               if (jx<-SENSITIVE)\r
+                       ci->dir=dir_West;\r
+               else\r
+               if (jx>SENSITIVE)\r
+                       ci->dir=dir_East;\r
+\r
+               jb=IN_JoyButtons();\r
+               if (jb)\r
+               {\r
+                       ci->button0=jb&1;\r
+                       ci->button1=jb&2;\r
+                       if (joypadenabled)\r
+                       {\r
+                               ci->button2=jb&4;\r
+                               ci->button3=jb&8;\r
+                       }\r
+                       else\r
+                               ci->button2=ci->button3=false;\r
+               }\r
+       }\r
+}\r
+\r
+\r
+////////////////////////////////////////////////////////////////////\r
+//\r
+// DRAW DIALOG AND CONFIRM YES OR NO TO QUESTION\r
+//\r
+////////////////////////////////////////////////////////////////////\r
+int Confirm(char far *string)\r
+{\r
+       int xit=0,i,x,y,tick=0,time,whichsnd[2]={ESCPRESSEDSND,SHOOTSND};\r
+\r
+\r
+       Message(string);\r
+       IN_ClearKeysDown();\r
+\r
+       //\r
+       // BLINK CURSOR\r
+       //\r
+       x=PrintX;\r
+       y=PrintY;\r
+       TimeCount=0;\r
+\r
+       do\r
+       {\r
+               if (TimeCount>=10)\r
+               {\r
+                       switch(tick)\r
+                       {\r
+                               case 0:\r
+                                       VWB_Bar(x,y,8,13,TEXTCOLOR);\r
+                                       break;\r
+                               case 1:\r
+                                       PrintX=x;\r
+                                       PrintY=y;\r
+                                       US_Print("_");\r
+                       }\r
+                       VW_UpdateScreen();\r
+                       tick^=1;\r
+                       TimeCount=0;\r
+               }\r
+\r
+               #ifndef SPEAR\r
+               if (Keyboard[sc_Tab] && Keyboard[sc_P] && MS_CheckParm("goobers"))\r
+                       PicturePause();\r
+               #endif\r
+\r
+       #ifdef SPANISH\r
+       } while(!Keyboard[sc_S] && !Keyboard[sc_N] && !Keyboard[sc_Escape]);\r
+       #else\r
+       } while(!Keyboard[sc_Y] && !Keyboard[sc_N] && !Keyboard[sc_Escape]);\r
+       #endif\r
+\r
+       #ifdef SPANISH\r
+       if (Keyboard[sc_S])\r
+       {\r
+               xit=1;\r
+               ShootSnd();\r
+       }\r
+\r
+       while(Keyboard[sc_S] || Keyboard[sc_N] || Keyboard[sc_Escape]);\r
+\r
+       #else\r
+\r
+       if (Keyboard[sc_Y])\r
+       {\r
+               xit=1;\r
+               ShootSnd();\r
+       }\r
+\r
+       while(Keyboard[sc_Y] || Keyboard[sc_N] || Keyboard[sc_Escape]);\r
+       #endif\r
+\r
+       IN_ClearKeysDown();\r
+       SD_PlaySound(whichsnd[xit]);\r
+       return xit;\r
+}\r
+\r
+#ifdef JAPAN\r
+////////////////////////////////////////////////////////////////////\r
+//\r
+// DRAW MESSAGE & GET Y OR N\r
+//\r
+////////////////////////////////////////////////////////////////////\r
+int GetYorN(int x,int y,int pic)\r
+{\r
+       int xit=0,whichsnd[2]={ESCPRESSEDSND,SHOOTSND};\r
+\r
+\r
+       CA_CacheGrChunk(pic);\r
+       VWB_DrawPic(x * 8,y * 8,pic);\r
+       UNCACHEGRCHUNK(pic);\r
+       VW_UpdateScreen();\r
+       IN_ClearKeysDown();\r
+\r
+       do\r
+       {\r
+               #ifndef SPEAR\r
+               if (Keyboard[sc_Tab] && Keyboard[sc_P] && MS_CheckParm("goobers"))\r
+                       PicturePause();\r
+               #endif\r
+\r
+       #ifdef SPANISH\r
+       } while(!Keyboard[sc_S] && !Keyboard[sc_N] && !Keyboard[sc_Escape]);\r
+       #else\r
+       } while(!Keyboard[sc_Y] && !Keyboard[sc_N] && !Keyboard[sc_Escape]);\r
+       #endif\r
+\r
+       #ifdef SPANISH\r
+       if (Keyboard[sc_S])\r
+       {\r
+               xit=1;\r
+               ShootSnd();\r
+       }\r
+\r
+       while(Keyboard[sc_S] || Keyboard[sc_N] || Keyboard[sc_Escape]);\r
+\r
+       #else\r
+\r
+       if (Keyboard[sc_Y])\r
+       {\r
+               xit=1;\r
+               ShootSnd();\r
+       }\r
+\r
+       while(Keyboard[sc_Y] || Keyboard[sc_N] || Keyboard[sc_Escape]);\r
+       #endif\r
+\r
+       IN_ClearKeysDown();\r
+       SD_PlaySound(whichsnd[xit]);\r
+       return xit;\r
+}\r
+#endif\r
+\r
+\r
+////////////////////////////////////////////////////////////////////\r
+//\r
+// PRINT A MESSAGE IN A WINDOW\r
+//\r
+////////////////////////////////////////////////////////////////////\r
+void Message(char far *string)\r
+{\r
+       int h=0,w=0,mw=0,i,x,y,time;\r
+       fontstruct _seg *font;\r
+\r
+\r
+       CA_CacheGrChunk (STARTFONT+1);\r
+       fontnumber=1;\r
+       font=grsegs[STARTFONT+fontnumber];\r
+       h=font->height;\r
+       for (i=0;i<_fstrlen(string);i++)\r
+               if (string[i]=='\n')\r
+               {\r
+                       if (w>mw)\r
+                               mw=w;\r
+                       w=0;\r
+                       h+=font->height;\r
+               }\r
+               else\r
+                       w+=font->width[string[i]];\r
+\r
+       if (w+10>mw)\r
+               mw=w+10;\r
+\r
+       PrintY=(WindowH/2)-h/2;\r
+       PrintX=WindowX=160-mw/2;\r
+\r
+       DrawWindow(WindowX-5,PrintY-5,mw+10,h+10,TEXTCOLOR);\r
+       DrawOutline(WindowX-5,PrintY-5,mw+10,h+10,0,HIGHLIGHT);\r
+       SETFONTCOLOR(0,TEXTCOLOR);\r
+       US_Print(string);\r
+       VW_UpdateScreen();\r
+}\r
+\r
+\r
+////////////////////////////////////////////////////////////////////\r
+//\r
+// THIS MAY BE FIXED A LITTLE LATER...\r
+//\r
+////////////////////////////////////////////////////////////////////\r
+static int     lastmusic;\r
+\r
+void StartCPMusic(int song)\r
+{\r
+       musicnames      chunk;\r
+\r
+       if (audiosegs[STARTMUSIC + lastmusic])  // JDC\r
+               MM_FreePtr ((memptr *)&audiosegs[STARTMUSIC + lastmusic]);\r
+       lastmusic = song;\r
+\r
+       SD_MusicOff();\r
+       chunk = song;\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
+void FreeMusic (void)\r
+{\r
+       if (audiosegs[STARTMUSIC + lastmusic])  // JDC\r
+               MM_FreePtr ((memptr *)&audiosegs[STARTMUSIC + lastmusic]);\r
+}\r
+\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     IN_GetScanName() - Returns a string containing the name of the\r
+//             specified scan code\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+byte *\r
+IN_GetScanName(ScanCode scan)\r
+{\r
+       byte            **p;\r
+       ScanCode        far *s;\r
+\r
+       for (s = ExtScanCodes,p = ExtScanNames;*s;p++,s++)\r
+               if (*s == scan)\r
+                       return(*p);\r
+\r
+       return(ScanNames[scan]);\r
+}\r
+\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// CHECK FOR PAUSE KEY (FOR MUSIC ONLY)\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void CheckPause(void)\r
+{\r
+       if (Paused)\r
+       {\r
+               switch(SoundStatus)\r
+               {\r
+                       case 0: SD_MusicOn(); break;\r
+                       case 1: SD_MusicOff(); break;\r
+               }\r
+\r
+               SoundStatus^=1;\r
+               VW_WaitVBL(3);\r
+               IN_ClearKeysDown();\r
+               Paused=false;\r
+ }\r
+}\r
+\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// DRAW GUN CURSOR AT CORRECT POSITION IN MENU\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void DrawMenuGun(CP_iteminfo *iteminfo)\r
+{\r
+       int x,y;\r
+\r
+\r
+       x=iteminfo->x;\r
+       y=iteminfo->y+iteminfo->curpos*13-2;\r
+       VWB_DrawPic(x,y,C_CURSOR1PIC);\r
+}\r
+\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// DRAW SCREEN TITLE STRIPES\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void DrawStripes(int y)\r
+{\r
+#ifndef SPEAR\r
+       VWB_Bar(0,y,320,24,0);\r
+       VWB_Hlin(0,319,y+22,STRIPE);\r
+#else\r
+       VWB_Bar(0,y,320,22,0);\r
+       VWB_Hlin(0,319,y+23,0);\r
+#endif\r
+}\r
+\r
+void ShootSnd(void)\r
+{\r
+       SD_PlaySound(SHOOTSND);\r
+}\r
+\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// CHECK FOR EPISODES\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void CheckForEpisodes(void)\r
+{\r
+       struct ffblk f;\r
+\r
+//\r
+// JAPANESE VERSION\r
+//\r
+#ifdef JAPAN\r
+#ifdef JAPDEMO\r
+       if (!findfirst("*.WJ1",&f,FA_ARCH))\r
+       {\r
+               strcpy(extension,"WJ1");\r
+#else\r
+       if (!findfirst("*.WJ6",&f,FA_ARCH))\r
+       {\r
+               strcpy(extension,"WJ6");\r
+#endif\r
+               strcat(configname,extension);\r
+               strcat(SaveName,extension);\r
+               strcat(PageFileName,extension);\r
+               strcat(audioname,extension);\r
+               strcat(demoname,extension);\r
+               EpisodeSelect[1] =\r
+               EpisodeSelect[2] =\r
+               EpisodeSelect[3] =\r
+               EpisodeSelect[4] =\r
+               EpisodeSelect[5] = 1;\r
+       }\r
+       else\r
+               Quit("NO JAPANESE WOLFENSTEIN 3-D DATA FILES to be found!");\r
+#else\r
+\r
+//\r
+// ENGLISH\r
+//\r
+#ifndef UPLOAD\r
+#ifndef SPEAR\r
+       if (!findfirst("*.WL6",&f,FA_ARCH))\r
+       {\r
+               strcpy(extension,"WL6");\r
+               NewEmenu[2].active =\r
+               NewEmenu[4].active =\r
+               NewEmenu[6].active =\r
+               NewEmenu[8].active =\r
+               NewEmenu[10].active =\r
+               EpisodeSelect[1] =\r
+               EpisodeSelect[2] =\r
+               EpisodeSelect[3] =\r
+               EpisodeSelect[4] =\r
+               EpisodeSelect[5] = 1;\r
+       }\r
+       else\r
+       if (!findfirst("*.WL3",&f,FA_ARCH))\r
+       {\r
+               strcpy(extension,"WL3");\r
+               NewEmenu[2].active =\r
+               NewEmenu[4].active =\r
+               EpisodeSelect[1] =\r
+               EpisodeSelect[2] = 1;\r
+       }\r
+       else\r
+#endif\r
+#endif\r
+\r
+\r
+\r
+#ifdef SPEAR\r
+#ifndef SPEARDEMO\r
+       if (!findfirst("*.SOD",&f,FA_ARCH))\r
+       {\r
+               strcpy(extension,"SOD");\r
+       }\r
+       else\r
+               Quit("NO SPEAR OF DESTINY DATA FILES TO BE FOUND!");\r
+#else\r
+       if (!findfirst("*.SDM",&f,FA_ARCH))\r
+       {\r
+               strcpy(extension,"SDM");\r
+       }\r
+       else\r
+               Quit("NO SPEAR OF DESTINY DEMO DATA FILES TO BE FOUND!");\r
+#endif\r
+\r
+#else\r
+       if (!findfirst("*.WL1",&f,FA_ARCH))\r
+       {\r
+               strcpy(extension,"WL1");\r
+       }\r
+       else\r
+               Quit("NO WOLFENSTEIN 3-D DATA FILES to be found!");\r
+#endif\r
+\r
+       strcat(configname,extension);\r
+       strcat(SaveName,extension);\r
+       strcat(PageFileName,extension);\r
+       strcat(audioname,extension);\r
+       strcat(demoname,extension);\r
+#ifndef SPEAR\r
+#ifndef GOODTIMES\r
+       strcat(helpfilename,extension);\r
+#endif\r
+       strcat(endfilename,extension);\r
+#endif\r
+#endif\r
+}\r
diff --git a/src/lib/hb/wl_menu.h b/src/lib/hb/wl_menu.h
new file mode 100755 (executable)
index 0000000..dc03400
--- /dev/null
@@ -0,0 +1,234 @@
+//\r
+// WL_MENU.H\r
+//\r
+#ifdef SPEAR\r
+\r
+#define BORDCOLOR      0x99\r
+#define BORD2COLOR     0x93\r
+#define DEACTIVE       0x9b\r
+#define BKGDCOLOR      0x9d\r
+//#define STRIPE               0x9c\r
+\r
+#define MenuFadeOut()  VL_FadeOut(0,255,0,0,51,10)\r
+\r
+#else\r
+\r
+#define BORDCOLOR      0x29\r
+#define BORD2COLOR     0x23\r
+#define DEACTIVE       0x2b\r
+#define BKGDCOLOR      0x2d\r
+#define STRIPE         0x2c\r
+\r
+#define MenuFadeOut()  VL_FadeOut(0,255,43,0,0,10)\r
+\r
+#endif\r
+\r
+#define READCOLOR      0x4a\r
+#define READHCOLOR     0x47\r
+#define VIEWCOLOR      0x7f\r
+#define TEXTCOLOR      0x17\r
+#define HIGHLIGHT      0x13\r
+#define MenuFadeIn()   VL_FadeIn(0,255,&gamepal,10)\r
+\r
+\r
+#define MENUSONG       WONDERIN_MUS\r
+\r
+#ifndef SPEAR\r
+#define INTROSONG      NAZI_NOR_MUS\r
+#else\r
+#define INTROSONG      XTOWER2_MUS\r
+#endif\r
+\r
+#define SENSITIVE      60\r
+#define CENTER         SENSITIVE*2\r
+\r
+#define MENU_X 76\r
+#define MENU_Y 55\r
+#define MENU_W 178\r
+#ifndef SPEAR\r
+#define MENU_H 13*10+6\r
+#else\r
+#define MENU_H 13*9+6\r
+#endif\r
+\r
+#define SM_X   48\r
+#define SM_W   250\r
+\r
+#define SM_Y1  20\r
+#define SM_H1  4*13-7\r
+#define SM_Y2  SM_Y1+5*13\r
+#define SM_H2  4*13-7\r
+#define SM_Y3  SM_Y2+5*13\r
+#define SM_H3  3*13-7\r
+\r
+#define CTL_X  24\r
+#define CTL_Y  70\r
+#define CTL_W  284\r
+#define CTL_H  13*7-7\r
+\r
+#define LSM_X  85\r
+#define LSM_Y  55\r
+#define LSM_W  175\r
+#define LSM_H  10*13+10\r
+\r
+#define NM_X   50\r
+#define NM_Y   100\r
+#define NM_W   225\r
+#define NM_H   13*4+15\r
+\r
+#define NE_X   10\r
+#define NE_Y   23\r
+#define NE_W   320-NE_X*2\r
+#define NE_H   200-NE_Y*2\r
+\r
+#define CST_X          20\r
+#define CST_Y          48\r
+#define CST_START      60\r
+#define CST_SPC        60\r
+\r
+\r
+//\r
+// TYPEDEFS\r
+//\r
+typedef struct {\r
+               int x,y,amount,curpos,indent;\r
+               } CP_iteminfo;\r
+\r
+typedef struct {\r
+               int active;\r
+               char string[36];\r
+               void (* routine)(int temp1);\r
+               } CP_itemtype;\r
+\r
+typedef struct {\r
+               int allowed[4];\r
+               } CustomCtrls;\r
+\r
+extern CP_itemtype far MainMenu[],far NewEMenu[];\r
+extern CP_iteminfo MainItems;\r
+\r
+//\r
+// FUNCTION PROTOTYPES\r
+//\r
+void SetupControlPanel(void);\r
+void CleanupControlPanel(void);\r
+\r
+void DrawMenu(CP_iteminfo *item_i,CP_itemtype far *items);\r
+int  HandleMenu(CP_iteminfo *item_i,\r
+               CP_itemtype far *items,\r
+               void (*routine)(int w));\r
+void ClearMScreen(void);\r
+void DrawWindow(int x,int y,int w,int h,int wcolor);\r
+void DrawOutline(int x,int y,int w,int h,int color1,int color2);\r
+void WaitKeyUp(void);\r
+void ReadAnyControl(ControlInfo *ci);\r
+void TicDelay(int count);\r
+void CacheLump(int lumpstart,int lumpend);\r
+void UnCacheLump(int lumpstart,int lumpend);\r
+void StartCPMusic(int song);\r
+int  Confirm(char far *string);\r
+void Message(char far *string);\r
+void CheckPause(void);\r
+void ShootSnd(void);\r
+void CheckSecretMissions(void);\r
+void BossKey(void);\r
+\r
+void DrawGun(CP_iteminfo *item_i,CP_itemtype far *items,int x,int *y,int which,int basey,void (*routine)(int w));\r
+void DrawHalfStep(int x,int y);\r
+void EraseGun(CP_iteminfo *item_i,CP_itemtype far *items,int x,int y,int which);\r
+void SetTextColor(CP_itemtype far *items,int hlight);\r
+void DrawMenuGun(CP_iteminfo *iteminfo);\r
+void DrawStripes(int y);\r
+\r
+void DefineMouseBtns(void);\r
+void DefineJoyBtns(void);\r
+void DefineKeyBtns(void);\r
+void DefineKeyMove(void);\r
+void EnterCtrlData(int index,CustomCtrls *cust,void (*DrawRtn)(int),void (*PrintRtn)(int),int type);\r
+\r
+void DrawMainMenu(void);\r
+void DrawSoundMenu(void);\r
+void DrawLoadSaveScreen(int loadsave);\r
+void DrawNewEpisode(void);\r
+void DrawNewGame(void);\r
+void DrawChangeView(int view);\r
+void DrawMouseSens(void);\r
+void DrawCtlScreen(void);\r
+void DrawCustomScreen(void);\r
+void DrawLSAction(int which);\r
+void DrawCustMouse(int hilight);\r
+void DrawCustJoy(int hilight);\r
+void DrawCustKeybd(int hilight);\r
+void DrawCustKeys(int hilight);\r
+void PrintCustMouse(int i);\r
+void PrintCustJoy(int i);\r
+void PrintCustKeybd(int i);\r
+void PrintCustKeys(int i);\r
+\r
+void PrintLSEntry(int w,int color);\r
+void TrackWhichGame(int w);\r
+void DrawNewGameDiff(int w);\r
+void FixupCustom(int w);\r
+\r
+void CP_NewGame(void);\r
+void CP_Sound(void);\r
+int  CP_LoadGame(int quick);\r
+int  CP_SaveGame(int quick);\r
+void CP_Control(void);\r
+void CP_ChangeView(void);\r
+void CP_ExitOptions(void);\r
+void CP_Quit(void);\r
+void CP_ViewScores(void);\r
+int  CP_EndGame(void);\r
+int  CP_CheckQuick(unsigned scancode);\r
+void CustomControls(void);\r
+void MouseSensitivity(void);\r
+\r
+void CheckForEpisodes(void);\r
+\r
+//\r
+// VARIABLES\r
+//\r
+extern int SaveGamesAvail[10],StartGame,SoundStatus;\r
+extern char SaveGameNames[10][32],SaveName[13];\r
+\r
+enum {MOUSE,JOYSTICK,KEYBOARDBTNS,KEYBOARDMOVE};       // FOR INPUT TYPES\r
+\r
+#ifndef USO_FIX1\r
+extern\r
+#endif\r
+enum\r
+{\r
+       newgame,\r
+       soundmenu,\r
+       control,\r
+       loadgame,\r
+       savegame,\r
+       changeview,\r
+\r
+#ifndef GOODTIMES\r
+#ifndef SPEAR\r
+       readthis,\r
+#endif\r
+#endif\r
+\r
+       viewscores,\r
+       backtodemo,\r
+       quit\r
+} menuitems;\r
+\r
+//\r
+// WL_INTER\r
+//\r
+typedef struct {\r
+               int kill,secret,treasure;\r
+               long time;\r
+               } LRstruct;\r
+\r
+extern LRstruct LevelRatios[];\r
+\r
+void Write (int x,int y,char *string);\r
+void NonShareware(void);\r
+int GetYorN(int x,int y,int pic);\r
+\r
+\r
diff --git a/src/lib/hb/wl_play.c b/src/lib/hb/wl_play.c
new file mode 100755 (executable)
index 0000000..447c893
--- /dev/null
@@ -0,0 +1,1473 @@
+// WL_PLAY.C\r
+\r
+#include "WL_DEF.H"\r
+#pragma hdrstop\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+#define sc_Question    0x35\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                GLOBAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+boolean                madenoise;                                      // true when shooting or screaming\r
+\r
+exit_t         playstate;\r
+\r
+int                    DebugOk;\r
+\r
+objtype        objlist[MAXACTORS],*new,*obj,*player,*lastobj,\r
+                       *objfreelist,*killerobj;\r
+\r
+unsigned       farmapylookup[MAPSIZE];\r
+byte           *nearmapylookup[MAPSIZE];\r
+\r
+boolean                singlestep,godmode,noclip;\r
+int                    extravbls;\r
+\r
+byte           tilemap[MAPSIZE][MAPSIZE];      // wall values only\r
+byte           spotvis[MAPSIZE][MAPSIZE];\r
+objtype                *actorat[MAPSIZE][MAPSIZE];\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
+//uso: replace: byte            update[UPDATESIZE];\r
+//uso: is needed? byte    update[UPDATEHIGH][UPDATEWIDE];\r
+\r
+//\r
+// control info\r
+//\r
+boolean                mouseenabled,joystickenabled,joypadenabled,joystickprogressive;\r
+int                    joystickport;\r
+int                    dirscan[4] = {sc_UpArrow,sc_RightArrow,sc_DownArrow,sc_LeftArrow};\r
+int                    buttonscan[NUMBUTTONS] =\r
+                       {sc_Control,sc_Alt,sc_RShift,sc_Space,sc_1,sc_2,sc_3,sc_4};\r
+int                    buttonmouse[4]={bt_attack,bt_strafe,bt_use,bt_nobutton};\r
+int                    buttonjoy[4]={bt_attack,bt_strafe,bt_use,bt_run};\r
+\r
+int                    viewsize;\r
+\r
+boolean                buttonheld[NUMBUTTONS];\r
+\r
+boolean                demorecord,demoplayback;\r
+char           far *demoptr, far *lastdemoptr;\r
+memptr         demobuffer;\r
+\r
+//\r
+// curent user input\r
+//\r
+int                    controlx,controly;              // range from -100 to 100 per tic\r
+boolean                buttonstate[NUMBUTTONS];\r
+\r
+\r
+\r
+//===========================================================================\r
+\r
+\r
+void   CenterWindow(word w,word h);\r
+void   InitObjList (void);\r
+void   RemoveObj (objtype *gone);\r
+void   PollControls (void);\r
+void   StopMusic(void);\r
+void   StartMusic(void);\r
+void   PlayLoop (void);\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+objtype dummyobj;\r
+\r
+//\r
+// LIST OF SONGS FOR EACH VERSION\r
+//\r
+int songs[]=\r
+{\r
+#ifndef SPEAR\r
+ //\r
+ // Episode One\r
+ //\r
+ GETTHEM_MUS,\r
+ SEARCHN_MUS,\r
+ POW_MUS,\r
+ SUSPENSE_MUS,\r
+ GETTHEM_MUS,\r
+ SEARCHN_MUS,\r
+ POW_MUS,\r
+ SUSPENSE_MUS,\r
+\r
+ WARMARCH_MUS, // Boss level\r
+ CORNER_MUS,   // Secret level\r
+\r
+ //\r
+ // Episode Two\r
+ //\r
+ NAZI_OMI_MUS,\r
+ PREGNANT_MUS,\r
+ GOINGAFT_MUS,\r
+ HEADACHE_MUS,\r
+ NAZI_OMI_MUS,\r
+ PREGNANT_MUS,\r
+ HEADACHE_MUS,\r
+ GOINGAFT_MUS,\r
+\r
+ WARMARCH_MUS, // Boss level\r
+ DUNGEON_MUS,  // Secret level\r
+\r
+ //\r
+ // Episode Three\r
+ //\r
+ INTROCW3_MUS,\r
+ NAZI_RAP_MUS,\r
+ TWELFTH_MUS,\r
+ ZEROHOUR_MUS,\r
+ INTROCW3_MUS,\r
+ NAZI_RAP_MUS,\r
+ TWELFTH_MUS,\r
+ ZEROHOUR_MUS,\r
+\r
+ ULTIMATE_MUS, // Boss level\r
+ PACMAN_MUS,   // Secret level\r
+\r
+ //\r
+ // Episode Four\r
+ //\r
+ GETTHEM_MUS,\r
+ SEARCHN_MUS,\r
+ POW_MUS,\r
+ SUSPENSE_MUS,\r
+ GETTHEM_MUS,\r
+ SEARCHN_MUS,\r
+ POW_MUS,\r
+ SUSPENSE_MUS,\r
+\r
+ WARMARCH_MUS, // Boss level\r
+ CORNER_MUS,   // Secret level\r
+\r
+ //\r
+ // Episode Five\r
+ //\r
+ NAZI_OMI_MUS,\r
+ PREGNANT_MUS,\r
+ GOINGAFT_MUS,\r
+ HEADACHE_MUS,\r
+ NAZI_OMI_MUS,\r
+ PREGNANT_MUS,\r
+ HEADACHE_MUS,\r
+ GOINGAFT_MUS,\r
+\r
+ WARMARCH_MUS, // Boss level\r
+ DUNGEON_MUS,  // Secret level\r
+\r
+ //\r
+ // Episode Six\r
+ //\r
+ INTROCW3_MUS,\r
+ NAZI_RAP_MUS,\r
+ TWELFTH_MUS,\r
+ ZEROHOUR_MUS,\r
+ INTROCW3_MUS,\r
+ NAZI_RAP_MUS,\r
+ TWELFTH_MUS,\r
+ ZEROHOUR_MUS,\r
+\r
+ ULTIMATE_MUS, // Boss level\r
+ FUNKYOU_MUS           // Secret level\r
+#else\r
+\r
+ //////////////////////////////////////////////////////////////\r
+ //\r
+ // SPEAR OF DESTINY TRACKS\r
+ //\r
+ //////////////////////////////////////////////////////////////\r
+ XTIPTOE_MUS,\r
+ XFUNKIE_MUS,\r
+ XDEATH_MUS,\r
+ XGETYOU_MUS,          // DON'T KNOW\r
+ ULTIMATE_MUS, // Trans Gr\94sse\r
+\r
+ DUNGEON_MUS,\r
+ GOINGAFT_MUS,\r
+ POW_MUS,\r
+ TWELFTH_MUS,\r
+ ULTIMATE_MUS, // Barnacle Wilhelm BOSS\r
+\r
+ NAZI_OMI_MUS,\r
+ GETTHEM_MUS,\r
+ SUSPENSE_MUS,\r
+ SEARCHN_MUS,\r
+ ZEROHOUR_MUS,\r
+ ULTIMATE_MUS, // Super Mutant BOSS\r
+\r
+ XPUTIT_MUS,\r
+ ULTIMATE_MUS, // Death Knight BOSS\r
+\r
+ XJAZNAZI_MUS, // Secret level\r
+ XFUNKIE_MUS,  // Secret level (DON'T KNOW)\r
+\r
+ XEVIL_MUS             // Angel of Death BOSS\r
+\r
+#endif\r
+};\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                 USER CONTROL\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+#define BASEMOVE               35\r
+#define RUNMOVE                        70\r
+#define BASETURN               35\r
+#define RUNTURN                        70\r
+\r
+#define JOYSCALE               2\r
+\r
+/*\r
+===================\r
+=\r
+= PollKeyboardButtons\r
+=\r
+===================\r
+*/\r
+\r
+void PollKeyboardButtons (void)\r
+{\r
+       int             i;\r
+\r
+       for (i=0;i<NUMBUTTONS;i++)\r
+               if (Keyboard[buttonscan[i]])\r
+                       buttonstate[i] = true;\r
+}\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= PollMouseButtons\r
+=\r
+===================\r
+*/\r
+\r
+void PollMouseButtons (void)\r
+{\r
+       int     buttons;\r
+\r
+       buttons = IN_MouseButtons ();\r
+\r
+       if (buttons&1)\r
+               buttonstate[buttonmouse[0]] = true;\r
+       if (buttons&2)\r
+               buttonstate[buttonmouse[1]] = true;\r
+       if (buttons&4)\r
+               buttonstate[buttonmouse[2]] = true;\r
+}\r
+\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= PollJoystickButtons\r
+=\r
+===================\r
+*/\r
+\r
+void PollJoystickButtons (void)\r
+{\r
+       int     buttons;\r
+\r
+       buttons = IN_JoyButtons ();\r
+\r
+       if (joystickport && !joypadenabled)\r
+       {\r
+               if (buttons&4)\r
+                       buttonstate[buttonjoy[0]] = true;\r
+               if (buttons&8)\r
+                       buttonstate[buttonjoy[1]] = true;\r
+       }\r
+       else\r
+       {\r
+               if (buttons&1)\r
+                       buttonstate[buttonjoy[0]] = true;\r
+               if (buttons&2)\r
+                       buttonstate[buttonjoy[1]] = true;\r
+               if (joypadenabled)\r
+               {\r
+                       if (buttons&4)\r
+                               buttonstate[buttonjoy[2]] = true;\r
+                       if (buttons&8)\r
+                               buttonstate[buttonjoy[3]] = true;\r
+               }\r
+       }\r
+}\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= PollKeyboardMove\r
+=\r
+===================\r
+*/\r
+\r
+void PollKeyboardMove (void)\r
+{\r
+       if (buttonstate[bt_run])\r
+       {\r
+               if (Keyboard[dirscan[di_north]])\r
+                       controly -= RUNMOVE*tics;\r
+               if (Keyboard[dirscan[di_south]])\r
+                       controly += RUNMOVE*tics;\r
+               if (Keyboard[dirscan[di_west]])\r
+                       controlx -= RUNMOVE*tics;\r
+               if (Keyboard[dirscan[di_east]])\r
+                       controlx += RUNMOVE*tics;\r
+       }\r
+       else\r
+       {\r
+               if (Keyboard[dirscan[di_north]])\r
+                       controly -= BASEMOVE*tics;\r
+               if (Keyboard[dirscan[di_south]])\r
+                       controly += BASEMOVE*tics;\r
+               if (Keyboard[dirscan[di_west]])\r
+                       controlx -= BASEMOVE*tics;\r
+               if (Keyboard[dirscan[di_east]])\r
+                       controlx += BASEMOVE*tics;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= PollMouseMove\r
+=\r
+===================\r
+*/\r
+\r
+void PollMouseMove (void)\r
+{\r
+       int     mousexmove,mouseymove;\r
+\r
+       Mouse(MDelta);\r
+       mousexmove = _CX;\r
+       mouseymove = _DX;\r
+\r
+       controlx += mousexmove*10/(13-mouseadjustment);\r
+       controly += mouseymove*20/(13-mouseadjustment);\r
+}\r
+\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= PollJoystickMove\r
+=\r
+===================\r
+*/\r
+\r
+void PollJoystickMove (void)\r
+{\r
+       int     joyx,joyy;\r
+\r
+       INL_GetJoyDelta(joystickport,&joyx,&joyy);\r
+\r
+       if (joystickprogressive)\r
+       {\r
+               if (joyx > 64)\r
+                       controlx += (joyx-64)*JOYSCALE*tics;\r
+               else if (joyx < -64)\r
+                       controlx -= (-joyx-64)*JOYSCALE*tics;\r
+               if (joyy > 64)\r
+                       controlx += (joyy-64)*JOYSCALE*tics;\r
+               else if (joyy < -64)\r
+                       controly -= (-joyy-64)*JOYSCALE*tics;\r
+       }\r
+       else if (buttonstate[bt_run])\r
+       {\r
+               if (joyx > 64)\r
+                       controlx += RUNMOVE*tics;\r
+               else if (joyx < -64)\r
+                       controlx -= RUNMOVE*tics;\r
+               if (joyy > 64)\r
+                       controly += RUNMOVE*tics;\r
+               else if (joyy < -64)\r
+                       controly -= RUNMOVE*tics;\r
+       }\r
+       else\r
+       {\r
+               if (joyx > 64)\r
+                       controlx += BASEMOVE*tics;\r
+               else if (joyx < -64)\r
+                       controlx -= BASEMOVE*tics;\r
+               if (joyy > 64)\r
+                       controly += BASEMOVE*tics;\r
+               else if (joyy < -64)\r
+                       controly -= BASEMOVE*tics;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= PollControls\r
+=\r
+= Gets user or demo input, call once each frame\r
+=\r
+= controlx             set between -100 and 100 per tic\r
+= controly\r
+= buttonheld[] the state of the buttons LAST frame\r
+= buttonstate[]        the state of the buttons THIS frame\r
+=\r
+===================\r
+*/\r
+\r
+void PollControls (void)\r
+{\r
+       int             max,min,i;\r
+       byte    buttonbits;\r
+\r
+//\r
+// get timing info for last frame\r
+//\r
+       if (demoplayback)\r
+       {\r
+               while (TimeCount<lasttimecount+DEMOTICS)\r
+               ;\r
+               TimeCount = lasttimecount + DEMOTICS;\r
+               lasttimecount += DEMOTICS;\r
+               tics = DEMOTICS;\r
+       }\r
+       else if (demorecord)                    // 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
+               while (TimeCount<lasttimecount+DEMOTICS)\r
+               ;\r
+               TimeCount = lasttimecount + DEMOTICS;\r
+               lasttimecount += DEMOTICS;\r
+               tics = DEMOTICS;\r
+       }\r
+       else\r
+               CalcTics ();\r
+\r
+       controlx = 0;\r
+       controly = 0;\r
+       memcpy (buttonheld,buttonstate,sizeof(buttonstate));\r
+       memset (buttonstate,0,sizeof(buttonstate));\r
+\r
+       if (demoplayback)\r
+       {\r
+       //\r
+       // read commands from demo buffer\r
+       //\r
+               buttonbits = *demoptr++;\r
+               for (i=0;i<NUMBUTTONS;i++)\r
+               {\r
+                       buttonstate[i] = buttonbits&1;\r
+                       buttonbits >>= 1;\r
+               }\r
+\r
+               controlx = *demoptr++;\r
+               controly = *demoptr++;\r
+\r
+               if (demoptr == lastdemoptr)\r
+                       playstate = ex_completed;               // demo is done\r
+\r
+               controlx *= (int)tics;\r
+               controly *= (int)tics;\r
+\r
+               return;\r
+       }\r
+\r
+\r
+//\r
+// get button states\r
+//\r
+       PollKeyboardButtons ();\r
+\r
+       if (mouseenabled)\r
+               PollMouseButtons ();\r
+\r
+       if (joystickenabled)\r
+               PollJoystickButtons ();\r
+\r
+//\r
+// get movements\r
+//\r
+       PollKeyboardMove ();\r
+\r
+       if (mouseenabled)\r
+               PollMouseMove ();\r
+\r
+       if (joystickenabled)\r
+               PollJoystickMove ();\r
+\r
+//\r
+// bound movement to a maximum\r
+//\r
+       max = 100*tics;\r
+       min = -max;\r
+       if (controlx > max)\r
+               controlx = max;\r
+       else if (controlx < min)\r
+               controlx = min;\r
+\r
+       if (controly > max)\r
+               controly = max;\r
+       else if (controly < min)\r
+               controly = min;\r
+\r
+       if (demorecord)\r
+       {\r
+       //\r
+       // save info out to demo buffer\r
+       //\r
+               controlx /= (int)tics;\r
+               controly /= (int)tics;\r
+\r
+               buttonbits = 0;\r
+\r
+               for (i=NUMBUTTONS-1;i>=0;i--)\r
+               {\r
+                       buttonbits <<= 1;\r
+                       if (buttonstate[i])\r
+                               buttonbits |= 1;\r
+               }\r
+\r
+               *demoptr++ = buttonbits;\r
+               *demoptr++ = controlx;\r
+               *demoptr++ = controly;\r
+\r
+               if (demoptr >= lastdemoptr)\r
+                       Quit ("Demo buffer overflowed!");\r
+\r
+               controlx *= (int)tics;\r
+               controly *= (int)tics;\r
+       }\r
+}\r
+\r
+\r
+\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   320\r
+#define MAXY   160\r
+\r
+void   CenterWindow(word w,word h)\r
+{\r
+       FixOfs ();\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
+       int             i;\r
+       byte    scan;\r
+       unsigned        temp;\r
+\r
+\r
+       if (screenfaded || demoplayback)        // don't do anything with a faded screen\r
+               return;\r
+\r
+       scan = LastScan;\r
+\r
+\r
+       #ifdef SPEAR\r
+       //\r
+       // SECRET CHEAT CODE: TAB-G-F10\r
+       //\r
+       if (Keyboard[sc_Tab] &&\r
+               Keyboard[sc_G] &&\r
+               Keyboard[sc_F10])\r
+       {\r
+               WindowH = 160;\r
+               if (godmode)\r
+               {\r
+                       Message ("God mode OFF");\r
+                       SD_PlaySound (NOBONUSSND);\r
+               }\r
+               else\r
+               {\r
+                       Message ("God mode ON");\r
+                       SD_PlaySound (ENDBONUS2SND);\r
+               }\r
+\r
+               IN_Ack();\r
+               godmode ^= 1;\r
+               DrawAllPlayBorderSides ();\r
+               IN_ClearKeysDown();\r
+               return;\r
+       }\r
+       #endif\r
+\r
+\r
+       //\r
+       // SECRET CHEAT CODE: 'MLI'\r
+       //\r
+       if (Keyboard[sc_M] &&\r
+               Keyboard[sc_L] &&\r
+               Keyboard[sc_I])\r
+       {\r
+               gamestate.health = 100;\r
+               gamestate.ammo = 99;\r
+               gamestate.keys = 3;\r
+               gamestate.score = 0;\r
+               gamestate.TimeCount += 42000L;\r
+               GiveWeapon (wp_chaingun);\r
+\r
+               DrawWeapon();\r
+               DrawHealth();\r
+               DrawKeys();\r
+               DrawAmmo();\r
+               DrawScore();\r
+\r
+               ClearMemory ();\r
+               CA_CacheGrChunk (STARTFONT+1);\r
+               ClearSplitVWB ();\r
+               VW_ScreenToScreen (displayofs,bufferofs,80,160);\r
+\r
+               Message(STR_CHEATER1"\n"\r
+                               STR_CHEATER2"\n\n"\r
+                               STR_CHEATER3"\n"\r
+                               STR_CHEATER4"\n"\r
+                               STR_CHEATER5);\r
+\r
+               UNCACHEGRCHUNK(STARTFONT+1);\r
+               PM_CheckMainMem ();\r
+               IN_ClearKeysDown();\r
+               IN_Ack();\r
+\r
+               DrawAllPlayBorder ();\r
+       }\r
+\r
+       //\r
+       // OPEN UP DEBUG KEYS\r
+       //\r
+#ifndef SPEAR\r
+       if (Keyboard[sc_BackSpace] &&\r
+               Keyboard[sc_LShift] &&\r
+               Keyboard[sc_Alt] &&\r
+               MS_CheckParm("goobers"))\r
+#else\r
+       if (Keyboard[sc_BackSpace] &&\r
+               Keyboard[sc_LShift] &&\r
+               Keyboard[sc_Alt] &&\r
+               MS_CheckParm("debugmode"))\r
+#endif\r
+       {\r
+        ClearMemory ();\r
+        CA_CacheGrChunk (STARTFONT+1);\r
+        ClearSplitVWB ();\r
+        VW_ScreenToScreen (displayofs,bufferofs,80,160);\r
+\r
+        Message("Debugging keys are\nnow available!");\r
+        UNCACHEGRCHUNK(STARTFONT+1);\r
+        PM_CheckMainMem ();\r
+        IN_ClearKeysDown();\r
+        IN_Ack();\r
+\r
+        DrawAllPlayBorderSides ();\r
+        DebugOk=1;\r
+       }\r
+\r
+       //\r
+       // TRYING THE KEEN CHEAT CODE!\r
+       //\r
+       if (Keyboard[sc_B] &&\r
+               Keyboard[sc_A] &&\r
+               Keyboard[sc_T])\r
+       {\r
+        ClearMemory ();\r
+        CA_CacheGrChunk (STARTFONT+1);\r
+        ClearSplitVWB ();\r
+        VW_ScreenToScreen (displayofs,bufferofs,80,160);\r
+\r
+        Message("Commander Keen is also\n"\r
+                        "available from Apogee, but\n"\r
+                        "then, you already know\n"\r
+                        "that - right, Cheatmeister?!");\r
+\r
+        UNCACHEGRCHUNK(STARTFONT+1);\r
+        PM_CheckMainMem ();\r
+        IN_ClearKeysDown();\r
+        IN_Ack();\r
+\r
+        DrawAllPlayBorder ();\r
+       }\r
+\r
+//\r
+// pause key weirdness can't be checked as a scan code\r
+//\r
+       if (Paused)\r
+       {\r
+               bufferofs = displayofs;\r
+               LatchDrawPic (20-4,80-2*8,PAUSEDPIC);\r
+               SD_MusicOff();\r
+               IN_Ack();\r
+               IN_ClearKeysDown ();\r
+               SD_MusicOn();\r
+               Paused = false;\r
+               if (MousePresent)\r
+                       Mouse(MDelta);  // Clear accumulated mouse movement\r
+               return;\r
+       }\r
+\r
+\r
+//\r
+// F1-F7/ESC to enter control panel\r
+//\r
+       if (\r
+#ifndef DEBCHECK\r
+               scan == sc_F10 ||\r
+#endif\r
+               scan == sc_F9 ||\r
+               scan == sc_F7 ||\r
+               scan == sc_F8)                  // pop up quit dialog\r
+       {\r
+               ClearMemory ();\r
+               ClearSplitVWB ();\r
+               VW_ScreenToScreen (displayofs,bufferofs,80,160);\r
+               US_ControlPanel(scan);\r
+\r
+                DrawAllPlayBorderSides ();\r
+\r
+               if (scan == sc_F9)\r
+                 StartMusic ();\r
+\r
+               PM_CheckMainMem ();\r
+               SETFONTCOLOR(0,15);\r
+               IN_ClearKeysDown();\r
+               return;\r
+       }\r
+\r
+       if ( (scan >= sc_F1 && scan <= sc_F9) || scan == sc_Escape)\r
+       {\r
+               StopMusic ();\r
+               ClearMemory ();\r
+               VW_FadeOut ();\r
+\r
+               US_ControlPanel(scan);\r
+\r
+               SETFONTCOLOR(0,15);\r
+               IN_ClearKeysDown();\r
+               DrawPlayScreen ();\r
+               if (!startgame && !loadedgame)\r
+               {\r
+                       VW_FadeIn ();\r
+                       StartMusic ();\r
+               }\r
+               if (loadedgame)\r
+                       playstate = ex_abort;\r
+               lasttimecount = TimeCount;\r
+               if (MousePresent)\r
+                       Mouse(MDelta);  // Clear accumulated mouse movement\r
+               PM_CheckMainMem ();\r
+               return;\r
+       }\r
+\r
+//\r
+// TAB-? debug keys\r
+//\r
+       if (Keyboard[sc_Tab] && DebugOk)\r
+       {\r
+               CA_CacheGrChunk (STARTFONT);\r
+               fontnumber=0;\r
+               SETFONTCOLOR(0,15);\r
+               DebugKeys();\r
+               if (MousePresent)\r
+                       Mouse(MDelta);  // Clear accumulated mouse movement\r
+               lasttimecount = TimeCount;\r
+               return;\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
+= InitActorList\r
+=\r
+= Call to clear out the actor object lists returning them all to the free\r
+= list.  Allocates a special spot for the player.\r
+=\r
+=========================\r
+*/\r
+\r
+int    objcount;\r
+\r
+void InitActorList (void)\r
+{\r
+       int     i;\r
+\r
+//\r
+// init the actor lists\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
+       objcount = 0;\r
+\r
+//\r
+// give the player the first free spots\r
+//\r
+       GetNewActor ();\r
+       player = new;\r
+\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+=========================\r
+=\r
+= GetNewActor\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 GetNewActor (void)\r
+{\r
+       if (!objfreelist)\r
+               Quit ("GetNewActor: No free spots in objlist!");\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
+       objcount++;\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
+       gone->state = NULL;\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
+       objcount--;\r
+}\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                               MUSIC STUFF\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
+void StartMusic(void)\r
+{\r
+       musicnames      chunk;\r
+\r
+       SD_MusicOff();\r
+       chunk = songs[gamestate.mapon+gamestate.episode*10];\r
+\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
+                                       PALETTE SHIFTING STUFF\r
+\r
+=============================================================================\r
+*/\r
+\r
+#define NUMREDSHIFTS   6\r
+#define REDSTEPS               8\r
+\r
+#define NUMWHITESHIFTS 3\r
+#define WHITESTEPS             20\r
+#define WHITETICS              6\r
+\r
+\r
+byte   far redshifts[NUMREDSHIFTS][768];\r
+byte   far whiteshifts[NUMREDSHIFTS][768];\r
+\r
+int            damagecount,bonuscount;\r
+boolean        palshifted;\r
+\r
+extern         byte    far     gamepal;\r
+\r
+/*\r
+=====================\r
+=\r
+= InitRedShifts\r
+=\r
+=====================\r
+*/\r
+\r
+void InitRedShifts (void)\r
+{\r
+       byte    far *workptr, far *baseptr;\r
+       int             i,j,delta;\r
+\r
+\r
+//\r
+// fade through intermediate frames\r
+//\r
+       for (i=1;i<=NUMREDSHIFTS;i++)\r
+       {\r
+               workptr = (byte far *)&redshifts[i-1][0];\r
+               baseptr = &gamepal;\r
+\r
+               for (j=0;j<=255;j++)\r
+               {\r
+                       delta = 64-*baseptr;\r
+                       *workptr++ = *baseptr++ + delta * i / REDSTEPS;\r
+                       delta = -*baseptr;\r
+                       *workptr++ = *baseptr++ + delta * i / REDSTEPS;\r
+                       delta = -*baseptr;\r
+                       *workptr++ = *baseptr++ + delta * i / REDSTEPS;\r
+               }\r
+       }\r
+\r
+       for (i=1;i<=NUMWHITESHIFTS;i++)\r
+       {\r
+               workptr = (byte far *)&whiteshifts[i-1][0];\r
+               baseptr = &gamepal;\r
+\r
+               for (j=0;j<=255;j++)\r
+               {\r
+                       delta = 64-*baseptr;\r
+                       *workptr++ = *baseptr++ + delta * i / WHITESTEPS;\r
+                       delta = 62-*baseptr;\r
+                       *workptr++ = *baseptr++ + delta * i / WHITESTEPS;\r
+                       delta = 0-*baseptr;\r
+                       *workptr++ = *baseptr++ + delta * i / WHITESTEPS;\r
+               }\r
+       }\r
+}\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= ClearPaletteShifts\r
+=\r
+=====================\r
+*/\r
+\r
+void ClearPaletteShifts (void)\r
+{\r
+       bonuscount = damagecount = 0;\r
+}\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= StartBonusFlash\r
+=\r
+=====================\r
+*/\r
+\r
+void StartBonusFlash (void)\r
+{\r
+       bonuscount = NUMWHITESHIFTS*WHITETICS;          // white shift palette\r
+}\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= StartDamageFlash\r
+=\r
+=====================\r
+*/\r
+\r
+void StartDamageFlash (int damage)\r
+{\r
+       damagecount += damage;\r
+}\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= UpdatePaletteShifts\r
+=\r
+=====================\r
+*/\r
+\r
+void UpdatePaletteShifts (void)\r
+{\r
+       int     red,white;\r
+\r
+       if (bonuscount)\r
+       {\r
+               white = bonuscount/WHITETICS +1;\r
+               if (white>NUMWHITESHIFTS)\r
+                       white = NUMWHITESHIFTS;\r
+               bonuscount -= tics;\r
+               if (bonuscount < 0)\r
+                       bonuscount = 0;\r
+       }\r
+       else\r
+               white = 0;\r
+\r
+\r
+       if (damagecount)\r
+       {\r
+               red = damagecount/10 +1;\r
+               if (red>NUMREDSHIFTS)\r
+                       red = NUMREDSHIFTS;\r
+\r
+               damagecount -= tics;\r
+               if (damagecount < 0)\r
+                       damagecount = 0;\r
+       }\r
+       else\r
+               red = 0;\r
+\r
+       if (red)\r
+       {\r
+               VW_WaitVBL(1);\r
+               VL_SetPalette (redshifts[red-1]);\r
+               palshifted = true;\r
+       }\r
+       else if (white)\r
+       {\r
+               VW_WaitVBL(1);\r
+               VL_SetPalette (whiteshifts[white-1]);\r
+               palshifted = true;\r
+       }\r
+       else if (palshifted)\r
+       {\r
+               VW_WaitVBL(1);\r
+               VL_SetPalette (&gamepal);               // back to normal\r
+               palshifted = false;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= FinishPaletteShifts\r
+=\r
+= Resets palette to normal if needed\r
+=\r
+=====================\r
+*/\r
+\r
+void FinishPaletteShifts (void)\r
+{\r
+       if (palshifted)\r
+       {\r
+               palshifted = 0;\r
+               VW_WaitVBL(1);\r
+               VL_SetPalette (&gamepal);\r
+       }\r
+}\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                               CORE PLAYLOOP\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= DoActor\r
+=\r
+=====================\r
+*/\r
+\r
+void DoActor (objtype *ob)\r
+{\r
+       void (*think)(objtype *);\r
+\r
+       if (!ob->active && !areabyplayer[ob->areanumber])\r
+               return;\r
+\r
+       if (!(ob->flags&(FL_NONMARK|FL_NEVERMARK)) )\r
+               actorat[ob->tilex][ob->tiley] = NULL;\r
+\r
+//\r
+// non transitional object\r
+//\r
+\r
+       if (!ob->ticcount)\r
+       {\r
+               think = ob->state->think;\r
+               if (think)\r
+               {\r
+                       think (ob);\r
+                       if (!ob->state)\r
+                       {\r
+                               RemoveObj (ob);\r
+                               return;\r
+                       }\r
+               }\r
+\r
+               if (ob->flags&FL_NEVERMARK)\r
+                       return;\r
+\r
+               if ( (ob->flags&FL_NONMARK) && actorat[ob->tilex][ob->tiley])\r
+                       return;\r
+\r
+               actorat[ob->tilex][ob->tiley] = ob;\r
+               return;\r
+       }\r
+\r
+//\r
+// transitional object\r
+//\r
+       ob->ticcount-=tics;\r
+       while ( ob->ticcount <= 0)\r
+       {\r
+               think = ob->state->action;                      // end of state action\r
+               if (think)\r
+               {\r
+                       think (ob);\r
+                       if (!ob->state)\r
+                       {\r
+                               RemoveObj (ob);\r
+                               return;\r
+                       }\r
+               }\r
+\r
+               ob->state = ob->state->next;\r
+\r
+               if (!ob->state)\r
+               {\r
+                       RemoveObj (ob);\r
+                       return;\r
+               }\r
+\r
+               if (!ob->state->tictime)\r
+               {\r
+                       ob->ticcount = 0;\r
+                       goto think;\r
+               }\r
+\r
+               ob->ticcount += ob->state->tictime;\r
+       }\r
+\r
+think:\r
+       //\r
+       // think\r
+       //\r
+       think = ob->state->think;\r
+       if (think)\r
+       {\r
+               think (ob);\r
+               if (!ob->state)\r
+               {\r
+                       RemoveObj (ob);\r
+                       return;\r
+               }\r
+       }\r
+\r
+       if (ob->flags&FL_NEVERMARK)\r
+               return;\r
+\r
+       if ( (ob->flags&FL_NONMARK) && actorat[ob->tilex][ob->tiley])\r
+               return;\r
+\r
+       actorat[ob->tilex][ob->tiley] = ob;\r
+}\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= PlayLoop\r
+=\r
+===================\r
+*/\r
+long funnyticount;\r
+\r
+\r
+void PlayLoop (void)\r
+{\r
+       int             give;\r
+       int     helmetangle;\r
+\r
+       playstate = TimeCount = lasttimecount = 0;\r
+       frameon = 0;\r
+       running = false;\r
+       anglefrac = 0;\r
+       facecount = 0;\r
+       funnyticount = 0;\r
+       memset (buttonstate,0,sizeof(buttonstate));\r
+       ClearPaletteShifts ();\r
+\r
+       if (MousePresent)\r
+               Mouse(MDelta);  // Clear accumulated mouse movement\r
+\r
+       if (demoplayback)\r
+               IN_StartAck ();\r
+\r
+       do\r
+       {\r
+               if (virtualreality)\r
+               {\r
+                       helmetangle = peek (0x40,0xf0);\r
+                       player->angle += helmetangle;\r
+                       if (player->angle >= ANGLES)\r
+                               player->angle -= ANGLES;\r
+               }\r
+\r
+\r
+               PollControls();\r
+\r
+//\r
+// actor thinking\r
+//\r
+               madenoise = false;\r
+\r
+               MoveDoors ();\r
+               MovePWalls ();\r
+\r
+               for (obj = player;obj;obj = obj->next)\r
+                       DoActor (obj);\r
+\r
+               UpdatePaletteShifts ();\r
+\r
+               ThreeDRefresh ();\r
+\r
+               //\r
+               // MAKE FUNNY FACE IF BJ DOESN'T MOVE FOR AWHILE\r
+               //\r
+               #ifdef SPEAR\r
+               funnyticount += tics;\r
+               if (funnyticount > 30l*70)\r
+               {\r
+                       funnyticount = 0;\r
+                       StatusDrawPic (17,4,BJWAITING1PIC+(US_RndT()&1));\r
+                       facecount = 0;\r
+               }\r
+               #endif\r
+\r
+               gamestate.TimeCount+=tics;\r
+\r
+               SD_Poll ();\r
+               UpdateSoundLoc();       // JAB\r
+\r
+               if (screenfaded)\r
+                       VW_FadeIn ();\r
+\r
+               CheckKeys();\r
+\r
+//\r
+// debug aids\r
+//\r
+               if (singlestep)\r
+               {\r
+                       VW_WaitVBL(14);\r
+                       lasttimecount = TimeCount;\r
+               }\r
+               if (extravbls)\r
+                       VW_WaitVBL(extravbls);\r
+\r
+               if (demoplayback)\r
+               {\r
+                       if (IN_CheckAck ())\r
+                       {\r
+                               IN_ClearKeysDown ();\r
+                               playstate = ex_abort;\r
+                       }\r
+               }\r
+\r
+\r
+               if (virtualreality)\r
+               {\r
+                       player->angle -= helmetangle;\r
+                       if (player->angle < 0)\r
+                               player->angle += ANGLES;\r
+               }\r
+\r
+       }while (!playstate && !startgame);\r
+\r
+       if (playstate != ex_died)\r
+               FinishPaletteShifts ();\r
+}\r
+\r
diff --git a/src/lib/hb/wl_scale.c b/src/lib/hb/wl_scale.c
new file mode 100755 (executable)
index 0000000..9c1e102
--- /dev/null
@@ -0,0 +1,741 @@
+// WL_SCALE.C\r
+\r
+#include "WL_DEF.H"\r
+#pragma hdrstop\r
+\r
+#define OP_RETF        0xcb\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                 GLOBALS\r
+\r
+=============================================================================\r
+*/\r
+\r
+t_compscale _seg *scaledirectory[MAXSCALEHEIGHT+1];\r
+long                   fullscalefarcall[MAXSCALEHEIGHT+1];\r
+\r
+int                    maxscale,maxscaleshl2;\r
+\r
+boolean        insetupscaling;\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                 LOCALS\r
+\r
+=============================================================================\r
+*/\r
+\r
+t_compscale    _seg *work;\r
+unsigned BuildCompScale (int height, memptr *finalspot);\r
+\r
+int                    stepbytwo;\r
+\r
+//===========================================================================\r
+\r
+/*\r
+==============\r
+=\r
+= BadScale\r
+=\r
+==============\r
+*/\r
+\r
+void far BadScale (void)\r
+{\r
+       Quit ("BadScale called!");\r
+}\r
+\r
+\r
+/*\r
+==========================\r
+=\r
+= SetupScaling\r
+=\r
+==========================\r
+*/\r
+\r
+void SetupScaling (int maxscaleheight)\r
+{\r
+       int             i,x,y;\r
+       byte    far *dest;\r
+\r
+       insetupscaling = true;\r
+\r
+       maxscaleheight/=2;                      // one scaler every two pixels\r
+\r
+       maxscale = maxscaleheight-1;\r
+       maxscaleshl2 = maxscale<<2;\r
+\r
+//\r
+// free up old scalers\r
+//\r
+       for (i=1;i<MAXSCALEHEIGHT;i++)\r
+       {\r
+               if (scaledirectory[i])\r
+                       MM_FreePtr (&(memptr)scaledirectory[i]);\r
+               if (i>=stepbytwo)\r
+                       i += 2;\r
+       }\r
+       memset (scaledirectory,0,sizeof(scaledirectory));\r
+\r
+       MM_SortMem ();\r
+\r
+//\r
+// build the compiled scalers\r
+//\r
+       stepbytwo = viewheight/2;       // save space by double stepping\r
+       MM_GetPtr (&(memptr)work,20000);\r
+\r
+       for (i=1;i<=maxscaleheight;i++)\r
+       {\r
+               BuildCompScale (i*2,&(memptr)scaledirectory[i]);\r
+               if (i>=stepbytwo)\r
+                       i+= 2;\r
+       }\r
+       MM_FreePtr (&(memptr)work);\r
+\r
+//\r
+// compact memory and lock down scalers\r
+//\r
+       MM_SortMem ();\r
+       for (i=1;i<=maxscaleheight;i++)\r
+       {\r
+               MM_SetLock (&(memptr)scaledirectory[i],true);\r
+               fullscalefarcall[i] = (unsigned)scaledirectory[i];\r
+               fullscalefarcall[i] <<=16;\r
+               fullscalefarcall[i] += scaledirectory[i]->codeofs[0];\r
+               if (i>=stepbytwo)\r
+               {\r
+                       scaledirectory[i+1] = scaledirectory[i];\r
+                       fullscalefarcall[i+1] = fullscalefarcall[i];\r
+                       scaledirectory[i+2] = scaledirectory[i];\r
+                       fullscalefarcall[i+2] = fullscalefarcall[i];\r
+                       i+=2;\r
+               }\r
+       }\r
+       scaledirectory[0] = scaledirectory[1];\r
+       fullscalefarcall[0] = fullscalefarcall[1];\r
+\r
+//\r
+// check for oversize wall drawing\r
+//\r
+       for (i=maxscaleheight;i<MAXSCALEHEIGHT;i++)\r
+               fullscalefarcall[i] = (long)BadScale;\r
+\r
+       insetupscaling = false;\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
+       byte            far *code;\r
+\r
+       int                     i;\r
+       long            fix,step;\r
+       unsigned        src,totalscaled,totalsize;\r
+       int                     startpix,endpix,toppix;\r
+\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
+               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
+               // mov [es:di+heightofs],al\r
+               //\r
+                       *code++ = 0x26;\r
+                       *code++ = 0x88;\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
+\r
+       return totalsize;\r
+}\r
+\r
+\r
+/*\r
+=======================\r
+=\r
+= ScaleLine\r
+=\r
+= linescale should have the high word set to the segment of the scaler\r
+=\r
+=======================\r
+*/\r
+\r
+extern int                     slinex,slinewidth;\r
+extern unsigned        far *linecmds;\r
+extern long            linescale;\r
+extern unsigned        maskword;\r
+\r
+byte   mask1,mask2,mask3;\r
+\r
+\r
+void near ScaleLine (void)\r
+{\r
+asm    mov     cx,WORD PTR [linescale+2]\r
+asm    mov     es,cx                                           // segment of scaler\r
+\r
+asm    mov bp,WORD PTR [linecmds]\r
+asm    mov     dx,SC_INDEX+1                           // to set SC_MAPMASK\r
+\r
+asm    mov     bx,[slinex]\r
+asm    mov     di,bx\r
+asm    shr     di,1                                            // X in bytes\r
+asm    shr     di,1\r
+asm    add     di,[bufferofs]\r
+asm    and     bx,3\r
+/* begin 8086 hack\r
+asm    shl     bx,3\r
+*/\r
+asm push cx\r
+asm mov cl,3\r
+asm shl bx,cl\r
+asm pop cx\r
+/* end 8086 hack */\r
+asm    add     bx,[slinewidth]                         // bx = (pixel*8+pixwidth)\r
+asm    mov     al,BYTE [mapmasks3-1+bx]        // -1 because pixwidth of 1 is first\r
+asm    mov     ds,WORD PTR [linecmds+2]\r
+asm    or      al,al\r
+asm    jz      notthreebyte                            // scale across three bytes\r
+asm    jmp     threebyte\r
+notthreebyte:\r
+asm    mov     al,BYTE PTR ss:[mapmasks2-1+bx] // -1 because pixwidth of 1 is first\r
+asm    or      al,al\r
+asm    jnz     twobyte                                         // scale across two bytes\r
+\r
+//\r
+// one byte scaling\r
+//\r
+asm    mov     al,BYTE PTR ss:[mapmasks1-1+bx] // -1 because pixwidth of 1 is first\r
+asm    out     dx,al                                           // set map mask register\r
+\r
+scalesingle:\r
+\r
+asm    mov     bx,[ds:bp]                                      // table location of rtl to patch\r
+asm    or      bx,bx\r
+asm    jz      linedone                                        // 0 signals end of segment list\r
+asm    mov     bx,[es:bx]\r
+asm    mov     dl,[es:bx]                                      // save old value\r
+asm    mov     BYTE PTR es:[bx],OP_RETF        // patch a RETF in\r
+asm    mov     si,[ds:bp+4]                            // table location of entry spot\r
+asm    mov     ax,[es:si]\r
+asm    mov     WORD PTR ss:[linescale],ax      // call here to start scaling\r
+asm    mov     si,[ds:bp+2]                            // corrected top of shape for this segment\r
+asm    add     bp,6                                            // next segment list\r
+\r
+asm    mov     ax,SCREENSEG\r
+asm    mov     es,ax\r
+asm    call ss:[linescale]                             // scale the segment of pixels\r
+\r
+asm    mov     es,cx                                           // segment of scaler\r
+asm    mov     BYTE PTR es:[bx],dl                     // unpatch the RETF\r
+asm    jmp     scalesingle                                     // do the next segment\r
+\r
+\r
+//\r
+// done\r
+//\r
+linedone:\r
+asm    mov     ax,ss\r
+asm    mov     ds,ax\r
+return;\r
+\r
+//\r
+// two byte scaling\r
+//\r
+twobyte:\r
+asm    mov     ss:[mask2],al\r
+asm    mov     al,BYTE PTR ss:[mapmasks1-1+bx] // -1 because pixwidth of 1 is first\r
+asm    mov     ss:[mask1],al\r
+\r
+scaledouble:\r
+\r
+asm    mov     bx,[ds:bp]                                      // table location of rtl to patch\r
+asm    or      bx,bx\r
+asm    jz      linedone                                        // 0 signals end of segment list\r
+asm    mov     bx,[es:bx]\r
+asm    mov     cl,[es:bx]                                      // save old value\r
+asm    mov     BYTE PTR es:[bx],OP_RETF        // patch a RETF in\r
+asm    mov     si,[ds:bp+4]                            // table location of entry spot\r
+asm    mov     ax,[es:si]\r
+asm    mov     WORD PTR ss:[linescale],ax      // call here to start scaling\r
+asm    mov     si,[ds:bp+2]                            // corrected top of shape for this segment\r
+asm    add     bp,6                                            // next segment list\r
+\r
+asm    mov     ax,SCREENSEG\r
+asm    mov     es,ax\r
+asm    mov     al,ss:[mask1]\r
+asm    out     dx,al                                           // set map mask register\r
+asm    call ss:[linescale]                             // scale the segment of pixels\r
+asm    inc     di\r
+asm    mov     al,ss:[mask2]\r
+asm    out     dx,al                                           // set map mask register\r
+asm    call ss:[linescale]                             // scale the segment of pixels\r
+asm    dec     di\r
+\r
+asm    mov     es,WORD PTR ss:[linescale+2] // segment of scaler\r
+asm    mov     BYTE PTR es:[bx],cl                     // unpatch the RETF\r
+asm    jmp     scaledouble                                     // do the next segment\r
+\r
+\r
+//\r
+// three byte scaling\r
+//\r
+threebyte:\r
+asm    mov     ss:[mask3],al\r
+asm    mov     al,BYTE PTR ss:[mapmasks2-1+bx] // -1 because pixwidth of 1 is first\r
+asm    mov     ss:[mask2],al\r
+asm    mov     al,BYTE PTR ss:[mapmasks1-1+bx] // -1 because pixwidth of 1 is first\r
+asm    mov     ss:[mask1],al\r
+\r
+scaletriple:\r
+\r
+asm    mov     bx,[ds:bp]                                      // table location of rtl to patch\r
+asm    or      bx,bx\r
+asm    jz      linedone                                        // 0 signals end of segment list\r
+asm    mov     bx,[es:bx]\r
+asm    mov     cl,[es:bx]                                      // save old value\r
+asm    mov     BYTE PTR es:[bx],OP_RETF        // patch a RETF in\r
+asm    mov     si,[ds:bp+4]                            // table location of entry spot\r
+asm    mov     ax,[es:si]\r
+asm    mov     WORD PTR ss:[linescale],ax      // call here to start scaling\r
+asm    mov     si,[ds:bp+2]                            // corrected top of shape for this segment\r
+asm    add     bp,6                                            // next segment list\r
+\r
+asm    mov     ax,SCREENSEG\r
+asm    mov     es,ax\r
+asm    mov     al,ss:[mask1]\r
+asm    out     dx,al                                           // set map mask register\r
+asm    call ss:[linescale]                             // scale the segment of pixels\r
+asm    inc     di\r
+asm    mov     al,ss:[mask2]\r
+asm    out     dx,al                                           // set map mask register\r
+asm    call ss:[linescale]                             // scale the segment of pixels\r
+asm    inc     di\r
+asm    mov     al,ss:[mask3]\r
+asm    out     dx,al                                           // set map mask register\r
+asm    call ss:[linescale]                             // scale the segment of pixels\r
+asm    dec     di\r
+asm    dec     di\r
+\r
+asm    mov     es,WORD PTR ss:[linescale+2] // segment of scaler\r
+asm    mov     BYTE PTR es:[bx],cl                     // unpatch the RETF\r
+asm    jmp     scaletriple                                     // do the next segment\r
+\r
+\r
+}\r
+\r
+\r
+/*\r
+=======================\r
+=\r
+= ScaleShape\r
+=\r
+= Draws a compiled shape at [scale] pixels high\r
+=\r
+= each vertical line of the shape has a pointer to segment data:\r
+=      end of segment pixel*2 (0 terminates line) used to patch rtl in scaler\r
+=      top of virtual line with segment in proper place\r
+=      start of segment pixel*2, used to jsl into compiled scaler\r
+=      <repeat>\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, int shapenum, unsigned height)\r
+{\r
+       t_compshape     _seg *shape;\r
+       t_compscale _seg *comptable;\r
+       unsigned        scale,srcx,stopx,tempx;\r
+       int                     t;\r
+       unsigned        far *cmdptr;\r
+       boolean         leftvis,rightvis;\r
+\r
+\r
+       shape = PM_GetSpritePage (shapenum);\r
+\r
+       scale = height>>3;                                              // low three bits are fractional\r
+       if (!scale || scale>maxscale)\r
+               return;                                                         // too close or far away\r
+       comptable = scaledirectory[scale];\r
+\r
+       *(((unsigned *)&linescale)+1)=(unsigned)comptable;      // seg of far call\r
+       *(((unsigned *)&linecmds)+1)=(unsigned)shape;           // seg of shape\r
+\r
+//\r
+// scale to the left (from pixel 31 to shape->leftpix)\r
+//\r
+       srcx = 32;\r
+       slinex = xcenter;\r
+       stopx = shape->leftpix;\r
+       cmdptr = &shape->dataofs[31-stopx];\r
+\r
+       while ( --srcx >=stopx && slinex>0)\r
+       {\r
+               (unsigned)linecmds = *cmdptr--;\r
+               if ( !(slinewidth = comptable->width[srcx]) )\r
+                       continue;\r
+\r
+               if (slinewidth == 1)\r
+               {\r
+                       slinex--;\r
+                       if (slinex<viewwidth)\r
+                       {\r
+                               if (wallheight[slinex] >= height)\r
+                                       continue;               // obscured by closer wall\r
+                               ScaleLine ();\r
+                       }\r
+                       continue;\r
+               }\r
+\r
+               //\r
+               // handle multi pixel lines\r
+               //\r
+               if (slinex>viewwidth)\r
+               {\r
+                       slinex -= slinewidth;\r
+                       slinewidth = viewwidth-slinex;\r
+                       if (slinewidth<1)\r
+                               continue;               // still off the right side\r
+               }\r
+               else\r
+               {\r
+                       if (slinewidth>slinex)\r
+                               slinewidth = slinex;\r
+                       slinex -= slinewidth;\r
+               }\r
+\r
+\r
+               leftvis = (wallheight[slinex] < height);\r
+               rightvis = (wallheight[slinex+slinewidth-1] < height);\r
+\r
+               if (leftvis)\r
+               {\r
+                       if (rightvis)\r
+                               ScaleLine ();\r
+                       else\r
+                       {\r
+                               while (wallheight[slinex+slinewidth-1] >= height)\r
+                                       slinewidth--;\r
+                               ScaleLine ();\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       if (!rightvis)\r
+                               continue;               // totally obscured\r
+\r
+                       while (wallheight[slinex] >= height)\r
+                       {\r
+                               slinex++;\r
+                               slinewidth--;\r
+                       }\r
+                       ScaleLine ();\r
+                       break;                  // the rest of the shape is gone\r
+               }\r
+       }\r
+\r
+\r
+//\r
+// scale to the right\r
+//\r
+       slinex = xcenter;\r
+       stopx = shape->rightpix;\r
+       if (shape->leftpix<31)\r
+       {\r
+               srcx = 31;\r
+               cmdptr = &shape->dataofs[32-shape->leftpix];\r
+       }\r
+       else\r
+       {\r
+               srcx = shape->leftpix-1;\r
+               cmdptr = &shape->dataofs[0];\r
+       }\r
+       slinewidth = 0;\r
+\r
+       while ( ++srcx <= stopx && (slinex+=slinewidth)<viewwidth)\r
+       {\r
+               (unsigned)linecmds = *cmdptr++;\r
+               if ( !(slinewidth = comptable->width[srcx]) )\r
+                       continue;\r
+\r
+               if (slinewidth == 1)\r
+               {\r
+                       if (slinex>=0 && wallheight[slinex] < height)\r
+                       {\r
+                               ScaleLine ();\r
+                       }\r
+                       continue;\r
+               }\r
+\r
+               //\r
+               // handle multi pixel lines\r
+               //\r
+               if (slinex<0)\r
+               {\r
+                       if (slinewidth <= -slinex)\r
+                               continue;               // still off the left edge\r
+\r
+                       slinewidth += slinex;\r
+                       slinex = 0;\r
+               }\r
+               else\r
+               {\r
+                       if (slinex + slinewidth > viewwidth)\r
+                               slinewidth = viewwidth-slinex;\r
+               }\r
+\r
+\r
+               leftvis = (wallheight[slinex] < height);\r
+               rightvis = (wallheight[slinex+slinewidth-1] < height);\r
+\r
+               if (leftvis)\r
+               {\r
+                       if (rightvis)\r
+                       {\r
+                               ScaleLine ();\r
+                       }\r
+                       else\r
+                       {\r
+                               while (wallheight[slinex+slinewidth-1] >= height)\r
+                                       slinewidth--;\r
+                               ScaleLine ();\r
+                               break;                  // the rest of the shape is gone\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       if (rightvis)\r
+                       {\r
+                               while (wallheight[slinex] >= height)\r
+                               {\r
+                                       slinex++;\r
+                                       slinewidth--;\r
+                               }\r
+                               ScaleLine ();\r
+                       }\r
+                       else\r
+                               continue;               // totally obscured\r
+               }\r
+       }\r
+}\r
+\r
+\r
+\r
+/*\r
+=======================\r
+=\r
+= SimpleScaleShape\r
+=\r
+= NO CLIPPING, height in pixels\r
+=\r
+= Draws a compiled shape at [scale] pixels high\r
+=\r
+= each vertical line of the shape has a pointer to segment data:\r
+=      end of segment pixel*2 (0 terminates line) used to patch rtl in scaler\r
+=      top of virtual line with segment in proper place\r
+=      start of segment pixel*2, used to jsl into compiled scaler\r
+=      <repeat>\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
+void SimpleScaleShape (int xcenter, int shapenum, unsigned height)\r
+{\r
+       t_compshape     _seg *shape;\r
+       t_compscale _seg *comptable;\r
+       unsigned        scale,srcx,stopx,tempx;\r
+       int                     t;\r
+       unsigned        far *cmdptr;\r
+       boolean         leftvis,rightvis;\r
+\r
+\r
+       shape = PM_GetSpritePage (shapenum);\r
+\r
+       scale = height>>1;\r
+       comptable = scaledirectory[scale];\r
+\r
+       *(((unsigned *)&linescale)+1)=(unsigned)comptable;      // seg of far call\r
+       *(((unsigned *)&linecmds)+1)=(unsigned)shape;           // seg of shape\r
+\r
+//\r
+// scale to the left (from pixel 31 to shape->leftpix)\r
+//\r
+       srcx = 32;\r
+       slinex = xcenter;\r
+       stopx = shape->leftpix;\r
+       cmdptr = &shape->dataofs[31-stopx];\r
+\r
+       while ( --srcx >=stopx )\r
+       {\r
+               (unsigned)linecmds = *cmdptr--;\r
+               if ( !(slinewidth = comptable->width[srcx]) )\r
+                       continue;\r
+\r
+               slinex -= slinewidth;\r
+               ScaleLine ();\r
+       }\r
+\r
+\r
+//\r
+// scale to the right\r
+//\r
+       slinex = xcenter;\r
+       stopx = shape->rightpix;\r
+       if (shape->leftpix<31)\r
+       {\r
+               srcx = 31;\r
+               cmdptr = &shape->dataofs[32-shape->leftpix];\r
+       }\r
+       else\r
+       {\r
+               srcx = shape->leftpix-1;\r
+               cmdptr = &shape->dataofs[0];\r
+       }\r
+       slinewidth = 0;\r
+\r
+       while ( ++srcx <= stopx )\r
+       {\r
+               (unsigned)linecmds = *cmdptr++;\r
+               if ( !(slinewidth = comptable->width[srcx]) )\r
+                       continue;\r
+\r
+               ScaleLine ();\r
+               slinex+=slinewidth;\r
+       }\r
+}\r
+\r
+\r
+\r
+\r
+//\r
+// bit mask tables for drawing scaled strips up to eight pixels wide\r
+//\r
+// down here so the STUPID inline assembler doesn't get confused!\r
+//\r
+\r
+\r
+byte   mapmasks1[4][8] = {\r
+{1 ,3 ,7 ,15,15,15,15,15},\r
+{2 ,6 ,14,14,14,14,14,14},\r
+{4 ,12,12,12,12,12,12,12},\r
+{8 ,8 ,8 ,8 ,8 ,8 ,8 ,8} };\r
+\r
+byte   mapmasks2[4][8] = {\r
+{0 ,0 ,0 ,0 ,1 ,3 ,7 ,15},\r
+{0 ,0 ,0 ,1 ,3 ,7 ,15,15},\r
+{0 ,0 ,1 ,3 ,7 ,15,15,15},\r
+{0 ,1 ,3 ,7 ,15,15,15,15} };\r
+\r
+byte   mapmasks3[4][8] = {\r
+{0 ,0 ,0 ,0 ,0 ,0 ,0 ,0},\r
+{0 ,0 ,0 ,0 ,0 ,0 ,0 ,1},\r
+{0 ,0 ,0 ,0 ,0 ,0 ,1 ,3},\r
+{0 ,0 ,0 ,0 ,0 ,1 ,3 ,7} };\r
+\r
+\r
+unsigned       wordmasks[8][8] = {\r
+{0x0080,0x00c0,0x00e0,0x00f0,0x00f8,0x00fc,0x00fe,0x00ff},\r
+{0x0040,0x0060,0x0070,0x0078,0x007c,0x007e,0x007f,0x807f},\r
+{0x0020,0x0030,0x0038,0x003c,0x003e,0x003f,0x803f,0xc03f},\r
+{0x0010,0x0018,0x001c,0x001e,0x001f,0x801f,0xc01f,0xe01f},\r
+{0x0008,0x000c,0x000e,0x000f,0x800f,0xc00f,0xe00f,0xf00f},\r
+{0x0004,0x0006,0x0007,0x8007,0xc007,0xe007,0xf007,0xf807},\r
+{0x0002,0x0003,0x8003,0xc003,0xe003,0xf003,0xf803,0xfc03},\r
+{0x0001,0x8001,0xc001,0xe001,0xf001,0xf801,0xfc01,0xfe01} };\r
+\r
+int                    slinex,slinewidth;\r
+unsigned       far *linecmds;\r
+long           linescale;\r
+unsigned       maskword;\r
+\r
diff --git a/src/lib/hb/wl_state.c b/src/lib/hb/wl_state.c
new file mode 100755 (executable)
index 0000000..ad534ba
--- /dev/null
@@ -0,0 +1,1480 @@
+// WL_STATE.C\r
+\r
+#include "WL_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
+dirtype opposite[9] =\r
+       {west,southwest,south,southeast,east,northeast,north,northwest,nodir};\r
+\r
+dirtype diagonal[9][9] =\r
+{\r
+/* east */     {nodir,nodir,northeast,nodir,nodir,nodir,southeast,nodir,nodir},\r
+                       {nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir},\r
+/* north */ {northeast,nodir,nodir,nodir,northwest,nodir,nodir,nodir,nodir},\r
+                       {nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir},\r
+/* west */  {nodir,nodir,northwest,nodir,nodir,nodir,southwest,nodir,nodir},\r
+                       {nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir},\r
+/* south */ {southeast,nodir,nodir,nodir,southwest,nodir,nodir,nodir,nodir},\r
+                       {nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir},\r
+                       {nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir}\r
+};\r
+\r
+\r
+\r
+void   SpawnNewObj (unsigned tilex, unsigned tiley, statetype *state);\r
+void   NewState (objtype *ob, statetype *state);\r
+\r
+boolean TryWalk (objtype *ob);\r
+void   MoveObj (objtype *ob, long move);\r
+\r
+void   KillActor (objtype *ob);\r
+void   DamageActor (objtype *ob, unsigned damage);\r
+\r
+boolean CheckLine (objtype *ob);\r
+void FirstSighting (objtype *ob);\r
+boolean        CheckSight (objtype *ob);\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= SpawnNewObj\r
+=\r
+= Spaws a new actor at the given TILE coordinates, with the given state, and\r
+= the given size in GLOBAL units.\r
+=\r
+= new                  = a pointer to an initialized new actor\r
+=\r
+===================\r
+*/\r
+\r
+void SpawnNewObj (unsigned tilex, unsigned tiley, statetype *state)\r
+{\r
+       GetNewActor ();\r
+       new->state = state;\r
+       if (state->tictime)\r
+               new->ticcount = US_RndT () % state->tictime;\r
+       else\r
+               new->ticcount = 0;\r
+\r
+       new->tilex = tilex;\r
+       new->tiley = tiley;\r
+       new->x = ((long)tilex<<TILESHIFT)+TILEGLOBAL/2;\r
+       new->y = ((long)tiley<<TILESHIFT)+TILEGLOBAL/2;\r
+       new->dir = nodir;\r
+\r
+       actorat[tilex][tiley] = new;\r
+       new->areanumber =\r
+               *(mapsegs[0] + farmapylookup[new->tiley]+new->tilex) - AREATILE;\r
+}\r
+\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= NewState\r
+=\r
+= Changes ob to a new state, setting ticcount to the max for that state\r
+=\r
+===================\r
+*/\r
+\r
+void NewState (objtype *ob, statetype *state)\r
+{\r
+       ob->state = state;\r
+       ob->ticcount = state->tictime;\r
+}\r
+\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                               ENEMY TILE WORLD MOVEMENT CODE\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+/*\r
+==================================\r
+=\r
+= TryWalk\r
+=\r
+= Attempts to move ob in its current (ob->dir) direction.\r
+=\r
+= If blocked by either a wall or an actor returns FALSE\r
+=\r
+= If move is either clear or blocked only by a door, returns TRUE and sets\r
+=\r
+= ob->tilex                    = new destination\r
+= ob->tiley\r
+= ob->areanumber    = the floor tile number (0-(NUMAREAS-1)) of destination\r
+= ob->distance         = TILEGLOBAl, or -doornumber if a door is blocking the way\r
+=\r
+= If a door is in the way, an OpenDoor call is made to start it opening.\r
+= The actor code should wait until\r
+=      doorobjlist[-ob->distance].action = dr_open, meaning the door has been\r
+=      fully opened\r
+=\r
+==================================\r
+*/\r
+\r
+#define CHECKDIAG(x,y)                                                         \\r
+{                                                   \\r
+       temp=(unsigned)actorat[x][y];                   \\r
+       if (temp)                                       \\r
+       {                                               \\r
+               if (temp<256)                               \\r
+                       return false;                           \\r
+               if (((objtype *)temp)->flags&FL_SHOOTABLE)  \\r
+                       return false;                           \\r
+       }                                               \\r
+}\r
+\r
+#define CHECKSIDE(x,y)                                                         \\r
+{                                                   \\r
+       temp=(unsigned)actorat[x][y];                   \\r
+       if (temp)                                       \\r
+       {                                               \\r
+               if (temp<128)                               \\r
+                       return false;                           \\r
+               if (temp<256)                               \\r
+                       doornum = temp&63;                      \\r
+               else if (((objtype *)temp)->flags&FL_SHOOTABLE)\\r
+                       return false;                           \\r
+       }                                               \\r
+}\r
+\r
+\r
+boolean TryWalk (objtype *ob)\r
+{\r
+       int                     doornum;\r
+       unsigned        temp;\r
+\r
+       doornum = -1;\r
+\r
+       if (ob->obclass == inertobj)\r
+       {\r
+               switch (ob->dir)\r
+               {\r
+               case north:\r
+                       ob->tiley--;\r
+                       break;\r
+\r
+               case northeast:\r
+                       ob->tilex++;\r
+                       ob->tiley--;\r
+                       break;\r
+\r
+               case east:\r
+                       ob->tilex++;\r
+                       break;\r
+\r
+               case southeast:\r
+                       ob->tilex++;\r
+                       ob->tiley++;\r
+                       break;\r
+\r
+               case south:\r
+                       ob->tiley++;\r
+                       break;\r
+\r
+               case southwest:\r
+                       ob->tilex--;\r
+                       ob->tiley++;\r
+                       break;\r
+\r
+               case west:\r
+                       ob->tilex--;\r
+                       break;\r
+\r
+               case northwest:\r
+                       ob->tilex--;\r
+                       ob->tiley--;\r
+                       break;\r
+               }\r
+       }\r
+       else\r
+               switch (ob->dir)\r
+               {\r
+               case north:\r
+                       if (ob->obclass == dogobj || ob->obclass == fakeobj)\r
+                       {\r
+                               CHECKDIAG(ob->tilex,ob->tiley-1);\r
+                       }\r
+                       else\r
+                       {\r
+                               CHECKSIDE(ob->tilex,ob->tiley-1);\r
+                       }\r
+                       ob->tiley--;\r
+                       break;\r
+\r
+               case northeast:\r
+                       CHECKDIAG(ob->tilex+1,ob->tiley-1);\r
+                       CHECKDIAG(ob->tilex+1,ob->tiley);\r
+                       CHECKDIAG(ob->tilex,ob->tiley-1);\r
+                       ob->tilex++;\r
+                       ob->tiley--;\r
+                       break;\r
+\r
+               case east:\r
+                       if (ob->obclass == dogobj || ob->obclass == fakeobj)\r
+                       {\r
+                               CHECKDIAG(ob->tilex+1,ob->tiley);\r
+                       }\r
+                       else\r
+                       {\r
+                               CHECKSIDE(ob->tilex+1,ob->tiley);\r
+                       }\r
+                       ob->tilex++;\r
+                       break;\r
+\r
+               case southeast:\r
+                       CHECKDIAG(ob->tilex+1,ob->tiley+1);\r
+                       CHECKDIAG(ob->tilex+1,ob->tiley);\r
+                       CHECKDIAG(ob->tilex,ob->tiley+1);\r
+                       ob->tilex++;\r
+                       ob->tiley++;\r
+                       break;\r
+\r
+               case south:\r
+                       if (ob->obclass == dogobj || ob->obclass == fakeobj)\r
+                       {\r
+                               CHECKDIAG(ob->tilex,ob->tiley+1);\r
+                       }\r
+                       else\r
+                       {\r
+                               CHECKSIDE(ob->tilex,ob->tiley+1);\r
+                       }\r
+                       ob->tiley++;\r
+                       break;\r
+\r
+               case southwest:\r
+                       CHECKDIAG(ob->tilex-1,ob->tiley+1);\r
+                       CHECKDIAG(ob->tilex-1,ob->tiley);\r
+                       CHECKDIAG(ob->tilex,ob->tiley+1);\r
+                       ob->tilex--;\r
+                       ob->tiley++;\r
+                       break;\r
+\r
+               case west:\r
+                       if (ob->obclass == dogobj || ob->obclass == fakeobj)\r
+                       {\r
+                               CHECKDIAG(ob->tilex-1,ob->tiley);\r
+                       }\r
+                       else\r
+                       {\r
+                               CHECKSIDE(ob->tilex-1,ob->tiley);\r
+                       }\r
+                       ob->tilex--;\r
+                       break;\r
+\r
+               case northwest:\r
+                       CHECKDIAG(ob->tilex-1,ob->tiley-1);\r
+                       CHECKDIAG(ob->tilex-1,ob->tiley);\r
+                       CHECKDIAG(ob->tilex,ob->tiley-1);\r
+                       ob->tilex--;\r
+                       ob->tiley--;\r
+                       break;\r
+\r
+               case nodir:\r
+                       return false;\r
+\r
+               default:\r
+                       Quit ("Walk: Bad dir");\r
+               }\r
+\r
+       if (doornum != -1)\r
+       {\r
+               OpenDoor (doornum);\r
+               ob->distance = -doornum-1;\r
+               return true;\r
+       }\r
+\r
+\r
+       ob->areanumber =\r
+               *(mapsegs[0] + farmapylookup[ob->tiley]+ob->tilex) - AREATILE;\r
+\r
+       ob->distance = TILEGLOBAL;\r
+       return true;\r
+}\r
+\r
+\r
+\r
+/*\r
+==================================\r
+=\r
+= SelectDodgeDir\r
+=\r
+= Attempts to choose and initiate a movement for ob that sends it towards\r
+= the player while dodging\r
+=\r
+= If there is no possible move (ob is totally surrounded)\r
+=\r
+= ob->dir                      =       nodir\r
+=\r
+= Otherwise\r
+=\r
+= ob->dir                      = new direction to follow\r
+= ob->distance         = TILEGLOBAL or -doornumber\r
+= ob->tilex                    = new destination\r
+= ob->tiley\r
+= ob->areanumber    = the floor tile number (0-(NUMAREAS-1)) of destination\r
+=\r
+==================================\r
+*/\r
+\r
+void SelectDodgeDir (objtype *ob)\r
+{\r
+       int             deltax,deltay,i;\r
+       unsigned        absdx,absdy;\r
+       dirtype         dirtry[5];\r
+       dirtype         turnaround,tdir;\r
+\r
+       if (ob->flags & FL_FIRSTATTACK)\r
+       {\r
+       //\r
+       // turning around is only ok the very first time after noticing the\r
+       // player\r
+       //\r
+               turnaround = nodir;\r
+               ob->flags &= ~FL_FIRSTATTACK;\r
+       }\r
+       else\r
+               turnaround=opposite[ob->dir];\r
+\r
+       deltax = player->tilex - ob->tilex;\r
+       deltay = player->tiley - ob->tiley;\r
+\r
+//\r
+// arange 5 direction choices in order of preference\r
+// the four cardinal directions plus the diagonal straight towards\r
+// the player\r
+//\r
+\r
+       if (deltax>0)\r
+       {\r
+               dirtry[1]= east;\r
+               dirtry[3]= west;\r
+       }\r
+       else\r
+       {\r
+               dirtry[1]= west;\r
+               dirtry[3]= east;\r
+       }\r
+\r
+       if (deltay>0)\r
+       {\r
+               dirtry[2]= south;\r
+               dirtry[4]= north;\r
+       }\r
+       else\r
+       {\r
+               dirtry[2]= north;\r
+               dirtry[4]= south;\r
+       }\r
+\r
+//\r
+// randomize a bit for dodging\r
+//\r
+       absdx = abs(deltax);\r
+       absdy = abs(deltay);\r
+\r
+       if (absdx > absdy)\r
+       {\r
+               tdir = dirtry[1];\r
+               dirtry[1] = dirtry[2];\r
+               dirtry[2] = tdir;\r
+               tdir = dirtry[3];\r
+               dirtry[3] = dirtry[4];\r
+               dirtry[4] = tdir;\r
+       }\r
+\r
+       if (US_RndT() < 128)\r
+       {\r
+               tdir = dirtry[1];\r
+               dirtry[1] = dirtry[2];\r
+               dirtry[2] = tdir;\r
+               tdir = dirtry[3];\r
+               dirtry[3] = dirtry[4];\r
+               dirtry[4] = tdir;\r
+       }\r
+\r
+       dirtry[0] = diagonal [ dirtry[1] ] [ dirtry[2] ];\r
+\r
+//\r
+// try the directions util one works\r
+//\r
+       for (i=0;i<5;i++)\r
+       {\r
+               if ( dirtry[i] == nodir || dirtry[i] == turnaround)\r
+                       continue;\r
+\r
+               ob->dir = dirtry[i];\r
+               if (TryWalk(ob))\r
+                       return;\r
+       }\r
+\r
+//\r
+// turn around only as a last resort\r
+//\r
+       if (turnaround != nodir)\r
+       {\r
+               ob->dir = turnaround;\r
+\r
+               if (TryWalk(ob))\r
+                       return;\r
+       }\r
+\r
+       ob->dir = nodir;\r
+}\r
+\r
+\r
+/*\r
+============================\r
+=\r
+= SelectChaseDir\r
+=\r
+= As SelectDodgeDir, but doesn't try to dodge\r
+=\r
+============================\r
+*/\r
+\r
+void SelectChaseDir (objtype *ob)\r
+{\r
+       int deltax,deltay,i;\r
+       dirtype d[3];\r
+       dirtype tdir, olddir, turnaround;\r
+\r
+\r
+       olddir=ob->dir;\r
+       turnaround=opposite[olddir];\r
+\r
+       deltax=player->tilex - ob->tilex;\r
+       deltay=player->tiley - ob->tiley;\r
+\r
+       d[1]=nodir;\r
+       d[2]=nodir;\r
+\r
+       if (deltax>0)\r
+               d[1]= east;\r
+       else if (deltax<0)\r
+               d[1]= west;\r
+       if (deltay>0)\r
+               d[2]=south;\r
+       else if (deltay<0)\r
+               d[2]=north;\r
+\r
+       if (abs(deltay)>abs(deltax))\r
+       {\r
+               tdir=d[1];\r
+               d[1]=d[2];\r
+               d[2]=tdir;\r
+       }\r
+\r
+       if (d[1]==turnaround)\r
+               d[1]=nodir;\r
+       if (d[2]==turnaround)\r
+               d[2]=nodir;\r
+\r
+\r
+       if (d[1]!=nodir)\r
+       {\r
+               ob->dir=d[1];\r
+               if (TryWalk(ob))\r
+                       return;     /*either moved forward or attacked*/\r
+       }\r
+\r
+       if (d[2]!=nodir)\r
+       {\r
+               ob->dir=d[2];\r
+               if (TryWalk(ob))\r
+                       return;\r
+       }\r
+\r
+/* there is no direct path to the player, so pick another direction */\r
+\r
+       if (olddir!=nodir)\r
+       {\r
+               ob->dir=olddir;\r
+               if (TryWalk(ob))\r
+                       return;\r
+       }\r
+\r
+       if (US_RndT()>128)      /*randomly determine direction of search*/\r
+       {\r
+               for (tdir=north;tdir<=west;tdir++)\r
+               {\r
+                       if (tdir!=turnaround)\r
+                       {\r
+                               ob->dir=tdir;\r
+                               if ( TryWalk(ob) )\r
+                                       return;\r
+                       }\r
+               }\r
+       }\r
+       else\r
+       {\r
+               for (tdir=west;tdir>=north;tdir--)\r
+               {\r
+                       if (tdir!=turnaround)\r
+                       {\r
+                         ob->dir=tdir;\r
+                         if ( TryWalk(ob) )\r
+                               return;\r
+                       }\r
+               }\r
+       }\r
+\r
+       if (turnaround !=  nodir)\r
+       {\r
+               ob->dir=turnaround;\r
+               if (ob->dir != nodir)\r
+               {\r
+                       if ( TryWalk(ob) )\r
+                               return;\r
+               }\r
+       }\r
+\r
+       ob->dir = nodir;                // can't move\r
+}\r
+\r
+\r
+/*\r
+============================\r
+=\r
+= SelectRunDir\r
+=\r
+= Run Away from player\r
+=\r
+============================\r
+*/\r
+\r
+void SelectRunDir (objtype *ob)\r
+{\r
+       int deltax,deltay,i;\r
+       dirtype d[3];\r
+       dirtype tdir, olddir, turnaround;\r
+\r
+\r
+       deltax=player->tilex - ob->tilex;\r
+       deltay=player->tiley - ob->tiley;\r
+\r
+       if (deltax<0)\r
+               d[1]= east;\r
+       else\r
+               d[1]= west;\r
+       if (deltay<0)\r
+               d[2]=south;\r
+       else\r
+               d[2]=north;\r
+\r
+       if (abs(deltay)>abs(deltax))\r
+       {\r
+               tdir=d[1];\r
+               d[1]=d[2];\r
+               d[2]=tdir;\r
+       }\r
+\r
+       ob->dir=d[1];\r
+       if (TryWalk(ob))\r
+               return;     /*either moved forward or attacked*/\r
+\r
+       ob->dir=d[2];\r
+       if (TryWalk(ob))\r
+               return;\r
+\r
+/* there is no direct path to the player, so pick another direction */\r
+\r
+       if (US_RndT()>128)      /*randomly determine direction of search*/\r
+       {\r
+               for (tdir=north;tdir<=west;tdir++)\r
+               {\r
+                       ob->dir=tdir;\r
+                       if ( TryWalk(ob) )\r
+                               return;\r
+               }\r
+       }\r
+       else\r
+       {\r
+               for (tdir=west;tdir>=north;tdir--)\r
+               {\r
+                       ob->dir=tdir;\r
+                       if ( TryWalk(ob) )\r
+                         return;\r
+               }\r
+       }\r
+\r
+       ob->dir = nodir;                // can't move\r
+}\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= MoveObj\r
+=\r
+= Moves ob be move global units in ob->dir direction\r
+= Actors are not allowed to move inside the player\r
+= Does NOT check to see if the move is tile map valid\r
+=\r
+= ob->x                        = adjusted for new position\r
+= ob->y\r
+=\r
+=================\r
+*/\r
+\r
+void MoveObj (objtype *ob, long move)\r
+{\r
+       long    deltax,deltay;\r
+\r
+       switch (ob->dir)\r
+       {\r
+       case north:\r
+               ob->y -= move;\r
+               break;\r
+       case northeast:\r
+               ob->x += move;\r
+               ob->y -= move;\r
+               break;\r
+       case east:\r
+               ob->x += move;\r
+               break;\r
+       case southeast:\r
+               ob->x += move;\r
+               ob->y += move;\r
+               break;\r
+       case south:\r
+               ob->y += move;\r
+               break;\r
+       case southwest:\r
+               ob->x -= move;\r
+               ob->y += move;\r
+               break;\r
+       case west:\r
+               ob->x -= move;\r
+               break;\r
+       case northwest:\r
+               ob->x -= move;\r
+               ob->y -= move;\r
+               break;\r
+\r
+       case nodir:\r
+               return;\r
+\r
+       default:\r
+               Quit ("MoveObj: bad dir!");\r
+       }\r
+\r
+//\r
+// check to make sure it's not on top of player\r
+//\r
+       if (areabyplayer[ob->areanumber])\r
+       {\r
+               deltax = ob->x - player->x;\r
+               if (deltax < -MINACTORDIST || deltax > MINACTORDIST)\r
+                       goto moveok;\r
+               deltay = ob->y - player->y;\r
+               if (deltay < -MINACTORDIST || deltay > MINACTORDIST)\r
+                       goto moveok;\r
+\r
+               if (ob->obclass == ghostobj || ob->obclass == spectreobj)\r
+                       TakeDamage (tics*2,ob);\r
+\r
+       //\r
+       // back up\r
+       //\r
+               switch (ob->dir)\r
+               {\r
+               case north:\r
+                       ob->y += move;\r
+                       break;\r
+               case northeast:\r
+                       ob->x -= move;\r
+                       ob->y += move;\r
+                       break;\r
+               case east:\r
+                       ob->x -= move;\r
+                       break;\r
+               case southeast:\r
+                       ob->x -= move;\r
+                       ob->y -= move;\r
+                       break;\r
+               case south:\r
+                       ob->y -= move;\r
+                       break;\r
+               case southwest:\r
+                       ob->x += move;\r
+                       ob->y -= move;\r
+                       break;\r
+               case west:\r
+                       ob->x += move;\r
+                       break;\r
+               case northwest:\r
+                       ob->x += move;\r
+                       ob->y += move;\r
+                       break;\r
+\r
+               case nodir:\r
+                       return;\r
+               }\r
+               return;\r
+       }\r
+moveok:\r
+       ob->distance -=move;\r
+}\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                       STUFF\r
+\r
+=============================================================================\r
+*/\r
+\r
+/*\r
+===============\r
+=\r
+= DropItem\r
+=\r
+= Tries to drop a bonus item somewhere in the tiles surrounding the\r
+= given tilex/tiley\r
+=\r
+===============\r
+*/\r
+\r
+void DropItem (stat_t itemtype, int tilex, int tiley)\r
+{\r
+       int     x,y,xl,xh,yl,yh;\r
+\r
+//\r
+// find a free spot to put it in\r
+//\r
+       if (!actorat[tilex][tiley])\r
+       {\r
+               PlaceItemType (itemtype, tilex,tiley);\r
+               return;\r
+       }\r
+\r
+       xl = tilex-1;\r
+       xh = tilex+1;\r
+       yl = tiley-1;\r
+       yh = tiley+1;\r
+\r
+       for (x=xl ; x<= xh ; x++)\r
+               for (y=yl ; y<= yh ; y++)\r
+                       if (!actorat[x][y])\r
+                       {\r
+                               PlaceItemType (itemtype, x,y);\r
+                               return;\r
+                       }\r
+}\r
+\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= KillActor\r
+=\r
+===============\r
+*/\r
+\r
+void KillActor (objtype *ob)\r
+{\r
+       int     tilex,tiley;\r
+\r
+       tilex = ob->tilex = ob->x >> TILESHIFT;         // drop item on center\r
+       tiley = ob->tiley = ob->y >> TILESHIFT;\r
+\r
+       switch (ob->obclass)\r
+       {\r
+       case guardobj:\r
+               GivePoints (100);\r
+               NewState (ob,&s_grddie1);\r
+               PlaceItemType (bo_clip2,tilex,tiley);\r
+               break;\r
+\r
+       case officerobj:\r
+               GivePoints (400);\r
+               NewState (ob,&s_ofcdie1);\r
+               PlaceItemType (bo_clip2,tilex,tiley);\r
+               break;\r
+\r
+       case mutantobj:\r
+               GivePoints (700);\r
+               NewState (ob,&s_mutdie1);\r
+               PlaceItemType (bo_clip2,tilex,tiley);\r
+               break;\r
+\r
+       case ssobj:\r
+               GivePoints (500);\r
+               NewState (ob,&s_ssdie1);\r
+               if (gamestate.bestweapon < wp_machinegun)\r
+                       PlaceItemType (bo_machinegun,tilex,tiley);\r
+               else\r
+                       PlaceItemType (bo_clip2,tilex,tiley);\r
+               break;\r
+\r
+       case dogobj:\r
+               GivePoints (200);\r
+               NewState (ob,&s_dogdie1);\r
+               break;\r
+\r
+#ifndef SPEAR\r
+       case bossobj:\r
+               GivePoints (5000);\r
+               NewState (ob,&s_bossdie1);\r
+               PlaceItemType (bo_key1,tilex,tiley);\r
+               break;\r
+\r
+       case gretelobj:\r
+               GivePoints (5000);\r
+               NewState (ob,&s_greteldie1);\r
+               PlaceItemType (bo_key1,tilex,tiley);\r
+               break;\r
+\r
+       case giftobj:\r
+               GivePoints (5000);\r
+               gamestate.killx = player->x;\r
+               gamestate.killy = player->y;\r
+               NewState (ob,&s_giftdie1);\r
+               break;\r
+\r
+       case fatobj:\r
+               GivePoints (5000);\r
+               gamestate.killx = player->x;\r
+               gamestate.killy = player->y;\r
+               NewState (ob,&s_fatdie1);\r
+               break;\r
+\r
+       case schabbobj:\r
+               GivePoints (5000);\r
+               gamestate.killx = player->x;\r
+               gamestate.killy = player->y;\r
+               NewState (ob,&s_schabbdie1);\r
+               A_DeathScream(ob);\r
+               break;\r
+       case fakeobj:\r
+               GivePoints (2000);\r
+               NewState (ob,&s_fakedie1);\r
+               break;\r
+\r
+       case mechahitlerobj:\r
+               GivePoints (5000);\r
+               NewState (ob,&s_mechadie1);\r
+               break;\r
+       case realhitlerobj:\r
+               GivePoints (5000);\r
+               gamestate.killx = player->x;\r
+               gamestate.killy = player->y;\r
+               NewState (ob,&s_hitlerdie1);\r
+               A_DeathScream(ob);\r
+               break;\r
+#else\r
+       case spectreobj:\r
+               GivePoints (200);\r
+               NewState (ob,&s_spectredie1);\r
+               break;\r
+\r
+       case angelobj:\r
+               GivePoints (5000);\r
+               NewState (ob,&s_angeldie1);\r
+               break;\r
+\r
+       case transobj:\r
+               GivePoints (5000);\r
+               NewState (ob,&s_transdie0);\r
+               PlaceItemType (bo_key1,tilex,tiley);\r
+               break;\r
+\r
+       case uberobj:\r
+               GivePoints (5000);\r
+               NewState (ob,&s_uberdie0);\r
+               PlaceItemType (bo_key1,tilex,tiley);\r
+               break;\r
+\r
+       case willobj:\r
+               GivePoints (5000);\r
+               NewState (ob,&s_willdie1);\r
+               PlaceItemType (bo_key1,tilex,tiley);\r
+               break;\r
+\r
+       case deathobj:\r
+               GivePoints (5000);\r
+               NewState (ob,&s_deathdie1);\r
+               PlaceItemType (bo_key1,tilex,tiley);\r
+               break;\r
+#endif\r
+       }\r
+\r
+       gamestate.killcount++;\r
+       ob->flags &= ~FL_SHOOTABLE;\r
+       actorat[ob->tilex][ob->tiley] = NULL;\r
+       ob->flags |= FL_NONMARK;\r
+}\r
+\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= DamageActor\r
+=\r
+= Called when the player succesfully hits an enemy.\r
+=\r
+= Does damage points to enemy ob, either putting it into a stun frame or\r
+= killing it.\r
+=\r
+===================\r
+*/\r
+\r
+void DamageActor (objtype *ob, unsigned damage)\r
+{\r
+       madenoise = true;\r
+\r
+//\r
+// do double damage if shooting a non attack mode actor\r
+//\r
+       if ( !(ob->flags & FL_ATTACKMODE) )\r
+               damage <<= 1;\r
+\r
+       ob->hitpoints -= damage;\r
+\r
+       if (ob->hitpoints<=0)\r
+               KillActor (ob);\r
+       else\r
+       {\r
+               if (! (ob->flags & FL_ATTACKMODE) )\r
+                       FirstSighting (ob);             // put into combat mode\r
+\r
+               switch (ob->obclass)            // dogs only have one hit point\r
+               {\r
+               case guardobj:\r
+                       if (ob->hitpoints&1)\r
+                               NewState (ob,&s_grdpain);\r
+                       else\r
+                               NewState (ob,&s_grdpain1);\r
+                       break;\r
+\r
+               case officerobj:\r
+                       if (ob->hitpoints&1)\r
+                               NewState (ob,&s_ofcpain);\r
+                       else\r
+                               NewState (ob,&s_ofcpain1);\r
+                       break;\r
+\r
+               case mutantobj:\r
+                       if (ob->hitpoints&1)\r
+                               NewState (ob,&s_mutpain);\r
+                       else\r
+                               NewState (ob,&s_mutpain1);\r
+                       break;\r
+\r
+               case ssobj:\r
+                       if (ob->hitpoints&1)\r
+                               NewState (ob,&s_sspain);\r
+                       else\r
+                               NewState (ob,&s_sspain1);\r
+\r
+                       break;\r
+\r
+               }\r
+       }\r
+}\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                       CHECKSIGHT\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= CheckLine\r
+=\r
+= Returns true if a straight line between the player and ob is unobstructed\r
+=\r
+=====================\r
+*/\r
+\r
+boolean CheckLine (objtype *ob)\r
+{\r
+       int     x1,y1,xt1,yt1,x2,y2,xt2,yt2;\r
+       int     x,y;\r
+       int     xdist,ydist,xstep,ystep;\r
+       int     temp;\r
+       int     partial,delta;\r
+       long    ltemp;\r
+       int     xfrac,yfrac,deltafrac;\r
+       unsigned        value,intercept;\r
+\r
+       x1 = ob->x >> UNSIGNEDSHIFT;            // 1/256 tile precision\r
+       y1 = ob->y >> UNSIGNEDSHIFT;\r
+       xt1 = x1 >> 8;\r
+       yt1 = y1 >> 8;\r
+\r
+       x2 = plux;\r
+       y2 = pluy;\r
+       xt2 = player->tilex;\r
+       yt2 = player->tiley;\r
+\r
+\r
+       xdist = abs(xt2-xt1);\r
+\r
+       if (xdist > 0)\r
+       {\r
+               if (xt2 > xt1)\r
+               {\r
+                       partial = 256-(x1&0xff);\r
+                       xstep = 1;\r
+               }\r
+               else\r
+               {\r
+                       partial = x1&0xff;\r
+                       xstep = -1;\r
+               }\r
+\r
+               deltafrac = abs(x2-x1);\r
+               delta = y2-y1;\r
+               ltemp = ((long)delta<<8)/deltafrac;\r
+               if (ltemp > 0x7fffl)\r
+                       ystep = 0x7fff;\r
+               else if (ltemp < -0x7fffl)\r
+                       ystep = -0x7fff;\r
+               else\r
+                       ystep = ltemp;\r
+               yfrac = y1 + (((long)ystep*partial) >>8);\r
+\r
+               x = xt1+xstep;\r
+               xt2 += xstep;\r
+               do\r
+               {\r
+                       y = yfrac>>8;\r
+                       yfrac += ystep;\r
+\r
+                       value = (unsigned)tilemap[x][y];\r
+                       x += xstep;\r
+\r
+                       if (!value)\r
+                               continue;\r
+\r
+                       if (value<128 || value>256)\r
+                               return false;\r
+\r
+                       //\r
+                       // see if the door is open enough\r
+                       //\r
+                       value &= ~0x80;\r
+                       intercept = yfrac-ystep/2;\r
+\r
+                       if (intercept>doorposition[value])\r
+                               return false;\r
+\r
+               } while (x != xt2);\r
+       }\r
+\r
+       ydist = abs(yt2-yt1);\r
+\r
+       if (ydist > 0)\r
+       {\r
+               if (yt2 > yt1)\r
+               {\r
+                       partial = 256-(y1&0xff);\r
+                       ystep = 1;\r
+               }\r
+               else\r
+               {\r
+                       partial = y1&0xff;\r
+                       ystep = -1;\r
+               }\r
+\r
+               deltafrac = abs(y2-y1);\r
+               delta = x2-x1;\r
+               ltemp = ((long)delta<<8)/deltafrac;\r
+               if (ltemp > 0x7fffl)\r
+                       xstep = 0x7fff;\r
+               else if (ltemp < -0x7fffl)\r
+                       xstep = -0x7fff;\r
+               else\r
+                       xstep = ltemp;\r
+               xfrac = x1 + (((long)xstep*partial) >>8);\r
+\r
+               y = yt1 + ystep;\r
+               yt2 += ystep;\r
+               do\r
+               {\r
+                       x = xfrac>>8;\r
+                       xfrac += xstep;\r
+\r
+                       value = (unsigned)tilemap[x][y];\r
+                       y += ystep;\r
+\r
+                       if (!value)\r
+                               continue;\r
+\r
+                       if (value<128 || value>256)\r
+                               return false;\r
+\r
+                       //\r
+                       // see if the door is open enough\r
+                       //\r
+                       value &= ~0x80;\r
+                       intercept = xfrac-xstep/2;\r
+\r
+                       if (intercept>doorposition[value])\r
+                               return false;\r
+               } while (y != yt2);\r
+       }\r
+\r
+       return true;\r
+}\r
+\r
+\r
+\r
+/*\r
+================\r
+=\r
+= CheckSight\r
+=\r
+= Checks a straight line between player and current object\r
+=\r
+= If the sight is ok, check alertness and angle to see if they notice\r
+=\r
+= returns true if the player has been spoted\r
+=\r
+================\r
+*/\r
+\r
+#define MINSIGHT       0x18000l\r
+\r
+boolean CheckSight (objtype *ob)\r
+{\r
+       long            deltax,deltay;\r
+\r
+//\r
+// don't bother tracing a line if the area isn't connected to the player's\r
+//\r
+       if (!areabyplayer[ob->areanumber])\r
+               return false;\r
+\r
+//\r
+// if the player is real close, sight is automatic\r
+//\r
+       deltax = player->x - ob->x;\r
+       deltay = player->y - ob->y;\r
+\r
+       if (deltax > -MINSIGHT && deltax < MINSIGHT\r
+       && deltay > -MINSIGHT && deltay < MINSIGHT)\r
+               return true;\r
+\r
+//\r
+// see if they are looking in the right direction\r
+//\r
+       switch (ob->dir)\r
+       {\r
+       case north:\r
+               if (deltay > 0)\r
+                       return false;\r
+               break;\r
+\r
+       case east:\r
+               if (deltax < 0)\r
+                       return false;\r
+               break;\r
+\r
+       case south:\r
+               if (deltay < 0)\r
+                       return false;\r
+               break;\r
+\r
+       case west:\r
+               if (deltax > 0)\r
+                       return false;\r
+               break;\r
+       }\r
+\r
+//\r
+// trace a line to check for blocking tiles (corners)\r
+//\r
+       return CheckLine (ob);\r
+\r
+}\r
+\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= FirstSighting\r
+=\r
+= Puts an actor into attack mode and possibly reverses the direction\r
+= if the player is behind it\r
+=\r
+===============\r
+*/\r
+\r
+void FirstSighting (objtype *ob)\r
+{\r
+//\r
+// react to the player\r
+//\r
+       switch (ob->obclass)\r
+       {\r
+       case guardobj:\r
+               PlaySoundLocActor(HALTSND,ob);\r
+               NewState (ob,&s_grdchase1);\r
+               ob->speed *= 3;                 // go faster when chasing player\r
+               break;\r
+\r
+       case officerobj:\r
+               PlaySoundLocActor(SPIONSND,ob);\r
+               NewState (ob,&s_ofcchase1);\r
+               ob->speed *= 5;                 // go faster when chasing player\r
+               break;\r
+\r
+       case mutantobj:\r
+               NewState (ob,&s_mutchase1);\r
+               ob->speed *= 3;                 // go faster when chasing player\r
+               break;\r
+\r
+       case ssobj:\r
+               PlaySoundLocActor(SCHUTZADSND,ob);\r
+               NewState (ob,&s_sschase1);\r
+               ob->speed *= 4;                 // go faster when chasing player\r
+               break;\r
+\r
+       case dogobj:\r
+               PlaySoundLocActor(DOGBARKSND,ob);\r
+               NewState (ob,&s_dogchase1);\r
+               ob->speed *= 2;                 // go faster when chasing player\r
+               break;\r
+\r
+#ifndef SPEAR\r
+       case bossobj:\r
+               SD_PlaySound(GUTENTAGSND);\r
+               NewState (ob,&s_bosschase1);\r
+               ob->speed = SPDPATROL*3;        // go faster when chasing player\r
+               break;\r
+\r
+       case gretelobj:\r
+               SD_PlaySound(KEINSND);\r
+               NewState (ob,&s_gretelchase1);\r
+               ob->speed *= 3;                 // go faster when chasing player\r
+               break;\r
+\r
+       case giftobj:\r
+               SD_PlaySound(EINESND);\r
+               NewState (ob,&s_giftchase1);\r
+               ob->speed *= 3;                 // go faster when chasing player\r
+               break;\r
+\r
+       case fatobj:\r
+               SD_PlaySound(ERLAUBENSND);\r
+               NewState (ob,&s_fatchase1);\r
+               ob->speed *= 3;                 // go faster when chasing player\r
+               break;\r
+\r
+       case schabbobj:\r
+               SD_PlaySound(SCHABBSHASND);\r
+               NewState (ob,&s_schabbchase1);\r
+               ob->speed *= 3;                 // go faster when chasing player\r
+               break;\r
+\r
+       case fakeobj:\r
+               SD_PlaySound(TOT_HUNDSND);\r
+               NewState (ob,&s_fakechase1);\r
+               ob->speed *= 3;                 // go faster when chasing player\r
+               break;\r
+\r
+       case mechahitlerobj:\r
+               SD_PlaySound(DIESND);\r
+               NewState (ob,&s_mechachase1);\r
+               ob->speed *= 3;                 // go faster when chasing player\r
+               break;\r
+\r
+       case realhitlerobj:\r
+               SD_PlaySound(DIESND);\r
+               NewState (ob,&s_hitlerchase1);\r
+               ob->speed *= 5;                 // go faster when chasing player\r
+               break;\r
+\r
+       case ghostobj:\r
+               NewState (ob,&s_blinkychase1);\r
+               ob->speed *= 2;                 // go faster when chasing player\r
+               break;\r
+#else\r
+\r
+       case spectreobj:\r
+               SD_PlaySound(GHOSTSIGHTSND);\r
+               NewState (ob,&s_spectrechase1);\r
+               ob->speed = 800;                        // go faster when chasing player\r
+               break;\r
+\r
+       case angelobj:\r
+               SD_PlaySound(ANGELSIGHTSND);\r
+               NewState (ob,&s_angelchase1);\r
+               ob->speed = 1536;                       // go faster when chasing player\r
+               break;\r
+\r
+       case transobj:\r
+               SD_PlaySound(TRANSSIGHTSND);\r
+               NewState (ob,&s_transchase1);\r
+               ob->speed = 1536;                       // go faster when chasing player\r
+               break;\r
+\r
+       case uberobj:\r
+               NewState (ob,&s_uberchase1);\r
+               ob->speed = 3000;                       // go faster when chasing player\r
+               break;\r
+\r
+       case willobj:\r
+               SD_PlaySound(WILHELMSIGHTSND);\r
+               NewState (ob,&s_willchase1);\r
+               ob->speed = 2048;                       // go faster when chasing player\r
+               break;\r
+\r
+       case deathobj:\r
+               SD_PlaySound(KNIGHTSIGHTSND);\r
+               NewState (ob,&s_deathchase1);\r
+               ob->speed = 2048;                       // go faster when chasing player\r
+               break;\r
+\r
+#endif\r
+       }\r
+\r
+       if (ob->distance < 0)\r
+               ob->distance = 0;       // ignore the door opening command\r
+\r
+       ob->flags |= FL_ATTACKMODE|FL_FIRSTATTACK;\r
+}\r
+\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= SightPlayer\r
+=\r
+= Called by actors that ARE NOT chasing the player.  If the player\r
+= is detected (by sight, noise, or proximity), the actor is put into\r
+= it's combat frame and true is returned.\r
+=\r
+= Incorporates a random reaction delay\r
+=\r
+===============\r
+*/\r
+\r
+boolean SightPlayer (objtype *ob)\r
+{\r
+       if (ob->flags & FL_ATTACKMODE)\r
+               Quit ("An actor in ATTACKMODE called SightPlayer!");\r
+\r
+       if (ob->temp2)\r
+       {\r
+       //\r
+       // count down reaction time\r
+       //\r
+               ob->temp2 -= tics;\r
+               if (ob->temp2 > 0)\r
+                       return false;\r
+               ob->temp2 = 0;                                  // time to react\r
+       }\r
+       else\r
+       {\r
+               if (!areabyplayer[ob->areanumber])\r
+                       return false;\r
+\r
+               if (ob->flags & FL_AMBUSH)\r
+               {\r
+                       if (!CheckSight (ob))\r
+                               return false;\r
+                       ob->flags &= ~FL_AMBUSH;\r
+               }\r
+               else\r
+               {\r
+                       if (!madenoise && !CheckSight (ob))\r
+                               return false;\r
+               }\r
+\r
+\r
+               switch (ob->obclass)\r
+               {\r
+               case guardobj:\r
+                       ob->temp2 = 1+US_RndT()/4;\r
+                       break;\r
+               case officerobj:\r
+                       ob->temp2 = 2;\r
+                       break;\r
+               case mutantobj:\r
+                       ob->temp2 = 1+US_RndT()/6;\r
+                       break;\r
+               case ssobj:\r
+                       ob->temp2 = 1+US_RndT()/6;\r
+                       break;\r
+               case dogobj:\r
+                       ob->temp2 = 1+US_RndT()/8;\r
+                       break;\r
+\r
+               case bossobj:\r
+               case schabbobj:\r
+               case fakeobj:\r
+               case mechahitlerobj:\r
+               case realhitlerobj:\r
+               case gretelobj:\r
+               case giftobj:\r
+               case fatobj:\r
+               case spectreobj:\r
+               case angelobj:\r
+               case transobj:\r
+               case uberobj:\r
+               case willobj:\r
+               case deathobj:\r
+                       ob->temp2 = 1;\r
+                       break;\r
+               }\r
+               return false;\r
+       }\r
+\r
+       FirstSighting (ob);\r
+\r
+       return true;\r
+}\r
+\r
+\r
diff --git a/src/lib/hb/wl_text.c b/src/lib/hb/wl_text.c
new file mode 100755 (executable)
index 0000000..1df86b8
--- /dev/null
@@ -0,0 +1,859 @@
+// WL_TEXT.C\r
+\r
+#include "WL_DEF.H"\r
+#pragma        hdrstop\r
+\r
+/*\r
+=============================================================================\r
+\r
+TEXT FORMATTING COMMANDS\r
+------------------------\r
+^C<hex digit>                          Change text color\r
+^E[enter]                              End of layout (all pages)\r
+^G<y>,<x>,<pic>[enter] Draw a graphic and push margins\r
+^P[enter]                              start new page, must be the first chars in a layout\r
+^L<x>,<y>[ENTER]               Locate to a specific spot, x in pixels, y in lines\r
+\r
+=============================================================================\r
+*/\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+#define BACKCOLOR              0x11\r
+\r
+\r
+#define WORDLIMIT              80\r
+#define FONTHEIGHT             10\r
+#define        TOPMARGIN               16\r
+#define BOTTOMMARGIN   32\r
+#define LEFTMARGIN             16\r
+#define RIGHTMARGIN            16\r
+#define PICMARGIN              8\r
+#define TEXTROWS               ((200-TOPMARGIN-BOTTOMMARGIN)/FONTHEIGHT)\r
+#define        SPACEWIDTH              7\r
+#define SCREENPIXWIDTH 320\r
+#define SCREENMID              (SCREENPIXWIDTH/2)\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+int                    pagenum,numpages;\r
+\r
+unsigned       leftmargin[TEXTROWS],rightmargin[TEXTROWS];\r
+char           far *text;\r
+unsigned       rowon;\r
+\r
+int                    picx,picy,picnum,picdelay;\r
+boolean                layoutdone;\r
+\r
+//===========================================================================\r
+\r
+#ifndef JAPAN\r
+/*\r
+=====================\r
+=\r
+= RipToEOL\r
+=\r
+=====================\r
+*/\r
+\r
+void RipToEOL (void)\r
+{\r
+       while (*text++ != '\n')         // scan to end of line\r
+       ;\r
+}\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= ParseNumber\r
+=\r
+=====================\r
+*/\r
+\r
+int    ParseNumber (void)\r
+{\r
+       char    ch;\r
+       char    num[80],*numptr;\r
+\r
+//\r
+// scan until a number is found\r
+//\r
+       ch = *text;\r
+       while (ch < '0' || ch >'9')\r
+               ch = *++text;\r
+\r
+//\r
+// copy the number out\r
+//\r
+       numptr = num;\r
+       do\r
+       {\r
+               *numptr++ = ch;\r
+               ch = *++text;\r
+       } while (ch >= '0' && ch <= '9');\r
+       *numptr = 0;\r
+\r
+       return atoi (num);\r
+}\r
+\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= ParsePicCommand\r
+=\r
+= Call with text pointing just after a ^P\r
+= Upon exit text points to the start of next line\r
+=\r
+=====================\r
+*/\r
+\r
+void   ParsePicCommand (void)\r
+{\r
+       picy=ParseNumber();\r
+       picx=ParseNumber();\r
+       picnum=ParseNumber();\r
+       RipToEOL ();\r
+}\r
+\r
+\r
+void   ParseTimedCommand (void)\r
+{\r
+       picy=ParseNumber();\r
+       picx=ParseNumber();\r
+       picnum=ParseNumber();\r
+       picdelay=ParseNumber();\r
+       RipToEOL ();\r
+}\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= TimedPicCommand\r
+=\r
+= Call with text pointing just after a ^P\r
+= Upon exit text points to the start of next line\r
+=\r
+=====================\r
+*/\r
+\r
+void   TimedPicCommand (void)\r
+{\r
+       ParseTimedCommand ();\r
+\r
+//\r
+// update the screen, and wait for time delay\r
+//\r
+       VW_UpdateScreen ();\r
+\r
+//\r
+// wait for time\r
+//\r
+       TimeCount = 0;\r
+       while (TimeCount < picdelay)\r
+       ;\r
+\r
+//\r
+// draw pic\r
+//\r
+       VWB_DrawPic (picx&~7,picy,picnum);\r
+}\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= HandleCommand\r
+=\r
+=====================\r
+*/\r
+\r
+void HandleCommand (void)\r
+{\r
+       int     i,margin,top,bottom;\r
+       int     picwidth,picheight,picmid;\r
+\r
+       switch (toupper(*++text))\r
+       {\r
+       case 'B':\r
+               picy=ParseNumber();\r
+               picx=ParseNumber();\r
+               picwidth=ParseNumber();\r
+               picheight=ParseNumber();\r
+               VWB_Bar(picx,picy,picwidth,picheight,BACKCOLOR);\r
+               RipToEOL();\r
+               break;\r
+       case ';':               // comment\r
+               RipToEOL();\r
+               break;\r
+       case 'P':               // ^P is start of next page, ^E is end of file\r
+       case 'E':\r
+               layoutdone = true;\r
+               text--;         // back up to the '^'\r
+               break;\r
+\r
+       case 'C':               // ^c<hex digit> changes text color\r
+               i = toupper(*++text);\r
+               if (i>='0' && i<='9')\r
+                       fontcolor = i-'0';\r
+               else if (i>='A' && i<='F')\r
+                       fontcolor = i-'A'+10;\r
+\r
+               fontcolor *= 16;\r
+               i = toupper(*++text);\r
+               if (i>='0' && i<='9')\r
+                       fontcolor += i-'0';\r
+               else if (i>='A' && i<='F')\r
+                       fontcolor += i-'A'+10;\r
+               text++;\r
+               break;\r
+\r
+       case '>':\r
+               px = 160;\r
+               text++;\r
+               break;\r
+\r
+       case 'L':\r
+               py=ParseNumber();\r
+               rowon = (py-TOPMARGIN)/FONTHEIGHT;\r
+               py = TOPMARGIN+rowon*FONTHEIGHT;\r
+               px=ParseNumber();\r
+               while (*text++ != '\n')         // scan to end of line\r
+               ;\r
+               break;\r
+\r
+       case 'T':               // ^Tyyy,xxx,ppp,ttt waits ttt tics, then draws pic\r
+               TimedPicCommand ();\r
+               break;\r
+\r
+       case 'G':               // ^Gyyy,xxx,ppp draws graphic\r
+               ParsePicCommand ();\r
+               VWB_DrawPic (picx&~7,picy,picnum);\r
+               picwidth = pictable[picnum-STARTPICS].width;\r
+               picheight = pictable[picnum-STARTPICS].height;\r
+               //\r
+               // adjust margins\r
+               //\r
+               picmid = picx + picwidth/2;\r
+               if (picmid > SCREENMID)\r
+                       margin = picx-PICMARGIN;                        // new right margin\r
+               else\r
+                       margin = picx+picwidth+PICMARGIN;       // new left margin\r
+\r
+               top = (picy-TOPMARGIN)/FONTHEIGHT;\r
+               if (top<0)\r
+                       top = 0;\r
+               bottom = (picy+picheight-TOPMARGIN)/FONTHEIGHT;\r
+               if (bottom>=TEXTROWS)\r
+                       bottom = TEXTROWS-1;\r
+\r
+               for (i=top;i<=bottom;i++)\r
+                       if (picmid > SCREENMID)\r
+                               rightmargin[i] = margin;\r
+                       else\r
+                               leftmargin[i] = margin;\r
+\r
+               //\r
+               // adjust this line if needed\r
+               //\r
+               if (px < leftmargin[rowon])\r
+                       px = leftmargin[rowon];\r
+               break;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= NewLine\r
+=\r
+=====================\r
+*/\r
+\r
+void NewLine (void)\r
+{\r
+       char    ch;\r
+\r
+       if (++rowon == TEXTROWS)\r
+       {\r
+       //\r
+       // overflowed the page, so skip until next page break\r
+       //\r
+               layoutdone = true;\r
+               do\r
+               {\r
+                       if (*text == '^')\r
+                       {\r
+                               ch = toupper(*(text+1));\r
+                               if (ch == 'E' || ch == 'P')\r
+                               {\r
+                                       layoutdone = true;\r
+                                       return;\r
+                               }\r
+                       }\r
+                       text++;\r
+\r
+               } while (1);\r
+\r
+       }\r
+       px = leftmargin[rowon];\r
+       py+= FONTHEIGHT;\r
+}\r
+\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= HandleCtrls\r
+=\r
+=====================\r
+*/\r
+\r
+void HandleCtrls (void)\r
+{\r
+       char    ch;\r
+\r
+       ch = *text++;                   // get the character and advance\r
+\r
+       if (ch == '\n')\r
+       {\r
+               NewLine ();\r
+               return;\r
+       }\r
+\r
+}\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= HandleWord\r
+=\r
+=====================\r
+*/\r
+\r
+void HandleWord (void)\r
+{\r
+       char            word[WORDLIMIT];\r
+       int                     i,wordindex;\r
+       unsigned        wwidth,wheight,newpos;\r
+\r
+\r
+       //\r
+       // copy the next word into [word]\r
+       //\r
+       word[0] = *text++;\r
+       wordindex = 1;\r
+       while (*text>32)\r
+       {\r
+               word[wordindex] = *text++;\r
+               if (++wordindex == WORDLIMIT)\r
+                       Quit ("PageLayout: Word limit exceeded");\r
+       }\r
+       word[wordindex] = 0;            // stick a null at end for C\r
+\r
+       //\r
+       // see if it fits on this line\r
+       //\r
+       VW_MeasurePropString (word,&wwidth,&wheight);\r
+\r
+       while (px+wwidth > rightmargin[rowon])\r
+       {\r
+               NewLine ();\r
+               if (layoutdone)\r
+                       return;         // overflowed page\r
+       }\r
+\r
+       //\r
+       // print it\r
+       //\r
+       newpos = px+wwidth;\r
+       VWB_DrawPropString (word);\r
+       px = newpos;\r
+\r
+       //\r
+       // suck up any extra spaces\r
+       //\r
+       while (*text == ' ')\r
+       {\r
+               px += SPACEWIDTH;\r
+               text++;\r
+       }\r
+}\r
+\r
+/*\r
+=====================\r
+=\r
+= PageLayout\r
+=\r
+= Clears the screen, draws the pics on the page, and word wraps the text.\r
+= Returns a pointer to the terminating command\r
+=\r
+=====================\r
+*/\r
+\r
+void PageLayout (boolean shownumber)\r
+{\r
+       int             i,oldfontcolor;\r
+       char    ch;\r
+\r
+       oldfontcolor = fontcolor;\r
+\r
+       fontcolor = 0;\r
+\r
+//\r
+// clear the screen\r
+//\r
+       VWB_Bar (0,0,320,200,BACKCOLOR);\r
+       VWB_DrawPic (0,0,H_TOPWINDOWPIC);\r
+       VWB_DrawPic (0,8,H_LEFTWINDOWPIC);\r
+       VWB_DrawPic (312,8,H_RIGHTWINDOWPIC);\r
+       VWB_DrawPic (8,176,H_BOTTOMINFOPIC);\r
+\r
+\r
+       for (i=0;i<TEXTROWS;i++)\r
+       {\r
+               leftmargin[i] = LEFTMARGIN;\r
+               rightmargin[i] = SCREENPIXWIDTH-RIGHTMARGIN;\r
+       }\r
+\r
+       px = LEFTMARGIN;\r
+       py = TOPMARGIN;\r
+       rowon = 0;\r
+       layoutdone = false;\r
+\r
+//\r
+// make sure we are starting layout text (^P first command)\r
+//\r
+       while (*text <= 32)\r
+               text++;\r
+\r
+       if (*text != '^' || toupper(*++text) != 'P')\r
+               Quit ("PageLayout: Text not headed with ^P");\r
+\r
+       while (*text++ != '\n')\r
+       ;\r
+\r
+\r
+//\r
+// process text stream\r
+//\r
+       do\r
+       {\r
+               ch = *text;\r
+\r
+               if (ch == '^')\r
+                       HandleCommand ();\r
+               else\r
+               if (ch == 9)\r
+               {\r
+                px = (px+8)&0xf8;\r
+                text++;\r
+               }\r
+               else if (ch <= 32)\r
+                       HandleCtrls ();\r
+               else\r
+                       HandleWord ();\r
+\r
+       } while (!layoutdone);\r
+\r
+       pagenum++;\r
+\r
+       if (shownumber)\r
+       {\r
+               #ifdef SPANISH\r
+               strcpy (str,"Hoja ");\r
+               itoa (pagenum,str2,10);\r
+               strcat (str,str2);\r
+               strcat (str," de ");\r
+               py = 183;\r
+               px = 208;\r
+               #else\r
+               strcpy (str,"pg ");\r
+               itoa (pagenum,str2,10);\r
+               strcat (str,str2);\r
+               strcat (str," of ");\r
+               py = 183;\r
+               px = 213;\r
+               #endif\r
+               itoa (numpages,str2,10);\r
+               strcat (str,str2);\r
+               fontcolor = 0x4f;                          //12^BACKCOLOR;\r
+\r
+               VWB_DrawPropString (str);\r
+       }\r
+\r
+       fontcolor = oldfontcolor;\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+=====================\r
+=\r
+= BackPage\r
+=\r
+= Scans for a previous ^P\r
+=\r
+=====================\r
+*/\r
+\r
+void BackPage (void)\r
+{\r
+       pagenum--;\r
+       do\r
+       {\r
+               text--;\r
+               if (*text == '^' && toupper(*(text+1)) == 'P')\r
+                       return;\r
+       } while (1);\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= CacheLayoutGraphics\r
+=\r
+= Scans an entire layout file (until a ^E) marking all graphics used, and\r
+= counting pages, then caches the graphics in\r
+=\r
+=====================\r
+*/\r
+void CacheLayoutGraphics (void)\r
+{\r
+       char    far *bombpoint, far *textstart;\r
+       char    ch;\r
+\r
+       textstart = text;\r
+       bombpoint = text+30000;\r
+       numpages = pagenum = 0;\r
+\r
+       do\r
+       {\r
+               if (*text == '^')\r
+               {\r
+                       ch = toupper(*++text);\r
+                       if (ch == 'P')          // start of a page\r
+                               numpages++;\r
+                       if (ch == 'E')          // end of file, so load graphics and return\r
+                       {\r
+                               CA_MarkGrChunk(H_TOPWINDOWPIC);\r
+                               CA_MarkGrChunk(H_LEFTWINDOWPIC);\r
+                               CA_MarkGrChunk(H_RIGHTWINDOWPIC);\r
+                               CA_MarkGrChunk(H_BOTTOMINFOPIC);\r
+                               CA_CacheMarks ();\r
+                               text = textstart;\r
+                               return;\r
+                       }\r
+                       if (ch == 'G')          // draw graphic command, so mark graphics\r
+                       {\r
+                               ParsePicCommand ();\r
+                               CA_MarkGrChunk (picnum);\r
+                       }\r
+                       if (ch == 'T')          // timed draw graphic command, so mark graphics\r
+                       {\r
+                               ParseTimedCommand ();\r
+                               CA_MarkGrChunk (picnum);\r
+                       }\r
+               }\r
+               else\r
+                       text++;\r
+\r
+       } while (text<bombpoint);\r
+\r
+       Quit ("CacheLayoutGraphics: No ^E to terminate file!");\r
+}\r
+#endif\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= ShowArticle\r
+=\r
+=====================\r
+*/\r
+\r
+#ifdef JAPAN\r
+void ShowArticle (int which)\r
+#else\r
+void ShowArticle (char far *article)\r
+#endif\r
+{\r
+       #ifdef JAPAN\r
+       int             snames[10] = {  H_HELP1PIC,\r
+                                                       H_HELP2PIC,\r
+                                                       H_HELP3PIC,\r
+                                                       H_HELP4PIC,\r
+                                                       H_HELP5PIC,\r
+                                                       H_HELP6PIC,\r
+                                                       H_HELP7PIC,\r
+                                                       H_HELP8PIC,\r
+                                                       H_HELP9PIC,\r
+                                                       H_HELP10PIC};\r
+       int             enames[14] = {\r
+                                                       0,0,\r
+                                                       #ifndef JAPDEMO\r
+                                                       C_ENDGAME1APIC,\r
+                                                       C_ENDGAME1BPIC,\r
+                                                       C_ENDGAME2APIC,\r
+                                                       C_ENDGAME2BPIC,\r
+                                                       C_ENDGAME3APIC,\r
+                                                       C_ENDGAME3BPIC,\r
+                                                       C_ENDGAME4APIC,\r
+                                                       C_ENDGAME4BPIC,\r
+                                                       C_ENDGAME5APIC,\r
+                                                       C_ENDGAME5BPIC,\r
+                                                       C_ENDGAME6APIC,\r
+                                                       C_ENDGAME6BPIC\r
+                                                       #endif\r
+                                                       };\r
+       #endif\r
+       unsigned        oldfontnumber;\r
+       unsigned        temp;\r
+       boolean         newpage,firstpage;\r
+\r
+       #ifdef JAPAN\r
+       pagenum = 1;\r
+       if (!which)\r
+               numpages = 10;\r
+       else\r
+               numpages = 2;\r
+\r
+       #else\r
+\r
+       text = article;\r
+       oldfontnumber = fontnumber;\r
+       fontnumber = 0;\r
+       CA_MarkGrChunk(STARTFONT);\r
+       VWB_Bar (0,0,320,200,BACKCOLOR);\r
+       CacheLayoutGraphics ();\r
+       #endif\r
+\r
+       newpage = true;\r
+       firstpage = true;\r
+\r
+       do\r
+       {\r
+               if (newpage)\r
+               {\r
+                       newpage = false;\r
+                       #ifdef JAPAN\r
+                       if (!which)\r
+                               CA_CacheScreen(snames[pagenum - 1]);\r
+                       else\r
+                               CA_CacheScreen(enames[which*2 + pagenum - 1]);\r
+                       #else\r
+                       PageLayout (true);\r
+                       #endif\r
+                       VW_UpdateScreen ();\r
+                       if (firstpage)\r
+                       {\r
+                               VL_FadeIn(0,255,&gamepal,10);\r
+                               // VW_FadeIn ()\r
+                               firstpage = false;\r
+                       }\r
+               }\r
+\r
+               LastScan = 0;\r
+               while (!LastScan)\r
+               ;\r
+\r
+               switch (LastScan)\r
+               {\r
+               case sc_UpArrow:\r
+               case sc_PgUp:\r
+               case sc_LeftArrow:\r
+                       if (pagenum>1)\r
+                       {\r
+                               #ifndef JAPAN\r
+                               BackPage ();\r
+                               BackPage ();\r
+                               #else\r
+                               pagenum--;\r
+                               #endif\r
+                               newpage = true;\r
+                       }\r
+                       break;\r
+\r
+               case sc_Enter:\r
+               case sc_DownArrow:\r
+               case sc_PgDn:\r
+               case sc_RightArrow:             // the text allready points at next page\r
+                       if (pagenum<numpages)\r
+                       {\r
+                               newpage = true;\r
+                               #ifdef JAPAN\r
+                               pagenum++;\r
+                               #endif\r
+                       }\r
+                       break;\r
+               }\r
+\r
+               #ifndef SPEAR\r
+               if (Keyboard[sc_Tab] && Keyboard[sc_P] && MS_CheckParm("goobers"))\r
+                       PicturePause();\r
+               #endif\r
+\r
+       } while (LastScan != sc_Escape);\r
+\r
+       IN_ClearKeysDown ();\r
+       fontnumber = oldfontnumber;\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+#ifndef JAPAN\r
+#ifdef ARTSEXTERN\r
+int    endextern = T_ENDART1;\r
+#ifndef SPEAR\r
+int            helpextern = T_HELPART;\r
+#endif\r
+#endif\r
+char helpfilename[13] = "HELPART.",\r
+        endfilename[13] = "ENDART1.";\r
+#endif\r
+\r
+/*\r
+=================\r
+=\r
+= HelpScreens\r
+=\r
+=================\r
+*/\r
+#ifndef SPEAR\r
+void HelpScreens (void)\r
+{\r
+       int                     artnum;\r
+       char far        *text;\r
+       memptr          layout;\r
+\r
+\r
+       CA_UpLevel ();\r
+       MM_SortMem ();\r
+#ifdef JAPAN\r
+       ShowArticle (0);\r
+       VW_FadeOut();\r
+       FreeMusic ();\r
+       CA_DownLevel ();\r
+       MM_SortMem ();\r
+#else\r
+\r
+\r
+\r
+\r
+#ifdef ARTSEXTERN\r
+       artnum = helpextern;\r
+       CA_CacheGrChunk (artnum);\r
+       text = (char _seg *)grsegs[artnum];\r
+       MM_SetLock (&grsegs[artnum], true);\r
+#else\r
+       CA_LoadFile (helpfilename,&layout);\r
+       text = (char _seg *)layout;\r
+       MM_SetLock (&layout, true);\r
+#endif\r
+\r
+       ShowArticle (text);\r
+\r
+#ifdef ARTSEXTERN\r
+       MM_FreePtr (&grsegs[artnum]);\r
+#else\r
+       MM_FreePtr (&layout);\r
+#endif\r
+\r
+\r
+\r
+       VW_FadeOut();\r
+\r
+       FreeMusic ();\r
+       CA_DownLevel ();\r
+       MM_SortMem ();\r
+#endif\r
+}\r
+#endif\r
+\r
+//\r
+// END ARTICLES\r
+//\r
+void EndText (void)\r
+{\r
+       int                     artnum;\r
+       char far        *text;\r
+       memptr          layout;\r
+\r
+\r
+       ClearMemory ();\r
+\r
+       CA_UpLevel ();\r
+       MM_SortMem ();\r
+#ifdef JAPAN\r
+       ShowArticle(gamestate.episode + 1);\r
+\r
+       VW_FadeOut();\r
+\r
+       SETFONTCOLOR(0,15);\r
+       IN_ClearKeysDown();\r
+       if (MousePresent)\r
+               Mouse(MDelta);  // Clear accumulated mouse movement\r
+\r
+       FreeMusic ();\r
+       CA_DownLevel ();\r
+       MM_SortMem ();\r
+#else\r
+\r
+\r
+\r
+#ifdef ARTSEXTERN\r
+       artnum = endextern+gamestate.episode;\r
+       CA_CacheGrChunk (artnum);\r
+       text = (char _seg *)grsegs[artnum];\r
+       MM_SetLock (&grsegs[artnum], true);\r
+#else\r
+       endfilename[6] = '1'+gamestate.episode;\r
+       CA_LoadFile (endfilename,&layout);\r
+       text = (char _seg *)layout;\r
+       MM_SetLock (&layout, true);\r
+#endif\r
+\r
+       ShowArticle (text);\r
+\r
+#ifdef ARTSEXTERN\r
+       MM_FreePtr (&grsegs[artnum]);\r
+#else\r
+       MM_FreePtr (&layout);\r
+#endif\r
+\r
+\r
+       VW_FadeOut();\r
+       SETFONTCOLOR(0,15);\r
+       IN_ClearKeysDown();\r
+       if (MousePresent)\r
+               Mouse(MDelta);  // Clear accumulated mouse movement\r
+\r
+       FreeMusic ();\r
+       CA_DownLevel ();\r
+       MM_SortMem ();\r
+#endif\r
+}\r