From 7499dc78fbb151b6daac45f2643a15bf1b40beb7 Mon Sep 17 00:00:00 2001 From: sparky4 Date: Mon, 14 Nov 2022 01:25:10 -0600 Subject: [PATCH] got 8086 port of wolf3d to work and sod to work --- 16/WOLFSRC/AUDIOSDM.H | 142 + 16/WOLFSRC/AUDIOSOD.H | 142 + 16/WOLFSRC/AUDIOWL1.H | 133 + 16/WOLFSRC/AUDIOWL6.H | 151 + 16/WOLFSRC/BUDIOSOD.H | 142 + 16/WOLFSRC/BUDIOWL6.H | 151 + 16/WOLFSRC/C0.ASM | 843 ++ 16/WOLFSRC/CONTIGSC.C | 745 ++ 16/WOLFSRC/DETECT.C | 87 + 16/WOLFSRC/FOREIGN.H | 110 + 16/WOLFSRC/F_SPEAR.H | 87 + 16/WOLFSRC/GFXE_SOD.EQU | 47 + 16/WOLFSRC/GFXE_SOD.H | 53 + 16/WOLFSRC/GFXE_WL1.EQU | 201 + 16/WOLFSRC/GFXE_WL1.H | 211 + 16/WOLFSRC/GFXE_WL6.EQU | 47 + 16/WOLFSRC/GFXE_WL6.H | 53 + 16/WOLFSRC/GFXV_SDM.EQU | 208 + 16/WOLFSRC/GFXV_SDM.H | 224 + 16/WOLFSRC/GFXV_SOD.EQU | 259 + 16/WOLFSRC/GFXV_SOD.H | 280 + 16/WOLFSRC/GFXV_WL1.EQU | 199 + 16/WOLFSRC/GFXV_WL1.H | 209 + 16/WOLFSRC/GFXV_WL6.EQU | 206 + 16/WOLFSRC/GFXV_WL6.H | 216 + 16/WOLFSRC/GO.BAT | 5 + 16/WOLFSRC/GOODSTUF.TXT | 56 + 16/WOLFSRC/H_LDIV.ASM | 227 + 16/WOLFSRC/ID_CA.C | 1768 +++++ 16/WOLFSRC/ID_CA.H | 101 + 16/WOLFSRC/ID_HEAD.H | 34 + 16/WOLFSRC/ID_HEADS.H | 123 + 16/WOLFSRC/ID_IN.C | 990 +++ 16/WOLFSRC/ID_IN.H | 202 + 16/WOLFSRC/ID_MM.C | 953 +++ 16/WOLFSRC/ID_MM.H | 96 + 16/WOLFSRC/ID_PM.C | 1199 +++ 16/WOLFSRC/ID_PM.H | 83 + 16/WOLFSRC/ID_SD.C | 2367 ++++++ 16/WOLFSRC/ID_SD.EQU | 38 + 16/WOLFSRC/ID_SD.H | 237 + 16/WOLFSRC/ID_SD_A.ASM | 572 ++ 16/WOLFSRC/ID_SD_A.BAK | 572 ++ 16/WOLFSRC/ID_US.H | 123 + 16/WOLFSRC/ID_US_1.C | 755 ++ 16/WOLFSRC/ID_US_A.ASM | 101 + 16/WOLFSRC/ID_VH.H | 134 + 16/WOLFSRC/ID_VH_A.ASM | 110 + 16/WOLFSRC/ID_VL.BAK | 1085 +++ 16/WOLFSRC/ID_VL.C | 1085 +++ 16/WOLFSRC/ID_VL.EQU | 58 + 16/WOLFSRC/ID_VL.H | 161 + 16/WOLFSRC/ID_VL_A.ASM | 742 ++ 16/WOLFSRC/JABHACK.ASM | 103 + 16/WOLFSRC/MAPSSDM.H | 14 + 16/WOLFSRC/MAPSSOD.H | 33 + 16/WOLFSRC/MAPSWL1.H | 42 + 16/WOLFSRC/MAPSWL6.H | 73 + 16/WOLFSRC/MAPSWLF.H | 16 + 16/WOLFSRC/MUNGE.C | 48 + .../obj/wolf3d.exe => WOLFSRC/OBJ/WOLF3D.EXE} | Bin 16/WOLFSRC/OBJ/WOLF3D.MAP | 3638 +++++++++ 16/WOLFSRC/OLDSCALE.C | 738 ++ 16/WOLFSRC/PICLIST.H | 36 + 16/WOLFSRC/README.USO | 39 + 16/WOLFSRC/README/LICENSE.DOC | 129 + 16/WOLFSRC/README/README.TXT | 8 + 16/WOLFSRC/README/RELEASE.TXT | 53 + 16/WOLFSRC/RULES.ASI | 692 ++ 16/WOLFSRC/SDMVER.H | 8 + 16/WOLFSRC/SHAREMSG.H | 9 + 16/WOLFSRC/SODVER.H | 7 + 16/WOLFSRC/SPANISH.H | 112 + 16/WOLFSRC/SPANVER.H | 8 + 16/WOLFSRC/SV.EXE | Bin 0 -> 6746 bytes 16/WOLFSRC/VERSION.H | 10 + 16/WOLFSRC/WHACK_A.ASM | 112 + 16/WOLFSRC/WLFJ1VER.H | 9 + 16/WOLFSRC/WL_ACT1.C | 900 +++ 16/WOLFSRC/WL_ACT2.C | 3872 ++++++++++ 16/WOLFSRC/WL_AGENT.C | 1421 ++++ 16/WOLFSRC/WL_ASM.ASM | 69 + 16/WOLFSRC/WL_DEBUG.C | 722 ++ 16/WOLFSRC/WL_DEF.H | 1276 +++ 16/WOLFSRC/WL_DRAW.C | 1419 ++++ 16/WOLFSRC/WL_DR_A.ASM | 795 ++ 16/WOLFSRC/WL_GAME.C | 1484 ++++ 16/WOLFSRC/WL_INTER.C | 1718 +++++ 16/WOLFSRC/WL_MAIN.C | 1616 ++++ 16/WOLFSRC/WL_MENU.C | 3986 ++++++++++ 16/WOLFSRC/WL_SCALE.C | 741 ++ 16/WOLFSRC/WL_STATE.C | 1480 ++++ 16/WOLFSRC/WL_TEXT.C | 859 +++ 16/WOLFSRC/WOLF.IDE | Bin 0 -> 30962 bytes 16/WOLFSRC/WOLF.OBR | Bin 0 -> 467 bytes 16/WOLFSRC/WOLF.~DE | Bin 0 -> 28360 bytes 16/WOLFSRC/WOLF1VER.H | 7 + 16/WOLFSRC/WOLF3D.DSK | Bin 0 -> 1677 bytes 16/WOLFSRC/WOLF3D.MAP | 3660 +++++++++ 16/WOLFSRC/WOLF3D.PRJ | Bin 0 -> 14880 bytes 16/WOLFSRC/WOLFGTV.H | 10 + 16/WOLFSRC/WOLFHACK.C | 186 + 16/WOLFSRC/WOLFJVER.H | 8 + 16/WOLFSRC/WOLFVER.H | 7 + 16/WOLFSRC/id_vh.c | 547 ++ 16/WOLFSRC/makefile.wl6 | 203 + 16/WOLFSRC/wl_menu.h | 234 + 16/WOLFSRC/wl_play.c | 1473 ++++ 16/sod8086/WOLF3D.SYM | Bin 0 -> 738039 bytes 16/sod8086/audiosdm.h | 142 + 16/sod8086/audiosod.h | 142 + 16/sod8086/audiowl1.h | 133 + 16/sod8086/audiowl6.h | 151 + 16/sod8086/budiosod.h | 142 + 16/sod8086/budiowl6.h | 151 + 16/sod8086/c0.asm | 843 ++ 16/sod8086/c0.bak | 843 ++ 16/sod8086/clean.bat | 6 + 16/sod8086/contigsc.bak | 745 ++ 16/sod8086/contigsc.c | 745 ++ 16/sod8086/detect.c | 87 + 16/sod8086/f_spear.h | 87 + 16/sod8086/foreign.h | 110 + 16/sod8086/gfxe_sod.equ | 47 + 16/sod8086/gfxe_sod.h | 53 + 16/sod8086/gfxe_wl1.equ | 201 + 16/sod8086/gfxe_wl1.h | 211 + 16/sod8086/gfxe_wl6.equ | 47 + 16/sod8086/gfxe_wl6.h | 53 + 16/sod8086/gfxv_sdm.equ | 208 + 16/sod8086/gfxv_sdm.h | 224 + 16/sod8086/gfxv_sod.equ | 259 + 16/sod8086/gfxv_sod.h | 280 + 16/sod8086/gfxv_wl1.equ | 199 + 16/sod8086/gfxv_wl1.h | 209 + 16/sod8086/gfxv_wl6.equ | 206 + 16/sod8086/gfxv_wl6.h | 216 + 16/sod8086/go.bat | 5 + 16/sod8086/goodstuf.txt | 56 + 16/sod8086/h_ldiv.asm | 227 + 16/sod8086/id_ca.c | 1768 +++++ 16/sod8086/id_ca.h | 101 + 16/sod8086/id_head.h | 34 + 16/sod8086/id_heads.h | 123 + 16/sod8086/id_in.c | 990 +++ 16/sod8086/id_in.h | 202 + 16/sod8086/id_mm.c | 953 +++ 16/sod8086/id_mm.h | 96 + 16/sod8086/id_pm.c | 1199 +++ 16/sod8086/id_pm.h | 83 + 16/sod8086/id_sd.c | 2367 ++++++ 16/sod8086/id_sd.equ | 38 + 16/sod8086/id_sd.h | 237 + 16/sod8086/id_sd_a.asm | 572 ++ 16/sod8086/id_sd_a.bak | 572 ++ 16/sod8086/id_us.h | 123 + 16/sod8086/id_us_1.c | 755 ++ 16/sod8086/id_us_a.asm | 101 + 16/sod8086/id_vh.c | 547 ++ 16/sod8086/id_vh.h | 134 + 16/sod8086/id_vh_a.asm | 110 + 16/sod8086/id_vl.bak | 1085 +++ 16/sod8086/id_vl.c | 1085 +++ 16/sod8086/id_vl.equ | 58 + 16/sod8086/id_vl.h | 161 + 16/sod8086/id_vl_a.asm | 742 ++ 16/sod8086/jabhack.asm | 103 + 16/sod8086/makefile.wl6 | 203 + 16/sod8086/mapssdm.h | 14 + 16/sod8086/mapssod.h | 33 + 16/sod8086/mapswl1.h | 42 + 16/sod8086/mapswl6.h | 73 + 16/sod8086/mapswlf.h | 16 + 16/sod8086/moveexe.bat | 3 + 16/sod8086/munge.c | 48 + 16/sod8086/obj/wolf3d.map | 3516 +++++++++ 16/sod8086/oldscale.c | 738 ++ 16/sod8086/piclist.h | 37 + 16/sod8086/readme.uso | 39 + 16/sod8086/readme/license.doc | 129 + 16/sod8086/readme/readme.txt | 8 + 16/sod8086/readme/release.txt | 53 + 16/sod8086/rules.asi | 692 ++ 16/sod8086/sdmver.h | 8 + 16/sod8086/sharemsg.h | 9 + 16/sod8086/spanish.h | 112 + 16/sod8086/spanver.h | 8 + 16/sod8086/sv.exe | Bin 0 -> 6746 bytes 16/sod8086/version.h | 7 + 16/sod8086/wf3dver.h | 10 + 16/sod8086/whack_a.asm | 112 + 16/sod8086/wl_act1.c | 900 +++ 16/sod8086/wl_act2.c | 3872 ++++++++++ 16/sod8086/wl_agent.c | 1421 ++++ 16/sod8086/wl_asm.asm | 69 + 16/sod8086/wl_debug.c | 722 ++ 16/sod8086/wl_def.h | 1276 +++ 16/sod8086/wl_dr_a.asm | 795 ++ 16/sod8086/wl_draw.c | 1419 ++++ 16/sod8086/wl_game.c | 1484 ++++ 16/sod8086/wl_inter.c | 1720 +++++ 16/sod8086/wl_main.c | 1618 ++++ 16/sod8086/wl_menu.c | 3987 ++++++++++ 16/sod8086/wl_menu.h | 234 + 16/sod8086/wl_play.c | 1473 ++++ 16/sod8086/wl_scale.c | 741 ++ 16/sod8086/wl_state.c | 1480 ++++ 16/sod8086/wl_text.c | 862 +++ 16/sod8086/wlfj1ver.h | 9 + 16/sod8086/wolf.ide | Bin 0 -> 30962 bytes 16/sod8086/wolf.obr | Bin 0 -> 467 bytes 16/sod8086/wolf.~de | Bin 0 -> 28360 bytes 16/sod8086/wolf1ver.h | 7 + 16/sod8086/wolf3d.cfg | 24 + 16/sod8086/wolf3d.dsk | Bin 0 -> 1927 bytes 16/sod8086/wolf3d.map | 3660 +++++++++ 16/sod8086/wolf3d.prj | Bin 0 -> 15365 bytes 16/sod8086/wolfgtv.h | 10 + 16/sod8086/wolfhack.c | 186 + 16/sod8086/wolfjver.h | 8 + 16/sod8086/wolfver.h | 7 + 16/wf3d8086/c0.asm | 20 +- 16/wf3d8086/c0.bak | 843 ++ 16/wf3d8086/clean.bat | 6 + 16/wf3d8086/contigsc.bak | 745 ++ 16/wf3d8086/makefile.wl6 | 4 +- 16/wf3d8086/moveexe.bat | 3 + 16/wf3d8086/obj/wolf3d.map | 6856 ++++++++--------- 16/wf3d8086/piclist.h | 3 +- 16/wf3d8086/wl_main.c | 2 +- 16/wf3d8086/wolf3d.cfg | 24 + 16/wf3d8086/wolf3d.dsk | Bin 1677 -> 1927 bytes 16/wf3d8086/wolf3d.prj | Bin 14880 -> 15800 bytes 16/wf3d8086/wolf3d.sym | Bin 0 -> 260663 bytes 234 files changed, 114074 insertions(+), 3446 deletions(-) create mode 100755 16/WOLFSRC/AUDIOSDM.H create mode 100755 16/WOLFSRC/AUDIOSOD.H create mode 100755 16/WOLFSRC/AUDIOWL1.H create mode 100755 16/WOLFSRC/AUDIOWL6.H create mode 100755 16/WOLFSRC/BUDIOSOD.H create mode 100755 16/WOLFSRC/BUDIOWL6.H create mode 100755 16/WOLFSRC/C0.ASM create mode 100755 16/WOLFSRC/CONTIGSC.C create mode 100755 16/WOLFSRC/DETECT.C create mode 100755 16/WOLFSRC/FOREIGN.H create mode 100755 16/WOLFSRC/F_SPEAR.H create mode 100755 16/WOLFSRC/GFXE_SOD.EQU create mode 100755 16/WOLFSRC/GFXE_SOD.H create mode 100755 16/WOLFSRC/GFXE_WL1.EQU create mode 100755 16/WOLFSRC/GFXE_WL1.H create mode 100755 16/WOLFSRC/GFXE_WL6.EQU create mode 100755 16/WOLFSRC/GFXE_WL6.H create mode 100755 16/WOLFSRC/GFXV_SDM.EQU create mode 100755 16/WOLFSRC/GFXV_SDM.H create mode 100755 16/WOLFSRC/GFXV_SOD.EQU create mode 100755 16/WOLFSRC/GFXV_SOD.H create mode 100755 16/WOLFSRC/GFXV_WL1.EQU create mode 100755 16/WOLFSRC/GFXV_WL1.H create mode 100755 16/WOLFSRC/GFXV_WL6.EQU create mode 100755 16/WOLFSRC/GFXV_WL6.H create mode 100755 16/WOLFSRC/GO.BAT create mode 100755 16/WOLFSRC/GOODSTUF.TXT create mode 100755 16/WOLFSRC/H_LDIV.ASM create mode 100755 16/WOLFSRC/ID_CA.C create mode 100755 16/WOLFSRC/ID_CA.H create mode 100755 16/WOLFSRC/ID_HEAD.H create mode 100755 16/WOLFSRC/ID_HEADS.H create mode 100755 16/WOLFSRC/ID_IN.C create mode 100755 16/WOLFSRC/ID_IN.H create mode 100755 16/WOLFSRC/ID_MM.C create mode 100755 16/WOLFSRC/ID_MM.H create mode 100755 16/WOLFSRC/ID_PM.C create mode 100755 16/WOLFSRC/ID_PM.H create mode 100755 16/WOLFSRC/ID_SD.C create mode 100755 16/WOLFSRC/ID_SD.EQU create mode 100755 16/WOLFSRC/ID_SD.H create mode 100755 16/WOLFSRC/ID_SD_A.ASM create mode 100755 16/WOLFSRC/ID_SD_A.BAK create mode 100755 16/WOLFSRC/ID_US.H create mode 100755 16/WOLFSRC/ID_US_1.C create mode 100755 16/WOLFSRC/ID_US_A.ASM create mode 100755 16/WOLFSRC/ID_VH.H create mode 100755 16/WOLFSRC/ID_VH_A.ASM create mode 100755 16/WOLFSRC/ID_VL.BAK create mode 100755 16/WOLFSRC/ID_VL.C create mode 100755 16/WOLFSRC/ID_VL.EQU create mode 100755 16/WOLFSRC/ID_VL.H create mode 100755 16/WOLFSRC/ID_VL_A.ASM create mode 100755 16/WOLFSRC/JABHACK.ASM create mode 100755 16/WOLFSRC/MAPSSDM.H create mode 100755 16/WOLFSRC/MAPSSOD.H create mode 100755 16/WOLFSRC/MAPSWL1.H create mode 100755 16/WOLFSRC/MAPSWL6.H create mode 100755 16/WOLFSRC/MAPSWLF.H create mode 100755 16/WOLFSRC/MUNGE.C rename 16/{wf3d8086/obj/wolf3d.exe => WOLFSRC/OBJ/WOLF3D.EXE} (100%) create mode 100755 16/WOLFSRC/OBJ/WOLF3D.MAP create mode 100755 16/WOLFSRC/OLDSCALE.C create mode 100755 16/WOLFSRC/PICLIST.H create mode 100755 16/WOLFSRC/README.USO create mode 100755 16/WOLFSRC/README/LICENSE.DOC create mode 100755 16/WOLFSRC/README/README.TXT create mode 100755 16/WOLFSRC/README/RELEASE.TXT create mode 100755 16/WOLFSRC/RULES.ASI create mode 100755 16/WOLFSRC/SDMVER.H create mode 100755 16/WOLFSRC/SHAREMSG.H create mode 100755 16/WOLFSRC/SODVER.H create mode 100755 16/WOLFSRC/SPANISH.H create mode 100755 16/WOLFSRC/SPANVER.H create mode 100755 16/WOLFSRC/SV.EXE create mode 100755 16/WOLFSRC/VERSION.H create mode 100755 16/WOLFSRC/WHACK_A.ASM create mode 100755 16/WOLFSRC/WLFJ1VER.H create mode 100755 16/WOLFSRC/WL_ACT1.C create mode 100755 16/WOLFSRC/WL_ACT2.C create mode 100755 16/WOLFSRC/WL_AGENT.C create mode 100755 16/WOLFSRC/WL_ASM.ASM create mode 100755 16/WOLFSRC/WL_DEBUG.C create mode 100755 16/WOLFSRC/WL_DEF.H create mode 100755 16/WOLFSRC/WL_DRAW.C create mode 100755 16/WOLFSRC/WL_DR_A.ASM create mode 100755 16/WOLFSRC/WL_GAME.C create mode 100755 16/WOLFSRC/WL_INTER.C create mode 100755 16/WOLFSRC/WL_MAIN.C create mode 100755 16/WOLFSRC/WL_MENU.C create mode 100755 16/WOLFSRC/WL_SCALE.C create mode 100755 16/WOLFSRC/WL_STATE.C create mode 100755 16/WOLFSRC/WL_TEXT.C create mode 100755 16/WOLFSRC/WOLF.IDE create mode 100755 16/WOLFSRC/WOLF.OBR create mode 100755 16/WOLFSRC/WOLF.~DE create mode 100755 16/WOLFSRC/WOLF1VER.H create mode 100755 16/WOLFSRC/WOLF3D.DSK create mode 100755 16/WOLFSRC/WOLF3D.MAP create mode 100755 16/WOLFSRC/WOLF3D.PRJ create mode 100755 16/WOLFSRC/WOLFGTV.H create mode 100755 16/WOLFSRC/WOLFHACK.C create mode 100755 16/WOLFSRC/WOLFJVER.H create mode 100755 16/WOLFSRC/WOLFVER.H create mode 100755 16/WOLFSRC/id_vh.c create mode 100755 16/WOLFSRC/makefile.wl6 create mode 100755 16/WOLFSRC/wl_menu.h create mode 100755 16/WOLFSRC/wl_play.c create mode 100755 16/sod8086/WOLF3D.SYM create mode 100755 16/sod8086/audiosdm.h create mode 100755 16/sod8086/audiosod.h create mode 100755 16/sod8086/audiowl1.h create mode 100755 16/sod8086/audiowl6.h create mode 100755 16/sod8086/budiosod.h create mode 100755 16/sod8086/budiowl6.h create mode 100755 16/sod8086/c0.asm create mode 100755 16/sod8086/c0.bak create mode 100755 16/sod8086/clean.bat create mode 100755 16/sod8086/contigsc.bak create mode 100755 16/sod8086/contigsc.c create mode 100755 16/sod8086/detect.c create mode 100755 16/sod8086/f_spear.h create mode 100755 16/sod8086/foreign.h create mode 100755 16/sod8086/gfxe_sod.equ create mode 100755 16/sod8086/gfxe_sod.h create mode 100755 16/sod8086/gfxe_wl1.equ create mode 100755 16/sod8086/gfxe_wl1.h create mode 100755 16/sod8086/gfxe_wl6.equ create mode 100755 16/sod8086/gfxe_wl6.h create mode 100755 16/sod8086/gfxv_sdm.equ create mode 100755 16/sod8086/gfxv_sdm.h create mode 100755 16/sod8086/gfxv_sod.equ create mode 100755 16/sod8086/gfxv_sod.h create mode 100755 16/sod8086/gfxv_wl1.equ create mode 100755 16/sod8086/gfxv_wl1.h create mode 100755 16/sod8086/gfxv_wl6.equ create mode 100755 16/sod8086/gfxv_wl6.h create mode 100755 16/sod8086/go.bat create mode 100755 16/sod8086/goodstuf.txt create mode 100755 16/sod8086/h_ldiv.asm create mode 100755 16/sod8086/id_ca.c create mode 100755 16/sod8086/id_ca.h create mode 100755 16/sod8086/id_head.h create mode 100755 16/sod8086/id_heads.h create mode 100755 16/sod8086/id_in.c create mode 100755 16/sod8086/id_in.h create mode 100755 16/sod8086/id_mm.c create mode 100755 16/sod8086/id_mm.h create mode 100755 16/sod8086/id_pm.c create mode 100755 16/sod8086/id_pm.h create mode 100755 16/sod8086/id_sd.c create mode 100755 16/sod8086/id_sd.equ create mode 100755 16/sod8086/id_sd.h create mode 100755 16/sod8086/id_sd_a.asm create mode 100755 16/sod8086/id_sd_a.bak create mode 100755 16/sod8086/id_us.h create mode 100755 16/sod8086/id_us_1.c create mode 100755 16/sod8086/id_us_a.asm create mode 100755 16/sod8086/id_vh.c create mode 100755 16/sod8086/id_vh.h create mode 100755 16/sod8086/id_vh_a.asm create mode 100755 16/sod8086/id_vl.bak create mode 100755 16/sod8086/id_vl.c create mode 100755 16/sod8086/id_vl.equ create mode 100755 16/sod8086/id_vl.h create mode 100755 16/sod8086/id_vl_a.asm create mode 100755 16/sod8086/jabhack.asm create mode 100755 16/sod8086/makefile.wl6 create mode 100755 16/sod8086/mapssdm.h create mode 100755 16/sod8086/mapssod.h create mode 100755 16/sod8086/mapswl1.h create mode 100755 16/sod8086/mapswl6.h create mode 100755 16/sod8086/mapswlf.h create mode 100755 16/sod8086/moveexe.bat create mode 100755 16/sod8086/munge.c create mode 100755 16/sod8086/obj/wolf3d.map create mode 100755 16/sod8086/oldscale.c create mode 100755 16/sod8086/piclist.h create mode 100755 16/sod8086/readme.uso create mode 100755 16/sod8086/readme/license.doc create mode 100755 16/sod8086/readme/readme.txt create mode 100755 16/sod8086/readme/release.txt create mode 100755 16/sod8086/rules.asi create mode 100755 16/sod8086/sdmver.h create mode 100755 16/sod8086/sharemsg.h create mode 100755 16/sod8086/spanish.h create mode 100755 16/sod8086/spanver.h create mode 100755 16/sod8086/sv.exe create mode 100755 16/sod8086/version.h create mode 100755 16/sod8086/wf3dver.h create mode 100755 16/sod8086/whack_a.asm create mode 100755 16/sod8086/wl_act1.c create mode 100755 16/sod8086/wl_act2.c create mode 100755 16/sod8086/wl_agent.c create mode 100755 16/sod8086/wl_asm.asm create mode 100755 16/sod8086/wl_debug.c create mode 100755 16/sod8086/wl_def.h create mode 100755 16/sod8086/wl_dr_a.asm create mode 100755 16/sod8086/wl_draw.c create mode 100755 16/sod8086/wl_game.c create mode 100755 16/sod8086/wl_inter.c create mode 100755 16/sod8086/wl_main.c create mode 100755 16/sod8086/wl_menu.c create mode 100755 16/sod8086/wl_menu.h create mode 100755 16/sod8086/wl_play.c create mode 100755 16/sod8086/wl_scale.c create mode 100755 16/sod8086/wl_state.c create mode 100755 16/sod8086/wl_text.c create mode 100755 16/sod8086/wlfj1ver.h create mode 100755 16/sod8086/wolf.ide create mode 100755 16/sod8086/wolf.obr create mode 100755 16/sod8086/wolf.~de create mode 100755 16/sod8086/wolf1ver.h create mode 100755 16/sod8086/wolf3d.cfg create mode 100755 16/sod8086/wolf3d.dsk create mode 100755 16/sod8086/wolf3d.map create mode 100755 16/sod8086/wolf3d.prj create mode 100755 16/sod8086/wolfgtv.h create mode 100755 16/sod8086/wolfhack.c create mode 100755 16/sod8086/wolfjver.h create mode 100755 16/sod8086/wolfver.h create mode 100755 16/wf3d8086/c0.bak create mode 100755 16/wf3d8086/clean.bat create mode 100755 16/wf3d8086/contigsc.bak create mode 100755 16/wf3d8086/moveexe.bat create mode 100755 16/wf3d8086/wolf3d.cfg create mode 100755 16/wf3d8086/wolf3d.sym diff --git a/16/WOLFSRC/AUDIOSDM.H b/16/WOLFSRC/AUDIOSDM.H new file mode 100755 index 00000000..11546466 --- /dev/null +++ b/16/WOLFSRC/AUDIOSDM.H @@ -0,0 +1,142 @@ +///////////////////////////////////////////////// +// +// MUSE Header for .SDM +// Created Thu Aug 27 07:12:39 1992 +// +///////////////////////////////////////////////// + +#define NUMSOUNDS 81 +#define NUMSNDCHUNKS 267 + +// +// Sound names & indexes +// +typedef enum { + HITWALLSND, // 0 + MISSILEHITSND, // 1 + SELECTITEMSND, // 2 + GHOSTSIGHTSND, // 3 + MOVEGUN2SND, // 4 + MOVEGUN1SND, // 5 + NOWAYSND, // 6 + NAZIHITPLAYERSND, // 7 + MISSILEFIRESND, // 8 + PLAYERDEATHSND, // 9 + DOGDEATHSND, // 10 + ATKGATLINGSND, // 11 + GETKEYSND, // 12 + NOITEMSND, // 13 + WALK1SND, // 14 + WALK2SND, // 15 + TAKEDAMAGESND, // 16 + GAMEOVERSND, // 17 + OPENDOORSND, // 18 + CLOSEDOORSND, // 19 + DONOTHINGSND, // 20 + HALTSND, // 21 + DEATHSCREAM2SND, // 22 + ATKKNIFESND, // 23 + ATKPISTOLSND, // 24 + DEATHSCREAM3SND, // 25 + ATKMACHINEGUNSND, // 26 + HITENEMYSND, // 27 + SHOOTDOORSND, // 28 + DEATHSCREAM1SND, // 29 + GETMACHINESND, // 30 + GETAMMOSND, // 31 + SHOOTSND, // 32 + HEALTH1SND, // 33 + HEALTH2SND, // 34 + BONUS1SND, // 35 + BONUS2SND, // 36 + BONUS3SND, // 37 + GETGATLINGSND, // 38 + ESCPRESSEDSND, // 39 + LEVELDONESND, // 40 + DOGBARKSND, // 41 + ENDBONUS1SND, // 42 + ENDBONUS2SND, // 43 + BONUS1UPSND, // 44 + BONUS4SND, // 45 + PUSHWALLSND, // 46 + NOBONUSSND, // 47 + PERCENT100SND, // 48 + BOSSACTIVESND, // 49 + DEATHSCREAM4SND, // 50 + SCHUTZADSND, // 51 + AHHHGSND, // 52 + DEATHSCREAM5SND, // 53 + DEATHSCREAM7SND, // 54 + DEATHSCREAM8SND, // 55 + LEBENSND, // 56 + DEATHSCREAM6SND, // 57 + NAZIFIRESND, // 58 + BOSSFIRESND, // 59 + SSFIRESND, // 60 + SLURPIESND, // 61 + GHOSTFADESND, // 62 + DEATHSCREAM9SND, // 63 + GETAMMOBOXSND, // 64 + ANGELSIGHTSND, // 65 + SPIONSND, // 66 + NEINSOVASSND, // 67 + DOGATTACKSND, // 68 + ANGELFIRESND, // 69 + TRANSSIGHTSND, // 70 + TRANSDEATHSND, // 71 + WILHELMSIGHTSND, // 72 + WILHELMDEATHSND, // 73 + UBERDEATHSND, // 74 + KNIGHTSIGHTSND, // 75 + KNIGHTDEATHSND, // 76 + ANGELDEATHSND, // 77 + KNIGHTMISSILESND, // 78 + GETSPEARSND, // 79 + ANGELTIREDSND, // 80 + LASTSOUND + } soundnames; + +// +// Base offsets +// +#define STARTPCSOUNDS 0 +#define STARTADLIBSOUNDS 81 +#define STARTDIGISOUNDS 162 +#define STARTMUSIC 243 + +// +// Music names & indexes +// +typedef enum { + XFUNKIE_MUS, // 0 + DUNGEON_MUS, // 1 + XDEATH_MUS, // 2 + GETTHEM_MUS, // 3 + XTIPTOE_MUS, // 4 + GOINGAFT_MUS, // 5 + URAHERO_MUS, // 6 + XTHEEND_MUS, // 7 + NAZI_OMI_MUS, // 8 + POW_MUS, // 9 + TWELFTH_MUS, // 10 + SEARCHN_MUS, // 11 + SUSPENSE_MUS, // 12 + ZEROHOUR_MUS, // 13 + WONDERIN_MUS, // 14 + ULTIMATE_MUS, // 15 + ENDLEVEL_MUS, // 16 + XEVIL_MUS, // 17 + XJAZNAZI_MUS, // 18 + COPYPRO_MUS, // 19 + XAWARD_MUS, // 20 + XPUTIT_MUS, // 21 + XGETYOU_MUS, // 22 + XTOWER2_MUS, // 23 + LASTMUSIC + } musicnames; + +///////////////////////////////////////////////// +// +// Thanks for playing with MUSE! +// +///////////////////////////////////////////////// diff --git a/16/WOLFSRC/AUDIOSOD.H b/16/WOLFSRC/AUDIOSOD.H new file mode 100755 index 00000000..543e2c13 --- /dev/null +++ b/16/WOLFSRC/AUDIOSOD.H @@ -0,0 +1,142 @@ +///////////////////////////////////////////////// +// +// MUSE Header for .SOD +// Created Thu Aug 13 09:25:58 1992 +// +///////////////////////////////////////////////// + +#define NUMSOUNDS 81 +#define NUMSNDCHUNKS 267 + +// +// Sound names & indexes +// +typedef enum { + HITWALLSND, // 0 + MISSILEHITSND, // 1 + SELECTITEMSND, // 2 + GHOSTSIGHTSND, // 3 + MOVEGUN2SND, // 4 + MOVEGUN1SND, // 5 + NOWAYSND, // 6 + NAZIHITPLAYERSND, // 7 + MISSILEFIRESND, // 8 + PLAYERDEATHSND, // 9 + DOGDEATHSND, // 10 + ATKGATLINGSND, // 11 + GETKEYSND, // 12 + NOITEMSND, // 13 + WALK1SND, // 14 + WALK2SND, // 15 + TAKEDAMAGESND, // 16 + GAMEOVERSND, // 17 + OPENDOORSND, // 18 + CLOSEDOORSND, // 19 + DONOTHINGSND, // 20 + HALTSND, // 21 + DEATHSCREAM2SND, // 22 + ATKKNIFESND, // 23 + ATKPISTOLSND, // 24 + DEATHSCREAM3SND, // 25 + ATKMACHINEGUNSND, // 26 + HITENEMYSND, // 27 + SHOOTDOORSND, // 28 + DEATHSCREAM1SND, // 29 + GETMACHINESND, // 30 + GETAMMOSND, // 31 + SHOOTSND, // 32 + HEALTH1SND, // 33 + HEALTH2SND, // 34 + BONUS1SND, // 35 + BONUS2SND, // 36 + BONUS3SND, // 37 + GETGATLINGSND, // 38 + ESCPRESSEDSND, // 39 + LEVELDONESND, // 40 + DOGBARKSND, // 41 + ENDBONUS1SND, // 42 + ENDBONUS2SND, // 43 + BONUS1UPSND, // 44 + BONUS4SND, // 45 + PUSHWALLSND, // 46 + NOBONUSSND, // 47 + PERCENT100SND, // 48 + BOSSACTIVESND, // 49 + DEATHSCREAM4SND, // 50 + SCHUTZADSND, // 51 + AHHHGSND, // 52 + DEATHSCREAM5SND, // 53 + DEATHSCREAM7SND, // 54 + DEATHSCREAM8SND, // 55 + LEBENSND, // 56 + DEATHSCREAM6SND, // 57 + NAZIFIRESND, // 58 + BOSSFIRESND, // 59 + SSFIRESND, // 60 + SLURPIESND, // 61 + GHOSTFADESND, // 62 + DEATHSCREAM9SND, // 63 + GETAMMOBOXSND, // 64 + ANGELSIGHTSND, // 65 + SPIONSND, // 66 + NEINSOVASSND, // 67 + DOGATTACKSND, // 68 + ANGELFIRESND, // 69 + TRANSSIGHTSND, // 70 + TRANSDEATHSND, // 71 + WILHELMSIGHTSND, // 72 + WILHELMDEATHSND, // 73 + UBERDEATHSND, // 74 + KNIGHTSIGHTSND, // 75 + KNIGHTDEATHSND, // 76 + ANGELDEATHSND, // 77 + KNIGHTMISSILESND, // 78 + GETSPEARSND, // 79 + ANGELTIREDSND, // 80 + LASTSOUND + } soundnames; + +// +// Base offsets +// +#define STARTPCSOUNDS 0 +#define STARTADLIBSOUNDS 81 +#define STARTDIGISOUNDS 162 +#define STARTMUSIC 243 + +// +// Music names & indexes +// +typedef enum { + XFUNKIE_MUS, // 0 + DUNGEON_MUS, // 1 + XDEATH_MUS, // 2 + GETTHEM_MUS, // 3 + XTIPTOE_MUS, // 4 + GOINGAFT_MUS, // 5 + URAHERO_MUS, // 6 + XTHEEND_MUS, // 7 + NAZI_OMI_MUS, // 8 + POW_MUS, // 9 + TWELFTH_MUS, // 10 + SEARCHN_MUS, // 11 + SUSPENSE_MUS, // 12 + ZEROHOUR_MUS, // 13 + WONDERIN_MUS, // 14 + ULTIMATE_MUS, // 15 + ENDLEVEL_MUS, // 16 + XEVIL_MUS, // 17 + XJAZNAZI_MUS, // 18 + COPYPRO_MUS, // 19 + XAWARD_MUS, // 20 + XPUTIT_MUS, // 21 + XGETYOU_MUS, // 22 + XTOWER2_MUS, // 23 + LASTMUSIC + } musicnames; + +///////////////////////////////////////////////// +// +// Thanks for playing with MUSE! +// +///////////////////////////////////////////////// diff --git a/16/WOLFSRC/AUDIOWL1.H b/16/WOLFSRC/AUDIOWL1.H new file mode 100755 index 00000000..7ce44c09 --- /dev/null +++ b/16/WOLFSRC/AUDIOWL1.H @@ -0,0 +1,133 @@ +///////////////////////////////////////////////// +// +// MUSE Header for .WL1 +// Created Tue Apr 28 23:57:08 1992 +// +///////////////////////////////////////////////// + +#define NUMSOUNDS 69 +#define NUMSNDCHUNKS 234 + +// +// Sound names & indexes +// +typedef enum { + HITWALLSND, // 0 + SELECTWPNSND, // 1 + SELECTITEMSND, // 2 + HEARTBEATSND, // 3 + MOVEGUN2SND, // 4 + MOVEGUN1SND, // 5 + NOWAYSND, // 6 + NAZIHITPLAYERSND, // 7 + NAZIMISSSND, // 8 + PLAYERDEATHSND, // 9 + DOGDEATHSND, // 10 + ATKGATLINGSND, // 11 + GETKEYSND, // 12 + NOITEMSND, // 13 + WALK1SND, // 14 + WALK2SND, // 15 + TAKEDAMAGESND, // 16 + GAMEOVERSND, // 17 + OPENDOORSND, // 18 + CLOSEDOORSND, // 19 + DONOTHINGSND, // 20 + HALTSND, // 21 + DEATHSCREAM2SND, // 22 + ATKKNIFESND, // 23 + ATKPISTOLSND, // 24 + DEATHSCREAM3SND, // 25 + ATKMACHINEGUNSND, // 26 + HITENEMYSND, // 27 + SHOOTDOORSND, // 28 + DEATHSCREAM1SND, // 29 + GETMACHINESND, // 30 + GETAMMOSND, // 31 + SHOOTSND, // 32 + HEALTH1SND, // 33 + HEALTH2SND, // 34 + BONUS1SND, // 35 + BONUS2SND, // 36 + BONUS3SND, // 37 + GETGATLINGSND, // 38 + ESCPRESSEDSND, // 39 + LEVELDONESND, // 40 + DOGBARKSND, // 41 + ENDBONUS1SND, // 42 + ENDBONUS2SND, // 43 + BONUS1UPSND, // 44 + BONUS4SND, // 45 + PUSHWALLSND, // 46 + NOBONUSSND, // 47 + PERCENT100SND, // 48 + BOSSACTIVESND, // 49 + BOSSDIESSND, // 50 + SCHUTZADSND, // 51 + AHHHGSND, // 52 + DIESND, // 53 + EVASND, // 54 + GUTENTAGSND, // 55 + LEBENSND, // 56 + MUTTISND, // 57 + NAZIFIRESND, // 58 + BOSSFIRESND, // 59 + SSFIRESND, // 60 + SLURPIESND, // 61 + TOT_HUNDSND, // 62 + MEINGOTTSND, // 63 + SCHABBSHASND, // 64 + HILTERHASND, // 65 + SPIONSND, // 66 + NEINSOVASSND, // 67 + DOGATTACKSND, // 68 + LASTSOUND + } soundnames; + +// +// Base offsets +// +#define STARTPCSOUNDS 0 +#define STARTADLIBSOUNDS 69 +#define STARTDIGISOUNDS 138 +#define STARTMUSIC 207 + +// +// Music names & indexes +// +typedef enum { + CORNER_MUS, // 0 + DUNGEON_MUS, // 1 + GETOUT_MUS, // 2 + GETTHEM_MUS, // 3 + HEADACHE_MUS, // 4 + HITLWLTZ_MUS, // 5 + INTROCW3_MUS, // 6 + NAZI_NOR_MUS, // 7 + NAZI_OMI_MUS, // 8 + POW_MUS, // 9 + SALUTE_MUS, // 10 + SEARCHN_MUS, // 11 + SUSPENSE_MUS, // 12 + VICTORS_MUS, // 13 + WONDERIN_MUS, // 14 + FUNKYOU_MUS, // 15 + ENDLEVEL_MUS, // 16 + GOINGAFT_MUS, // 17 + PREGNANT_MUS, // 18 + ULTIMATE_MUS, // 19 + NAZI_RAP_MUS, // 20 + ZEROHOUR_MUS, // 21 + TWELFTH_MUS, // 22 + ROSTER_MUS, // 23 + URAHERO_MUS, // 24 + VICMARCH_MUS, // 25 + WARMRCH1_MUS, // 26 + LASTMUSIC + } musicnames; + +///////////////////////////////////////////////// +// +// Thanks for playing with MUSE! +// +///////////////////////////////////////////////// diff --git a/16/WOLFSRC/AUDIOWL6.H b/16/WOLFSRC/AUDIOWL6.H new file mode 100755 index 00000000..3cb747be --- /dev/null +++ b/16/WOLFSRC/AUDIOWL6.H @@ -0,0 +1,151 @@ +///////////////////////////////////////////////// +// +// MUSE Header for .WL6 +// Created Tue Jul 14 15:04:53 1992 +// +///////////////////////////////////////////////// + +#define NUMSOUNDS 87 +#define NUMSNDCHUNKS 288 + +// +// Sound names & indexes +// +typedef enum { + HITWALLSND, // 0 + SELECTWPNSND, // 1 + SELECTITEMSND, // 2 + HEARTBEATSND, // 3 + MOVEGUN2SND, // 4 + MOVEGUN1SND, // 5 + NOWAYSND, // 6 + NAZIHITPLAYERSND, // 7 + SCHABBSTHROWSND, // 8 + PLAYERDEATHSND, // 9 + DOGDEATHSND, // 10 + ATKGATLINGSND, // 11 + GETKEYSND, // 12 + NOITEMSND, // 13 + WALK1SND, // 14 + WALK2SND, // 15 + TAKEDAMAGESND, // 16 + GAMEOVERSND, // 17 + OPENDOORSND, // 18 + CLOSEDOORSND, // 19 + DONOTHINGSND, // 20 + HALTSND, // 21 + DEATHSCREAM2SND, // 22 + ATKKNIFESND, // 23 + ATKPISTOLSND, // 24 + DEATHSCREAM3SND, // 25 + ATKMACHINEGUNSND, // 26 + HITENEMYSND, // 27 + SHOOTDOORSND, // 28 + DEATHSCREAM1SND, // 29 + GETMACHINESND, // 30 + GETAMMOSND, // 31 + SHOOTSND, // 32 + HEALTH1SND, // 33 + HEALTH2SND, // 34 + BONUS1SND, // 35 + BONUS2SND, // 36 + BONUS3SND, // 37 + GETGATLINGSND, // 38 + ESCPRESSEDSND, // 39 + LEVELDONESND, // 40 + DOGBARKSND, // 41 + ENDBONUS1SND, // 42 + ENDBONUS2SND, // 43 + BONUS1UPSND, // 44 + BONUS4SND, // 45 + PUSHWALLSND, // 46 + NOBONUSSND, // 47 + PERCENT100SND, // 48 + BOSSACTIVESND, // 49 + MUTTISND, // 50 + SCHUTZADSND, // 51 + AHHHGSND, // 52 + DIESND, // 53 + EVASND, // 54 + GUTENTAGSND, // 55 + LEBENSND, // 56 + SCHEISTSND, // 57 + NAZIFIRESND, // 58 + BOSSFIRESND, // 59 + SSFIRESND, // 60 + SLURPIESND, // 61 + TOT_HUNDSND, // 62 + MEINGOTTSND, // 63 + SCHABBSHASND, // 64 + HITLERHASND, // 65 + SPIONSND, // 66 + NEINSOVASSND, // 67 + DOGATTACKSND, // 68 + FLAMETHROWERSND, // 69 + MECHSTEPSND, // 70 + GOOBSSND, // 71 + YEAHSND, // 72 + DEATHSCREAM4SND, // 73 + DEATHSCREAM5SND, // 74 + DEATHSCREAM6SND, // 75 + DEATHSCREAM7SND, // 76 + DEATHSCREAM8SND, // 77 + DEATHSCREAM9SND, // 78 + DONNERSND, // 79 + EINESND, // 80 + ERLAUBENSND, // 81 + KEINSND, // 82 + MEINSND, // 83 + ROSESND, // 84 + MISSILEFIRESND, // 85 + MISSILEHITSND, // 86 + LASTSOUND + } soundnames; + +// +// Base offsets +// +#define STARTPCSOUNDS 0 +#define STARTADLIBSOUNDS 87 +#define STARTDIGISOUNDS 174 +#define STARTMUSIC 261 + +// +// Music names & indexes +// +typedef enum { + CORNER_MUS, // 0 + DUNGEON_MUS, // 1 + WARMARCH_MUS, // 2 + GETTHEM_MUS, // 3 + HEADACHE_MUS, // 4 + HITLWLTZ_MUS, // 5 + INTROCW3_MUS, // 6 + NAZI_NOR_MUS, // 7 + NAZI_OMI_MUS, // 8 + POW_MUS, // 9 + SALUTE_MUS, // 10 + SEARCHN_MUS, // 11 + SUSPENSE_MUS, // 12 + VICTORS_MUS, // 13 + WONDERIN_MUS, // 14 + FUNKYOU_MUS, // 15 + ENDLEVEL_MUS, // 16 + GOINGAFT_MUS, // 17 + PREGNANT_MUS, // 18 + ULTIMATE_MUS, // 19 + NAZI_RAP_MUS, // 20 + ZEROHOUR_MUS, // 21 + TWELFTH_MUS, // 22 + ROSTER_MUS, // 23 + URAHERO_MUS, // 24 + VICMARCH_MUS, // 25 + PACMAN_MUS, // 26 + LASTMUSIC + } musicnames; + +///////////////////////////////////////////////// +// +// Thanks for playing with MUSE! +// +///////////////////////////////////////////////// diff --git a/16/WOLFSRC/BUDIOSOD.H b/16/WOLFSRC/BUDIOSOD.H new file mode 100755 index 00000000..543e2c13 --- /dev/null +++ b/16/WOLFSRC/BUDIOSOD.H @@ -0,0 +1,142 @@ +///////////////////////////////////////////////// +// +// MUSE Header for .SOD +// Created Thu Aug 13 09:25:58 1992 +// +///////////////////////////////////////////////// + +#define NUMSOUNDS 81 +#define NUMSNDCHUNKS 267 + +// +// Sound names & indexes +// +typedef enum { + HITWALLSND, // 0 + MISSILEHITSND, // 1 + SELECTITEMSND, // 2 + GHOSTSIGHTSND, // 3 + MOVEGUN2SND, // 4 + MOVEGUN1SND, // 5 + NOWAYSND, // 6 + NAZIHITPLAYERSND, // 7 + MISSILEFIRESND, // 8 + PLAYERDEATHSND, // 9 + DOGDEATHSND, // 10 + ATKGATLINGSND, // 11 + GETKEYSND, // 12 + NOITEMSND, // 13 + WALK1SND, // 14 + WALK2SND, // 15 + TAKEDAMAGESND, // 16 + GAMEOVERSND, // 17 + OPENDOORSND, // 18 + CLOSEDOORSND, // 19 + DONOTHINGSND, // 20 + HALTSND, // 21 + DEATHSCREAM2SND, // 22 + ATKKNIFESND, // 23 + ATKPISTOLSND, // 24 + DEATHSCREAM3SND, // 25 + ATKMACHINEGUNSND, // 26 + HITENEMYSND, // 27 + SHOOTDOORSND, // 28 + DEATHSCREAM1SND, // 29 + GETMACHINESND, // 30 + GETAMMOSND, // 31 + SHOOTSND, // 32 + HEALTH1SND, // 33 + HEALTH2SND, // 34 + BONUS1SND, // 35 + BONUS2SND, // 36 + BONUS3SND, // 37 + GETGATLINGSND, // 38 + ESCPRESSEDSND, // 39 + LEVELDONESND, // 40 + DOGBARKSND, // 41 + ENDBONUS1SND, // 42 + ENDBONUS2SND, // 43 + BONUS1UPSND, // 44 + BONUS4SND, // 45 + PUSHWALLSND, // 46 + NOBONUSSND, // 47 + PERCENT100SND, // 48 + BOSSACTIVESND, // 49 + DEATHSCREAM4SND, // 50 + SCHUTZADSND, // 51 + AHHHGSND, // 52 + DEATHSCREAM5SND, // 53 + DEATHSCREAM7SND, // 54 + DEATHSCREAM8SND, // 55 + LEBENSND, // 56 + DEATHSCREAM6SND, // 57 + NAZIFIRESND, // 58 + BOSSFIRESND, // 59 + SSFIRESND, // 60 + SLURPIESND, // 61 + GHOSTFADESND, // 62 + DEATHSCREAM9SND, // 63 + GETAMMOBOXSND, // 64 + ANGELSIGHTSND, // 65 + SPIONSND, // 66 + NEINSOVASSND, // 67 + DOGATTACKSND, // 68 + ANGELFIRESND, // 69 + TRANSSIGHTSND, // 70 + TRANSDEATHSND, // 71 + WILHELMSIGHTSND, // 72 + WILHELMDEATHSND, // 73 + UBERDEATHSND, // 74 + KNIGHTSIGHTSND, // 75 + KNIGHTDEATHSND, // 76 + ANGELDEATHSND, // 77 + KNIGHTMISSILESND, // 78 + GETSPEARSND, // 79 + ANGELTIREDSND, // 80 + LASTSOUND + } soundnames; + +// +// Base offsets +// +#define STARTPCSOUNDS 0 +#define STARTADLIBSOUNDS 81 +#define STARTDIGISOUNDS 162 +#define STARTMUSIC 243 + +// +// Music names & indexes +// +typedef enum { + XFUNKIE_MUS, // 0 + DUNGEON_MUS, // 1 + XDEATH_MUS, // 2 + GETTHEM_MUS, // 3 + XTIPTOE_MUS, // 4 + GOINGAFT_MUS, // 5 + URAHERO_MUS, // 6 + XTHEEND_MUS, // 7 + NAZI_OMI_MUS, // 8 + POW_MUS, // 9 + TWELFTH_MUS, // 10 + SEARCHN_MUS, // 11 + SUSPENSE_MUS, // 12 + ZEROHOUR_MUS, // 13 + WONDERIN_MUS, // 14 + ULTIMATE_MUS, // 15 + ENDLEVEL_MUS, // 16 + XEVIL_MUS, // 17 + XJAZNAZI_MUS, // 18 + COPYPRO_MUS, // 19 + XAWARD_MUS, // 20 + XPUTIT_MUS, // 21 + XGETYOU_MUS, // 22 + XTOWER2_MUS, // 23 + LASTMUSIC + } musicnames; + +///////////////////////////////////////////////// +// +// Thanks for playing with MUSE! +// +///////////////////////////////////////////////// diff --git a/16/WOLFSRC/BUDIOWL6.H b/16/WOLFSRC/BUDIOWL6.H new file mode 100755 index 00000000..9cd66cac --- /dev/null +++ b/16/WOLFSRC/BUDIOWL6.H @@ -0,0 +1,151 @@ +///////////////////////////////////////////////// +// +// MUSE Header for .WL6 +// Created Sat May 30 18:41:31 1992 +// +///////////////////////////////////////////////// + +#define NUMSOUNDS 87 +#define NUMSNDCHUNKS 288 + +// +// Sound names & indexes +// +typedef enum { + HITWALLSND, // 0 + SELECTWPNSND, // 1 + SELECTITEMSND, // 2 + HEARTBEATSND, // 3 + MOVEGUN2SND, // 4 + MOVEGUN1SND, // 5 + NOWAYSND, // 6 + NAZIHITPLAYERSND, // 7 + SCHABBSTHROWSND, // 8 + PLAYERDEATHSND, // 9 + DOGDEATHSND, // 10 + ATKGATLINGSND, // 11 + GETKEYSND, // 12 + NOITEMSND, // 13 + WALK1SND, // 14 + WALK2SND, // 15 + TAKEDAMAGESND, // 16 + GAMEOVERSND, // 17 + OPENDOORSND, // 18 + CLOSEDOORSND, // 19 + DONOTHINGSND, // 20 + HALTSND, // 21 + DEATHSCREAM2SND, // 22 + ATKKNIFESND, // 23 + ATKPISTOLSND, // 24 + DEATHSCREAM3SND, // 25 + ATKMACHINEGUNSND, // 26 + HITENEMYSND, // 27 + SHOOTDOORSND, // 28 + DEATHSCREAM1SND, // 29 + GETMACHINESND, // 30 + GETAMMOSND, // 31 + SHOOTSND, // 32 + HEALTH1SND, // 33 + HEALTH2SND, // 34 + BONUS1SND, // 35 + BONUS2SND, // 36 + BONUS3SND, // 37 + GETGATLINGSND, // 38 + ESCPRESSEDSND, // 39 + LEVELDONESND, // 40 + DOGBARKSND, // 41 + ENDBONUS1SND, // 42 + ENDBONUS2SND, // 43 + BONUS1UPSND, // 44 + BONUS4SND, // 45 + PUSHWALLSND, // 46 + NOBONUSSND, // 47 + PERCENT100SND, // 48 + BOSSACTIVESND, // 49 + MUTTISND, // 50 + SCHUTZADSND, // 51 + AHHHGSND, // 52 + DIESND, // 53 + EVASND, // 54 + GUTENTAGSND, // 55 + LEBENSND, // 56 + SCHEISTSND, // 57 + NAZIFIRESND, // 58 + BOSSFIRESND, // 59 + SSFIRESND, // 60 + SLURPIESND, // 61 + TOT_HUNDSND, // 62 + MEINGOTTSND, // 63 + SCHABBSHASND, // 64 + HITLERHASND, // 65 + SPIONSND, // 66 + NEINSOVASSND, // 67 + DOGATTACKSND, // 68 + FLAMETHROWERSND, // 69 + MECHSTEPSND, // 70 + GOOBSSND, // 71 + YEAHSND, // 72 + DEATHSCREAM4SND, // 73 + DEATHSCREAM5SND, // 74 + DEATHSCREAM6SND, // 75 + DEATHSCREAM7SND, // 76 + DEATHSCREAM8SND, // 77 + DEATHSCREAM9SND, // 78 + DONNERSND, // 79 + EINESND, // 80 + ERLAUBENSND, // 81 + KEINSND, // 82 + MEINSND, // 83 + ROSESND, // 84 + MISSILEFIRESND, // 85 + MISSILEHITSND, // 86 + LASTSOUND + } soundnames; + +// +// Base offsets +// +#define STARTPCSOUNDS 0 +#define STARTADLIBSOUNDS 87 +#define STARTDIGISOUNDS 174 +#define STARTMUSIC 261 + +// +// Music names & indexes +// +typedef enum { + CORNER_MUS, // 0 + DUNGEON_MUS, // 1 + WARMARCH_MUS, // 2 + GETTHEM_MUS, // 3 + HEADACHE_MUS, // 4 + HITLWLTZ_MUS, // 5 + INTROCW3_MUS, // 6 + NAZI_NOR_MUS, // 7 + NAZI_OMI_MUS, // 8 + POW_MUS, // 9 + SALUTE_MUS, // 10 + SEARCHN_MUS, // 11 + SUSPENSE_MUS, // 12 + VICTORS_MUS, // 13 + WONDERIN_MUS, // 14 + FUNKYOU_MUS, // 15 + ENDLEVEL_MUS, // 16 + GOINGAFT_MUS, // 17 + PREGNANT_MUS, // 18 + ULTIMATE_MUS, // 19 + NAZI_RAP_MUS, // 20 + ZEROHOUR_MUS, // 21 + TWELFTH_MUS, // 22 + ROSTER_MUS, // 23 + URAHERO_MUS, // 24 + VICMARCH_MUS, // 25 + PACMAN_MUS, // 26 + LASTMUSIC + } musicnames; + +///////////////////////////////////////////////// +// +// Thanks for playing with MUSE! +// +///////////////////////////////////////////////// diff --git a/16/WOLFSRC/C0.ASM b/16/WOLFSRC/C0.ASM new file mode 100755 index 00000000..8adb36b1 --- /dev/null +++ b/16/WOLFSRC/C0.ASM @@ -0,0 +1,843 @@ + NAME c0 + PAGE 60,132 + LOCALS +;[]------------------------------------------------------------[] +;| C0.ASM -- Start Up Code | +;| | +;| Turbo C++ Run Time Library | +;| | +;| Copyright (c) 1987, 1991 by Borland International Inc. | +;| All Rights Reserved. | +;[]------------------------------------------------------------[] + + __C0__ = 1 +INCLUDE RULES.ASI + +; Segment and Group declarations + +_TEXT SEGMENT BYTE PUBLIC 'CODE' + ENDS +_FARDATA SEGMENT PARA PUBLIC 'FAR_DATA' + ENDS +_FARBSS SEGMENT PARA PUBLIC 'FAR_BSS' + ENDS +IFNDEF __TINY__ +_OVERLAY_ SEGMENT PARA PUBLIC 'OVRINFO' + ENDS +_1STUB_ SEGMENT PARA PUBLIC 'STUBSEG' + ENDS +ENDIF +_DATA SEGMENT PARA PUBLIC 'DATA' + ENDS +_INIT_ SEGMENT WORD PUBLIC 'INITDATA' +InitStart label byte + ENDS +_INITEND_ SEGMENT BYTE PUBLIC 'INITDATA' +InitEnd label byte + ENDS +_EXIT_ SEGMENT WORD PUBLIC 'EXITDATA' +ExitStart label byte + ENDS +_EXITEND_ SEGMENT BYTE PUBLIC 'EXITDATA' +ExitEnd label byte + ENDS +_CVTSEG SEGMENT WORD PUBLIC 'DATA' + ENDS +_SCNSEG SEGMENT WORD PUBLIC 'DATA' + ENDS +IFNDEF __HUGE__ + _BSS SEGMENT WORD PUBLIC 'BSS' + ENDS + _BSSEND SEGMENT BYTE PUBLIC 'BSSEND' + ENDS +ENDIF +IFNDEF __TINY__ + _STACK SEGMENT STACK 'STACK' + ENDS +ENDIF + + ASSUME CS:_TEXT, DS:DGROUP + +; External References + +extrn _main:DIST +extrn _exit:DIST +extrn __exit:DIST +extrn __nfile:word +extrn __setupio:near ;required! +extrn __stklen:word +IF LDATA EQ false +extrn __heaplen:word +ENDIF + + SUBTTL Start Up Code + PAGE +;/* */ +;/*-----------------------------------------------------*/ +;/* */ +;/* Start Up Code */ +;/* ------------- */ +;/* */ +;/*-----------------------------------------------------*/ +;/* */ +PSPHigh equ 00002h +PSPEnv equ 0002ch +PSPCmd equ 00080h + + public __AHINCR +__AHINCR equ 1000h + public __AHSHIFT +__AHSHIFT equ 12 + +IFDEF __NOFLOAT__ +MINSTACK equ 128 ; minimal stack size in words +ELSE +MINSTACK equ 256 ; minimal stack size in words +ENDIF +; +; At the start, DS and ES both point to the segment prefix. +; SS points to the stack segment except in TINY model where +; SS is equal to CS +; +_TEXT SEGMENT +IFDEF __TINY__ + ORG 100h +ENDIF +STARTX PROC NEAR +; Save general information, such as : +; DGROUP segment address +; DOS version number +; Program Segment Prefix address +; Environment address +; Top of far heap + +IFDEF __TINY__ + mov dx, cs ; DX = GROUP Segment address +ELSE + mov dx, DGROUP ; DX = GROUP Segment address +ENDIF +IFNDEF __BOSS__ + mov cs:DGROUP@@, dx ; __BOSS__ +ENDIF + mov ah, 30h + int 21h ; get DOS version number + mov bp, ds:[PSPHigh]; BP = Highest Memory Segment Addr + mov bx, ds:[PSPEnv] ; BX = Environment Segment address + mov ds, dx + mov _version@, ax ; Keep major and minor version number + mov _psp@, es ; Keep Program Segment Prefix address + mov _envseg@, bx ; Keep Environment Segment address + mov word ptr _heaptop@ + 2, bp +; +; Save several vectors and install default divide by zero handler. +; + call SaveVectors + +;=================== +; +; IDsoft - Check to make sure that we're running on a 286 or better + + pushf ; Save original flags + xor ax,ax ; Clear AX + push ax + popf ; Try to pop the 0 + pushf + pop ax ; Get results of popping 0 into flags + popf ; Restore original flags + or ax,ax + ;begin 8086 hack + ;jns @@Have286 ; If no sign bit, have a 286 + jmp @@Have286 + + mov cx, lgth_no286MSG + mov dx, offset DGROUP: no286MSG + jmp MsgExit3 + +@@Have286: +; IDsoft - End of modifications (there's also a code segment string) +; +;=================== + +IFDEF __BOSS__ +; Determine if in real mode + mov ax,0FB42h ; find out if DPMI loader is here + mov bx,1 ; get info function + int 2fh ; + + push ax ; + mov ax, cs ; now, save DGROUP + add ax, cx ; + mov es, ax ; + mov dx, ds ; + mov es:DGROUP@@, dx ; + mov es:CSalias@@, ax ; + pop ax ; + +; cmp ax,0001h ; if not "TRUE" +; JNE InRealMode + +; 8 is the value of the alias selector +; in this system + MOV _protected@, cx + MOV _hugeincval@, cx + clc + mov ax, cx + xor cx, cx + or ax, ax + je @@gotshift +@@shiftcnt: + rcr ax,1 + jc @@gotshift + inc cx + jmp @@shiftcnt +@@gotshift: + mov _shiftcount@,cx + +; used by emulator +; PUSH DS +; MOV AX, 0E502H ; prot kernel function, get LDT alias +; INT 21H +; POP DS +; MOV _LDT@, AX + +; cmp _protected@,0001h ; if not "TRUE" +; JNE InRealMode + + .286P +IFE LDATA + mov dx, ds ; +; LSL AX, DX ; +; DEC AX ; + MOV AX, 0FFFEh ; + MOV SP, AX ; + MOV SS, DX ; +ENDIF + .8086 +; JMP BossSkip + +InRealMode label near + +ENDIF + +; Count the number of environment variables and compute the size. +; Each variable is ended by a 0 and a zero-length variable stops +; the environment. The environment can NOT be greater than 32k. + + les di, dword ptr _envLng@ + mov ax, di + mov bx, ax + mov cx, 07FFFh ; Environment cannot be > 32 Kbytes + cld +@@EnvLoop: + repnz scasb + jcxz InitFailed ; Bad environment !!! +IFDEF __BOSS__ + jmp InitOK +InitFailed: jmp near ptr _abort +InitOK: +ENDIF + + inc bx ; BX = Nb environment variables + cmp es:[di], al + jne @@EnvLoop ; Next variable ... + or ch, 10000000b + neg cx + mov _envLng@, cx ; Save Environment size + mov cx, dPtrSize / 2 + shl bx, cl + add bx, dPtrSize * 4 + and bx, not ((dPtrSize * 4) - 1) + mov _envSize@, bx ; Save Environment Variables Nb. + +IFNDEF __BOSS__ + +; Determine the amount of memory that we need to keep + +IFDEF _DSSTACK_ + mov dx, ds +ELSE + mov dx, ss +ENDIF + sub bp, dx ; BP = remaining size in paragraphs +IF LDATA + mov di, seg __stklen + mov es, di + mov di, es:__stklen ; DI = Requested stack size +ELSE + mov di, __stklen ; DI = Requested stack size +ENDIF +; +; Make sure that the requested stack size is at least MINSTACK words. +; + cmp di, 2*MINSTACK ; requested stack big enough ? + jae AskedStackOK + mov di, 2*MINSTACK ; no --> use minimal value +IF LDATA + mov es:__stklen, di ; override requested stack size +ELSE + mov __stklen, di ; override requested stack size +ENDIF + +AskedStackOK label near +IFDEF _DSSTACK_ + add di, offset DGROUP: edata@ + jb InitFailed ; DATA segment can NOT be > 64 Kbytes +ENDIF +IF LDATA EQ false + add di, __heaplen + jb InitFailed ; DATA segment can NOT be > 64 Kbytes +ENDIF + mov cl, 4 + shr di, cl ; $$$ Do not destroy CL $$$ + inc di ; DI = DS size in paragraphs + cmp bp, di +IF LDATA EQ false + jb InitFailed ; Not enough memory + cmp __stklen, 0 + je ExpandDS ; Expand DS up to 64 Kb + cmp __heaplen, 0 + jne ExcessOfMemory ; Much more available than needed +ExpandDS label near + mov di, 1000h + cmp bp, di + ja ExcessOfMemory ; Enough to run the program + mov di, bp + jmp short ExcessOfMemory ; Enough to run the program +ELSE + jnb ExcessOfMemory ; Much more available than needed +ENDIF + +; All initialization errors arrive here + +InitFailed label near + jmp near ptr _abort + +; Return to DOS the amount of memory in excess +; Set far heap base and pointer + +ExcessOfMemory label near + mov bx, di + add bx, dx + mov word ptr _heapbase@ + 2, bx + mov word ptr _brklvl@ + 2, bx + mov ax, _psp@ + sub bx, ax ; BX = Number of paragraphs to keep + mov es, ax ; ES = Program Segment Prefix address + mov ah, 04Ah + push di ; preserve DI + int 021h ; this call clobbers SI,DI,BP !!!!!! + pop di ; restore DI + + shl di, cl ; $$$ CX is still equal to 4 $$$ + + cli ; req'd for pre-1983 88/86s + mov ss, dx ; Set the program stack + mov sp, di + sti + +IFNDEF _DSSTACK_ + mov ax, seg __stklen + mov es, ax + mov es:__stklen, di ; If separate stack segment, save size +ENDIF + +ENDIF ; __BOSS__ + +IFNDEF __HUGE__ + +; Reset uninitialized data area + + xor ax, ax + mov es, cs:DGROUP@@ + mov di, offset DGROUP: bdata@ + mov cx, offset DGROUP: edata@ + sub cx, di + cld + rep stosb +ENDIF + +; If default number of file handles have changed then tell DOS + cmp __nfile, 20 + jbe @@NoChange + + cmp _osmajor@, 3 ; Check for >= DOS 3.3 + jb @@NoChange + ja @@DoChange + cmp _osminor@, 1Eh + jb @@NoChange +@@DoChange: + mov ax, 5801h ; Set last fit allocation + mov bx, 2 + int 21h + jc @@BadInit + + mov ah, 67h ; Expand handle table + mov bx, __nfile + int 21h + jc @@BadInit + + mov ah, 48h ; Allocate 16 bytes to find new + mov bx, 1 ; top of memory address + int 21h + jc @@BadInit + inc ax ; Adjust address to point after block + mov word ptr _heaptop@ + 2, ax + + dec ax ; Change back and release block + mov es, ax + mov ah, 49h + int 21h + jc @@BadInit + + mov ax, 5801h ; Set first fit allocation + mov bx, 0 + int 21h + jnc @@NoChange + +@@BadInit: jmp near ptr _abort + +@@NoChange: + +; Prepare main arguments + + mov ah, 0 + int 1ah ; get current BIOS time in ticks + mov word ptr _StartTime@,dx ; save it for clock() fn + mov word ptr _StartTime@+2,cx + or al,al ; was midnight flag set? + jz @@NotMidnight + mov ax,40h ; set BIOS midnight flag + mov es,ax ; at 40:70 + mov bx,70h + mov byte ptr es:[bx],1 + +@@NotMidnight: + xor bp,bp ; set BP to 0 for overlay mgr + + mov es, cs:DGROUP@@ + mov si,offset DGROUP:InitStart ;si = start of table + mov di,offset DGROUP:InitEnd ;di = end of table + call StartExit + +; ExitCode = main(argc,argv,envp); + +IF LDATA + push word ptr __C0environ+2 + push word ptr __C0environ + push word ptr __C0argv+2 + push word ptr __C0argv +ELSE + push word ptr __C0environ + push word ptr __C0argv +ENDIF + push __C0argc + call _main + +; Flush and close streams and files + + push ax + call _exit + +;--------------------------------------------------------------------------- +; _cleanup() call all #pragma exit cleanup routines. +; _checknull() check for null pointer zapping copyright message +; _terminate(int) exit program with error code +; +; These functions are called by exit(), _exit(), _cexit(), +; and _c_exit(). +;--------------------------------------------------------------------------- + +; Call cleanup routines + +__cleanup PROC DIST + PUBLIC __cleanup + + mov es, cs:DGROUP@@ + push si + push di + mov si,offset DGROUP:ExitStart + mov di,offset DGROUP:ExitEnd + call StartExit + pop di + pop si + ret +__cleanup ENDP + +; Check for null pointers before exit + +__checknull PROC DIST + PUBLIC __checknull + +IF LDATA EQ false + IFNDEF __TINY__ + push si + push di + mov es, cs:DGROUP@@ + xor ax, ax + mov si, ax + mov cx, lgth_CopyRight +ComputeChecksum label near + add al, es:[si] + adc ah, 0 + inc si + loop ComputeChecksum + sub ax, CheckSum + jz @@SumOk + mov cx, lgth_NullCheck + mov dx, offset DGROUP: NullCheck + call ErrorDisplay +@@SumOK: pop di + pop si + ENDIF +ENDIF + ret +__checknull ENDP + +; Exit to DOS + +__terminate PROC DIST + PUBLIC __terminate + mov bp,sp + mov ah,4Ch + mov al,[bp+cPtrSize] + int 21h ; Exit to DOS +__terminate ENDP + +STARTX ENDP + + SUBTTL Vector save/restore & default Zero divide routines + PAGE +;[]------------------------------------------------------------[] +;| | +;| Interrupt Save/Restore routines and default divide by zero | +;| handler. | +;| | +;[]------------------------------------------------------------[] + +ZeroDivision PROC FAR + mov cx, lgth_ZeroDivMSG + mov dx, offset DGROUP: ZeroDivMSG + jmp MsgExit3 +ZeroDivision ENDP + +;-------------------------------------------------------------------------- +; savevectors() +; +; Save vectors for 0, 4, 5 & 6 interrupts. This is for extended +; signal()/raise() support as the signal functions can steal these +; vectors during runtime. +;-------------------------------------------------------------------------- +SaveVectors PROC NEAR + push ds +; Save INT 0 + mov ax, 3500h + int 021h + mov word ptr _Int0Vector@, bx + mov word ptr _Int0Vector@+2, es +; Save INT 4 + mov ax, 3504h + int 021h + mov word ptr _Int4Vector@, bx + mov word ptr _Int4Vector@+2, es +; Save INT 5 + mov ax, 3505h + int 021h + mov word ptr _Int5Vector@, bx + mov word ptr _Int5Vector@+2, es +; Save INT 6 + mov ax, 3506h + int 021h + mov word ptr _Int6Vector@, bx + mov word ptr _Int6Vector@+2, es +; +; Install default divide by zero handler. +; + mov ax, 2500h + mov dx, cs + mov ds, dx + mov dx, offset ZeroDivision + int 21h + + pop ds + ret +SaveVectors ENDP + +;-------------------------------------------------------------------------- +; _restorezero() puts back all the vectors that SaveVectors took. +; +;NOTE : TSRs must BE AWARE that signal() functions which take these +; vectors will be deactivated if the keep() function is executed. +; If a TSR wants to use the signal functions when it is active it +; will have to save/restore these vectors itself when activated and +; deactivated. +;-------------------------------------------------------------------------- +__restorezero PROC DIST + PUBLIC __restorezero +IFDEF __HUGE__ + push ds + mov ds, cs: DGROUP@@ +ENDIF + push ds + mov ax, 2500h + lds dx, _Int0Vector@ + int 21h + pop ds + + push ds + mov ax, 2504h + lds dx, _Int4Vector@ + int 21h + pop ds + + push ds + mov ax, 2505h + lds dx, _Int5Vector@ + int 21h + pop ds + +IFNDEF __HUGE__ + push ds +ENDIF + mov ax, 2506h + lds dx, _Int6Vector@ + int 21h + pop ds + + ret + ENDP + +;------------------------------------------------------------------ +; Loop through a startup/exit (SE) table, +; calling functions in order of priority. +; ES:SI is assumed to point to the beginning of the SE table +; ES:DI is assumed to point to the end of the SE table +; First 64 priorities are reserved by Borland +;------------------------------------------------------------------ +PNEAR EQU 0 +PFAR EQU 1 +NOTUSED EQU 0ffh + +SE STRUC +calltype db ? ; 0=near,1=far,ff=not used +priority db ? ; 0=highest,ff=lowest +addrlow dw ? +addrhigh dw ? +SE ENDS + +StartExit proc near +@@Start: cmp si,offset DGROUP:InitStart ; startup or exit? + je @@StartLow ; it's startup + xor ah,ah ; start with high priority + jmp short @@SaveEnd +@@StartLow: mov ah,0ffh ;start with lowest priority +@@SaveEnd: mov dx,di ;set sentinel to end of table + mov bx,si ;bx = start of table + +@@TopOfTable: cmp bx,di ;and the end of the table? + je @@EndOfTable ;yes, exit the loop + cmp es:[bx.calltype],NOTUSED;check the call type + je @@Next + cmp si,offset DGROUP:InitStart ; startup or exit? + je @@CompareHigh ; it's startup + cmp ah,es:[bx.priority] ; it's exit + jmp short @@CheckPrior ; if priority too low, skip +@@CompareHigh: cmp es:[bx.priority],ah ;check the priority +@@CheckPrior: ja @@Next ;too high? skip + mov ah,es:[bx.priority] ;keep priority + mov dx,bx ;keep index in dx +@@Next: add bx,SIZE SE ;bx = next item in table + jmp @@TopOfTable + +@@EndOfTable: cmp dx,di ;did we exhaust the table? + je @@Done ;yes, quit + mov bx,dx ;bx = highest priority item + cmp es:[bx.calltype],PNEAR ;is it near or far? + mov es:[bx.calltype],NOTUSED;wipe the call type + push es ;save es + je @@NearCall + +@@FarCall: call DWORD PTR es:[bx.addrlow] + pop es ;restore es + jmp short @@Start + +@@NearCall: call WORD PTR es:[bx.addrlow] + pop es ;restore es + jmp short @@Start + +@@Done: ret + endp + +;------------------------------------------------------------------ + +ErrorDisplay PROC NEAR + mov ah, 040h + mov bx, 2 + int 021h + ret +ErrorDisplay ENDP + +_abort PROC DIST + PUBLIC _abort + mov cx, lgth_abortMSG + mov dx, offset DGROUP: abortMSG +MsgExit3 label near + mov ds, cs: DGROUP@@ + call ErrorDisplay +CallExit3 label near + mov ax, 3 + push ax + call __exit ; _exit(3); + ENDP + +; The DGROUP@ variable is used to reload DS with DGROUP + +PubSym@ DGROUP@, , __PASCAL__ + +IFDEF __BOSS__ +PubSym@ CSalias@,, __PASCAL__ +ENDIF + + +; __MMODEL is used to determine the memory model or the default +; pointer types at run time. + + public __MMODEL +__MMODEL dw MMODEL + +_TEXT ENDS + + SUBTTL Start Up Data Area + PAGE +;[]------------------------------------------------------------[] +;| Start Up Data Area | +;| | +;| WARNING Do not move any variables in the data | +;| segment unless you're absolutely sure | +;| that it does not matter. | +;[]------------------------------------------------------------[] + +_DATA SEGMENT + +; Magic symbol used by the debug info to locate the data segment + public DATASEG@ +DATASEG@ label byte + +; The CopyRight string must NOT be moved or changed without +; changing the null pointer check logic + +CopyRight db 4 dup(0) + db 'Borland C++ - Copyright 1991 Borland Intl.',0 +lgth_CopyRight equ $ - CopyRight + +IF LDATA EQ false +IFNDEF __TINY__ +CheckSum equ 00D5Ch +NullCheck db 'Null pointer assignment', 13, 10 +lgth_NullCheck equ $ - NullCheck +ENDIF +ENDIF + +ZeroDivMSG db 'Divide error', 13, 10 +lgth_ZeroDivMSG equ $ - ZeroDivMSG + +abortMSG db 'Abnormal program termination', 13, 10 +lgth_abortMSG equ $ - abortMSG + +; JAB - Added string for no 286 +no286MSG db 'Sorry, this program requires a 286 or better.', 13, 10 +lgth_no286MSG equ $ - no286MSG +; JAB - End of modifications + +; +; Interrupt vector save areas +; +; Interrupt vectors 0,4,5 & 6 are saved at startup and then restored +; when the program terminates. The signal/raise functions might +; steal these vectors during execution. +; +; Note: These vectors save area must not be altered +; without changing the save/restore logic. +; +PubSym@ _Int0Vector
, __CDECL__ +PubSym@ _Int4Vector
, __CDECL__ +PubSym@ _Int5Vector
, __CDECL__ +PubSym@ _Int6Vector
, __CDECL__ +; +; Miscellaneous variables +; +PubSym@ _C0argc, , __CDECL__ +dPtrPub@ _C0argv, 0, __CDECL__ +dPtrPub@ _C0environ, 0, __CDECL__ +PubSym@ _envLng, , __CDECL__ +PubSym@ _envseg, , __CDECL__ +PubSym@ _envSize, , __CDECL__ +PubSym@ _psp, , __CDECL__ +PubSym@ _version,
, __CDECL__ +PubSym@ _brklvl,
, __CDECL__ +PubSym@ _heaptop,
, __CDECL__ + +; If stack in DS and Large data model then override location of __emu + +IFDEF _DSSTACK_ +IF LDATA +public __emu +__emu db 044h DUP (0) + db 0CCh DUP (?) +ENDIF +ENDIF + +_DATA ENDS + + +_CVTSEG SEGMENT +PubSym@ _RealCvtVector,
, sName + ENDM + +dPtrPub@ MACRO Sym, VALUE, sName ;; Global Data Pointer +PubSym@ Sym,
, sName + ENDM + +dPtrExt@ MACRO Sym, sName ;; External Data Pointer +ExtSym@ Sym, DWORD, sName + ENDM +ELSE +DPTR_ equ WORD PTR +dPtrSize equ 2 +LES_ equ MOV +ES_ equ DS: +SS_ equ DS: +LDS_ equ MOV + +pushDS_ MACRO + ENDM + +popDS_ MACRO + ENDM + +PushPtr MACRO dPtrOff, dPtrSeg + PUSH dPtrOff + ENDM + +dPtr@ MACRO Sym, VALUE, sName ;; Static Data pointer +Static@ Sym, , sName + ENDM + +dPtrPub@ MACRO Sym, VALUE, sName ;; Global Data Pointer +PubSym@ Sym, , sName + ENDM + +dPtrExt@ MACRO Sym, sName ;; External Data Pointer +ExtSym@ Sym, WORD, sName + ENDM +ENDIF + PAGE +;[]------------------------------------------------------------[] +;| | +;| Macros which are Code Size Dependent | +;| | +;[]------------------------------------------------------------[] + +IF LPROG +CPTR_ equ DWORD PTR +cPtrSize equ 4 + +Proc@ MACRO Sym, sName ;; Open a Static function +Static@ Sym, , sName + ENDM + +PubProc@ MACRO Sym, sName ;; Open a Public function +PubSym@ Sym, , sName + ENDM + +ExtProc@ MACRO Sym, sName ;; External Function +ExtSym@ Sym, FAR, sName + ENDM + +cPtr@ MACRO Sym, VALUE, sName ;; Static Function pointer +Static@ Sym,
, sName + ENDM + +cPtrPub@ MACRO Sym, VALUE, sName;; Global Function Pointer +PubSym@ Sym,
, sName + ENDM + +cPtrExt@ MACRO Sym, sName ;; External Function Pointer +ExtSym@ Sym, DWORD, sName + ENDM +ELSE +CPTR_ equ WORD PTR +cPtrSize equ 2 + +Proc@ MACRO Sym, sName ;; Open a Static function +Static@ Sym, , sName + ENDM + +PubProc@ MACRO Sym, sName ;; Open a Public function +PubSym@ Sym, , sName + ENDM + +ExtProc@ MACRO Sym, sName ;; External Function +ExtSym@ Sym, NEAR, sName + ENDM + +cPtr@ MACRO Sym, VALUE, sName ;; Static Function pointer +Static@ Sym, , sName + ENDM + +cPtrPub@ MACRO Sym, VALUE, sName ;; Global Function Pointer +PubSym@ Sym, , sName + ENDM + +cPtrExt@ MACRO Sym, sName ;; External Function Pointer +ExtSym@ Sym, WORD, sName + ENDM +ENDIF + +EndProc@ MACRO Sym, sName ;; Close a function +Static@ Sym, ENDP, sName + ENDM + + PAGE +;[]------------------------------------------------------------[] +;| | +;| Miscellaneous Definitions | +;| | +;[]------------------------------------------------------------[] + +;*** Set up some macros for procedure parameters and export/import + +nearCall STRUC +nearBP dw ? +nearIP dw ? +nearParam dw ? +nearCall ENDS + +farCall STRUC +farBP dw ? +farCSIP dd ? +aParam dw ? +farCall ENDS + +;*** Next, we define some convenient structures to access the parts +; of larger objects. + +_twoBytes STRUC +BY0 db ? +BY1 db ? +_twoBytes ENDS + +_fourWords STRUC +W0 dw ? +W1 dw ? +W2 dw ? +W3 dw ? +_fourWords ENDS + +_twoDwords STRUC +DD0 dd ? +DD1 dd ? +_twoDwords ENDS + +_aFloat STRUC +double dq ? +_aFloat ENDS + +; How to invoke MSDOS. + +MSDOS@ MACRO + int 21h + ENDM + PAGE + +; The next section concerns the use of registers. SI and DI are used +; for register variables, and must be conserved. + +; Registers AX, BX, CX, DX will not be preserved across function calls. + +; Firstly, the registers to be conserved through function calls, including +; the setup of local variables. + +link@ MACRO _si,_di,_ES,locals + push bp + mov bp, sp + IFNB + lea sp, locals + ENDIF + IFNB <_si> + push si + ENDIF + IFNB <_di> + push di + ENDIF +ENDM + +unLink@ MACRO _si,_di,_ES,locals + IFNB <_di> + pop di + ENDIF + IFNB <_si> + pop si + ENDIF + IFNB + mov sp, bp + ENDIF + pop bp +ENDM + +.LIST diff --git a/16/WOLFSRC/SDMVER.H b/16/WOLFSRC/SDMVER.H new file mode 100755 index 00000000..e5f48728 --- /dev/null +++ b/16/WOLFSRC/SDMVER.H @@ -0,0 +1,8 @@ +#define SPEAR +#define SPEARDEMO +#define ARTSEXTERN +#define DEMOSEXTERN +#define CARMACIZED +//#define MYPROFILE +//#define DEBCHECK +//#define UPLOAD diff --git a/16/WOLFSRC/SHAREMSG.H b/16/WOLFSRC/SHAREMSG.H new file mode 100755 index 00000000..39c27974 --- /dev/null +++ b/16/WOLFSRC/SHAREMSG.H @@ -0,0 +1,9 @@ +"This game is shareware.\n" +"Share it with everyone.\n" +"Thanks.\n\n" +" Id Software\n" + +"This game is NOT shareware.\n" +"Please do not distribute it.\n" +"Thanks.\n\n" +" Id Software\n" diff --git a/16/WOLFSRC/SODVER.H b/16/WOLFSRC/SODVER.H new file mode 100755 index 00000000..b964b80b --- /dev/null +++ b/16/WOLFSRC/SODVER.H @@ -0,0 +1,7 @@ +#define SPEAR +#define ARTSEXTERN +#define DEMOSEXTERN +#define CARMACIZED +//#define MYPROFILE +//#define DEBCHECK +//#define UPLOAD diff --git a/16/WOLFSRC/SPANISH.H b/16/WOLFSRC/SPANISH.H new file mode 100755 index 00000000..361ca499 --- /dev/null +++ b/16/WOLFSRC/SPANISH.H @@ -0,0 +1,112 @@ +#define QUITSUR "Estas seguro que quieres\n"\ + "parar este gran juego?" + +#define CURGAME "Ahora estas en\n"\ + "un juego. Si continuas\n"\ + "borras el juego viejo. O.K.?" + +#define GAMESVD "Ya hay un juego\n"\ + "guardado en esta posicion.\n"\ + "sobre-escribir?" + +#define ENDGAMESTR "Estas seguro que quieres\n"\ + "terminar el juego que\n"\ + "estas jugando? (S o N):" + +#define STR_NG "Juego nuevo" +#define STR_SD "Sonido" +#define STR_CL "Control" +#define STR_LG "Cargar juego" +#define STR_SG "Guardar juego" +#define STR_CV "Cambiar vista" +#define STR_VS "Ver anotacion" +#define STR_EG "Abandonar" +#define STR_BD "Regresar al demo" +#define STR_QT "Parar" + +#define STR_LOADING "Cargando" +#define STR_SAVING "Guardando" + +#define STR_GAME "Regresar, jugar" +#define STR_DEMO "Regresar al Demo" +#define STR_LGC "Cargar juego llamado\n\"" +#define STR_EMPTY "vacio" +#define STR_CALIB "Calibrar" +#define STR_JOYST "Joystick" +#define STR_MOVEJOY "Mover joystick a\n"\ + "arriba izq y\n"\ + "oprimir boton 0\n" +#define STR_MOVEJOY2 "Mover joystick a\n"\ + "abajo derecha y\n"\ + "oprimir boton 1\n" +#define STR_ESCEXIT "ESC para salir" +#define STR_NONE "Ninguno" +#define STR_PC "P.C. bocina" +#define STR_ALSB "AdLib/Sound Blaster" +#define STR_DISNEY "Disney Sound Source" +#define STR_SB "Sound Blaster" + +#define STR_MOUSEEN "Raton activado" +#define STR_JOYEN "Joystick activado" +#define STR_PORT2 "Use joystick puerto 2" +#define STR_GAMEPAD "Gravis Gamepad Activada" +#define STR_SENS "Raton Sensibilidad" +#define STR_CUSTOM "Modificar controles" +#define STR_DADDY "Papi puedo jugar?" +#define STR_HURTME "No me hieras." +#define STR_BRINGEM "­Echamelos!" +#define STR_DEATH "La muerte encarnada" + +#define STR_MOUSEADJ "Raton ajustar sensibilidad" +#define STR_SLOW "Lento" +#define STR_FAST "Rapido" + +#define STR_CRUN "Corre" +#define STR_COPEN "Abre" +#define STR_CFIRE "Fuego" +#define STR_CSTRAFE "Ametrallar" + +#define STR_LEFT "Izquierda" +#define STR_RIGHT "Derecha" +#define STR_FRWD "Adelante" +#define STR_BKWD "Atras" +#define STR_THINK "Pensando" + +#define STR_SIZE1 "Use flechas para ajustar" +#define STR_SIZE2 "Enter para aceptar" +#define STR_SIZE3 "Esc para cancelar" + +#define STR_YOUWIN "Tu ganas" + +#define STR_TOTALTIME "Tiempo total" + +#define STR_RATKILL "Muertes %" +#define STR_RATSECRET "Secreto %" +#define STR_RATTREASURE "Tesoros %" + +#define STR_BONUS "Bono" +#define STR_TIME "Tiempo" +#define STR_PAR "Par" + +#define STR_RAT2KILL "Muertes %" // ratio = promedio +#define STR_RAT2SECRET "Secreto %" +#define STR_RAT2TREASURE "Tesoros %" + +#define STR_DEFEATED "Derrotado!" + +#define STR_CHEATER1 "Ahora tienes 100% salud" +#define STR_CHEATER2 "99 balas y dos llaves" +#define STR_CHEATER3 "Notar que has basicamente" +#define STR_CHEATER4 "eliminado tus chances de" +#define STR_CHEATER5 "obtener puntos altos" + +#define STR_NOSPACE1 "No hay suficiente espacio" +#define STR_NOSPACE2 "en tu disco para guardar juego" + +#define STR_SAVECHT1 "Tu archivo para guardar juego es" +#define STR_SAVECHT2 "diremos,\"corrupto\"." +#define STR_SAVECHT3 "Pero te dire, sigue y" +#define STR_SAVECHT4 "de todos modos juega" + +#define STR_SEEAGAIN "Veamos eso de nuevo" + diff --git a/16/WOLFSRC/SPANVER.H b/16/WOLFSRC/SPANVER.H new file mode 100755 index 00000000..b0f3f62b --- /dev/null +++ b/16/WOLFSRC/SPANVER.H @@ -0,0 +1,8 @@ +//#define SPEAR +#define SPANISH +#define ARTSEXTERN +#define DEMOSEXTERN +//#define MYPROFILE +//#define DEBCHECK +#define CARMACIZED +//#define UPLOAD diff --git a/16/WOLFSRC/SV.EXE b/16/WOLFSRC/SV.EXE new file mode 100755 index 0000000000000000000000000000000000000000..72d3ff022660dc7c8740c9a819fd7559621977cf GIT binary patch literal 6746 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 literal 0 HcmV?d00001 diff --git a/16/WOLFSRC/VERSION.H b/16/WOLFSRC/VERSION.H new file mode 100755 index 00000000..05abb0e5 --- /dev/null +++ b/16/WOLFSRC/VERSION.H @@ -0,0 +1,10 @@ +//#define SPEAR +//#define JAPAN +#define GOODTIMES +#define ARTSEXTERN +#define DEMOSEXTERN +//#define MYPROFILE +//#define DEBCHECK +#define CARMACIZED +//#define UPLOAD + \ No newline at end of file diff --git a/16/WOLFSRC/WHACK_A.ASM b/16/WOLFSRC/WHACK_A.ASM new file mode 100755 index 00000000..45fd0980 --- /dev/null +++ b/16/WOLFSRC/WHACK_A.ASM @@ -0,0 +1,112 @@ +; WOLFHACK.ASM + +.386C +IDEAL +MODEL MEDIUM,C + + +;============================================================================ + +DATASEG + +EXTRN mr_rowofs:WORD +EXTRN mr_count:WORD +EXTRN mr_xstep:WORD +EXTRN mr_ystep:WORD +EXTRN mr_xfrac:WORD +EXTRN mr_yfrac:WORD +EXTRN mr_dest:WORD + +FARDATA + +planepics db 8192 dup(?) ; // 4k of ceiling, 4k of floor +PUBLIC planepics + + +;============================================================================ + +CODESEG + +;============================ +; +; MapRow +; +; +;============================ + +PROC MapRow +PUBLIC MapRow + push esi + push edi + push ebp + push ds + + mov bp,[mr_rowofs] + mov cx,[mr_count] + mov dx,[mr_ystep] + ;begin 8086 hack + ;shl edx,16 + push cx + mov cl,16 + shl edx,cl + pop cx + ;end 8086 hack + mov dx,[mr_xstep] + mov si,[mr_yfrac] + ;begin 8086 hack + ;shl esi,16 + push cx + mov cl,16 + shl esi,cl + pop cx + ;end 8086 hack + mov si,[mr_xfrac] + mov di,[mr_dest] + mov ax,SEG planepics + mov ds,ax + mov ax,0a000h + mov es,ax + mov ax,1111111111110b + +; eax color lookup +; ebx scratch offset and pixel values +; ecx loop counter +; edx packed x / y step values +; esi packed x / y fractional values +; edi write pointer +; ebp toprow to bottomrow delta +; es: screenseg +; ds: pictures + +; mov al,[esi] +; mov al,[eax] +; mov [edi],al + +; mov ax,[_variable+ebx+2] + + +pixelloop: + shld ebx,esi,22 ; shift y units in + shld ebx,esi,7 ; shift x units in and one extra bit + and bx,63*65*2 ; mask off extra top bits and 0 low bit + add esi,edx ; position += step + mov al,[bx] + mov al,[eax] + mov [es:di],al ; write ceiling pixel + mov al,[bx+1] + mov al,[eax] + mov [es:di+bp],al ; write floor pixel + inc di + loop pixelloop + + pop ds + pop ebp + pop edi + pop esi + + retf + +ENDP + +END + diff --git a/16/WOLFSRC/WLFJ1VER.H b/16/WOLFSRC/WLFJ1VER.H new file mode 100755 index 00000000..13e1340b --- /dev/null +++ b/16/WOLFSRC/WLFJ1VER.H @@ -0,0 +1,9 @@ +//#define SPEAR +#define JAPAN +#define JAPDEMO +#define UPLOAD +#define ARTSEXTERN +#define DEMOSEXTERN +//#define MYPROFILE +//#define DEBCHECK +#define CARMACIZED diff --git a/16/WOLFSRC/WL_ACT1.C b/16/WOLFSRC/WL_ACT1.C new file mode 100755 index 00000000..10d84e4e --- /dev/null +++ b/16/WOLFSRC/WL_ACT1.C @@ -0,0 +1,900 @@ +// WL_ACT1.C + +#include "WL_DEF.H" +#pragma hdrstop + +/* +============================================================================= + + STATICS + +============================================================================= +*/ + + +statobj_t statobjlist[MAXSTATS],*laststatobj; + + +struct +{ + int picnum; + stat_t type; +} statinfo[] = +{ +{SPR_STAT_0}, // puddle spr1v +{SPR_STAT_1,block}, // Green Barrel " +{SPR_STAT_2,block}, // Table/chairs " +{SPR_STAT_3,block}, // Floor lamp " +{SPR_STAT_4}, // Chandelier " +{SPR_STAT_5,block}, // Hanged man " +{SPR_STAT_6,bo_alpo}, // Bad food " +{SPR_STAT_7,block}, // Red pillar " +// +// NEW PAGE +// +{SPR_STAT_8,block}, // Tree spr2v +{SPR_STAT_9}, // Skeleton flat " +{SPR_STAT_10,block}, // Sink " (SOD:gibs) +{SPR_STAT_11,block}, // Potted plant " +{SPR_STAT_12,block}, // Urn " +{SPR_STAT_13,block}, // Bare table " +{SPR_STAT_14}, // Ceiling light " +#ifndef SPEAR +{SPR_STAT_15}, // Kitchen stuff " +#else +{SPR_STAT_15,block}, // Gibs! +#endif +// +// NEW PAGE +// +{SPR_STAT_16,block}, // suit of armor spr3v +{SPR_STAT_17,block}, // Hanging cage " +{SPR_STAT_18,block}, // SkeletoninCage " +{SPR_STAT_19}, // Skeleton relax " +{SPR_STAT_20,bo_key1}, // Key 1 " +{SPR_STAT_21,bo_key2}, // Key 2 " +{SPR_STAT_22,block}, // stuff (SOD:gibs) +{SPR_STAT_23}, // stuff +// +// NEW PAGE +// +{SPR_STAT_24,bo_food}, // Good food spr4v +{SPR_STAT_25,bo_firstaid}, // First aid " +{SPR_STAT_26,bo_clip}, // Clip " +{SPR_STAT_27,bo_machinegun}, // Machine gun " +{SPR_STAT_28,bo_chaingun}, // Gatling gun " +{SPR_STAT_29,bo_cross}, // Cross " +{SPR_STAT_30,bo_chalice}, // Chalice " +{SPR_STAT_31,bo_bible}, // Bible " +// +// NEW PAGE +// +{SPR_STAT_32,bo_crown}, // crown spr5v +{SPR_STAT_33,bo_fullheal}, // one up " +{SPR_STAT_34,bo_gibs}, // gibs " +{SPR_STAT_35,block}, // barrel " +{SPR_STAT_36,block}, // well " +{SPR_STAT_37,block}, // Empty well " +{SPR_STAT_38,bo_gibs}, // Gibs 2 " +{SPR_STAT_39,block}, // flag " +// +// NEW PAGE +// +#ifndef SPEAR +{SPR_STAT_40,block}, // Call Apogee spr7v +#else +{SPR_STAT_40}, // Red light +#endif +// +// NEW PAGE +// +{SPR_STAT_41}, // junk " +{SPR_STAT_42}, // junk " +{SPR_STAT_43}, // junk " +#ifndef SPEAR +{SPR_STAT_44}, // pots " +#else +{SPR_STAT_44,block}, // Gibs! +#endif +{SPR_STAT_45,block}, // stove " (SOD:gibs) +{SPR_STAT_46,block}, // spears " (SOD:gibs) +{SPR_STAT_47}, // vines " +// +// NEW PAGE +// +#ifdef SPEAR +{SPR_STAT_48,block}, // marble pillar +{SPR_STAT_49,bo_25clip}, // bonus 25 clip +{SPR_STAT_50,block}, // truck +{SPR_STAT_51,bo_spear}, // SPEAR OF DESTINY! +#endif + +{SPR_STAT_26,bo_clip2}, // Clip " +{-1} // terminator +}; + +/* +=============== += += InitStaticList += +=============== +*/ + +void InitStaticList (void) +{ + laststatobj = &statobjlist[0]; +} + + + +/* +=============== += += SpawnStatic += +=============== +*/ + +void SpawnStatic (int tilex, int tiley, int type) +{ + laststatobj->shapenum = statinfo[type].picnum; + laststatobj->tilex = tilex; + laststatobj->tiley = tiley; + laststatobj->visspot = &spotvis[tilex][tiley]; + + switch (statinfo[type].type) + { + case block: + (unsigned)actorat[tilex][tiley] = 1; // consider it a blocking tile + case dressing: + laststatobj->flags = 0; + break; + + case bo_cross: + case bo_chalice: + case bo_bible: + case bo_crown: + case bo_fullheal: + if (!loadedgame) + gamestate.treasuretotal++; + + case bo_firstaid: + case bo_key1: + case bo_key2: + case bo_key3: + case bo_key4: + case bo_clip: + case bo_25clip: + case bo_machinegun: + case bo_chaingun: + case bo_food: + case bo_alpo: + case bo_gibs: + case bo_spear: + laststatobj->flags = FL_BONUS; + laststatobj->itemnumber = statinfo[type].type; + break; + } + + laststatobj++; + + if (laststatobj == &statobjlist[MAXSTATS]) + Quit ("Too many static objects!\n"); +} + + +/* +=============== += += PlaceItemType += += Called during game play to drop actors' items. It finds the proper += item number based on the item type (bo_???). If there are no free item += spots, nothing is done. += +=============== +*/ + +void PlaceItemType (int itemtype, int tilex, int tiley) +{ + int type; + statobj_t *spot; + +// +// find the item number +// + for (type=0 ; ; type++) + { + if (statinfo[type].picnum == -1) // end of list + Quit ("PlaceItemType: couldn't find type!"); + if (statinfo[type].type == itemtype) + break; + } + +// +// find a spot in statobjlist to put it in +// + for (spot=&statobjlist[0] ; ; spot++) + { + if (spot==laststatobj) + { + if (spot == &statobjlist[MAXSTATS]) + return; // no free spots + laststatobj++; // space at end + break; + } + + if (spot->shapenum == -1) // -1 is a free spot + break; + } +// +// place it +// + spot->shapenum = statinfo[type].picnum; + spot->tilex = tilex; + spot->tiley = tiley; + spot->visspot = &spotvis[tilex][tiley]; + spot->flags = FL_BONUS; + spot->itemnumber = statinfo[type].type; +} + + + +/* +============================================================================= + + DOORS + +doorobjlist[] holds most of the information for the doors + +doorposition[] holds the amount the door is open, ranging from 0 to 0xffff + this is directly accessed by AsmRefresh during rendering + +The number of doors is limited to 64 because a spot in tilemap holds the + door number in the low 6 bits, with the high bit meaning a door center + and bit 6 meaning a door side tile + +Open doors conect two areas, so sounds will travel between them and sight + will be checked when the player is in a connected area. + +Areaconnect is incremented/decremented by each door. If >0 they connect + +Every time a door opens or closes the areabyplayer matrix gets recalculated. + An area is true if it connects with the player's current spor. + +============================================================================= +*/ + +#define DOORWIDTH 0x7800 +#define OPENTICS 300 + +doorobj_t doorobjlist[MAXDOORS],*lastdoorobj; +int doornum; + +unsigned doorposition[MAXDOORS]; // leading edge of door 0=closed + // 0xffff = fully open + +byte far areaconnect[NUMAREAS][NUMAREAS]; + +boolean areabyplayer[NUMAREAS]; + + +/* +============== += += ConnectAreas += += Scans outward from playerarea, marking all connected areas += +============== +*/ + +void RecursiveConnect (int areanumber) +{ + int i; + + for (i=0;iareanumber] = true; + RecursiveConnect (player->areanumber); +} + + +void InitAreas (void) +{ + memset (areabyplayer,0,sizeof(areabyplayer)); + areabyplayer[player->areanumber] = true; +} + + + +/* +=============== += += InitDoorList += +=============== +*/ + +void InitDoorList (void) +{ + memset (areabyplayer,0,sizeof(areabyplayer)); + _fmemset (areaconnect,0,sizeof(areaconnect)); + + lastdoorobj = &doorobjlist[0]; + doornum = 0; +} + + +/* +=============== += += SpawnDoor += +=============== +*/ + +void SpawnDoor (int tilex, int tiley, boolean vertical, int lock) +{ + int areanumber; + unsigned far *map; + + if (doornum==64) + Quit ("64+ doors on level!"); + + doorposition[doornum] = 0; // doors start out fully closed + lastdoorobj->tilex = tilex; + lastdoorobj->tiley = tiley; + lastdoorobj->vertical = vertical; + lastdoorobj->lock = lock; + lastdoorobj->action = dr_closed; + + (unsigned)actorat[tilex][tiley] = doornum | 0x80; // consider it a solid wall + +// +// make the door tile a special tile, and mark the adjacent tiles +// for door sides +// + tilemap[tilex][tiley] = doornum | 0x80; + map = mapsegs[0] + farmapylookup[tiley]+tilex; + if (vertical) + { + *map = *(map-1); // set area number + tilemap[tilex][tiley-1] |= 0x40; + tilemap[tilex][tiley+1] |= 0x40; + } + else + { + *map = *(map-mapwidth); // set area number + tilemap[tilex-1][tiley] |= 0x40; + tilemap[tilex+1][tiley] |= 0x40; + } + + doornum++; + lastdoorobj++; +} + +//=========================================================================== + +/* +===================== += += OpenDoor += +===================== +*/ + +void OpenDoor (int door) +{ + if (doorobjlist[door].action == dr_open) + doorobjlist[door].ticcount = 0; // reset open time + else + doorobjlist[door].action = dr_opening; // start it opening +} + + +/* +===================== += += CloseDoor += +===================== +*/ + +void CloseDoor (int door) +{ + int tilex,tiley,area; + objtype *check; + +// +// don't close on anything solid +// + tilex = doorobjlist[door].tilex; + tiley = doorobjlist[door].tiley; + + if (actorat[tilex][tiley]) + return; + + if (player->tilex == tilex && player->tiley == tiley) + return; + + if (doorobjlist[door].vertical) + { + if ( player->tiley == tiley ) + { + if ( ((player->x+MINDIST) >>TILESHIFT) == tilex ) + return; + if ( ((player->x-MINDIST) >>TILESHIFT) == tilex ) + return; + } + check = actorat[tilex-1][tiley]; + if (check && ((check->x+MINDIST) >> TILESHIFT) == tilex ) + return; + check = actorat[tilex+1][tiley]; + if (check && ((check->x-MINDIST) >> TILESHIFT) == tilex ) + return; + } + else if (!doorobjlist[door].vertical) + { + if (player->tilex == tilex) + { + if ( ((player->y+MINDIST) >>TILESHIFT) == tiley ) + return; + if ( ((player->y-MINDIST) >>TILESHIFT) == tiley ) + return; + } + check = actorat[tilex][tiley-1]; + if (check && ((check->y+MINDIST) >> TILESHIFT) == tiley ) + return; + check = actorat[tilex][tiley+1]; + if (check && ((check->y-MINDIST) >> TILESHIFT) == tiley ) + return; + } + + +// +// play door sound if in a connected area +// + area = *(mapsegs[0] + farmapylookup[doorobjlist[door].tiley] + +doorobjlist[door].tilex)-AREATILE; + if (areabyplayer[area]) + { + PlaySoundLocTile(CLOSEDOORSND,doorobjlist[door].tilex,doorobjlist[door].tiley); // JAB + } + + doorobjlist[door].action = dr_closing; +// +// make the door space solid +// + (unsigned)actorat[tilex][tiley] + = door | 0x80; +} + + + +/* +===================== += += OperateDoor += += The player wants to change the door's direction += +===================== +*/ + +void OperateDoor (int door) +{ + int lock; + + lock = doorobjlist[door].lock; + if (lock >= dr_lock1 && lock <= dr_lock4) + { + if ( ! (gamestate.keys & (1 << (lock-dr_lock1) ) ) ) + { + SD_PlaySound (NOWAYSND); // locked + return; + } + } + + switch (doorobjlist[door].action) + { + case dr_closed: + case dr_closing: + OpenDoor (door); + break; + case dr_open: + case dr_opening: + CloseDoor (door); + break; + } +} + + +//=========================================================================== + +/* +=============== += += DoorOpen += += Close the door after three seconds += +=============== +*/ + +void DoorOpen (int door) +{ + if ( (doorobjlist[door].ticcount += tics) >= OPENTICS) + CloseDoor (door); +} + + + +/* +=============== += += DoorOpening += +=============== +*/ + +void DoorOpening (int door) +{ + int area1,area2; + unsigned far *map; + long position; + + position = doorposition[door]; + if (!position) + { + // + // door is just starting to open, so connect the areas + // + map = mapsegs[0] + farmapylookup[doorobjlist[door].tiley] + +doorobjlist[door].tilex; + + if (doorobjlist[door].vertical) + { + area1 = *(map+1); + area2 = *(map-1); + } + else + { + area1 = *(map-mapwidth); + area2 = *(map+mapwidth); + } + area1 -= AREATILE; + area2 -= AREATILE; + areaconnect[area1][area2]++; + areaconnect[area2][area1]++; + ConnectAreas (); + if (areabyplayer[area1]) + { + PlaySoundLocTile(OPENDOORSND,doorobjlist[door].tilex,doorobjlist[door].tiley); // JAB + } + } + +// +// slide the door by an adaptive amount +// + position += tics<<10; + if (position >= 0xffff) + { + // + // door is all the way open + // + position = 0xffff; + doorobjlist[door].ticcount = 0; + doorobjlist[door].action = dr_open; + actorat[doorobjlist[door].tilex][doorobjlist[door].tiley] = 0; + } + + doorposition[door] = position; +} + + +/* +=============== += += DoorClosing += +=============== +*/ + +void DoorClosing (int door) +{ + int area1,area2,move; + unsigned far *map; + long position; + int tilex,tiley; + + tilex = doorobjlist[door].tilex; + tiley = doorobjlist[door].tiley; + + if ( ((unsigned)actorat[tilex][tiley] != (door | 0x80)) + || (player->tilex == tilex && player->tiley == tiley) ) + { // something got inside the door + OpenDoor (door); + return; + }; + + position = doorposition[door]; + +// +// slide the door by an adaptive amount +// + position -= tics<<10; + if (position <= 0) + { + // + // door is closed all the way, so disconnect the areas + // + position = 0; + + doorobjlist[door].action = dr_closed; + + map = mapsegs[0] + farmapylookup[doorobjlist[door].tiley] + +doorobjlist[door].tilex; + + if (doorobjlist[door].vertical) + { + area1 = *(map+1); + area2 = *(map-1); + } + else + { + area1 = *(map-mapwidth); + area2 = *(map+mapwidth); + } + area1 -= AREATILE; + area2 -= AREATILE; + areaconnect[area1][area2]--; + areaconnect[area2][area1]--; + + ConnectAreas (); + } + + doorposition[door] = position; +} + + + + +/* +===================== += += MoveDoors += += Called from PlayLoop += +===================== +*/ + +void MoveDoors (void) +{ + int door; + + if (gamestate.victoryflag) // don't move door during victory sequence + return; + + for (door = 0 ; door < doornum ; door++) + switch (doorobjlist[door].action) + { + case dr_open: + DoorOpen (door); + break; + + case dr_opening: + DoorOpening(door); + break; + + case dr_closing: + DoorClosing(door); + break; + } +} + + +/* +============================================================================= + + PUSHABLE WALLS + +============================================================================= +*/ + +unsigned pwallstate; +unsigned pwallpos; // amount a pushable wall has been moved (0-63) +unsigned pwallx,pwally; +int pwalldir; + +/* +=============== += += PushWall += +=============== +*/ + +void PushWall (int checkx, int checky, int dir) +{ + int oldtile; + + if (pwallstate) + return; + + + oldtile = tilemap[checkx][checky]; + if (!oldtile) + return; + + switch (dir) + { + case di_north: + if (actorat[checkx][checky-1]) + { + SD_PlaySound (NOWAYSND); + return; + } + (unsigned)actorat[checkx][checky-1] = + tilemap[checkx][checky-1] = oldtile; + break; + + case di_east: + if (actorat[checkx+1][checky]) + { + SD_PlaySound (NOWAYSND); + return; + } + (unsigned)actorat[checkx+1][checky] = + tilemap[checkx+1][checky] = oldtile; + break; + + case di_south: + if (actorat[checkx][checky+1]) + { + SD_PlaySound (NOWAYSND); + return; + } + (unsigned)actorat[checkx][checky+1] = + tilemap[checkx][checky+1] = oldtile; + break; + + case di_west: + if (actorat[checkx-1][checky]) + { + SD_PlaySound (NOWAYSND); + return; + } + (unsigned)actorat[checkx-1][checky] = + tilemap[checkx-1][checky] = oldtile; + break; + } + + gamestate.secretcount++; + pwallx = checkx; + pwally = checky; + pwalldir = dir; + pwallstate = 1; + pwallpos = 0; + tilemap[pwallx][pwally] |= 0xc0; + *(mapsegs[1]+farmapylookup[pwally]+pwallx) = 0; // remove P tile info + + SD_PlaySound (PUSHWALLSND); +} + + + +/* +================= += += MovePWalls += +================= +*/ + +void MovePWalls (void) +{ + int oldblock,oldtile; + + if (!pwallstate) + return; + + oldblock = pwallstate/128; + + pwallstate += tics; + + if (pwallstate/128 != oldblock) + { + // block crossed into a new block + oldtile = tilemap[pwallx][pwally] & 63; + + // + // the tile can now be walked into + // + tilemap[pwallx][pwally] = 0; + (unsigned)actorat[pwallx][pwally] = 0; + *(mapsegs[0]+farmapylookup[pwally]+pwallx) = player->areanumber+AREATILE; + + // + // see if it should be pushed farther + // + if (pwallstate>256) + { + // + // the block has been pushed two tiles + // + pwallstate = 0; + return; + } + else + { + switch (pwalldir) + { + case di_north: + pwally--; + if (actorat[pwallx][pwally-1]) + { + pwallstate = 0; + return; + } + (unsigned)actorat[pwallx][pwally-1] = + tilemap[pwallx][pwally-1] = oldtile; + break; + + case di_east: + pwallx++; + if (actorat[pwallx+1][pwally]) + { + pwallstate = 0; + return; + } + (unsigned)actorat[pwallx+1][pwally] = + tilemap[pwallx+1][pwally] = oldtile; + break; + + case di_south: + pwally++; + if (actorat[pwallx][pwally+1]) + { + pwallstate = 0; + return; + } + (unsigned)actorat[pwallx][pwally+1] = + tilemap[pwallx][pwally+1] = oldtile; + break; + + case di_west: + pwallx--; + if (actorat[pwallx-1][pwally]) + { + pwallstate = 0; + return; + } + (unsigned)actorat[pwallx-1][pwally] = + tilemap[pwallx-1][pwally] = oldtile; + break; + } + + tilemap[pwallx][pwally] = oldtile | 0xc0; + } + } + + + pwallpos = (pwallstate/2)&63; + +} + diff --git a/16/WOLFSRC/WL_ACT2.C b/16/WOLFSRC/WL_ACT2.C new file mode 100755 index 00000000..d9d99a0b --- /dev/null +++ b/16/WOLFSRC/WL_ACT2.C @@ -0,0 +1,3872 @@ +// WL_ACT2.C + +#include "WL_DEF.H" +#pragma hdrstop + +/* +============================================================================= + + LOCAL CONSTANTS + +============================================================================= +*/ + +#define PROJECTILESIZE 0xc000l + +#define BJRUNSPEED 2048 +#define BJJUMPSPEED 680 + + +/* +============================================================================= + + GLOBAL VARIABLES + +============================================================================= +*/ + + + +/* +============================================================================= + + LOCAL VARIABLES + +============================================================================= +*/ + + +dirtype dirtable[9] = {northwest,north,northeast,west,nodir,east, + southwest,south,southeast}; + +int starthitpoints[4][NUMENEMIES] = + // + // BABY MODE + // + { + {25, // guards + 50, // officer + 100, // SS + 1, // dogs + 850, // Hans + 850, // Schabbs + 200, // fake hitler + 800, // mecha hitler + 45, // mutants + 25, // ghosts + 25, // ghosts + 25, // ghosts + 25, // ghosts + + 850, // Gretel + 850, // Gift + 850, // Fat + 5, // en_spectre, + 1450, // en_angel, + 850, // en_trans, + 1050, // en_uber, + 950, // en_will, + 1250 // en_death + }, + // + // DON'T HURT ME MODE + // + {25, // guards + 50, // officer + 100, // SS + 1, // dogs + 950, // Hans + 950, // Schabbs + 300, // fake hitler + 950, // mecha hitler + 55, // mutants + 25, // ghosts + 25, // ghosts + 25, // ghosts + 25, // ghosts + + 950, // Gretel + 950, // Gift + 950, // Fat + 10, // en_spectre, + 1550, // en_angel, + 950, // en_trans, + 1150, // en_uber, + 1050, // en_will, + 1350 // en_death + }, + // + // BRING 'EM ON MODE + // + {25, // guards + 50, // officer + 100, // SS + 1, // dogs + + 1050, // Hans + 1550, // Schabbs + 400, // fake hitler + 1050, // mecha hitler + + 55, // mutants + 25, // ghosts + 25, // ghosts + 25, // ghosts + 25, // ghosts + + 1050, // Gretel + 1050, // Gift + 1050, // Fat + 15, // en_spectre, + 1650, // en_angel, + 1050, // en_trans, + 1250, // en_uber, + 1150, // en_will, + 1450 // en_death + }, + // + // DEATH INCARNATE MODE + // + {25, // guards + 50, // officer + 100, // SS + 1, // dogs + + 1200, // Hans + 2400, // Schabbs + 500, // fake hitler + 1200, // mecha hitler + + 65, // mutants + 25, // ghosts + 25, // ghosts + 25, // ghosts + 25, // ghosts + + 1200, // Gretel + 1200, // Gift + 1200, // Fat + 25, // en_spectre, + 2000, // en_angel, + 1200, // en_trans, + 1400, // en_uber, + 1300, // en_will, + 1600 // en_death + }} + ; + +void A_StartDeathCam (objtype *ob); + + +void T_Path (objtype *ob); +void T_Shoot (objtype *ob); +void T_Bite (objtype *ob); +void T_DogChase (objtype *ob); +void T_Chase (objtype *ob); +void T_Projectile (objtype *ob); +void T_Stand (objtype *ob); + +void A_DeathScream (objtype *ob); + +extern statetype s_rocket; +extern statetype s_smoke1; +extern statetype s_smoke2; +extern statetype s_smoke3; +extern statetype s_smoke4; +extern statetype s_boom2; +extern statetype s_boom3; + +void A_Smoke (objtype *ob); + +statetype s_rocket = {true,SPR_ROCKET_1,3,T_Projectile,A_Smoke,&s_rocket}; +statetype s_smoke1 = {false,SPR_SMOKE_1,3,NULL,NULL,&s_smoke2}; +statetype s_smoke2 = {false,SPR_SMOKE_2,3,NULL,NULL,&s_smoke3}; +statetype s_smoke3 = {false,SPR_SMOKE_3,3,NULL,NULL,&s_smoke4}; +statetype s_smoke4 = {false,SPR_SMOKE_4,3,NULL,NULL,NULL}; + +statetype s_boom1 = {false,SPR_BOOM_1,6,NULL,NULL,&s_boom2}; +statetype s_boom2 = {false,SPR_BOOM_2,6,NULL,NULL,&s_boom3}; +statetype s_boom3 = {false,SPR_BOOM_3,6,NULL,NULL,NULL}; + +#ifdef SPEAR + +extern statetype s_hrocket; +extern statetype s_hsmoke1; +extern statetype s_hsmoke2; +extern statetype s_hsmoke3; +extern statetype s_hsmoke4; +extern statetype s_hboom2; +extern statetype s_hboom3; + +void A_Smoke (objtype *ob); + +statetype s_hrocket = {true,SPR_HROCKET_1,3,T_Projectile,A_Smoke,&s_hrocket}; +statetype s_hsmoke1 = {false,SPR_HSMOKE_1,3,NULL,NULL,&s_hsmoke2}; +statetype s_hsmoke2 = {false,SPR_HSMOKE_2,3,NULL,NULL,&s_hsmoke3}; +statetype s_hsmoke3 = {false,SPR_HSMOKE_3,3,NULL,NULL,&s_hsmoke4}; +statetype s_hsmoke4 = {false,SPR_HSMOKE_4,3,NULL,NULL,NULL}; + +statetype s_hboom1 = {false,SPR_HBOOM_1,6,NULL,NULL,&s_hboom2}; +statetype s_hboom2 = {false,SPR_HBOOM_2,6,NULL,NULL,&s_hboom3}; +statetype s_hboom3 = {false,SPR_HBOOM_3,6,NULL,NULL,NULL}; + +#endif + +void T_Schabb (objtype *ob); +void T_SchabbThrow (objtype *ob); +void T_Fake (objtype *ob); +void T_FakeFire (objtype *ob); +void T_Ghosts (objtype *ob); + +void A_Slurpie (objtype *ob); +void A_HitlerMorph (objtype *ob); +void A_MechaSound (objtype *ob); + +/* +================= += += A_Smoke += +================= +*/ + +void A_Smoke (objtype *ob) +{ + GetNewActor (); +#ifdef SPEAR + if (ob->obclass == hrocketobj) + new->state = &s_hsmoke1; + else +#endif + new->state = &s_smoke1; + new->ticcount = 6; + + new->tilex = ob->tilex; + new->tiley = ob->tiley; + new->x = ob->x; + new->y = ob->y; + new->obclass = inertobj; + new->active = true; + + new->flags = FL_NEVERMARK; +} + + +/* +=================== += += ProjectileTryMove += += returns true if move ok +=================== +*/ + +#define PROJSIZE 0x2000 + +boolean ProjectileTryMove (objtype *ob) +{ + int xl,yl,xh,yh,x,y; + objtype *check; + long deltax,deltay; + + xl = (ob->x-PROJSIZE) >>TILESHIFT; + yl = (ob->y-PROJSIZE) >>TILESHIFT; + + xh = (ob->x+PROJSIZE) >>TILESHIFT; + yh = (ob->y+PROJSIZE) >>TILESHIFT; + +// +// check for solid walls +// + for (y=yl;y<=yh;y++) + for (x=xl;x<=xh;x++) + { + check = actorat[x][y]; + if (check && checkspeed*tics; + + deltax = FixedByFrac(speed,costable[ob->angle]); + deltay = -FixedByFrac(speed,sintable[ob->angle]); + + if (deltax>0x10000l) + deltax = 0x10000l; + if (deltay>0x10000l) + deltay = 0x10000l; + + ob->x += deltax; + ob->y += deltay; + + deltax = LABS(ob->x - player->x); + deltay = LABS(ob->y - player->y); + + if (!ProjectileTryMove (ob)) + { + if (ob->obclass == rocketobj) + { + PlaySoundLocActor(MISSILEHITSND,ob); + ob->state = &s_boom1; + } +#ifdef SPEAR + else if (ob->obclass == hrocketobj) + { + PlaySoundLocActor(MISSILEHITSND,ob); + ob->state = &s_hboom1; + } +#endif + else + ob->state = NULL; // mark for removal + + return; + } + + if (deltax < PROJECTILESIZE && deltay < PROJECTILESIZE) + { // hit the player + switch (ob->obclass) + { + case needleobj: + damage = (US_RndT() >>3) + 20; + break; + case rocketobj: + case hrocketobj: + case sparkobj: + damage = (US_RndT() >>3) + 30; + break; + case fireobj: + damage = (US_RndT() >>3); + break; + } + + TakeDamage (damage,ob); + ob->state = NULL; // mark for removal + return; + } + + ob->tilex = ob->x >> TILESHIFT; + ob->tiley = ob->y >> TILESHIFT; + +} + + + + +/* +============================================================================= + + GUARD + +============================================================================= +*/ + +// +// guards +// + +extern statetype s_grdstand; + +extern statetype s_grdpath1; +extern statetype s_grdpath1s; +extern statetype s_grdpath2; +extern statetype s_grdpath3; +extern statetype s_grdpath3s; +extern statetype s_grdpath4; + +extern statetype s_grdpain; +extern statetype s_grdpain1; + +extern statetype s_grdgiveup; + +extern statetype s_grdshoot1; +extern statetype s_grdshoot2; +extern statetype s_grdshoot3; +extern statetype s_grdshoot4; + +extern statetype s_grdchase1; +extern statetype s_grdchase1s; +extern statetype s_grdchase2; +extern statetype s_grdchase3; +extern statetype s_grdchase3s; +extern statetype s_grdchase4; + +extern statetype s_grddie1; +extern statetype s_grddie1d; +extern statetype s_grddie2; +extern statetype s_grddie3; +extern statetype s_grddie4; + +statetype s_grdstand = {true,SPR_GRD_S_1,0,T_Stand,NULL,&s_grdstand}; + +statetype s_grdpath1 = {true,SPR_GRD_W1_1,20,T_Path,NULL,&s_grdpath1s}; +statetype s_grdpath1s = {true,SPR_GRD_W1_1,5,NULL,NULL,&s_grdpath2}; +statetype s_grdpath2 = {true,SPR_GRD_W2_1,15,T_Path,NULL,&s_grdpath3}; +statetype s_grdpath3 = {true,SPR_GRD_W3_1,20,T_Path,NULL,&s_grdpath3s}; +statetype s_grdpath3s = {true,SPR_GRD_W3_1,5,NULL,NULL,&s_grdpath4}; +statetype s_grdpath4 = {true,SPR_GRD_W4_1,15,T_Path,NULL,&s_grdpath1}; + +statetype s_grdpain = {2,SPR_GRD_PAIN_1,10,NULL,NULL,&s_grdchase1}; +statetype s_grdpain1 = {2,SPR_GRD_PAIN_2,10,NULL,NULL,&s_grdchase1}; + +statetype s_grdshoot1 = {false,SPR_GRD_SHOOT1,20,NULL,NULL,&s_grdshoot2}; +statetype s_grdshoot2 = {false,SPR_GRD_SHOOT2,20,NULL,T_Shoot,&s_grdshoot3}; +statetype s_grdshoot3 = {false,SPR_GRD_SHOOT3,20,NULL,NULL,&s_grdchase1}; + +statetype s_grdchase1 = {true,SPR_GRD_W1_1,10,T_Chase,NULL,&s_grdchase1s}; +statetype s_grdchase1s = {true,SPR_GRD_W1_1,3,NULL,NULL,&s_grdchase2}; +statetype s_grdchase2 = {true,SPR_GRD_W2_1,8,T_Chase,NULL,&s_grdchase3}; +statetype s_grdchase3 = {true,SPR_GRD_W3_1,10,T_Chase,NULL,&s_grdchase3s}; +statetype s_grdchase3s = {true,SPR_GRD_W3_1,3,NULL,NULL,&s_grdchase4}; +statetype s_grdchase4 = {true,SPR_GRD_W4_1,8,T_Chase,NULL,&s_grdchase1}; + +statetype s_grddie1 = {false,SPR_GRD_DIE_1,15,NULL,A_DeathScream,&s_grddie2}; +statetype s_grddie2 = {false,SPR_GRD_DIE_2,15,NULL,NULL,&s_grddie3}; +statetype s_grddie3 = {false,SPR_GRD_DIE_3,15,NULL,NULL,&s_grddie4}; +statetype s_grddie4 = {false,SPR_GRD_DEAD,0,NULL,NULL,&s_grddie4}; + + +#ifndef SPEAR +// +// ghosts +// +extern statetype s_blinkychase1; +extern statetype s_blinkychase2; +extern statetype s_inkychase1; +extern statetype s_inkychase2; +extern statetype s_pinkychase1; +extern statetype s_pinkychase2; +extern statetype s_clydechase1; +extern statetype s_clydechase2; + +statetype s_blinkychase1 = {false,SPR_BLINKY_W1,10,T_Ghosts,NULL,&s_blinkychase2}; +statetype s_blinkychase2 = {false,SPR_BLINKY_W2,10,T_Ghosts,NULL,&s_blinkychase1}; + +statetype s_inkychase1 = {false,SPR_INKY_W1,10,T_Ghosts,NULL,&s_inkychase2}; +statetype s_inkychase2 = {false,SPR_INKY_W2,10,T_Ghosts,NULL,&s_inkychase1}; + +statetype s_pinkychase1 = {false,SPR_PINKY_W1,10,T_Ghosts,NULL,&s_pinkychase2}; +statetype s_pinkychase2 = {false,SPR_PINKY_W2,10,T_Ghosts,NULL,&s_pinkychase1}; + +statetype s_clydechase1 = {false,SPR_CLYDE_W1,10,T_Ghosts,NULL,&s_clydechase2}; +statetype s_clydechase2 = {false,SPR_CLYDE_W2,10,T_Ghosts,NULL,&s_clydechase1}; +#endif + +// +// dogs +// + +extern statetype s_dogpath1; +extern statetype s_dogpath1s; +extern statetype s_dogpath2; +extern statetype s_dogpath3; +extern statetype s_dogpath3s; +extern statetype s_dogpath4; + +extern statetype s_dogjump1; +extern statetype s_dogjump2; +extern statetype s_dogjump3; +extern statetype s_dogjump4; +extern statetype s_dogjump5; + +extern statetype s_dogchase1; +extern statetype s_dogchase1s; +extern statetype s_dogchase2; +extern statetype s_dogchase3; +extern statetype s_dogchase3s; +extern statetype s_dogchase4; + +extern statetype s_dogdie1; +extern statetype s_dogdie1d; +extern statetype s_dogdie2; +extern statetype s_dogdie3; +extern statetype s_dogdead; + +statetype s_dogpath1 = {true,SPR_DOG_W1_1,20,T_Path,NULL,&s_dogpath1s}; +statetype s_dogpath1s = {true,SPR_DOG_W1_1,5,NULL,NULL,&s_dogpath2}; +statetype s_dogpath2 = {true,SPR_DOG_W2_1,15,T_Path,NULL,&s_dogpath3}; +statetype s_dogpath3 = {true,SPR_DOG_W3_1,20,T_Path,NULL,&s_dogpath3s}; +statetype s_dogpath3s = {true,SPR_DOG_W3_1,5,NULL,NULL,&s_dogpath4}; +statetype s_dogpath4 = {true,SPR_DOG_W4_1,15,T_Path,NULL,&s_dogpath1}; + +statetype s_dogjump1 = {false,SPR_DOG_JUMP1,10,NULL,NULL,&s_dogjump2}; +statetype s_dogjump2 = {false,SPR_DOG_JUMP2,10,NULL,T_Bite,&s_dogjump3}; +statetype s_dogjump3 = {false,SPR_DOG_JUMP3,10,NULL,NULL,&s_dogjump4}; +statetype s_dogjump4 = {false,SPR_DOG_JUMP1,10,NULL,NULL,&s_dogjump5}; +statetype s_dogjump5 = {false,SPR_DOG_W1_1,10,NULL,NULL,&s_dogchase1}; + +statetype s_dogchase1 = {true,SPR_DOG_W1_1,10,T_DogChase,NULL,&s_dogchase1s}; +statetype s_dogchase1s = {true,SPR_DOG_W1_1,3,NULL,NULL,&s_dogchase2}; +statetype s_dogchase2 = {true,SPR_DOG_W2_1,8,T_DogChase,NULL,&s_dogchase3}; +statetype s_dogchase3 = {true,SPR_DOG_W3_1,10,T_DogChase,NULL,&s_dogchase3s}; +statetype s_dogchase3s = {true,SPR_DOG_W3_1,3,NULL,NULL,&s_dogchase4}; +statetype s_dogchase4 = {true,SPR_DOG_W4_1,8,T_DogChase,NULL,&s_dogchase1}; + +statetype s_dogdie1 = {false,SPR_DOG_DIE_1,15,NULL,A_DeathScream,&s_dogdie2}; +statetype s_dogdie2 = {false,SPR_DOG_DIE_2,15,NULL,NULL,&s_dogdie3}; +statetype s_dogdie3 = {false,SPR_DOG_DIE_3,15,NULL,NULL,&s_dogdead}; +statetype s_dogdead = {false,SPR_DOG_DEAD,15,NULL,NULL,&s_dogdead}; + + +// +// officers +// + +extern statetype s_ofcstand; + +extern statetype s_ofcpath1; +extern statetype s_ofcpath1s; +extern statetype s_ofcpath2; +extern statetype s_ofcpath3; +extern statetype s_ofcpath3s; +extern statetype s_ofcpath4; + +extern statetype s_ofcpain; +extern statetype s_ofcpain1; + +extern statetype s_ofcgiveup; + +extern statetype s_ofcshoot1; +extern statetype s_ofcshoot2; +extern statetype s_ofcshoot3; +extern statetype s_ofcshoot4; + +extern statetype s_ofcchase1; +extern statetype s_ofcchase1s; +extern statetype s_ofcchase2; +extern statetype s_ofcchase3; +extern statetype s_ofcchase3s; +extern statetype s_ofcchase4; + +extern statetype s_ofcdie1; +extern statetype s_ofcdie2; +extern statetype s_ofcdie3; +extern statetype s_ofcdie4; +extern statetype s_ofcdie5; + +statetype s_ofcstand = {true,SPR_OFC_S_1,0,T_Stand,NULL,&s_ofcstand}; + +statetype s_ofcpath1 = {true,SPR_OFC_W1_1,20,T_Path,NULL,&s_ofcpath1s}; +statetype s_ofcpath1s = {true,SPR_OFC_W1_1,5,NULL,NULL,&s_ofcpath2}; +statetype s_ofcpath2 = {true,SPR_OFC_W2_1,15,T_Path,NULL,&s_ofcpath3}; +statetype s_ofcpath3 = {true,SPR_OFC_W3_1,20,T_Path,NULL,&s_ofcpath3s}; +statetype s_ofcpath3s = {true,SPR_OFC_W3_1,5,NULL,NULL,&s_ofcpath4}; +statetype s_ofcpath4 = {true,SPR_OFC_W4_1,15,T_Path,NULL,&s_ofcpath1}; + +statetype s_ofcpain = {2,SPR_OFC_PAIN_1,10,NULL,NULL,&s_ofcchase1}; +statetype s_ofcpain1 = {2,SPR_OFC_PAIN_2,10,NULL,NULL,&s_ofcchase1}; + +statetype s_ofcshoot1 = {false,SPR_OFC_SHOOT1,6,NULL,NULL,&s_ofcshoot2}; +statetype s_ofcshoot2 = {false,SPR_OFC_SHOOT2,20,NULL,T_Shoot,&s_ofcshoot3}; +statetype s_ofcshoot3 = {false,SPR_OFC_SHOOT3,10,NULL,NULL,&s_ofcchase1}; + +statetype s_ofcchase1 = {true,SPR_OFC_W1_1,10,T_Chase,NULL,&s_ofcchase1s}; +statetype s_ofcchase1s = {true,SPR_OFC_W1_1,3,NULL,NULL,&s_ofcchase2}; +statetype s_ofcchase2 = {true,SPR_OFC_W2_1,8,T_Chase,NULL,&s_ofcchase3}; +statetype s_ofcchase3 = {true,SPR_OFC_W3_1,10,T_Chase,NULL,&s_ofcchase3s}; +statetype s_ofcchase3s = {true,SPR_OFC_W3_1,3,NULL,NULL,&s_ofcchase4}; +statetype s_ofcchase4 = {true,SPR_OFC_W4_1,8,T_Chase,NULL,&s_ofcchase1}; + +statetype s_ofcdie1 = {false,SPR_OFC_DIE_1,11,NULL,A_DeathScream,&s_ofcdie2}; +statetype s_ofcdie2 = {false,SPR_OFC_DIE_2,11,NULL,NULL,&s_ofcdie3}; +statetype s_ofcdie3 = {false,SPR_OFC_DIE_3,11,NULL,NULL,&s_ofcdie4}; +statetype s_ofcdie4 = {false,SPR_OFC_DIE_4,11,NULL,NULL,&s_ofcdie5}; +statetype s_ofcdie5 = {false,SPR_OFC_DEAD,0,NULL,NULL,&s_ofcdie5}; + + +// +// mutant +// + +extern statetype s_mutstand; + +extern statetype s_mutpath1; +extern statetype s_mutpath1s; +extern statetype s_mutpath2; +extern statetype s_mutpath3; +extern statetype s_mutpath3s; +extern statetype s_mutpath4; + +extern statetype s_mutpain; +extern statetype s_mutpain1; + +extern statetype s_mutgiveup; + +extern statetype s_mutshoot1; +extern statetype s_mutshoot2; +extern statetype s_mutshoot3; +extern statetype s_mutshoot4; + +extern statetype s_mutchase1; +extern statetype s_mutchase1s; +extern statetype s_mutchase2; +extern statetype s_mutchase3; +extern statetype s_mutchase3s; +extern statetype s_mutchase4; + +extern statetype s_mutdie1; +extern statetype s_mutdie2; +extern statetype s_mutdie3; +extern statetype s_mutdie4; +extern statetype s_mutdie5; + +statetype s_mutstand = {true,SPR_MUT_S_1,0,T_Stand,NULL,&s_mutstand}; + +statetype s_mutpath1 = {true,SPR_MUT_W1_1,20,T_Path,NULL,&s_mutpath1s}; +statetype s_mutpath1s = {true,SPR_MUT_W1_1,5,NULL,NULL,&s_mutpath2}; +statetype s_mutpath2 = {true,SPR_MUT_W2_1,15,T_Path,NULL,&s_mutpath3}; +statetype s_mutpath3 = {true,SPR_MUT_W3_1,20,T_Path,NULL,&s_mutpath3s}; +statetype s_mutpath3s = {true,SPR_MUT_W3_1,5,NULL,NULL,&s_mutpath4}; +statetype s_mutpath4 = {true,SPR_MUT_W4_1,15,T_Path,NULL,&s_mutpath1}; + +statetype s_mutpain = {2,SPR_MUT_PAIN_1,10,NULL,NULL,&s_mutchase1}; +statetype s_mutpain1 = {2,SPR_MUT_PAIN_2,10,NULL,NULL,&s_mutchase1}; + +statetype s_mutshoot1 = {false,SPR_MUT_SHOOT1,6,NULL,T_Shoot,&s_mutshoot2}; +statetype s_mutshoot2 = {false,SPR_MUT_SHOOT2,20,NULL,NULL,&s_mutshoot3}; +statetype s_mutshoot3 = {false,SPR_MUT_SHOOT3,10,NULL,T_Shoot,&s_mutshoot4}; +statetype s_mutshoot4 = {false,SPR_MUT_SHOOT4,20,NULL,NULL,&s_mutchase1}; + +statetype s_mutchase1 = {true,SPR_MUT_W1_1,10,T_Chase,NULL,&s_mutchase1s}; +statetype s_mutchase1s = {true,SPR_MUT_W1_1,3,NULL,NULL,&s_mutchase2}; +statetype s_mutchase2 = {true,SPR_MUT_W2_1,8,T_Chase,NULL,&s_mutchase3}; +statetype s_mutchase3 = {true,SPR_MUT_W3_1,10,T_Chase,NULL,&s_mutchase3s}; +statetype s_mutchase3s = {true,SPR_MUT_W3_1,3,NULL,NULL,&s_mutchase4}; +statetype s_mutchase4 = {true,SPR_MUT_W4_1,8,T_Chase,NULL,&s_mutchase1}; + +statetype s_mutdie1 = {false,SPR_MUT_DIE_1,7,NULL,A_DeathScream,&s_mutdie2}; +statetype s_mutdie2 = {false,SPR_MUT_DIE_2,7,NULL,NULL,&s_mutdie3}; +statetype s_mutdie3 = {false,SPR_MUT_DIE_3,7,NULL,NULL,&s_mutdie4}; +statetype s_mutdie4 = {false,SPR_MUT_DIE_4,7,NULL,NULL,&s_mutdie5}; +statetype s_mutdie5 = {false,SPR_MUT_DEAD,0,NULL,NULL,&s_mutdie5}; + + +// +// SS +// + +extern statetype s_ssstand; + +extern statetype s_sspath1; +extern statetype s_sspath1s; +extern statetype s_sspath2; +extern statetype s_sspath3; +extern statetype s_sspath3s; +extern statetype s_sspath4; + +extern statetype s_sspain; +extern statetype s_sspain1; + +extern statetype s_ssshoot1; +extern statetype s_ssshoot2; +extern statetype s_ssshoot3; +extern statetype s_ssshoot4; +extern statetype s_ssshoot5; +extern statetype s_ssshoot6; +extern statetype s_ssshoot7; +extern statetype s_ssshoot8; +extern statetype s_ssshoot9; + +extern statetype s_sschase1; +extern statetype s_sschase1s; +extern statetype s_sschase2; +extern statetype s_sschase3; +extern statetype s_sschase3s; +extern statetype s_sschase4; + +extern statetype s_ssdie1; +extern statetype s_ssdie2; +extern statetype s_ssdie3; +extern statetype s_ssdie4; + +statetype s_ssstand = {true,SPR_SS_S_1,0,T_Stand,NULL,&s_ssstand}; + +statetype s_sspath1 = {true,SPR_SS_W1_1,20,T_Path,NULL,&s_sspath1s}; +statetype s_sspath1s = {true,SPR_SS_W1_1,5,NULL,NULL,&s_sspath2}; +statetype s_sspath2 = {true,SPR_SS_W2_1,15,T_Path,NULL,&s_sspath3}; +statetype s_sspath3 = {true,SPR_SS_W3_1,20,T_Path,NULL,&s_sspath3s}; +statetype s_sspath3s = {true,SPR_SS_W3_1,5,NULL,NULL,&s_sspath4}; +statetype s_sspath4 = {true,SPR_SS_W4_1,15,T_Path,NULL,&s_sspath1}; + +statetype s_sspain = {2,SPR_SS_PAIN_1,10,NULL,NULL,&s_sschase1}; +statetype s_sspain1 = {2,SPR_SS_PAIN_2,10,NULL,NULL,&s_sschase1}; + +statetype s_ssshoot1 = {false,SPR_SS_SHOOT1,20,NULL,NULL,&s_ssshoot2}; +statetype s_ssshoot2 = {false,SPR_SS_SHOOT2,20,NULL,T_Shoot,&s_ssshoot3}; +statetype s_ssshoot3 = {false,SPR_SS_SHOOT3,10,NULL,NULL,&s_ssshoot4}; +statetype s_ssshoot4 = {false,SPR_SS_SHOOT2,10,NULL,T_Shoot,&s_ssshoot5}; +statetype s_ssshoot5 = {false,SPR_SS_SHOOT3,10,NULL,NULL,&s_ssshoot6}; +statetype s_ssshoot6 = {false,SPR_SS_SHOOT2,10,NULL,T_Shoot,&s_ssshoot7}; +statetype s_ssshoot7 = {false,SPR_SS_SHOOT3,10,NULL,NULL,&s_ssshoot8}; +statetype s_ssshoot8 = {false,SPR_SS_SHOOT2,10,NULL,T_Shoot,&s_ssshoot9}; +statetype s_ssshoot9 = {false,SPR_SS_SHOOT3,10,NULL,NULL,&s_sschase1}; + +statetype s_sschase1 = {true,SPR_SS_W1_1,10,T_Chase,NULL,&s_sschase1s}; +statetype s_sschase1s = {true,SPR_SS_W1_1,3,NULL,NULL,&s_sschase2}; +statetype s_sschase2 = {true,SPR_SS_W2_1,8,T_Chase,NULL,&s_sschase3}; +statetype s_sschase3 = {true,SPR_SS_W3_1,10,T_Chase,NULL,&s_sschase3s}; +statetype s_sschase3s = {true,SPR_SS_W3_1,3,NULL,NULL,&s_sschase4}; +statetype s_sschase4 = {true,SPR_SS_W4_1,8,T_Chase,NULL,&s_sschase1}; + +statetype s_ssdie1 = {false,SPR_SS_DIE_1,15,NULL,A_DeathScream,&s_ssdie2}; +statetype s_ssdie2 = {false,SPR_SS_DIE_2,15,NULL,NULL,&s_ssdie3}; +statetype s_ssdie3 = {false,SPR_SS_DIE_3,15,NULL,NULL,&s_ssdie4}; +statetype s_ssdie4 = {false,SPR_SS_DEAD,0,NULL,NULL,&s_ssdie4}; + + +#ifndef SPEAR +// +// hans +// +extern statetype s_bossstand; + +extern statetype s_bosschase1; +extern statetype s_bosschase1s; +extern statetype s_bosschase2; +extern statetype s_bosschase3; +extern statetype s_bosschase3s; +extern statetype s_bosschase4; + +extern statetype s_bossdie1; +extern statetype s_bossdie2; +extern statetype s_bossdie3; +extern statetype s_bossdie4; + +extern statetype s_bossshoot1; +extern statetype s_bossshoot2; +extern statetype s_bossshoot3; +extern statetype s_bossshoot4; +extern statetype s_bossshoot5; +extern statetype s_bossshoot6; +extern statetype s_bossshoot7; +extern statetype s_bossshoot8; + + +statetype s_bossstand = {false,SPR_BOSS_W1,0,T_Stand,NULL,&s_bossstand}; + +statetype s_bosschase1 = {false,SPR_BOSS_W1,10,T_Chase,NULL,&s_bosschase1s}; +statetype s_bosschase1s = {false,SPR_BOSS_W1,3,NULL,NULL,&s_bosschase2}; +statetype s_bosschase2 = {false,SPR_BOSS_W2,8,T_Chase,NULL,&s_bosschase3}; +statetype s_bosschase3 = {false,SPR_BOSS_W3,10,T_Chase,NULL,&s_bosschase3s}; +statetype s_bosschase3s = {false,SPR_BOSS_W3,3,NULL,NULL,&s_bosschase4}; +statetype s_bosschase4 = {false,SPR_BOSS_W4,8,T_Chase,NULL,&s_bosschase1}; + +statetype s_bossdie1 = {false,SPR_BOSS_DIE1,15,NULL,A_DeathScream,&s_bossdie2}; +statetype s_bossdie2 = {false,SPR_BOSS_DIE2,15,NULL,NULL,&s_bossdie3}; +statetype s_bossdie3 = {false,SPR_BOSS_DIE3,15,NULL,NULL,&s_bossdie4}; +statetype s_bossdie4 = {false,SPR_BOSS_DEAD,0,NULL,NULL,&s_bossdie4}; + +statetype s_bossshoot1 = {false,SPR_BOSS_SHOOT1,30,NULL,NULL,&s_bossshoot2}; +statetype s_bossshoot2 = {false,SPR_BOSS_SHOOT2,10,NULL,T_Shoot,&s_bossshoot3}; +statetype s_bossshoot3 = {false,SPR_BOSS_SHOOT3,10,NULL,T_Shoot,&s_bossshoot4}; +statetype s_bossshoot4 = {false,SPR_BOSS_SHOOT2,10,NULL,T_Shoot,&s_bossshoot5}; +statetype s_bossshoot5 = {false,SPR_BOSS_SHOOT3,10,NULL,T_Shoot,&s_bossshoot6}; +statetype s_bossshoot6 = {false,SPR_BOSS_SHOOT2,10,NULL,T_Shoot,&s_bossshoot7}; +statetype s_bossshoot7 = {false,SPR_BOSS_SHOOT3,10,NULL,T_Shoot,&s_bossshoot8}; +statetype s_bossshoot8 = {false,SPR_BOSS_SHOOT1,10,NULL,NULL,&s_bosschase1}; + + +// +// gretel +// +extern statetype s_gretelstand; + +extern statetype s_gretelchase1; +extern statetype s_gretelchase1s; +extern statetype s_gretelchase2; +extern statetype s_gretelchase3; +extern statetype s_gretelchase3s; +extern statetype s_gretelchase4; + +extern statetype s_greteldie1; +extern statetype s_greteldie2; +extern statetype s_greteldie3; +extern statetype s_greteldie4; + +extern statetype s_gretelshoot1; +extern statetype s_gretelshoot2; +extern statetype s_gretelshoot3; +extern statetype s_gretelshoot4; +extern statetype s_gretelshoot5; +extern statetype s_gretelshoot6; +extern statetype s_gretelshoot7; +extern statetype s_gretelshoot8; + + +statetype s_gretelstand = {false,SPR_GRETEL_W1,0,T_Stand,NULL,&s_gretelstand}; + +statetype s_gretelchase1 = {false,SPR_GRETEL_W1,10,T_Chase,NULL,&s_gretelchase1s}; +statetype s_gretelchase1s = {false,SPR_GRETEL_W1,3,NULL,NULL,&s_gretelchase2}; +statetype s_gretelchase2 = {false,SPR_GRETEL_W2,8,T_Chase,NULL,&s_gretelchase3}; +statetype s_gretelchase3 = {false,SPR_GRETEL_W3,10,T_Chase,NULL,&s_gretelchase3s}; +statetype s_gretelchase3s = {false,SPR_GRETEL_W3,3,NULL,NULL,&s_gretelchase4}; +statetype s_gretelchase4 = {false,SPR_GRETEL_W4,8,T_Chase,NULL,&s_gretelchase1}; + +statetype s_greteldie1 = {false,SPR_GRETEL_DIE1,15,NULL,A_DeathScream,&s_greteldie2}; +statetype s_greteldie2 = {false,SPR_GRETEL_DIE2,15,NULL,NULL,&s_greteldie3}; +statetype s_greteldie3 = {false,SPR_GRETEL_DIE3,15,NULL,NULL,&s_greteldie4}; +statetype s_greteldie4 = {false,SPR_GRETEL_DEAD,0,NULL,NULL,&s_greteldie4}; + +statetype s_gretelshoot1 = {false,SPR_GRETEL_SHOOT1,30,NULL,NULL,&s_gretelshoot2}; +statetype s_gretelshoot2 = {false,SPR_GRETEL_SHOOT2,10,NULL,T_Shoot,&s_gretelshoot3}; +statetype s_gretelshoot3 = {false,SPR_GRETEL_SHOOT3,10,NULL,T_Shoot,&s_gretelshoot4}; +statetype s_gretelshoot4 = {false,SPR_GRETEL_SHOOT2,10,NULL,T_Shoot,&s_gretelshoot5}; +statetype s_gretelshoot5 = {false,SPR_GRETEL_SHOOT3,10,NULL,T_Shoot,&s_gretelshoot6}; +statetype s_gretelshoot6 = {false,SPR_GRETEL_SHOOT2,10,NULL,T_Shoot,&s_gretelshoot7}; +statetype s_gretelshoot7 = {false,SPR_GRETEL_SHOOT3,10,NULL,T_Shoot,&s_gretelshoot8}; +statetype s_gretelshoot8 = {false,SPR_GRETEL_SHOOT1,10,NULL,NULL,&s_gretelchase1}; +#endif + + +/* +=============== += += SpawnStand += +=============== +*/ + +void SpawnStand (enemy_t which, int tilex, int tiley, int dir) +{ + unsigned far *map,tile; + + switch (which) + { + case en_guard: + SpawnNewObj (tilex,tiley,&s_grdstand); + new->speed = SPDPATROL; + if (!loadedgame) + gamestate.killtotal++; + break; + + case en_officer: + SpawnNewObj (tilex,tiley,&s_ofcstand); + new->speed = SPDPATROL; + if (!loadedgame) + gamestate.killtotal++; + break; + + case en_mutant: + SpawnNewObj (tilex,tiley,&s_mutstand); + new->speed = SPDPATROL; + if (!loadedgame) + gamestate.killtotal++; + break; + + case en_ss: + SpawnNewObj (tilex,tiley,&s_ssstand); + new->speed = SPDPATROL; + if (!loadedgame) + gamestate.killtotal++; + break; + } + + + map = mapsegs[0]+farmapylookup[tiley]+tilex; + if (*map == AMBUSHTILE) + { + tilemap[tilex][tiley] = 0; + + if (*(map+1) >= AREATILE) + tile = *(map+1); + if (*(map-mapwidth) >= AREATILE) + tile = *(map-mapwidth); + if (*(map+mapwidth) >= AREATILE) + tile = *(map+mapwidth); + if ( *(map-1) >= AREATILE) + tile = *(map-1); + + *map = tile; + new->areanumber = tile-AREATILE; + + new->flags |= FL_AMBUSH; + } + + new->obclass = guardobj+which; + new->hitpoints = starthitpoints[gamestate.difficulty][which]; + new->dir = dir*2; + new->flags |= FL_SHOOTABLE; +} + + + +/* +=============== += += SpawnDeadGuard += +=============== +*/ + +void SpawnDeadGuard (int tilex, int tiley) +{ + SpawnNewObj (tilex,tiley,&s_grddie4); + new->obclass = inertobj; +} + + + +#ifndef SPEAR +/* +=============== += += SpawnBoss += +=============== +*/ + +void SpawnBoss (int tilex, int tiley) +{ + unsigned far *map,tile; + + SpawnNewObj (tilex,tiley,&s_bossstand); + new->speed = SPDPATROL; + + new->obclass = bossobj; + new->hitpoints = starthitpoints[gamestate.difficulty][en_boss]; + new->dir = south; + new->flags |= FL_SHOOTABLE|FL_AMBUSH; + if (!loadedgame) + gamestate.killtotal++; +} + +/* +=============== += += SpawnGretel += +=============== +*/ + +void SpawnGretel (int tilex, int tiley) +{ + unsigned far *map,tile; + + SpawnNewObj (tilex,tiley,&s_gretelstand); + new->speed = SPDPATROL; + + new->obclass = gretelobj; + new->hitpoints = starthitpoints[gamestate.difficulty][en_gretel]; + new->dir = north; + new->flags |= FL_SHOOTABLE|FL_AMBUSH; + if (!loadedgame) + gamestate.killtotal++; +} +#endif + +/* +=============== += += SpawnPatrol += +=============== +*/ + +void SpawnPatrol (enemy_t which, int tilex, int tiley, int dir) +{ + switch (which) + { + case en_guard: + SpawnNewObj (tilex,tiley,&s_grdpath1); + new->speed = SPDPATROL; + if (!loadedgame) + gamestate.killtotal++; + break; + + case en_officer: + SpawnNewObj (tilex,tiley,&s_ofcpath1); + new->speed = SPDPATROL; + if (!loadedgame) + gamestate.killtotal++; + break; + + case en_ss: + SpawnNewObj (tilex,tiley,&s_sspath1); + new->speed = SPDPATROL; + if (!loadedgame) + gamestate.killtotal++; + break; + + case en_mutant: + SpawnNewObj (tilex,tiley,&s_mutpath1); + new->speed = SPDPATROL; + if (!loadedgame) + gamestate.killtotal++; + break; + + case en_dog: + SpawnNewObj (tilex,tiley,&s_dogpath1); + new->speed = SPDDOG; + if (!loadedgame) + gamestate.killtotal++; + break; + } + + new->obclass = guardobj+which; + new->dir = dir*2; + new->hitpoints = starthitpoints[gamestate.difficulty][which]; + new->distance = tileglobal; + new->flags |= FL_SHOOTABLE; + new->active = true; + + actorat[new->tilex][new->tiley] = NULL; // don't use original spot + + switch (dir) + { + case 0: + new->tilex++; + break; + case 1: + new->tiley--; + break; + case 2: + new->tilex--; + break; + case 3: + new->tiley++; + break; + } + + actorat[new->tilex][new->tiley] = new; +} + + + +/* +================== += += A_DeathScream += +================== +*/ + +void A_DeathScream (objtype *ob) +{ +#ifndef UPLOAD +#ifndef SPEAR + if (mapon==9 && !US_RndT()) +#else + if ((mapon==18 || mapon==19) && !US_RndT()) +#endif + { + switch(ob->obclass) + { + case mutantobj: + case guardobj: + case officerobj: + case ssobj: + case dogobj: + PlaySoundLocActor(DEATHSCREAM6SND,ob); + return; + } + } +#endif + + switch (ob->obclass) + { + case mutantobj: + PlaySoundLocActor(AHHHGSND,ob); + break; + + case guardobj: + { + int sounds[9]={ DEATHSCREAM1SND, + DEATHSCREAM2SND, + DEATHSCREAM3SND, + DEATHSCREAM4SND, + DEATHSCREAM5SND, + DEATHSCREAM7SND, + DEATHSCREAM8SND, + DEATHSCREAM9SND + }; + + #ifndef UPLOAD + PlaySoundLocActor(sounds[US_RndT()%8],ob); + #else + PlaySoundLocActor(sounds[US_RndT()%2],ob); + #endif + } + break; + case officerobj: + PlaySoundLocActor(NEINSOVASSND,ob); + break; + case ssobj: + PlaySoundLocActor(LEBENSND,ob); // JAB + break; + case dogobj: + PlaySoundLocActor(DOGDEATHSND,ob); // JAB + break; +#ifndef SPEAR + case bossobj: + SD_PlaySound(MUTTISND); // JAB + break; + case schabbobj: + SD_PlaySound(MEINGOTTSND); + break; + case fakeobj: + SD_PlaySound(HITLERHASND); + break; + case mechahitlerobj: + SD_PlaySound(SCHEISTSND); + break; + case realhitlerobj: + SD_PlaySound(EVASND); + break; + case gretelobj: + SD_PlaySound(MEINSND); + break; + case giftobj: + SD_PlaySound(DONNERSND); + break; + case fatobj: + SD_PlaySound(ROSESND); + break; +#else + case spectreobj: + SD_PlaySound(GHOSTFADESND); + break; + case angelobj: + SD_PlaySound(ANGELDEATHSND); + break; + case transobj: + SD_PlaySound(TRANSDEATHSND); + break; + case uberobj: + SD_PlaySound(UBERDEATHSND); + break; + case willobj: + SD_PlaySound(WILHELMDEATHSND); + break; + case deathobj: + SD_PlaySound(KNIGHTDEATHSND); + break; +#endif + } +} + + +/* +============================================================================= + + SPEAR ACTORS + +============================================================================= +*/ + +#ifdef SPEAR + +void T_Launch (objtype *ob); +void T_Will (objtype *ob); + +extern statetype s_angelshoot1; +extern statetype s_deathshoot1; +extern statetype s_spark1; + +// +// trans +// +extern statetype s_transstand; + +extern statetype s_transchase1; +extern statetype s_transchase1s; +extern statetype s_transchase2; +extern statetype s_transchase3; +extern statetype s_transchase3s; +extern statetype s_transchase4; + +extern statetype s_transdie0; +extern statetype s_transdie01; +extern statetype s_transdie1; +extern statetype s_transdie2; +extern statetype s_transdie3; +extern statetype s_transdie4; + +extern statetype s_transshoot1; +extern statetype s_transshoot2; +extern statetype s_transshoot3; +extern statetype s_transshoot4; +extern statetype s_transshoot5; +extern statetype s_transshoot6; +extern statetype s_transshoot7; +extern statetype s_transshoot8; + + +statetype s_transstand = {false,SPR_TRANS_W1,0,T_Stand,NULL,&s_transstand}; + +statetype s_transchase1 = {false,SPR_TRANS_W1,10,T_Chase,NULL,&s_transchase1s}; +statetype s_transchase1s = {false,SPR_TRANS_W1,3,NULL,NULL,&s_transchase2}; +statetype s_transchase2 = {false,SPR_TRANS_W2,8,T_Chase,NULL,&s_transchase3}; +statetype s_transchase3 = {false,SPR_TRANS_W3,10,T_Chase,NULL,&s_transchase3s}; +statetype s_transchase3s = {false,SPR_TRANS_W3,3,NULL,NULL,&s_transchase4}; +statetype s_transchase4 = {false,SPR_TRANS_W4,8,T_Chase,NULL,&s_transchase1}; + +statetype s_transdie0 = {false,SPR_TRANS_W1,1,NULL,A_DeathScream,&s_transdie01}; +statetype s_transdie01 = {false,SPR_TRANS_W1,1,NULL,NULL,&s_transdie1}; +statetype s_transdie1 = {false,SPR_TRANS_DIE1,15,NULL,NULL,&s_transdie2}; +statetype s_transdie2 = {false,SPR_TRANS_DIE2,15,NULL,NULL,&s_transdie3}; +statetype s_transdie3 = {false,SPR_TRANS_DIE3,15,NULL,NULL,&s_transdie4}; +statetype s_transdie4 = {false,SPR_TRANS_DEAD,0,NULL,NULL,&s_transdie4}; + +statetype s_transshoot1 = {false,SPR_TRANS_SHOOT1,30,NULL,NULL,&s_transshoot2}; +statetype s_transshoot2 = {false,SPR_TRANS_SHOOT2,10,NULL,T_Shoot,&s_transshoot3}; +statetype s_transshoot3 = {false,SPR_TRANS_SHOOT3,10,NULL,T_Shoot,&s_transshoot4}; +statetype s_transshoot4 = {false,SPR_TRANS_SHOOT2,10,NULL,T_Shoot,&s_transshoot5}; +statetype s_transshoot5 = {false,SPR_TRANS_SHOOT3,10,NULL,T_Shoot,&s_transshoot6}; +statetype s_transshoot6 = {false,SPR_TRANS_SHOOT2,10,NULL,T_Shoot,&s_transshoot7}; +statetype s_transshoot7 = {false,SPR_TRANS_SHOOT3,10,NULL,T_Shoot,&s_transshoot8}; +statetype s_transshoot8 = {false,SPR_TRANS_SHOOT1,10,NULL,NULL,&s_transchase1}; + + +/* +=============== += += SpawnTrans += +=============== +*/ + +void SpawnTrans (int tilex, int tiley) +{ + unsigned far *map,tile; + + if (SoundBlasterPresent && DigiMode != sds_Off) + s_transdie01.tictime = 105; + + SpawnNewObj (tilex,tiley,&s_transstand); + new->obclass = transobj; + new->hitpoints = starthitpoints[gamestate.difficulty][en_trans]; + new->flags |= FL_SHOOTABLE|FL_AMBUSH; + if (!loadedgame) + gamestate.killtotal++; +} + + +// +// uber +// +void T_UShoot (objtype *ob); + +extern statetype s_uberstand; + +extern statetype s_uberchase1; +extern statetype s_uberchase1s; +extern statetype s_uberchase2; +extern statetype s_uberchase3; +extern statetype s_uberchase3s; +extern statetype s_uberchase4; + +extern statetype s_uberdie0; +extern statetype s_uberdie01; +extern statetype s_uberdie1; +extern statetype s_uberdie2; +extern statetype s_uberdie3; +extern statetype s_uberdie4; +extern statetype s_uberdie5; + +extern statetype s_ubershoot1; +extern statetype s_ubershoot2; +extern statetype s_ubershoot3; +extern statetype s_ubershoot4; +extern statetype s_ubershoot5; +extern statetype s_ubershoot6; +extern statetype s_ubershoot7; + + +statetype s_uberstand = {false,SPR_UBER_W1,0,T_Stand,NULL,&s_uberstand}; + +statetype s_uberchase1 = {false,SPR_UBER_W1,10,T_Chase,NULL,&s_uberchase1s}; +statetype s_uberchase1s = {false,SPR_UBER_W1,3,NULL,NULL,&s_uberchase2}; +statetype s_uberchase2 = {false,SPR_UBER_W2,8,T_Chase,NULL,&s_uberchase3}; +statetype s_uberchase3 = {false,SPR_UBER_W3,10,T_Chase,NULL,&s_uberchase3s}; +statetype s_uberchase3s = {false,SPR_UBER_W3,3,NULL,NULL,&s_uberchase4}; +statetype s_uberchase4 = {false,SPR_UBER_W4,8,T_Chase,NULL,&s_uberchase1}; + +statetype s_uberdie0 = {false,SPR_UBER_W1,1,NULL,A_DeathScream,&s_uberdie01}; +statetype s_uberdie01 = {false,SPR_UBER_W1,1,NULL,NULL,&s_uberdie1}; +statetype s_uberdie1 = {false,SPR_UBER_DIE1,15,NULL,NULL,&s_uberdie2}; +statetype s_uberdie2 = {false,SPR_UBER_DIE2,15,NULL,NULL,&s_uberdie3}; +statetype s_uberdie3 = {false,SPR_UBER_DIE3,15,NULL,NULL,&s_uberdie4}; +statetype s_uberdie4 = {false,SPR_UBER_DIE4,15,NULL,NULL,&s_uberdie5}; +statetype s_uberdie5 = {false,SPR_UBER_DEAD,0,NULL,NULL,&s_uberdie5}; + +statetype s_ubershoot1 = {false,SPR_UBER_SHOOT1,30,NULL,NULL,&s_ubershoot2}; +statetype s_ubershoot2 = {false,SPR_UBER_SHOOT2,12,NULL,T_UShoot,&s_ubershoot3}; +statetype s_ubershoot3 = {false,SPR_UBER_SHOOT3,12,NULL,T_UShoot,&s_ubershoot4}; +statetype s_ubershoot4 = {false,SPR_UBER_SHOOT4,12,NULL,T_UShoot,&s_ubershoot5}; +statetype s_ubershoot5 = {false,SPR_UBER_SHOOT3,12,NULL,T_UShoot,&s_ubershoot6}; +statetype s_ubershoot6 = {false,SPR_UBER_SHOOT2,12,NULL,T_UShoot,&s_ubershoot7}; +statetype s_ubershoot7 = {false,SPR_UBER_SHOOT1,12,NULL,NULL,&s_uberchase1}; + + +/* +=============== += += SpawnUber += +=============== +*/ + +void SpawnUber (int tilex, int tiley) +{ + unsigned far *map,tile; + + if (SoundBlasterPresent && DigiMode != sds_Off) + s_uberdie01.tictime = 70; + + SpawnNewObj (tilex,tiley,&s_uberstand); + new->obclass = uberobj; + new->hitpoints = starthitpoints[gamestate.difficulty][en_uber]; + new->flags |= FL_SHOOTABLE|FL_AMBUSH; + if (!loadedgame) + gamestate.killtotal++; +} + + +/* +=============== += += T_UShoot += +=============== +*/ + +void T_UShoot (objtype *ob) +{ + int dx,dy,dist; + + T_Shoot (ob); + + dx = abs(ob->tilex - player->tilex); + dy = abs(ob->tiley - player->tiley); + dist = dx>dy ? dx : dy; + if (dist <= 1) + TakeDamage (10,ob); +} + + +// +// will +// +extern statetype s_willstand; + +extern statetype s_willchase1; +extern statetype s_willchase1s; +extern statetype s_willchase2; +extern statetype s_willchase3; +extern statetype s_willchase3s; +extern statetype s_willchase4; + +extern statetype s_willdie1; +extern statetype s_willdie2; +extern statetype s_willdie3; +extern statetype s_willdie4; +extern statetype s_willdie5; +extern statetype s_willdie6; + +extern statetype s_willshoot1; +extern statetype s_willshoot2; +extern statetype s_willshoot3; +extern statetype s_willshoot4; +extern statetype s_willshoot5; +extern statetype s_willshoot6; + + +statetype s_willstand = {false,SPR_WILL_W1,0,T_Stand,NULL,&s_willstand}; + +statetype s_willchase1 = {false,SPR_WILL_W1,10,T_Will,NULL,&s_willchase1s}; +statetype s_willchase1s = {false,SPR_WILL_W1,3,NULL,NULL,&s_willchase2}; +statetype s_willchase2 = {false,SPR_WILL_W2,8,T_Will,NULL,&s_willchase3}; +statetype s_willchase3 = {false,SPR_WILL_W3,10,T_Will,NULL,&s_willchase3s}; +statetype s_willchase3s = {false,SPR_WILL_W3,3,NULL,NULL,&s_willchase4}; +statetype s_willchase4 = {false,SPR_WILL_W4,8,T_Will,NULL,&s_willchase1}; + +statetype s_willdeathcam = {false,SPR_WILL_W1,1,NULL,NULL,&s_willdie1}; + +statetype s_willdie1 = {false,SPR_WILL_W1,1,NULL,A_DeathScream,&s_willdie2}; +statetype s_willdie2 = {false,SPR_WILL_W1,10,NULL,NULL,&s_willdie3}; +statetype s_willdie3 = {false,SPR_WILL_DIE1,10,NULL,NULL,&s_willdie4}; +statetype s_willdie4 = {false,SPR_WILL_DIE2,10,NULL,NULL,&s_willdie5}; +statetype s_willdie5 = {false,SPR_WILL_DIE3,10,NULL,NULL,&s_willdie6}; +statetype s_willdie6 = {false,SPR_WILL_DEAD,20,NULL,NULL,&s_willdie6}; + +statetype s_willshoot1 = {false,SPR_WILL_SHOOT1,30,NULL,NULL,&s_willshoot2}; +statetype s_willshoot2 = {false,SPR_WILL_SHOOT2,10,NULL,T_Launch,&s_willshoot3}; +statetype s_willshoot3 = {false,SPR_WILL_SHOOT3,10,NULL,T_Shoot,&s_willshoot4}; +statetype s_willshoot4 = {false,SPR_WILL_SHOOT4,10,NULL,T_Shoot,&s_willshoot5}; +statetype s_willshoot5 = {false,SPR_WILL_SHOOT3,10,NULL,T_Shoot,&s_willshoot6}; +statetype s_willshoot6 = {false,SPR_WILL_SHOOT4,10,NULL,T_Shoot,&s_willchase1}; + + +/* +=============== += += SpawnWill += +=============== +*/ + +void SpawnWill (int tilex, int tiley) +{ + unsigned far *map,tile; + + if (SoundBlasterPresent && DigiMode != sds_Off) + s_willdie2.tictime = 70; + + SpawnNewObj (tilex,tiley,&s_willstand); + new->obclass = willobj; + new->hitpoints = starthitpoints[gamestate.difficulty][en_will]; + new->flags |= FL_SHOOTABLE|FL_AMBUSH; + if (!loadedgame) + gamestate.killtotal++; +} + + +/* +================ += += T_Will += +================ +*/ + +void T_Will (objtype *ob) +{ + long move; + int dx,dy,dist; + boolean dodge; + + dodge = false; + dx = abs(ob->tilex - player->tilex); + dy = abs(ob->tiley - player->tiley); + dist = dx>dy ? dx : dy; + + if (CheckLine(ob)) // got a shot at player? + { + if ( US_RndT() < (tics<<3) ) + { + // + // go into attack frame + // + if (ob->obclass == willobj) + NewState (ob,&s_willshoot1); + else if (ob->obclass == angelobj) + NewState (ob,&s_angelshoot1); + else + NewState (ob,&s_deathshoot1); + return; + } + dodge = true; + } + + if (ob->dir == nodir) + { + if (dodge) + SelectDodgeDir (ob); + else + SelectChaseDir (ob); + if (ob->dir == nodir) + return; // object is blocked in + } + + move = ob->speed*tics; + + while (move) + { + if (ob->distance < 0) + { + // + // waiting for a door to open + // + OpenDoor (-ob->distance-1); + if (doorobjlist[-ob->distance-1].action != dr_open) + return; + ob->distance = TILEGLOBAL; // go ahead, the door is now opoen + } + + if (move < ob->distance) + { + MoveObj (ob,move); + break; + } + + // + // reached goal tile, so select another one + // + + // + // fix position to account for round off during moving + // + ob->x = ((long)ob->tilex<y = ((long)ob->tiley<distance; + + if (dist <4) + SelectRunDir (ob); + else if (dodge) + SelectDodgeDir (ob); + else + SelectChaseDir (ob); + + if (ob->dir == nodir) + return; // object is blocked in + } + +} + + +// +// death +// +extern statetype s_deathstand; + +extern statetype s_deathchase1; +extern statetype s_deathchase1s; +extern statetype s_deathchase2; +extern statetype s_deathchase3; +extern statetype s_deathchase3s; +extern statetype s_deathchase4; + +extern statetype s_deathdie1; +extern statetype s_deathdie2; +extern statetype s_deathdie3; +extern statetype s_deathdie4; +extern statetype s_deathdie5; +extern statetype s_deathdie6; +extern statetype s_deathdie7; +extern statetype s_deathdie8; +extern statetype s_deathdie9; + +extern statetype s_deathshoot1; +extern statetype s_deathshoot2; +extern statetype s_deathshoot3; +extern statetype s_deathshoot4; +extern statetype s_deathshoot5; + + +statetype s_deathstand = {false,SPR_DEATH_W1,0,T_Stand,NULL,&s_deathstand}; + +statetype s_deathchase1 = {false,SPR_DEATH_W1,10,T_Will,NULL,&s_deathchase1s}; +statetype s_deathchase1s = {false,SPR_DEATH_W1,3,NULL,NULL,&s_deathchase2}; +statetype s_deathchase2 = {false,SPR_DEATH_W2,8,T_Will,NULL,&s_deathchase3}; +statetype s_deathchase3 = {false,SPR_DEATH_W3,10,T_Will,NULL,&s_deathchase3s}; +statetype s_deathchase3s = {false,SPR_DEATH_W3,3,NULL,NULL,&s_deathchase4}; +statetype s_deathchase4 = {false,SPR_DEATH_W4,8,T_Will,NULL,&s_deathchase1}; + +statetype s_deathdeathcam = {false,SPR_DEATH_W1,1,NULL,NULL,&s_deathdie1}; + +statetype s_deathdie1 = {false,SPR_DEATH_W1,1,NULL,A_DeathScream,&s_deathdie2}; +statetype s_deathdie2 = {false,SPR_DEATH_W1,10,NULL,NULL,&s_deathdie3}; +statetype s_deathdie3 = {false,SPR_DEATH_DIE1,10,NULL,NULL,&s_deathdie4}; +statetype s_deathdie4 = {false,SPR_DEATH_DIE2,10,NULL,NULL,&s_deathdie5}; +statetype s_deathdie5 = {false,SPR_DEATH_DIE3,10,NULL,NULL,&s_deathdie6}; +statetype s_deathdie6 = {false,SPR_DEATH_DIE4,10,NULL,NULL,&s_deathdie7}; +statetype s_deathdie7 = {false,SPR_DEATH_DIE5,10,NULL,NULL,&s_deathdie8}; +statetype s_deathdie8 = {false,SPR_DEATH_DIE6,10,NULL,NULL,&s_deathdie9}; +statetype s_deathdie9 = {false,SPR_DEATH_DEAD,0,NULL,NULL,&s_deathdie9}; + +statetype s_deathshoot1 = {false,SPR_DEATH_SHOOT1,30,NULL,NULL,&s_deathshoot2}; +statetype s_deathshoot2 = {false,SPR_DEATH_SHOOT2,10,NULL,T_Launch,&s_deathshoot3}; +statetype s_deathshoot3 = {false,SPR_DEATH_SHOOT4,10,NULL,T_Shoot,&s_deathshoot4}; +statetype s_deathshoot4 = {false,SPR_DEATH_SHOOT3,10,NULL,T_Launch,&s_deathshoot5}; +statetype s_deathshoot5 = {false,SPR_DEATH_SHOOT4,10,NULL,T_Shoot,&s_deathchase1}; + + +/* +=============== += += SpawnDeath += +=============== +*/ + +void SpawnDeath (int tilex, int tiley) +{ + unsigned far *map,tile; + + if (SoundBlasterPresent && DigiMode != sds_Off) + s_deathdie2.tictime = 105; + + SpawnNewObj (tilex,tiley,&s_deathstand); + new->obclass = deathobj; + new->hitpoints = starthitpoints[gamestate.difficulty][en_death]; + new->flags |= FL_SHOOTABLE|FL_AMBUSH; + if (!loadedgame) + gamestate.killtotal++; +} + +/* +=============== += += T_Launch += +=============== +*/ + +void T_Launch (objtype *ob) +{ + long deltax,deltay; + float angle; + int iangle; + + deltax = player->x - ob->x; + deltay = ob->y - player->y; + angle = atan2 (deltay,deltax); + if (angle<0) + angle = M_PI*2+angle; + iangle = angle/(M_PI*2)*ANGLES; + if (ob->obclass == deathobj) + { + T_Shoot (ob); + if (ob->state == &s_deathshoot2) + { + iangle-=4; + if (iangle<0) + iangle+=ANGLES; + } + else + { + iangle+=4; + if (iangle>=ANGLES) + iangle-=ANGLES; + } + } + + GetNewActor (); + new->state = &s_rocket; + new->ticcount = 1; + + new->tilex = ob->tilex; + new->tiley = ob->tiley; + new->x = ob->x; + new->y = ob->y; + new->obclass = rocketobj; + switch(ob->obclass) + { + case deathobj: + new->state = &s_hrocket; + new->obclass = hrocketobj; + PlaySoundLocActor (KNIGHTMISSILESND,new); + break; + case angelobj: + new->state = &s_spark1; + new->obclass = sparkobj; + PlaySoundLocActor (ANGELFIRESND,new); + break; + default: + PlaySoundLocActor (MISSILEFIRESND,new); + } + + new->dir = nodir; + new->angle = iangle; + new->speed = 0x2000l; + new->flags = FL_NONMARK; + new->active = true; +} + + + +// +// angel +// +void A_Relaunch (objtype *ob); +void A_Victory (objtype *ob); +void A_StartAttack (objtype *ob); +void A_Breathing (objtype *ob); + +extern statetype s_angelstand; + +extern statetype s_angelchase1; +extern statetype s_angelchase1s; +extern statetype s_angelchase2; +extern statetype s_angelchase3; +extern statetype s_angelchase3s; +extern statetype s_angelchase4; + +extern statetype s_angeldie1; +extern statetype s_angeldie11; +extern statetype s_angeldie2; +extern statetype s_angeldie3; +extern statetype s_angeldie4; +extern statetype s_angeldie5; +extern statetype s_angeldie6; +extern statetype s_angeldie7; +extern statetype s_angeldie8; +extern statetype s_angeldie9; + +extern statetype s_angelshoot1; +extern statetype s_angelshoot2; +extern statetype s_angelshoot3; +extern statetype s_angelshoot4; +extern statetype s_angelshoot5; +extern statetype s_angelshoot6; + +extern statetype s_angeltired; +extern statetype s_angeltired2; +extern statetype s_angeltired3; +extern statetype s_angeltired4; +extern statetype s_angeltired5; +extern statetype s_angeltired6; +extern statetype s_angeltired7; + +extern statetype s_spark1; +extern statetype s_spark2; +extern statetype s_spark3; +extern statetype s_spark4; + + +statetype s_angelstand = {false,SPR_ANGEL_W1,0,T_Stand,NULL,&s_angelstand}; + +statetype s_angelchase1 = {false,SPR_ANGEL_W1,10,T_Will,NULL,&s_angelchase1s}; +statetype s_angelchase1s = {false,SPR_ANGEL_W1,3,NULL,NULL,&s_angelchase2}; +statetype s_angelchase2 = {false,SPR_ANGEL_W2,8,T_Will,NULL,&s_angelchase3}; +statetype s_angelchase3 = {false,SPR_ANGEL_W3,10,T_Will,NULL,&s_angelchase3s}; +statetype s_angelchase3s = {false,SPR_ANGEL_W3,3,NULL,NULL,&s_angelchase4}; +statetype s_angelchase4 = {false,SPR_ANGEL_W4,8,T_Will,NULL,&s_angelchase1}; + +statetype s_angeldie1 = {false,SPR_ANGEL_W1,1,NULL,A_DeathScream,&s_angeldie11}; +statetype s_angeldie11 = {false,SPR_ANGEL_W1,1,NULL,NULL,&s_angeldie2}; +statetype s_angeldie2 = {false,SPR_ANGEL_DIE1,10,NULL,A_Slurpie,&s_angeldie3}; +statetype s_angeldie3 = {false,SPR_ANGEL_DIE2,10,NULL,NULL,&s_angeldie4}; +statetype s_angeldie4 = {false,SPR_ANGEL_DIE3,10,NULL,NULL,&s_angeldie5}; +statetype s_angeldie5 = {false,SPR_ANGEL_DIE4,10,NULL,NULL,&s_angeldie6}; +statetype s_angeldie6 = {false,SPR_ANGEL_DIE5,10,NULL,NULL,&s_angeldie7}; +statetype s_angeldie7 = {false,SPR_ANGEL_DIE6,10,NULL,NULL,&s_angeldie8}; +statetype s_angeldie8 = {false,SPR_ANGEL_DIE7,10,NULL,NULL,&s_angeldie9}; +statetype s_angeldie9 = {false,SPR_ANGEL_DEAD,130,NULL,A_Victory,&s_angeldie9}; + +statetype s_angelshoot1 = {false,SPR_ANGEL_SHOOT1,10,NULL,A_StartAttack,&s_angelshoot2}; +statetype s_angelshoot2 = {false,SPR_ANGEL_SHOOT2,20,NULL,T_Launch,&s_angelshoot3}; +statetype s_angelshoot3 = {false,SPR_ANGEL_SHOOT1,10,NULL,A_Relaunch,&s_angelshoot2}; + +statetype s_angeltired = {false,SPR_ANGEL_TIRED1,40,NULL,A_Breathing,&s_angeltired2}; +statetype s_angeltired2 = {false,SPR_ANGEL_TIRED2,40,NULL,NULL,&s_angeltired3}; +statetype s_angeltired3 = {false,SPR_ANGEL_TIRED1,40,NULL,A_Breathing,&s_angeltired4}; +statetype s_angeltired4 = {false,SPR_ANGEL_TIRED2,40,NULL,NULL,&s_angeltired5}; +statetype s_angeltired5 = {false,SPR_ANGEL_TIRED1,40,NULL,A_Breathing,&s_angeltired6}; +statetype s_angeltired6 = {false,SPR_ANGEL_TIRED2,40,NULL,NULL,&s_angeltired7}; +statetype s_angeltired7 = {false,SPR_ANGEL_TIRED1,40,NULL,A_Breathing,&s_angelchase1}; + +statetype s_spark1 = {false,SPR_SPARK1,6,T_Projectile,NULL,&s_spark2}; +statetype s_spark2 = {false,SPR_SPARK2,6,T_Projectile,NULL,&s_spark3}; +statetype s_spark3 = {false,SPR_SPARK3,6,T_Projectile,NULL,&s_spark4}; +statetype s_spark4 = {false,SPR_SPARK4,6,T_Projectile,NULL,&s_spark1}; + + +#pragma argsused +void A_Slurpie (objtype *ob) +{ + SD_PlaySound(SLURPIESND); +} + +#pragma argsused +void A_Breathing (objtype *ob) +{ + SD_PlaySound(ANGELTIREDSND); +} + +/* +=============== += += SpawnAngel += +=============== +*/ + +void SpawnAngel (int tilex, int tiley) +{ + unsigned far *map,tile; + + + if (SoundBlasterPresent && DigiMode != sds_Off) + s_angeldie11.tictime = 105; + + SpawnNewObj (tilex,tiley,&s_angelstand); + new->obclass = angelobj; + new->hitpoints = starthitpoints[gamestate.difficulty][en_angel]; + new->flags |= FL_SHOOTABLE|FL_AMBUSH; + if (!loadedgame) + gamestate.killtotal++; +} + + +/* +================= += += A_Victory += +================= +*/ + +#pragma argsused +void A_Victory (objtype *ob) +{ + playstate = ex_victorious; +} + + +/* +================= += += A_StartAttack += +================= +*/ + +void A_StartAttack (objtype *ob) +{ + ob->temp1 = 0; +} + + +/* +================= += += A_Relaunch += +================= +*/ + +void A_Relaunch (objtype *ob) +{ + if (++ob->temp1 == 3) + { + NewState (ob,&s_angeltired); + return; + } + + if (US_RndT()&1) + { + NewState (ob,&s_angelchase1); + return; + } +} + + + + +// +// spectre +// +void T_SpectreWait (objtype *ob); +void A_Dormant (objtype *ob); + +extern statetype s_spectrewait1; +extern statetype s_spectrewait2; +extern statetype s_spectrewait3; +extern statetype s_spectrewait4; + +extern statetype s_spectrechase1; +extern statetype s_spectrechase2; +extern statetype s_spectrechase3; +extern statetype s_spectrechase4; + +extern statetype s_spectredie1; +extern statetype s_spectredie2; +extern statetype s_spectredie3; +extern statetype s_spectredie4; + +extern statetype s_spectrewake; + +statetype s_spectrewait1 = {false,SPR_SPECTRE_W1,10,T_Stand,NULL,&s_spectrewait2}; +statetype s_spectrewait2 = {false,SPR_SPECTRE_W2,10,T_Stand,NULL,&s_spectrewait3}; +statetype s_spectrewait3 = {false,SPR_SPECTRE_W3,10,T_Stand,NULL,&s_spectrewait4}; +statetype s_spectrewait4 = {false,SPR_SPECTRE_W4,10,T_Stand,NULL,&s_spectrewait1}; + +statetype s_spectrechase1 = {false,SPR_SPECTRE_W1,10,T_Ghosts,NULL,&s_spectrechase2}; +statetype s_spectrechase2 = {false,SPR_SPECTRE_W2,10,T_Ghosts,NULL,&s_spectrechase3}; +statetype s_spectrechase3 = {false,SPR_SPECTRE_W3,10,T_Ghosts,NULL,&s_spectrechase4}; +statetype s_spectrechase4 = {false,SPR_SPECTRE_W4,10,T_Ghosts,NULL,&s_spectrechase1}; + +statetype s_spectredie1 = {false,SPR_SPECTRE_F1,10,NULL,NULL,&s_spectredie2}; +statetype s_spectredie2 = {false,SPR_SPECTRE_F2,10,NULL,NULL,&s_spectredie3}; +statetype s_spectredie3 = {false,SPR_SPECTRE_F3,10,NULL,NULL,&s_spectredie4}; +statetype s_spectredie4 = {false,SPR_SPECTRE_F4,300,NULL,NULL,&s_spectrewake}; +statetype s_spectrewake = {false,SPR_SPECTRE_F4,10,NULL,A_Dormant,&s_spectrewake}; + +/* +=============== += += SpawnSpectre += +=============== +*/ + +void SpawnSpectre (int tilex, int tiley) +{ + unsigned far *map,tile; + + SpawnNewObj (tilex,tiley,&s_spectrewait1); + new->obclass = spectreobj; + new->hitpoints = starthitpoints[gamestate.difficulty][en_spectre]; + new->flags |= FL_SHOOTABLE|FL_AMBUSH; // |FL_NEVERMARK|FL_NONMARK; + if (!loadedgame) + gamestate.killtotal++; +} + + +/* +=============== += += A_Dormant += +=============== +*/ + +void A_Dormant (objtype *ob) +{ + long deltax,deltay; + int xl,xh,yl,yh; + int x,y; + unsigned tile; + + deltax = ob->x - player->x; + if (deltax < -MINACTORDIST || deltax > MINACTORDIST) + goto moveok; + deltay = ob->y - player->y; + if (deltay < -MINACTORDIST || deltay > MINACTORDIST) + goto moveok; + + return; +moveok: + + xl = (ob->x-MINDIST) >> TILESHIFT; + xh = (ob->x+MINDIST) >> TILESHIFT; + yl = (ob->y-MINDIST) >> TILESHIFT; + yh = (ob->y+MINDIST) >> TILESHIFT; + + for (y=yl ; y<=yh ; y++) + for (x=xl ; x<=xh ; x++) + { + tile = actorat[x][y]; + if (!tile) + continue; + if (tile<256) + return; + if (((objtype *)tile)->flags&FL_SHOOTABLE) + return; + } + + ob->flags |= FL_AMBUSH | FL_SHOOTABLE; + ob->flags &= ~FL_ATTACKMODE; + ob->dir = nodir; + NewState (ob,&s_spectrewait1); +} + + +#endif + +/* +============================================================================= + + SCHABBS / GIFT / FAT + +============================================================================= +*/ + +#ifndef SPEAR +/* +=============== += += SpawnGhosts += +=============== +*/ + +void SpawnGhosts (int which, int tilex, int tiley) +{ + unsigned far *map,tile; + + switch(which) + { + case en_blinky: + SpawnNewObj (tilex,tiley,&s_blinkychase1); + break; + case en_clyde: + SpawnNewObj (tilex,tiley,&s_clydechase1); + break; + case en_pinky: + SpawnNewObj (tilex,tiley,&s_pinkychase1); + break; + case en_inky: + SpawnNewObj (tilex,tiley,&s_inkychase1); + break; + } + + new->obclass = ghostobj; + new->speed = SPDDOG; + + new->dir = east; + new->flags |= FL_AMBUSH; + if (!loadedgame) + gamestate.killtotal++; +} + + + +void T_Gift (objtype *ob); +void T_GiftThrow (objtype *ob); + +void T_Fat (objtype *ob); +void T_FatThrow (objtype *ob); + +// +// schabb +// +extern statetype s_schabbstand; + +extern statetype s_schabbchase1; +extern statetype s_schabbchase1s; +extern statetype s_schabbchase2; +extern statetype s_schabbchase3; +extern statetype s_schabbchase3s; +extern statetype s_schabbchase4; + +extern statetype s_schabbdie1; +extern statetype s_schabbdie2; +extern statetype s_schabbdie3; +extern statetype s_schabbdie4; +extern statetype s_schabbdie5; +extern statetype s_schabbdie6; + +extern statetype s_schabbshoot1; +extern statetype s_schabbshoot2; + +extern statetype s_needle1; +extern statetype s_needle2; +extern statetype s_needle3; +extern statetype s_needle4; + +extern statetype s_schabbdeathcam; + + +statetype s_schabbstand = {false,SPR_SCHABB_W1,0,T_Stand,NULL,&s_schabbstand}; + +statetype s_schabbchase1 = {false,SPR_SCHABB_W1,10,T_Schabb,NULL,&s_schabbchase1s}; +statetype s_schabbchase1s = {false,SPR_SCHABB_W1,3,NULL,NULL,&s_schabbchase2}; +statetype s_schabbchase2 = {false,SPR_SCHABB_W2,8,T_Schabb,NULL,&s_schabbchase3}; +statetype s_schabbchase3 = {false,SPR_SCHABB_W3,10,T_Schabb,NULL,&s_schabbchase3s}; +statetype s_schabbchase3s = {false,SPR_SCHABB_W3,3,NULL,NULL,&s_schabbchase4}; +statetype s_schabbchase4 = {false,SPR_SCHABB_W4,8,T_Schabb,NULL,&s_schabbchase1}; + +statetype s_schabbdeathcam = {false,SPR_SCHABB_W1,1,NULL,NULL,&s_schabbdie1}; + +statetype s_schabbdie1 = {false,SPR_SCHABB_W1,10,NULL,A_DeathScream,&s_schabbdie2}; +statetype s_schabbdie2 = {false,SPR_SCHABB_W1,10,NULL,NULL,&s_schabbdie3}; +statetype s_schabbdie3 = {false,SPR_SCHABB_DIE1,10,NULL,NULL,&s_schabbdie4}; +statetype s_schabbdie4 = {false,SPR_SCHABB_DIE2,10,NULL,NULL,&s_schabbdie5}; +statetype s_schabbdie5 = {false,SPR_SCHABB_DIE3,10,NULL,NULL,&s_schabbdie6}; +statetype s_schabbdie6 = {false,SPR_SCHABB_DEAD,20,NULL,A_StartDeathCam,&s_schabbdie6}; + +statetype s_schabbshoot1 = {false,SPR_SCHABB_SHOOT1,30,NULL,NULL,&s_schabbshoot2}; +statetype s_schabbshoot2 = {false,SPR_SCHABB_SHOOT2,10,NULL,T_SchabbThrow,&s_schabbchase1}; + +statetype s_needle1 = {false,SPR_HYPO1,6,T_Projectile,NULL,&s_needle2}; +statetype s_needle2 = {false,SPR_HYPO2,6,T_Projectile,NULL,&s_needle3}; +statetype s_needle3 = {false,SPR_HYPO3,6,T_Projectile,NULL,&s_needle4}; +statetype s_needle4 = {false,SPR_HYPO4,6,T_Projectile,NULL,&s_needle1}; + + +// +// gift +// +extern statetype s_giftstand; + +extern statetype s_giftchase1; +extern statetype s_giftchase1s; +extern statetype s_giftchase2; +extern statetype s_giftchase3; +extern statetype s_giftchase3s; +extern statetype s_giftchase4; + +extern statetype s_giftdie1; +extern statetype s_giftdie2; +extern statetype s_giftdie3; +extern statetype s_giftdie4; +extern statetype s_giftdie5; +extern statetype s_giftdie6; + +extern statetype s_giftshoot1; +extern statetype s_giftshoot2; + +extern statetype s_needle1; +extern statetype s_needle2; +extern statetype s_needle3; +extern statetype s_needle4; + +extern statetype s_giftdeathcam; + +extern statetype s_boom1; +extern statetype s_boom2; +extern statetype s_boom3; + + +statetype s_giftstand = {false,SPR_GIFT_W1,0,T_Stand,NULL,&s_giftstand}; + +statetype s_giftchase1 = {false,SPR_GIFT_W1,10,T_Gift,NULL,&s_giftchase1s}; +statetype s_giftchase1s = {false,SPR_GIFT_W1,3,NULL,NULL,&s_giftchase2}; +statetype s_giftchase2 = {false,SPR_GIFT_W2,8,T_Gift,NULL,&s_giftchase3}; +statetype s_giftchase3 = {false,SPR_GIFT_W3,10,T_Gift,NULL,&s_giftchase3s}; +statetype s_giftchase3s = {false,SPR_GIFT_W3,3,NULL,NULL,&s_giftchase4}; +statetype s_giftchase4 = {false,SPR_GIFT_W4,8,T_Gift,NULL,&s_giftchase1}; + +statetype s_giftdeathcam = {false,SPR_GIFT_W1,1,NULL,NULL,&s_giftdie1}; + +statetype s_giftdie1 = {false,SPR_GIFT_W1,1,NULL,A_DeathScream,&s_giftdie2}; +statetype s_giftdie2 = {false,SPR_GIFT_W1,10,NULL,NULL,&s_giftdie3}; +statetype s_giftdie3 = {false,SPR_GIFT_DIE1,10,NULL,NULL,&s_giftdie4}; +statetype s_giftdie4 = {false,SPR_GIFT_DIE2,10,NULL,NULL,&s_giftdie5}; +statetype s_giftdie5 = {false,SPR_GIFT_DIE3,10,NULL,NULL,&s_giftdie6}; +statetype s_giftdie6 = {false,SPR_GIFT_DEAD,20,NULL,A_StartDeathCam,&s_giftdie6}; + +statetype s_giftshoot1 = {false,SPR_GIFT_SHOOT1,30,NULL,NULL,&s_giftshoot2}; +statetype s_giftshoot2 = {false,SPR_GIFT_SHOOT2,10,NULL,T_GiftThrow,&s_giftchase1}; + + +// +// fat +// +extern statetype s_fatstand; + +extern statetype s_fatchase1; +extern statetype s_fatchase1s; +extern statetype s_fatchase2; +extern statetype s_fatchase3; +extern statetype s_fatchase3s; +extern statetype s_fatchase4; + +extern statetype s_fatdie1; +extern statetype s_fatdie2; +extern statetype s_fatdie3; +extern statetype s_fatdie4; +extern statetype s_fatdie5; +extern statetype s_fatdie6; + +extern statetype s_fatshoot1; +extern statetype s_fatshoot2; +extern statetype s_fatshoot3; +extern statetype s_fatshoot4; +extern statetype s_fatshoot5; +extern statetype s_fatshoot6; + +extern statetype s_needle1; +extern statetype s_needle2; +extern statetype s_needle3; +extern statetype s_needle4; + +extern statetype s_fatdeathcam; + + +statetype s_fatstand = {false,SPR_FAT_W1,0,T_Stand,NULL,&s_fatstand}; + +statetype s_fatchase1 = {false,SPR_FAT_W1,10,T_Fat,NULL,&s_fatchase1s}; +statetype s_fatchase1s = {false,SPR_FAT_W1,3,NULL,NULL,&s_fatchase2}; +statetype s_fatchase2 = {false,SPR_FAT_W2,8,T_Fat,NULL,&s_fatchase3}; +statetype s_fatchase3 = {false,SPR_FAT_W3,10,T_Fat,NULL,&s_fatchase3s}; +statetype s_fatchase3s = {false,SPR_FAT_W3,3,NULL,NULL,&s_fatchase4}; +statetype s_fatchase4 = {false,SPR_FAT_W4,8,T_Fat,NULL,&s_fatchase1}; + +statetype s_fatdeathcam = {false,SPR_FAT_W1,1,NULL,NULL,&s_fatdie1}; + +statetype s_fatdie1 = {false,SPR_FAT_W1,1,NULL,A_DeathScream,&s_fatdie2}; +statetype s_fatdie2 = {false,SPR_FAT_W1,10,NULL,NULL,&s_fatdie3}; +statetype s_fatdie3 = {false,SPR_FAT_DIE1,10,NULL,NULL,&s_fatdie4}; +statetype s_fatdie4 = {false,SPR_FAT_DIE2,10,NULL,NULL,&s_fatdie5}; +statetype s_fatdie5 = {false,SPR_FAT_DIE3,10,NULL,NULL,&s_fatdie6}; +statetype s_fatdie6 = {false,SPR_FAT_DEAD,20,NULL,A_StartDeathCam,&s_fatdie6}; + +statetype s_fatshoot1 = {false,SPR_FAT_SHOOT1,30,NULL,NULL,&s_fatshoot2}; +statetype s_fatshoot2 = {false,SPR_FAT_SHOOT2,10,NULL,T_GiftThrow,&s_fatshoot3}; +statetype s_fatshoot3 = {false,SPR_FAT_SHOOT3,10,NULL,T_Shoot,&s_fatshoot4}; +statetype s_fatshoot4 = {false,SPR_FAT_SHOOT4,10,NULL,T_Shoot,&s_fatshoot5}; +statetype s_fatshoot5 = {false,SPR_FAT_SHOOT3,10,NULL,T_Shoot,&s_fatshoot6}; +statetype s_fatshoot6 = {false,SPR_FAT_SHOOT4,10,NULL,T_Shoot,&s_fatchase1}; + + +/* +=============== += += SpawnSchabbs += +=============== +*/ + +void SpawnSchabbs (int tilex, int tiley) +{ + unsigned far *map,tile; + + if (DigiMode != sds_Off) + s_schabbdie2.tictime = 140; + else + s_schabbdie2.tictime = 5; + + SpawnNewObj (tilex,tiley,&s_schabbstand); + new->speed = SPDPATROL; + + new->obclass = schabbobj; + new->hitpoints = starthitpoints[gamestate.difficulty][en_schabbs]; + new->dir = south; + new->flags |= FL_SHOOTABLE|FL_AMBUSH; + if (!loadedgame) + gamestate.killtotal++; +} + + +/* +=============== += += SpawnGift += +=============== +*/ + +void SpawnGift (int tilex, int tiley) +{ + unsigned far *map,tile; + + if (DigiMode != sds_Off) + s_giftdie2.tictime = 140; + else + s_giftdie2.tictime = 5; + + SpawnNewObj (tilex,tiley,&s_giftstand); + new->speed = SPDPATROL; + + new->obclass = giftobj; + new->hitpoints = starthitpoints[gamestate.difficulty][en_gift]; + new->dir = north; + new->flags |= FL_SHOOTABLE|FL_AMBUSH; + if (!loadedgame) + gamestate.killtotal++; +} + + +/* +=============== += += SpawnFat += +=============== +*/ + +void SpawnFat (int tilex, int tiley) +{ + unsigned far *map,tile; + + if (DigiMode != sds_Off) + s_fatdie2.tictime = 140; + else + s_fatdie2.tictime = 5; + + SpawnNewObj (tilex,tiley,&s_fatstand); + new->speed = SPDPATROL; + + new->obclass = fatobj; + new->hitpoints = starthitpoints[gamestate.difficulty][en_fat]; + new->dir = south; + new->flags |= FL_SHOOTABLE|FL_AMBUSH; + if (!loadedgame) + gamestate.killtotal++; +} + + +/* +================= += += T_SchabbThrow += +================= +*/ + +void T_SchabbThrow (objtype *ob) +{ + long deltax,deltay; + float angle; + int iangle; + + deltax = player->x - ob->x; + deltay = ob->y - player->y; + angle = atan2 (deltay,deltax); + if (angle<0) + angle = M_PI*2+angle; + iangle = angle/(M_PI*2)*ANGLES; + + GetNewActor (); + new->state = &s_needle1; + new->ticcount = 1; + + new->tilex = ob->tilex; + new->tiley = ob->tiley; + new->x = ob->x; + new->y = ob->y; + new->obclass = needleobj; + new->dir = nodir; + new->angle = iangle; + new->speed = 0x2000l; + + new->flags = FL_NONMARK; + new->active = true; + + PlaySoundLocActor (SCHABBSTHROWSND,new); +} + +/* +================= += += T_GiftThrow += +================= +*/ + +void T_GiftThrow (objtype *ob) +{ + long deltax,deltay; + float angle; + int iangle; + + deltax = player->x - ob->x; + deltay = ob->y - player->y; + angle = atan2 (deltay,deltax); + if (angle<0) + angle = M_PI*2+angle; + iangle = angle/(M_PI*2)*ANGLES; + + GetNewActor (); + new->state = &s_rocket; + new->ticcount = 1; + + new->tilex = ob->tilex; + new->tiley = ob->tiley; + new->x = ob->x; + new->y = ob->y; + new->obclass = rocketobj; + new->dir = nodir; + new->angle = iangle; + new->speed = 0x2000l; + new->flags = FL_NONMARK; + new->active = true; + + PlaySoundLocActor (MISSILEFIRESND,new); +} + + + +/* +================= += += T_Schabb += +================= +*/ + +void T_Schabb (objtype *ob) +{ + long move; + int dx,dy,dist; + boolean dodge; + + dodge = false; + dx = abs(ob->tilex - player->tilex); + dy = abs(ob->tiley - player->tiley); + dist = dx>dy ? dx : dy; + + if (CheckLine(ob)) // got a shot at player? + { + + if ( US_RndT() < (tics<<3) ) + { + // + // go into attack frame + // + NewState (ob,&s_schabbshoot1); + return; + } + dodge = true; + } + + if (ob->dir == nodir) + { + if (dodge) + SelectDodgeDir (ob); + else + SelectChaseDir (ob); + if (ob->dir == nodir) + return; // object is blocked in + } + + move = ob->speed*tics; + + while (move) + { + if (ob->distance < 0) + { + // + // waiting for a door to open + // + OpenDoor (-ob->distance-1); + if (doorobjlist[-ob->distance-1].action != dr_open) + return; + ob->distance = TILEGLOBAL; // go ahead, the door is now opoen + } + + if (move < ob->distance) + { + MoveObj (ob,move); + break; + } + + // + // reached goal tile, so select another one + // + + // + // fix position to account for round off during moving + // + ob->x = ((long)ob->tilex<y = ((long)ob->tiley<distance; + + if (dist <4) + SelectRunDir (ob); + else if (dodge) + SelectDodgeDir (ob); + else + SelectChaseDir (ob); + + if (ob->dir == nodir) + return; // object is blocked in + } + +} + + + + +/* +================= += += T_Gift += +================= +*/ + +void T_Gift (objtype *ob) +{ + long move; + int dx,dy,dist; + boolean dodge; + + dodge = false; + dx = abs(ob->tilex - player->tilex); + dy = abs(ob->tiley - player->tiley); + dist = dx>dy ? dx : dy; + + if (CheckLine(ob)) // got a shot at player? + { + + if ( US_RndT() < (tics<<3) ) + { + // + // go into attack frame + // + NewState (ob,&s_giftshoot1); + return; + } + dodge = true; + } + + if (ob->dir == nodir) + { + if (dodge) + SelectDodgeDir (ob); + else + SelectChaseDir (ob); + if (ob->dir == nodir) + return; // object is blocked in + } + + move = ob->speed*tics; + + while (move) + { + if (ob->distance < 0) + { + // + // waiting for a door to open + // + OpenDoor (-ob->distance-1); + if (doorobjlist[-ob->distance-1].action != dr_open) + return; + ob->distance = TILEGLOBAL; // go ahead, the door is now opoen + } + + if (move < ob->distance) + { + MoveObj (ob,move); + break; + } + + // + // reached goal tile, so select another one + // + + // + // fix position to account for round off during moving + // + ob->x = ((long)ob->tilex<y = ((long)ob->tiley<distance; + + if (dist <4) + SelectRunDir (ob); + else if (dodge) + SelectDodgeDir (ob); + else + SelectChaseDir (ob); + + if (ob->dir == nodir) + return; // object is blocked in + } + +} + + + + +/* +================= += += T_Fat += +================= +*/ + +void T_Fat (objtype *ob) +{ + long move; + int dx,dy,dist; + boolean dodge; + + dodge = false; + dx = abs(ob->tilex - player->tilex); + dy = abs(ob->tiley - player->tiley); + dist = dx>dy ? dx : dy; + + if (CheckLine(ob)) // got a shot at player? + { + + if ( US_RndT() < (tics<<3) ) + { + // + // go into attack frame + // + NewState (ob,&s_fatshoot1); + return; + } + dodge = true; + } + + if (ob->dir == nodir) + { + if (dodge) + SelectDodgeDir (ob); + else + SelectChaseDir (ob); + if (ob->dir == nodir) + return; // object is blocked in + } + + move = ob->speed*tics; + + while (move) + { + if (ob->distance < 0) + { + // + // waiting for a door to open + // + OpenDoor (-ob->distance-1); + if (doorobjlist[-ob->distance-1].action != dr_open) + return; + ob->distance = TILEGLOBAL; // go ahead, the door is now opoen + } + + if (move < ob->distance) + { + MoveObj (ob,move); + break; + } + + // + // reached goal tile, so select another one + // + + // + // fix position to account for round off during moving + // + ob->x = ((long)ob->tilex<y = ((long)ob->tiley<distance; + + if (dist <4) + SelectRunDir (ob); + else if (dodge) + SelectDodgeDir (ob); + else + SelectChaseDir (ob); + + if (ob->dir == nodir) + return; // object is blocked in + } + +} + + + +/* +============================================================================= + + HITLERS + +============================================================================= +*/ + + +// +// fake +// +extern statetype s_fakestand; + +extern statetype s_fakechase1; +extern statetype s_fakechase1s; +extern statetype s_fakechase2; +extern statetype s_fakechase3; +extern statetype s_fakechase3s; +extern statetype s_fakechase4; + +extern statetype s_fakedie1; +extern statetype s_fakedie2; +extern statetype s_fakedie3; +extern statetype s_fakedie4; +extern statetype s_fakedie5; +extern statetype s_fakedie6; + +extern statetype s_fakeshoot1; +extern statetype s_fakeshoot2; +extern statetype s_fakeshoot3; +extern statetype s_fakeshoot4; +extern statetype s_fakeshoot5; +extern statetype s_fakeshoot6; +extern statetype s_fakeshoot7; +extern statetype s_fakeshoot8; +extern statetype s_fakeshoot9; + +extern statetype s_fire1; +extern statetype s_fire2; + +statetype s_fakestand = {false,SPR_FAKE_W1,0,T_Stand,NULL,&s_fakestand}; + +statetype s_fakechase1 = {false,SPR_FAKE_W1,10,T_Fake,NULL,&s_fakechase1s}; +statetype s_fakechase1s = {false,SPR_FAKE_W1,3,NULL,NULL,&s_fakechase2}; +statetype s_fakechase2 = {false,SPR_FAKE_W2,8,T_Fake,NULL,&s_fakechase3}; +statetype s_fakechase3 = {false,SPR_FAKE_W3,10,T_Fake,NULL,&s_fakechase3s}; +statetype s_fakechase3s = {false,SPR_FAKE_W3,3,NULL,NULL,&s_fakechase4}; +statetype s_fakechase4 = {false,SPR_FAKE_W4,8,T_Fake,NULL,&s_fakechase1}; + +statetype s_fakedie1 = {false,SPR_FAKE_DIE1,10,NULL,A_DeathScream,&s_fakedie2}; +statetype s_fakedie2 = {false,SPR_FAKE_DIE2,10,NULL,NULL,&s_fakedie3}; +statetype s_fakedie3 = {false,SPR_FAKE_DIE3,10,NULL,NULL,&s_fakedie4}; +statetype s_fakedie4 = {false,SPR_FAKE_DIE4,10,NULL,NULL,&s_fakedie5}; +statetype s_fakedie5 = {false,SPR_FAKE_DIE5,10,NULL,NULL,&s_fakedie6}; +statetype s_fakedie6 = {false,SPR_FAKE_DEAD,0,NULL,NULL,&s_fakedie6}; + +statetype s_fakeshoot1 = {false,SPR_FAKE_SHOOT,8,NULL,T_FakeFire,&s_fakeshoot2}; +statetype s_fakeshoot2 = {false,SPR_FAKE_SHOOT,8,NULL,T_FakeFire,&s_fakeshoot3}; +statetype s_fakeshoot3 = {false,SPR_FAKE_SHOOT,8,NULL,T_FakeFire,&s_fakeshoot4}; +statetype s_fakeshoot4 = {false,SPR_FAKE_SHOOT,8,NULL,T_FakeFire,&s_fakeshoot5}; +statetype s_fakeshoot5 = {false,SPR_FAKE_SHOOT,8,NULL,T_FakeFire,&s_fakeshoot6}; +statetype s_fakeshoot6 = {false,SPR_FAKE_SHOOT,8,NULL,T_FakeFire,&s_fakeshoot7}; +statetype s_fakeshoot7 = {false,SPR_FAKE_SHOOT,8,NULL,T_FakeFire,&s_fakeshoot8}; +statetype s_fakeshoot8 = {false,SPR_FAKE_SHOOT,8,NULL,T_FakeFire,&s_fakeshoot9}; +statetype s_fakeshoot9 = {false,SPR_FAKE_SHOOT,8,NULL,NULL,&s_fakechase1}; + +statetype s_fire1 = {false,SPR_FIRE1,6,NULL,T_Projectile,&s_fire2}; +statetype s_fire2 = {false,SPR_FIRE2,6,NULL,T_Projectile,&s_fire1}; + +// +// hitler +// +extern statetype s_mechachase1; +extern statetype s_mechachase1s; +extern statetype s_mechachase2; +extern statetype s_mechachase3; +extern statetype s_mechachase3s; +extern statetype s_mechachase4; + +extern statetype s_mechadie1; +extern statetype s_mechadie2; +extern statetype s_mechadie3; +extern statetype s_mechadie4; + +extern statetype s_mechashoot1; +extern statetype s_mechashoot2; +extern statetype s_mechashoot3; +extern statetype s_mechashoot4; +extern statetype s_mechashoot5; +extern statetype s_mechashoot6; + + +extern statetype s_hitlerchase1; +extern statetype s_hitlerchase1s; +extern statetype s_hitlerchase2; +extern statetype s_hitlerchase3; +extern statetype s_hitlerchase3s; +extern statetype s_hitlerchase4; + +extern statetype s_hitlerdie1; +extern statetype s_hitlerdie2; +extern statetype s_hitlerdie3; +extern statetype s_hitlerdie4; +extern statetype s_hitlerdie5; +extern statetype s_hitlerdie6; +extern statetype s_hitlerdie7; +extern statetype s_hitlerdie8; +extern statetype s_hitlerdie9; +extern statetype s_hitlerdie10; + +extern statetype s_hitlershoot1; +extern statetype s_hitlershoot2; +extern statetype s_hitlershoot3; +extern statetype s_hitlershoot4; +extern statetype s_hitlershoot5; +extern statetype s_hitlershoot6; + +extern statetype s_hitlerdeathcam; + +statetype s_mechastand = {false,SPR_MECHA_W1,0,T_Stand,NULL,&s_mechastand}; + +statetype s_mechachase1 = {false,SPR_MECHA_W1,10,T_Chase,A_MechaSound,&s_mechachase1s}; +statetype s_mechachase1s = {false,SPR_MECHA_W1,6,NULL,NULL,&s_mechachase2}; +statetype s_mechachase2 = {false,SPR_MECHA_W2,8,T_Chase,NULL,&s_mechachase3}; +statetype s_mechachase3 = {false,SPR_MECHA_W3,10,T_Chase,A_MechaSound,&s_mechachase3s}; +statetype s_mechachase3s = {false,SPR_MECHA_W3,6,NULL,NULL,&s_mechachase4}; +statetype s_mechachase4 = {false,SPR_MECHA_W4,8,T_Chase,NULL,&s_mechachase1}; + +statetype s_mechadie1 = {false,SPR_MECHA_DIE1,10,NULL,A_DeathScream,&s_mechadie2}; +statetype s_mechadie2 = {false,SPR_MECHA_DIE2,10,NULL,NULL,&s_mechadie3}; +statetype s_mechadie3 = {false,SPR_MECHA_DIE3,10,NULL,A_HitlerMorph,&s_mechadie4}; +statetype s_mechadie4 = {false,SPR_MECHA_DEAD,0,NULL,NULL,&s_mechadie4}; + +statetype s_mechashoot1 = {false,SPR_MECHA_SHOOT1,30,NULL,NULL,&s_mechashoot2}; +statetype s_mechashoot2 = {false,SPR_MECHA_SHOOT2,10,NULL,T_Shoot,&s_mechashoot3}; +statetype s_mechashoot3 = {false,SPR_MECHA_SHOOT3,10,NULL,T_Shoot,&s_mechashoot4}; +statetype s_mechashoot4 = {false,SPR_MECHA_SHOOT2,10,NULL,T_Shoot,&s_mechashoot5}; +statetype s_mechashoot5 = {false,SPR_MECHA_SHOOT3,10,NULL,T_Shoot,&s_mechashoot6}; +statetype s_mechashoot6 = {false,SPR_MECHA_SHOOT2,10,NULL,T_Shoot,&s_mechachase1}; + + +statetype s_hitlerchase1 = {false,SPR_HITLER_W1,6,T_Chase,NULL,&s_hitlerchase1s}; +statetype s_hitlerchase1s = {false,SPR_HITLER_W1,4,NULL,NULL,&s_hitlerchase2}; +statetype s_hitlerchase2 = {false,SPR_HITLER_W2,2,T_Chase,NULL,&s_hitlerchase3}; +statetype s_hitlerchase3 = {false,SPR_HITLER_W3,6,T_Chase,NULL,&s_hitlerchase3s}; +statetype s_hitlerchase3s = {false,SPR_HITLER_W3,4,NULL,NULL,&s_hitlerchase4}; +statetype s_hitlerchase4 = {false,SPR_HITLER_W4,2,T_Chase,NULL,&s_hitlerchase1}; + +statetype s_hitlerdeathcam = {false,SPR_HITLER_W1,10,NULL,NULL,&s_hitlerdie1}; + +statetype s_hitlerdie1 = {false,SPR_HITLER_W1,1,NULL,A_DeathScream,&s_hitlerdie2}; +statetype s_hitlerdie2 = {false,SPR_HITLER_W1,10,NULL,NULL,&s_hitlerdie3}; +statetype s_hitlerdie3 = {false,SPR_HITLER_DIE1,10,NULL,A_Slurpie,&s_hitlerdie4}; +statetype s_hitlerdie4 = {false,SPR_HITLER_DIE2,10,NULL,NULL,&s_hitlerdie5}; +statetype s_hitlerdie5 = {false,SPR_HITLER_DIE3,10,NULL,NULL,&s_hitlerdie6}; +statetype s_hitlerdie6 = {false,SPR_HITLER_DIE4,10,NULL,NULL,&s_hitlerdie7}; +statetype s_hitlerdie7 = {false,SPR_HITLER_DIE5,10,NULL,NULL,&s_hitlerdie8}; +statetype s_hitlerdie8 = {false,SPR_HITLER_DIE6,10,NULL,NULL,&s_hitlerdie9}; +statetype s_hitlerdie9 = {false,SPR_HITLER_DIE7,10,NULL,NULL,&s_hitlerdie10}; +statetype s_hitlerdie10 = {false,SPR_HITLER_DEAD,20,NULL,A_StartDeathCam,&s_hitlerdie10}; + +statetype s_hitlershoot1 = {false,SPR_HITLER_SHOOT1,30,NULL,NULL,&s_hitlershoot2}; +statetype s_hitlershoot2 = {false,SPR_HITLER_SHOOT2,10,NULL,T_Shoot,&s_hitlershoot3}; +statetype s_hitlershoot3 = {false,SPR_HITLER_SHOOT3,10,NULL,T_Shoot,&s_hitlershoot4}; +statetype s_hitlershoot4 = {false,SPR_HITLER_SHOOT2,10,NULL,T_Shoot,&s_hitlershoot5}; +statetype s_hitlershoot5 = {false,SPR_HITLER_SHOOT3,10,NULL,T_Shoot,&s_hitlershoot6}; +statetype s_hitlershoot6 = {false,SPR_HITLER_SHOOT2,10,NULL,T_Shoot,&s_hitlerchase1}; + + + +/* +=============== += += SpawnFakeHitler += +=============== +*/ + +void SpawnFakeHitler (int tilex, int tiley) +{ + unsigned far *map,tile; + + + if (DigiMode != sds_Off) + s_hitlerdie2.tictime = 140; + else + s_hitlerdie2.tictime = 5; + + SpawnNewObj (tilex,tiley,&s_fakestand); + new->speed = SPDPATROL; + + new->obclass = fakeobj; + new->hitpoints = starthitpoints[gamestate.difficulty][en_fake]; + new->dir = north; + new->flags |= FL_SHOOTABLE|FL_AMBUSH; + if (!loadedgame) + gamestate.killtotal++; +} + + +/* +=============== += += SpawnHitler += +=============== +*/ + +void SpawnHitler (int tilex, int tiley) +{ + unsigned far *map,tile; + + if (DigiMode != sds_Off) + s_hitlerdie2.tictime = 140; + else + s_hitlerdie2.tictime = 5; + + + SpawnNewObj (tilex,tiley,&s_mechastand); + new->speed = SPDPATROL; + + new->obclass = mechahitlerobj; + new->hitpoints = starthitpoints[gamestate.difficulty][en_hitler]; + new->dir = south; + new->flags |= FL_SHOOTABLE|FL_AMBUSH; + if (!loadedgame) + gamestate.killtotal++; +} + + +/* +=============== += += A_HitlerMorph += +=============== +*/ + +void A_HitlerMorph (objtype *ob) +{ + unsigned far *map,tile,hitpoints[4]={500,700,800,900}; + + + SpawnNewObj (ob->tilex,ob->tiley,&s_hitlerchase1); + new->speed = SPDPATROL*5; + + new->x = ob->x; + new->y = ob->y; + + new->distance = ob->distance; + new->dir = ob->dir; + new->flags = ob->flags | FL_SHOOTABLE; + + new->obclass = realhitlerobj; + new->hitpoints = hitpoints[gamestate.difficulty]; +} + + +//////////////////////////////////////////////////////// +// +// A_MechaSound +// A_Slurpie +// +//////////////////////////////////////////////////////// +void A_MechaSound (objtype *ob) +{ + if (areabyplayer[ob->areanumber]) + PlaySoundLocActor (MECHSTEPSND,ob); +} + + +#pragma argsused +void A_Slurpie (objtype *ob) +{ + SD_PlaySound(SLURPIESND); +} + +/* +================= += += T_FakeFire += +================= +*/ + +void T_FakeFire (objtype *ob) +{ + long deltax,deltay; + float angle; + int iangle; + + deltax = player->x - ob->x; + deltay = ob->y - player->y; + angle = atan2 (deltay,deltax); + if (angle<0) + angle = M_PI*2+angle; + iangle = angle/(M_PI*2)*ANGLES; + + GetNewActor (); + new->state = &s_fire1; + new->ticcount = 1; + + new->tilex = ob->tilex; + new->tiley = ob->tiley; + new->x = ob->x; + new->y = ob->y; + new->dir = nodir; + new->angle = iangle; + new->obclass = fireobj; + new->speed = 0x1200l; + new->flags = FL_NEVERMARK; + new->active = true; + + PlaySoundLocActor (FLAMETHROWERSND,new); +} + + + +/* +================= += += T_Fake += +================= +*/ + +void T_Fake (objtype *ob) +{ + long move; + int dx,dy,dist; + boolean dodge; + + if (CheckLine(ob)) // got a shot at player? + { + if ( US_RndT() < (tics<<1) ) + { + // + // go into attack frame + // + NewState (ob,&s_fakeshoot1); + return; + } + } + + if (ob->dir == nodir) + { + SelectDodgeDir (ob); + if (ob->dir == nodir) + return; // object is blocked in + } + + move = ob->speed*tics; + + while (move) + { + if (move < ob->distance) + { + MoveObj (ob,move); + break; + } + + // + // reached goal tile, so select another one + // + + // + // fix position to account for round off during moving + // + ob->x = ((long)ob->tilex<y = ((long)ob->tiley<distance; + + SelectDodgeDir (ob); + + if (ob->dir == nodir) + return; // object is blocked in + } + +} + +#endif +/* +============================================================================ + + STAND + +============================================================================ +*/ + + +/* +=============== += += T_Stand += +=============== +*/ + +void T_Stand (objtype *ob) +{ + SightPlayer (ob); +} + + +/* +============================================================================ + + CHASE + +============================================================================ +*/ + +/* +================= += += T_Chase += +================= +*/ + +void T_Chase (objtype *ob) +{ + long move; + int dx,dy,dist,chance; + boolean dodge; + + if (gamestate.victoryflag) + return; + + dodge = false; + if (CheckLine(ob)) // got a shot at player? + { + dx = abs(ob->tilex - player->tilex); + dy = abs(ob->tiley - player->tiley); + dist = dx>dy ? dx : dy; + if (!dist || (dist==1 && ob->distance<0x4000) ) + chance = 300; + else + chance = (tics<<4)/dist; + + if ( US_RndT()obclass) + { + case guardobj: + NewState (ob,&s_grdshoot1); + break; + case officerobj: + NewState (ob,&s_ofcshoot1); + break; + case mutantobj: + NewState (ob,&s_mutshoot1); + break; + case ssobj: + NewState (ob,&s_ssshoot1); + break; +#ifndef SPEAR + case bossobj: + NewState (ob,&s_bossshoot1); + break; + case gretelobj: + NewState (ob,&s_gretelshoot1); + break; + case mechahitlerobj: + NewState (ob,&s_mechashoot1); + break; + case realhitlerobj: + NewState (ob,&s_hitlershoot1); + break; +#else + case angelobj: + NewState (ob,&s_angelshoot1); + break; + case transobj: + NewState (ob,&s_transshoot1); + break; + case uberobj: + NewState (ob,&s_ubershoot1); + break; + case willobj: + NewState (ob,&s_willshoot1); + break; + case deathobj: + NewState (ob,&s_deathshoot1); + break; +#endif + } + return; + } + dodge = true; + } + + if (ob->dir == nodir) + { + if (dodge) + SelectDodgeDir (ob); + else + SelectChaseDir (ob); + if (ob->dir == nodir) + return; // object is blocked in + } + + move = ob->speed*tics; + + while (move) + { + if (ob->distance < 0) + { + // + // waiting for a door to open + // + OpenDoor (-ob->distance-1); + if (doorobjlist[-ob->distance-1].action != dr_open) + return; + ob->distance = TILEGLOBAL; // go ahead, the door is now opoen + } + + if (move < ob->distance) + { + MoveObj (ob,move); + break; + } + + // + // reached goal tile, so select another one + // + + // + // fix position to account for round off during moving + // + ob->x = ((long)ob->tilex<y = ((long)ob->tiley<distance; + + if (dodge) + SelectDodgeDir (ob); + else + SelectChaseDir (ob); + + if (ob->dir == nodir) + return; // object is blocked in + } + +} + + +/* +================= += += T_Ghosts += +================= +*/ + +void T_Ghosts (objtype *ob) +{ + long move; + + + if (ob->dir == nodir) + { + SelectChaseDir (ob); + if (ob->dir == nodir) + return; // object is blocked in + } + + move = ob->speed*tics; + + while (move) + { + if (move < ob->distance) + { + MoveObj (ob,move); + break; + } + + // + // reached goal tile, so select another one + // + + // + // fix position to account for round off during moving + // + ob->x = ((long)ob->tilex<y = ((long)ob->tiley<distance; + + SelectChaseDir (ob); + + if (ob->dir == nodir) + return; // object is blocked in + } + +} + +/* +================= += += T_DogChase += +================= +*/ + +void T_DogChase (objtype *ob) +{ + long move; + int dist,chance; + long dx,dy; + + + if (ob->dir == nodir) + { + SelectDodgeDir (ob); + if (ob->dir == nodir) + return; // object is blocked in + } + + move = ob->speed*tics; + + while (move) + { + // + // check for byte range + // + dx = player->x - ob->x; + if (dx<0) + dx = -dx; + dx -= move; + if (dx <= MINACTORDIST) + { + dy = player->y - ob->y; + if (dy<0) + dy = -dy; + dy -= move; + if (dy <= MINACTORDIST) + { + NewState (ob,&s_dogjump1); + return; + } + } + + if (move < ob->distance) + { + MoveObj (ob,move); + break; + } + + // + // reached goal tile, so select another one + // + + // + // fix position to account for round off during moving + // + ob->x = ((long)ob->tilex<y = ((long)ob->tiley<distance; + + SelectDodgeDir (ob); + + if (ob->dir == nodir) + return; // object is blocked in + } + +} + + + +/* +============================================================================ + + PATH + +============================================================================ +*/ + + +/* +=============== += += SelectPathDir += +=============== +*/ + +void SelectPathDir (objtype *ob) +{ + unsigned spot; + + spot = MAPSPOT(ob->tilex,ob->tiley,1)-ICONARROWS; + + if (spot<8) + { + // new direction + ob->dir = spot; + } + + ob->distance = TILEGLOBAL; + + if (!TryWalk (ob)) + ob->dir = nodir; +} + + +/* +=============== += += T_Path += +=============== +*/ + +void T_Path (objtype *ob) +{ + long move; + long deltax,deltay,size; + + if (SightPlayer (ob)) + return; + + if (ob->dir == nodir) + { + SelectPathDir (ob); + if (ob->dir == nodir) + return; // all movement is blocked + } + + + move = ob->speed*tics; + + while (move) + { + if (ob->distance < 0) + { + // + // waiting for a door to open + // + OpenDoor (-ob->distance-1); + if (doorobjlist[-ob->distance-1].action != dr_open) + return; + ob->distance = TILEGLOBAL; // go ahead, the door is now opoen + } + + if (move < ob->distance) + { + MoveObj (ob,move); + break; + } + + if (ob->tilex>MAPSIZE || ob->tiley>MAPSIZE) + { + sprintf (str,"T_Path hit a wall at %u,%u, dir %u" + ,ob->tilex,ob->tiley,ob->dir); + Quit (str); + } + + + + ob->x = ((long)ob->tilex<y = ((long)ob->tiley<distance; + + SelectPathDir (ob); + + if (ob->dir == nodir) + return; // all movement is blocked + } +} + + +/* +============================================================================= + + FIGHT + +============================================================================= +*/ + + +/* +=============== += += T_Shoot += += Try to damage the player, based on skill level and player's speed += +=============== +*/ + +void T_Shoot (objtype *ob) +{ + int dx,dy,dist; + int hitchance,damage; + + hitchance = 128; + + if (!areabyplayer[ob->areanumber]) + return; + + if (!CheckLine (ob)) // player is behind a wall + return; + + dx = abs(ob->tilex - player->tilex); + dy = abs(ob->tiley - player->tiley); + dist = dx>dy ? dx:dy; + + if (ob->obclass == ssobj || ob->obclass == bossobj) + dist = dist*2/3; // ss are better shots + + if (thrustspeed >= RUNSPEED) + { + if (ob->flags&FL_VISABLE) + hitchance = 160-dist*16; // player can see to dodge + else + hitchance = 160-dist*8; + } + else + { + if (ob->flags&FL_VISABLE) + hitchance = 256-dist*16; // player can see to dodge + else + hitchance = 256-dist*8; + } + +// see if the shot was a hit + + if (US_RndT()>2; + else if (dist<4) + damage = US_RndT()>>3; + else + damage = US_RndT()>>4; + + TakeDamage (damage,ob); + } + + switch(ob->obclass) + { + case ssobj: + PlaySoundLocActor(SSFIRESND,ob); + break; +#ifndef SPEAR + case giftobj: + case fatobj: + PlaySoundLocActor(MISSILEFIRESND,ob); + break; + case mechahitlerobj: + case realhitlerobj: + case bossobj: + PlaySoundLocActor(BOSSFIRESND,ob); + break; + case schabbobj: + PlaySoundLocActor(SCHABBSTHROWSND,ob); + break; + case fakeobj: + PlaySoundLocActor(FLAMETHROWERSND,ob); + break; +#endif + default: + PlaySoundLocActor(NAZIFIRESND,ob); + } + +} + + +/* +=============== += += T_Bite += +=============== +*/ + +void T_Bite (objtype *ob) +{ + long dx,dy; + int hitchance,damage; + + + PlaySoundLocActor(DOGATTACKSND,ob); // JAB + + dx = player->x - ob->x; + if (dx<0) + dx = -dx; + dx -= TILEGLOBAL; + if (dx <= MINACTORDIST) + { + dy = player->y - ob->y; + if (dy<0) + dy = -dy; + dy -= TILEGLOBAL; + if (dy <= MINACTORDIST) + { + if (US_RndT()<180) + { + TakeDamage (US_RndT()>>4,ob); + return; + } + } + } + + return; +} + + +#ifndef SPEAR +/* +============================================================================ + + BJ VICTORY + +============================================================================ +*/ + + +// +// BJ victory +// + +void T_BJRun (objtype *ob); +void T_BJJump (objtype *ob); +void T_BJDone (objtype *ob); +void T_BJYell (objtype *ob); + +void T_DeathCam (objtype *ob); + +extern statetype s_bjrun1; +extern statetype s_bjrun1s; +extern statetype s_bjrun2; +extern statetype s_bjrun3; +extern statetype s_bjrun3s; +extern statetype s_bjrun4; + +extern statetype s_bjjump1; +extern statetype s_bjjump2; +extern statetype s_bjjump3; +extern statetype s_bjjump4; + + +statetype s_bjrun1 = {false,SPR_BJ_W1,12,T_BJRun,NULL,&s_bjrun1s}; +statetype s_bjrun1s = {false,SPR_BJ_W1,3, NULL,NULL,&s_bjrun2}; +statetype s_bjrun2 = {false,SPR_BJ_W2,8,T_BJRun,NULL,&s_bjrun3}; +statetype s_bjrun3 = {false,SPR_BJ_W3,12,T_BJRun,NULL,&s_bjrun3s}; +statetype s_bjrun3s = {false,SPR_BJ_W3,3, NULL,NULL,&s_bjrun4}; +statetype s_bjrun4 = {false,SPR_BJ_W4,8,T_BJRun,NULL,&s_bjrun1}; + + +statetype s_bjjump1 = {false,SPR_BJ_JUMP1,14,T_BJJump,NULL,&s_bjjump2}; +statetype s_bjjump2 = {false,SPR_BJ_JUMP2,14,T_BJJump,T_BJYell,&s_bjjump3}; +statetype s_bjjump3 = {false,SPR_BJ_JUMP3,14,T_BJJump,NULL,&s_bjjump4}; +statetype s_bjjump4 = {false,SPR_BJ_JUMP4,300,NULL,T_BJDone,&s_bjjump4}; + + +statetype s_deathcam = {false,0,0,NULL,NULL,NULL}; + + +/* +=============== += += SpawnBJVictory += +=============== +*/ + +void SpawnBJVictory (void) +{ + unsigned far *map,tile; + + SpawnNewObj (player->tilex,player->tiley+1,&s_bjrun1); + new->x = player->x; + new->y = player->y; + new->obclass = bjobj; + new->dir = north; + new->temp1 = 6; // tiles to run forward +} + + + +/* +=============== += += T_BJRun += +=============== +*/ + +void T_BJRun (objtype *ob) +{ + long move; + + move = BJRUNSPEED*tics; + + while (move) + { + if (move < ob->distance) + { + MoveObj (ob,move); + break; + } + + + ob->x = ((long)ob->tilex<y = ((long)ob->tiley<distance; + + SelectPathDir (ob); + + if ( !(--ob->temp1) ) + { + NewState (ob,&s_bjjump1); + return; + } + } +} + + +/* +=============== += += T_BJJump += +=============== +*/ + +void T_BJJump (objtype *ob) +{ + long move; + + move = BJJUMPSPEED*tics; + MoveObj (ob,move); +} + + +/* +=============== += += T_BJYell += +=============== +*/ + +void T_BJYell (objtype *ob) +{ + PlaySoundLocActor(YEAHSND,ob); // JAB +} + + +/* +=============== += += T_BJDone += +=============== +*/ + +#pragma argsused +void T_BJDone (objtype *ob) +{ + playstate = ex_victorious; // exit castle tile +} + + + +//=========================================================================== + + +/* +=============== += += CheckPosition += +=============== +*/ + +boolean CheckPosition (objtype *ob) +{ + int x,y,xl,yl,xh,yh; + objtype *check; + + xl = (ob->x-PLAYERSIZE) >>TILESHIFT; + yl = (ob->y-PLAYERSIZE) >>TILESHIFT; + + xh = (ob->x+PLAYERSIZE) >>TILESHIFT; + yh = (ob->y+PLAYERSIZE) >>TILESHIFT; + + // + // check for solid walls + // + for (y=yl;y<=yh;y++) + for (x=xl;x<=xh;x++) + { + check = actorat[x][y]; + if (check && checkx = gamestate.killx; + player->y = gamestate.killy; + + dx = ob->x - player->x; + dy = player->y - ob->y; + + fangle = atan2(dy,dx); // returns -pi to pi + if (fangle<0) + fangle = M_PI*2+fangle; + + player->angle = fangle/(M_PI*2)*ANGLES; + +// +// try to position as close as possible without being in a wall +// + dist = 0x14000l; + do + { + xmove = FixedByFrac(dist,costable[player->angle]); + ymove = -FixedByFrac(dist,sintable[player->angle]); + + player->x = ob->x - xmove; + player->y = ob->y - ymove; + dist += 0x1000; + + } while (!CheckPosition (player)); + plux = player->x >> UNSIGNEDSHIFT; // scale to fit in unsigned + pluy = player->y >> UNSIGNEDSHIFT; + player->tilex = player->x >> TILESHIFT; // scale to tile values + player->tiley = player->y >> TILESHIFT; + +// +// go back to the game +// + temp = bufferofs; + for (i=0;i<3;i++) + { + bufferofs = screenloc[i]; + DrawPlayBorder (); + } + bufferofs = temp; + + fizzlein = true; + switch (ob->obclass) + { +#ifndef SPEAR + case schabbobj: + NewState (ob,&s_schabbdeathcam); + break; + case realhitlerobj: + NewState (ob,&s_hitlerdeathcam); + break; + case giftobj: + NewState (ob,&s_giftdeathcam); + break; + case fatobj: + NewState (ob,&s_fatdeathcam); + break; +#endif + } + +} + +#endif diff --git a/16/WOLFSRC/WL_AGENT.C b/16/WOLFSRC/WL_AGENT.C new file mode 100755 index 00000000..631478d0 --- /dev/null +++ b/16/WOLFSRC/WL_AGENT.C @@ -0,0 +1,1421 @@ +// WL_AGENT.C + +#include "WL_DEF.H" +#pragma hdrstop + + +/* +============================================================================= + + LOCAL CONSTANTS + +============================================================================= +*/ + +#define MAXMOUSETURN 10 + + +#define MOVESCALE 150l +#define BACKMOVESCALE 100l +#define ANGLESCALE 20 + +/* +============================================================================= + + GLOBAL VARIABLES + +============================================================================= +*/ + + + +// +// player state info +// +boolean running; +long thrustspeed; + +unsigned plux,pluy; // player coordinates scaled to unsigned + +int anglefrac; +int gotgatgun; // JR + +objtype *LastAttacker; + +/* +============================================================================= + + LOCAL VARIABLES + +============================================================================= +*/ + + +void T_Player (objtype *ob); +void T_Attack (objtype *ob); + +statetype s_player = {false,0,0,T_Player,NULL,NULL}; +statetype s_attack = {false,0,0,T_Attack,NULL,NULL}; + + +long playerxmove,playerymove; + +struct atkinf +{ + char tics,attack,frame; // attack is 1 for gun, 2 for knife +} attackinfo[4][14] = + +{ +{ {6,0,1},{6,2,2},{6,0,3},{6,-1,4} }, +{ {6,0,1},{6,1,2},{6,0,3},{6,-1,4} }, +{ {6,0,1},{6,1,2},{6,3,3},{6,-1,4} }, +{ {6,0,1},{6,1,2},{6,4,3},{6,-1,4} }, +}; + + +int strafeangle[9] = {0,90,180,270,45,135,225,315,0}; + +void DrawWeapon (void); +void GiveWeapon (int weapon); +void GiveAmmo (int ammo); + +//=========================================================================== + +//---------- + +void Attack (void); +void Use (void); +void Search (objtype *ob); +void SelectWeapon (void); +void SelectItem (void); + +//---------- + +boolean TryMove (objtype *ob); +void T_Player (objtype *ob); + +void ClipMove (objtype *ob, long xmove, long ymove); + +/* +============================================================================= + + CONTROL STUFF + +============================================================================= +*/ + +/* +====================== += += CheckWeaponChange += += Keys 1-4 change weapons += +====================== +*/ + +void CheckWeaponChange (void) +{ + int i,buttons; + + if (!gamestate.ammo) // must use knife with no ammo + return; + + for (i=wp_knife ; i<=gamestate.bestweapon ; i++) + if (buttonstate[bt_readyknife+i-wp_knife]) + { + gamestate.weapon = gamestate.chosenweapon = i; + DrawWeapon (); + return; + } +} + + +/* +======================= += += ControlMovement += += Takes controlx,controly, and buttonstate[bt_strafe] += += Changes the player's angle and position += += There is an angle hack because when going 70 fps, the roundoff becomes += significant += +======================= +*/ + +void ControlMovement (objtype *ob) +{ + long oldx,oldy; + int angle,maxxmove; + int angleunits; + long speed; + + thrustspeed = 0; + + oldx = player->x; + oldy = player->y; + +// +// side to side move +// + if (buttonstate[bt_strafe]) + { + // + // strafing + // + // + if (controlx > 0) + { + angle = ob->angle - ANGLES/4; + if (angle < 0) + angle += ANGLES; + Thrust (angle,controlx*MOVESCALE); // move to left + } + else if (controlx < 0) + { + angle = ob->angle + ANGLES/4; + if (angle >= ANGLES) + angle -= ANGLES; + Thrust (angle,-controlx*MOVESCALE); // move to right + } + } + else + { + // + // not strafing + // + anglefrac += controlx; + angleunits = anglefrac/ANGLESCALE; + anglefrac -= angleunits*ANGLESCALE; + ob->angle -= angleunits; + + if (ob->angle >= ANGLES) + ob->angle -= ANGLES; + if (ob->angle < 0) + ob->angle += ANGLES; + + } + +// +// forward/backwards move +// + if (controly < 0) + { + Thrust (ob->angle,-controly*MOVESCALE); // move forwards + } + else if (controly > 0) + { + angle = ob->angle + ANGLES/2; + if (angle >= ANGLES) + angle -= ANGLES; + Thrust (angle,controly*BACKMOVESCALE); // move backwards + } + + if (gamestate.victoryflag) // watching the BJ actor + return; + +// +// calculate total move +// + playerxmove = player->x - oldx; + playerymove = player->y - oldy; +} + +/* +============================================================================= + + STATUS WINDOW STUFF + +============================================================================= +*/ + + +/* +================== += += StatusDrawPic += +================== +*/ + +void StatusDrawPic (unsigned x, unsigned y, unsigned picnum) +{ + unsigned temp; + + temp = bufferofs; + bufferofs = 0; + + bufferofs = PAGE1START+(200-STATUSLINES)*SCREENWIDTH; + LatchDrawPic (x,y,picnum); + bufferofs = PAGE2START+(200-STATUSLINES)*SCREENWIDTH; + LatchDrawPic (x,y,picnum); + bufferofs = PAGE3START+(200-STATUSLINES)*SCREENWIDTH; + LatchDrawPic (x,y,picnum); + + bufferofs = temp; +} + + +/* +================== += += DrawFace += +================== +*/ + +void DrawFace (void) +{ + if (gamestate.health) + { + #ifdef SPEAR + if (godmode) + StatusDrawPic (17,4,GODMODEFACE1PIC+gamestate.faceframe); + else + #endif + StatusDrawPic (17,4,FACE1APIC+3*((100-gamestate.health)/16)+gamestate.faceframe); + } + else + { +#ifndef SPEAR + if (LastAttacker->obclass == needleobj) + StatusDrawPic (17,4,MUTANTBJPIC); + else +#endif + StatusDrawPic (17,4,FACE8APIC); + } +} + + +/* +=============== += += UpdateFace += += Calls draw face if time to change += +=============== +*/ + +#define FACETICS 70 + +int facecount; + +void UpdateFace (void) +{ + + if (SD_SoundPlaying() == GETGATLINGSND) + return; + + facecount += tics; + if (facecount > US_RndT()) + { + gamestate.faceframe = (US_RndT()>>6); + if (gamestate.faceframe==3) + gamestate.faceframe = 1; + + facecount = 0; + DrawFace (); + } +} + + + +/* +=============== += += LatchNumber += += right justifies and pads with blanks += +=============== +*/ + +void LatchNumber (int x, int y, int width, long number) +{ + unsigned length,c; + char str[20]; + + ltoa (number,str,10); + + length = strlen (str); + + while (length>=2; + + if (!godmode) + gamestate.health -= points; + + if (gamestate.health<=0) + { + gamestate.health = 0; + playstate = ex_died; + killerobj = attacker; + } + + StartDamageFlash (points); + + gotgatgun=0; + + DrawHealth (); + DrawFace (); + + // + // MAKE BJ'S EYES BUG IF MAJOR DAMAGE! + // + #ifdef SPEAR + if (points > 30 && gamestate.health!=0 && !godmode) + { + StatusDrawPic (17,4,BJOUCHPIC); + facecount = 0; + } + #endif + +} + + +/* +=============== += += HealSelf += +=============== +*/ + +void HealSelf (int points) +{ + gamestate.health += points; + if (gamestate.health>100) + gamestate.health = 100; + + DrawHealth (); + gotgatgun = 0; // JR + DrawFace (); +} + + +//=========================================================================== + + +/* +=============== += += DrawLevel += +=============== +*/ + +void DrawLevel (void) +{ +#ifdef SPEAR + if (gamestate.mapon == 20) + LatchNumber (2,16,2,18); + else +#endif + LatchNumber (2,16,2,gamestate.mapon+1); +} + +//=========================================================================== + + +/* +=============== += += DrawLives += +=============== +*/ + +void DrawLives (void) +{ + LatchNumber (14,16,1,gamestate.lives); +} + + +/* +=============== += += GiveExtraMan += +=============== +*/ + +void GiveExtraMan (void) +{ + if (gamestate.lives<9) + gamestate.lives++; + DrawLives (); + SD_PlaySound (BONUS1UPSND); +} + +//=========================================================================== + +/* +=============== += += DrawScore += +=============== +*/ + +void DrawScore (void) +{ + LatchNumber (6,16,6,gamestate.score); +} + +/* +=============== += += GivePoints += +=============== +*/ + +void GivePoints (long points) +{ + gamestate.score += points; + while (gamestate.score >= gamestate.nextextra) + { + gamestate.nextextra += EXTRAPOINTS; + GiveExtraMan (); + } + DrawScore (); +} + +//=========================================================================== + +/* +================== += += DrawWeapon += +================== +*/ + +void DrawWeapon (void) +{ + StatusDrawPic (32,8,KNIFEPIC+gamestate.weapon); +} + + +/* +================== += += DrawKeys += +================== +*/ + +void DrawKeys (void) +{ + if (gamestate.keys & 1) + StatusDrawPic (30,4,GOLDKEYPIC); + else + StatusDrawPic (30,4,NOKEYPIC); + + if (gamestate.keys & 2) + StatusDrawPic (30,20,SILVERKEYPIC); + else + StatusDrawPic (30,20,NOKEYPIC); +} + + + +/* +================== += += GiveWeapon += +================== +*/ + +void GiveWeapon (int weapon) +{ + GiveAmmo (6); + + if (gamestate.bestweapon 99) + gamestate.ammo = 99; + DrawAmmo (); +} + +//=========================================================================== + +/* +================== += += GiveKey += +================== +*/ + +void GiveKey (int key) +{ + gamestate.keys |= (1<itemnumber) + { + case bo_firstaid: + if (gamestate.health == 100) + return; + + SD_PlaySound (HEALTH2SND); + HealSelf (25); + break; + + case bo_key1: + case bo_key2: + case bo_key3: + case bo_key4: + GiveKey (check->itemnumber - bo_key1); + SD_PlaySound (GETKEYSND); + break; + + case bo_cross: + SD_PlaySound (BONUS1SND); + GivePoints (100); + gamestate.treasurecount++; + break; + case bo_chalice: + SD_PlaySound (BONUS2SND); + GivePoints (500); + gamestate.treasurecount++; + break; + case bo_bible: + SD_PlaySound (BONUS3SND); + GivePoints (1000); + gamestate.treasurecount++; + break; + case bo_crown: + SD_PlaySound (BONUS4SND); + GivePoints (5000); + gamestate.treasurecount++; + break; + + case bo_clip: + if (gamestate.ammo == 99) + return; + + SD_PlaySound (GETAMMOSND); + GiveAmmo (8); + break; + case bo_clip2: + if (gamestate.ammo == 99) + return; + + SD_PlaySound (GETAMMOSND); + GiveAmmo (4); + break; + +#ifdef SPEAR + case bo_25clip: + if (gamestate.ammo == 99) + return; + + SD_PlaySound (GETAMMOBOXSND); + GiveAmmo (25); + break; +#endif + + case bo_machinegun: + SD_PlaySound (GETMACHINESND); + GiveWeapon (wp_machinegun); + break; + case bo_chaingun: + SD_PlaySound (GETGATLINGSND); + GiveWeapon (wp_chaingun); + + StatusDrawPic (17,4,GOTGATLINGPIC); + facecount = 0; + gotgatgun = 1; + break; + + case bo_fullheal: + SD_PlaySound (BONUS1UPSND); + HealSelf (99); + GiveAmmo (25); + GiveExtraMan (); + gamestate.treasurecount++; + break; + + case bo_food: + if (gamestate.health == 100) + return; + + SD_PlaySound (HEALTH1SND); + HealSelf (10); + break; + + case bo_alpo: + if (gamestate.health == 100) + return; + + SD_PlaySound (HEALTH1SND); + HealSelf (4); + break; + + case bo_gibs: + if (gamestate.health >10) + return; + + SD_PlaySound (SLURPIESND); + HealSelf (1); + break; + + case bo_spear: + spearflag = true; + spearx = player->x; + speary = player->y; + spearangle = player->angle; + playstate = ex_completed; + } + + StartBonusFlash (); + check->shapenum = -1; // remove from list +} + + +/* +=================== += += TryMove += += returns true if move ok += debug: use pointers to optimize +=================== +*/ + +boolean TryMove (objtype *ob) +{ + int xl,yl,xh,yh,x,y; + objtype *check; + long deltax,deltay; + + xl = (ob->x-PLAYERSIZE) >>TILESHIFT; + yl = (ob->y-PLAYERSIZE) >>TILESHIFT; + + xh = (ob->x+PLAYERSIZE) >>TILESHIFT; + yh = (ob->y+PLAYERSIZE) >>TILESHIFT; + +// +// check for solid walls +// + for (y=yl;y<=yh;y++) + for (x=xl;x<=xh;x++) + { + check = actorat[x][y]; + if (check && check0) + yl--; + if (yh0) + xl--; + if (xh objlist + && (check->flags & FL_SHOOTABLE) ) + { + deltax = ob->x - check->x; + if (deltax < -MINACTORDIST || deltax > MINACTORDIST) + continue; + deltay = ob->y - check->y; + if (deltay < -MINACTORDIST || deltay > MINACTORDIST) + continue; + + return false; + } + } + + return true; +} + + +/* +=================== += += ClipMove += +=================== +*/ + +void ClipMove (objtype *ob, long xmove, long ymove) +{ + long basex,basey; + + basex = ob->x; + basey = ob->y; + + ob->x = basex+xmove; + ob->y = basey+ymove; + if (TryMove (ob)) + return; + + if (noclip && ob->x > 2*TILEGLOBAL && ob->y > 2*TILEGLOBAL && + ob->x < (((long)(mapwidth-1))<y < (((long)(mapheight-1))<x = basex+xmove; + ob->y = basey; + if (TryMove (ob)) + return; + + ob->x = basex; + ob->y = basey+ymove; + if (TryMove (ob)) + return; + + ob->x = basex; + ob->y = basey; +} + +//========================================================================== + +/* +=================== += += VictoryTile += +=================== +*/ + +void VictoryTile (void) +{ +#ifndef SPEAR + SpawnBJVictory (); +#endif + + gamestate.victoryflag = true; +} + + +/* +=================== += += Thrust += +=================== +*/ + +void Thrust (int angle, long speed) +{ + long xmove,ymove; + long slowmax; + unsigned offset; + + + // + // ZERO FUNNY COUNTER IF MOVED! + // + #ifdef SPEAR + if (speed) + funnyticount = 0; + #endif + + thrustspeed += speed; +// +// moving bounds speed +// + if (speed >= MINDIST*2) + speed = MINDIST*2-1; + + xmove = FixedByFrac(speed,costable[angle]); + ymove = -FixedByFrac(speed,sintable[angle]); + + ClipMove(player,xmove,ymove); + + player->tilex = player->x >> TILESHIFT; // scale to tile values + player->tiley = player->y >> TILESHIFT; + + offset = farmapylookup[player->tiley]+player->tilex; + player->areanumber = *(mapsegs[0] + offset) -AREATILE; + + if (*(mapsegs[1] + offset) == EXITTILE) + VictoryTile (); +} + + +/* +============================================================================= + + ACTIONS + +============================================================================= +*/ + + +/* +=============== += += Cmd_Fire += +=============== +*/ + +void Cmd_Fire (void) +{ + buttonheld[bt_attack] = true; + + gamestate.weaponframe = 0; + + player->state = &s_attack; + + gamestate.attackframe = 0; + gamestate.attackcount = + attackinfo[gamestate.weapon][gamestate.attackframe].tics; + gamestate.weaponframe = + attackinfo[gamestate.weapon][gamestate.attackframe].frame; +} + +//=========================================================================== + +/* +=============== += += Cmd_Use += +=============== +*/ + +void Cmd_Use (void) +{ + objtype *check; + int checkx,checky,doornum,dir; + boolean elevatorok; + + +// +// find which cardinal direction the player is facing +// + if (player->angle < ANGLES/8 || player->angle > 7*ANGLES/8) + { + checkx = player->tilex + 1; + checky = player->tiley; + dir = di_east; + elevatorok = true; + } + else if (player->angle < 3*ANGLES/8) + { + checkx = player->tilex; + checky = player->tiley-1; + dir = di_north; + elevatorok = false; + } + else if (player->angle < 5*ANGLES/8) + { + checkx = player->tilex - 1; + checky = player->tiley; + dir = di_west; + elevatorok = true; + } + else + { + checkx = player->tilex; + checky = player->tiley + 1; + dir = di_south; + elevatorok = false; + } + + doornum = tilemap[checkx][checky]; + if (*(mapsegs[1]+farmapylookup[checky]+checkx) == PUSHABLETILE) + { + // + // pushable wall + // + + PushWall (checkx,checky,dir); + return; + } + if (!buttonheld[bt_use] && doornum == ELEVATORTILE && elevatorok) + { + // + // use elevator + // + buttonheld[bt_use] = true; + + tilemap[checkx][checky]++; // flip switch + if (*(mapsegs[0]+farmapylookup[player->tiley]+player->tilex) == ALTELEVATORTILE) + playstate = ex_secretlevel; + else + playstate = ex_completed; + SD_PlaySound (LEVELDONESND); + SD_WaitSoundDone(); + } + else if (!buttonheld[bt_use] && doornum & 0x80) + { + buttonheld[bt_use] = true; + OperateDoor (doornum & ~0x80); + } + else + SD_PlaySound (DONOTHINGSND); + +} + +/* +============================================================================= + + PLAYER CONTROL + +============================================================================= +*/ + + + +/* +=============== += += SpawnPlayer += +=============== +*/ + +void SpawnPlayer (int tilex, int tiley, int dir) +{ + player->obclass = playerobj; + player->active = true; + player->tilex = tilex; + player->tiley = tiley; + player->areanumber = + *(mapsegs[0] + farmapylookup[player->tiley]+player->tilex); + player->x = ((long)tilex<y = ((long)tiley<state = &s_player; + player->angle = (1-dir)*90; + if (player->angle<0) + player->angle += ANGLES; + player->flags = FL_NEVERMARK; + Thrust (0,0); // set some variables + + InitAreas (); +} + + +//=========================================================================== + +/* +=============== += += T_KnifeAttack += += Update player hands, and try to do damage when the proper frame is reached += +=============== +*/ + +void KnifeAttack (objtype *ob) +{ + objtype *check,*closest; + long dist; + + SD_PlaySound (ATKKNIFESND); +// actually fire + dist = 0x7fffffff; + closest = NULL; + for (check=ob->next ; check ; check=check->next) + if ( (check->flags & FL_SHOOTABLE) + && (check->flags & FL_VISABLE) + && abs (check->viewx-centerx) < shootdelta + ) + { + if (check->transx < dist) + { + dist = check->transx; + closest = check; + } + } + + if (!closest || dist> 0x18000l) + { + // missed + + return; + } + +// hit something + DamageActor (closest,US_RndT() >> 4); +} + + + +void GunAttack (objtype *ob) +{ + objtype *check,*closest,*oldclosest; + int damage; + int dx,dy,dist; + long viewdist; + + switch (gamestate.weapon) + { + case wp_pistol: + SD_PlaySound (ATKPISTOLSND); + break; + case wp_machinegun: + SD_PlaySound (ATKMACHINEGUNSND); + break; + case wp_chaingun: + SD_PlaySound (ATKGATLINGSND); + break; + } + + madenoise = true; + +// +// find potential targets +// + viewdist = 0x7fffffffl; + closest = NULL; + + while (1) + { + oldclosest = closest; + + for (check=ob->next ; check ; check=check->next) + if ( (check->flags & FL_SHOOTABLE) + && (check->flags & FL_VISABLE) + && abs (check->viewx-centerx) < shootdelta + ) + { + if (check->transx < viewdist) + { + viewdist = check->transx; + closest = check; + } + } + + if (closest == oldclosest) + return; // no more targets, all missed + + // + // trace a line from player to enemey + // + if (CheckLine(closest)) + break; + + } + +// +// hit something +// + dx = abs(closest->tilex - player->tilex); + dy = abs(closest->tiley - player->tiley); + dist = dx>dy ? dx:dy; + + if (dist<2) + damage = US_RndT() / 4; + else if (dist<4) + damage = US_RndT() / 6; + else + { + if ( (US_RndT() / 12) < dist) // missed + return; + damage = US_RndT() / 6; + } + + DamageActor (closest,damage); +} + +//=========================================================================== + +/* +=============== += += VictorySpin += +=============== +*/ + +void VictorySpin (void) +{ + long desty; + + if (player->angle > 270) + { + player->angle -= tics * 3; + if (player->angle < 270) + player->angle = 270; + } + else if (player->angle < 270) + { + player->angle += tics * 3; + if (player->angle > 270) + player->angle = 270; + } + + desty = (((long)player->tiley-5)<y > desty) + { + player->y -= tics*4096; + if (player->y < desty) + player->y = desty; + } +} + + +//=========================================================================== + +/* +=============== += += T_Attack += +=============== +*/ + +void T_Attack (objtype *ob) +{ + struct atkinf *cur; + + UpdateFace (); + + if (gamestate.victoryflag) // watching the BJ actor + { + VictorySpin (); + return; + } + + if ( buttonstate[bt_use] && !buttonheld[bt_use] ) + buttonstate[bt_use] = false; + + if ( buttonstate[bt_attack] && !buttonheld[bt_attack]) + buttonstate[bt_attack] = false; + + ControlMovement (ob); + if (gamestate.victoryflag) // watching the BJ actor + return; + + plux = player->x >> UNSIGNEDSHIFT; // scale to fit in unsigned + pluy = player->y >> UNSIGNEDSHIFT; + player->tilex = player->x >> TILESHIFT; // scale to tile values + player->tiley = player->y >> TILESHIFT; + +// +// change frame and fire +// + gamestate.attackcount -= tics; + while (gamestate.attackcount <= 0) + { + cur = &attackinfo[gamestate.weapon][gamestate.attackframe]; + switch (cur->attack) + { + case -1: + ob->state = &s_player; + if (!gamestate.ammo) + { + gamestate.weapon = wp_knife; + DrawWeapon (); + } + else + { + if (gamestate.weapon != gamestate.chosenweapon) + { + gamestate.weapon = gamestate.chosenweapon; + DrawWeapon (); + } + }; + gamestate.attackframe = gamestate.weaponframe = 0; + return; + + case 4: + if (!gamestate.ammo) + break; + if (buttonstate[bt_attack]) + gamestate.attackframe -= 2; + case 1: + if (!gamestate.ammo) + { // can only happen with chain gun + gamestate.attackframe++; + break; + } + GunAttack (ob); + gamestate.ammo--; + DrawAmmo (); + break; + + case 2: + KnifeAttack (ob); + break; + + case 3: + if (gamestate.ammo && buttonstate[bt_attack]) + gamestate.attackframe -= 2; + break; + } + + gamestate.attackcount += cur->tics; + gamestate.attackframe++; + gamestate.weaponframe = + attackinfo[gamestate.weapon][gamestate.attackframe].frame; + } + +} + + + +//=========================================================================== + +/* +=============== += += T_Player += +=============== +*/ + +void T_Player (objtype *ob) +{ + if (gamestate.victoryflag) // watching the BJ actor + { + VictorySpin (); + return; + } + + UpdateFace (); + CheckWeaponChange (); + + if ( buttonstate[bt_use] ) + Cmd_Use (); + + if ( buttonstate[bt_attack] && !buttonheld[bt_attack]) + Cmd_Fire (); + + ControlMovement (ob); + if (gamestate.victoryflag) // watching the BJ actor + return; + + + plux = player->x >> UNSIGNEDSHIFT; // scale to fit in unsigned + pluy = player->y >> UNSIGNEDSHIFT; + player->tilex = player->x >> TILESHIFT; // scale to tile values + player->tiley = player->y >> TILESHIFT; +} + + diff --git a/16/WOLFSRC/WL_ASM.ASM b/16/WOLFSRC/WL_ASM.ASM new file mode 100755 index 00000000..cca5d690 --- /dev/null +++ b/16/WOLFSRC/WL_ASM.ASM @@ -0,0 +1,69 @@ +; JABHACK.ASM + +.386C +IDEAL +MODEL MEDIUM + +EXTRN LDIV@:far + +;============================================================================ + +DATASEG + +;============================================================================ + +CODESEG + +; Hacked up Juan Jimenez's code a bit to just return 386/not 386 +PROC _CheckIs386 +PUBLIC _CheckIs386 + +;hack to never look for a 386, for benchmark comparisons of same code on all CPUs +; pushf ; Save flag registers, we use them here +; xor ax,ax ; Clear AX and... +; push ax ; ...push it onto the stack +; popf ; Pop 0 into flag registers (all bits to 0), +; pushf ; attempting to set bits 12-15 of flags to 0's +; pop ax ; Recover the save flags +; and ax,08000h ; If bits 12-15 of flags are set to +; cmp ax,08000h ; zero then it's 8088/86 or 80188/186 +; jz not386 +; +; mov ax,07000h ; Try to set flag bits 12-14 to 1's +; push ax ; Push the test value onto the stack +; popf ; Pop it into the flag register +; pushf ; Push it back onto the stack +; pop ax ; Pop it into AX for check +; and ax,07000h ; if bits 12-14 are cleared then +; jz not386 ; the chip is an 80286 +; +; mov ax,1 ; We now assume it's a 80386 or better +; popf +; retf +;end benchmark hack + +not386: + xor ax,ax + popf + retf + + ENDP + + +PROC _jabhack2 +PUBLIC _jabhack2 + + push es + + mov ax,seg LDIV@ + mov es,ax + mov ax,9090h ;Two NOP's + mov [WORD FAR es:LDIV@],ax ;Patch over XOR AX,AX + mov [WORD FAR es:LDIV@+2],ax ;and over JMP SHORT COMMON + + pop es + retf + + ENDP + + END diff --git a/16/WOLFSRC/WL_DEBUG.C b/16/WOLFSRC/WL_DEBUG.C new file mode 100755 index 00000000..dd4674b1 --- /dev/null +++ b/16/WOLFSRC/WL_DEBUG.C @@ -0,0 +1,722 @@ +// WL_DEBUG.C + +#include "WL_DEF.H" +#pragma hdrstop +#include + +/* +============================================================================= + + LOCAL CONSTANTS + +============================================================================= +*/ + +#define VIEWTILEX (viewwidth/16) +#define VIEWTILEY (viewheight/16) + +/* +============================================================================= + + GLOBAL VARIABLES + +============================================================================= +*/ + + +int DebugKeys (void); + +/* +============================================================================= + + LOCAL VARIABLES + +============================================================================= +*/ + + +int maporgx; +int maporgy; +enum {mapview,tilemapview,actoratview,visview} viewtype; + +void ViewMap (void); + +//=========================================================================== + +/* +================== += += DebugMemory += +================== +*/ + +void DebugMemory (void) +{ + int i; + char scratch[80],str[10]; + long mem; + spritetype _seg *block; + + CenterWindow (16,7); + + US_CPrint ("Memory Usage"); + US_CPrint ("------------"); + US_Print ("Total :"); + US_PrintUnsigned (mminfo.mainmem/1024); + US_Print ("k\nFree :"); + US_PrintUnsigned (MM_UnusedMemory()/1024); + US_Print ("k\nWith purge:"); + US_PrintUnsigned (MM_TotalFree()/1024); + US_Print ("k\n"); + VW_UpdateScreen(); + IN_Ack (); +} + +//=========================================================================== + +/* +================== += += CountObjects += +================== +*/ + +void CountObjects (void) +{ + int i,total,count,active,inactive,doors; + objtype *obj; + + CenterWindow (16,7); + active = inactive = count = doors = 0; + + US_Print ("Total statics :"); + total = laststatobj-&statobjlist[0]; + US_PrintUnsigned (total); + + US_Print ("\nIn use statics:"); + for (i=0;inext;obj;obj=obj->next) + { + if (obj->active) + active++; + else + inactive++; + } + + US_Print ("\nTotal actors :"); + US_PrintUnsigned (active+inactive); + + US_Print ("\nActive actors :"); + US_PrintUnsigned (active); + + VW_UpdateScreen(); + IN_Ack (); +} + +//=========================================================================== + +/* +================ += += PicturePause += +================ +*/ + +void PicturePause (void) +{ + int i; + byte p; + unsigned x; + byte far *dest,far *src; + memptr buffer; + + VW_ColorBorder (15); + FinishPaletteShifts (); + + LastScan = 0; + while (!LastScan) + ; + if (LastScan != sc_Enter) + { + VW_ColorBorder (0); + return; + } + + VW_ColorBorder (1); + VW_SetScreen (0,0); +// +// vga stuff... +// + + ClearMemory (); + CA_SetAllPurge(); + MM_GetPtr (&buffer,64000); + for (p=0;p<4;p++) + { + src = MK_FP(0xa000,displayofs); + dest = (byte far *)buffer+p; + VGAREADMAP(p); + for (x=0;x<16000;x++,dest+=4) + *dest = *src++; + } + + +#if 0 + for (p=0;p<4;p++) + { + src = MK_FP(0xa000,0); + dest = (byte far *)buffer+51200+p; + VGAREADMAP(p); + for (x=0;x<3200;x++,dest+=4) + *dest = *src++; + } +#endif + + asm mov ax,0x13 + asm int 0x10 + + dest = MK_FP(0xa000,0); + _fmemcpy (dest,buffer,64000); + + VL_SetPalette (&gamepal); + + + IN_Shutdown (); + + VW_WaitVBL(70); + bioskey(0); + VW_WaitVBL(70); + Quit (NULL); +} + + +//=========================================================================== + + +/* +================ += += ShapeTest += +================ +*/ + +#pragma warn -pia +void ShapeTest (void) +{ +extern word NumDigi; +extern word _seg *DigiList; +static char buf[10]; + + boolean done; + ScanCode scan; + int i,j,k,x; + longword l; + memptr addr; + PageListStruct far *page; + + CenterWindow(20,16); + VW_UpdateScreen(); + for (i = 0,done = false;!done;) + { + US_ClearWindow(); +// sound = -1; + + page = &PMPages[i]; + US_Print(" Page #"); + US_PrintUnsigned(i); + if (i < PMSpriteStart) + US_Print(" (Wall)"); + else if (i < PMSoundStart) + US_Print(" (Sprite)"); + else if (i == ChunksInFile - 1) + US_Print(" (Sound Info)"); + else + US_Print(" (Sound)"); + + US_Print("\n XMS: "); + if (page->xmsPage != -1) + US_PrintUnsigned(page->xmsPage); + else + US_Print("No"); + + US_Print("\n Main: "); + if (page->mainPage != -1) + US_PrintUnsigned(page->mainPage); + else if (page->emsPage != -1) + { + US_Print("EMS "); + US_PrintUnsigned(page->emsPage); + } + else + US_Print("No"); + + US_Print("\n Last hit: "); + US_PrintUnsigned(page->lastHit); + + US_Print("\n Address: "); + addr = PM_GetPageAddress(i); + sprintf(buf,"0x%04x",(word)addr); + US_Print(buf); + + if (addr) + { + if (i < PMSpriteStart) + { + // + // draw the wall + // + bufferofs += 32*SCREENWIDTH; + postx = 128; + postwidth = 1; + postsource = ((long)((unsigned)addr))<<16; + for (x=0;x<64;x++,postx++,postsource+=64) + { + wallheight[postx] = 256; + FarScalePost (); + } + bufferofs -= 32*SCREENWIDTH; + } + else if (i < PMSoundStart) + { + // + // draw the sprite + // + bufferofs += 32*SCREENWIDTH; + SimpleScaleShape (160, i-PMSpriteStart, 64); + bufferofs -= 32*SCREENWIDTH; + } + else if (i == ChunksInFile - 1) + { + US_Print("\n\n Number of sounds: "); + US_PrintUnsigned(NumDigi); + for (l = j = k = 0;j < NumDigi;j++) + { + l += DigiList[(j * 2) + 1]; + k += (DigiList[(j * 2) + 1] + (PMPageSize - 1)) / PMPageSize; + } + US_Print("\n Total bytes: "); + US_PrintUnsigned(l); + US_Print("\n Total pages: "); + US_PrintUnsigned(k); + } + else + { + byte far *dp = (byte far *)MK_FP(addr,0); + for (j = 0;j < NumDigi;j++) + { + k = (DigiList[(j * 2) + 1] + (PMPageSize - 1)) / PMPageSize; + if + ( + (i >= PMSoundStart + DigiList[j * 2]) + && (i < PMSoundStart + DigiList[j * 2] + k) + ) + break; + } + if (j < NumDigi) + { +// sound = j; + US_Print("\n Sound #"); + US_PrintUnsigned(j); + US_Print("\n Segment #"); + US_PrintUnsigned(i - PMSoundStart - DigiList[j * 2]); + } + for (j = 0;j < page->length;j += 32) + { + byte v = dp[j]; + int v2 = (unsigned)v; + v2 -= 128; + v2 /= 4; + if (v2 < 0) + VWB_Vlin(WindowY + WindowH - 32 + v2, + WindowY + WindowH - 32, + WindowX + 8 + (j / 32),BLACK); + else + VWB_Vlin(WindowY + WindowH - 32, + WindowY + WindowH - 32 + v2, + WindowX + 8 + (j / 32),BLACK); + } + } + } + + VW_UpdateScreen(); + + while (!(scan = LastScan)) + SD_Poll(); + + IN_ClearKey(scan); + switch (scan) + { + case sc_LeftArrow: + if (i) + i--; + break; + case sc_RightArrow: + if (++i >= ChunksInFile) + i--; + break; + case sc_W: // Walls + i = 0; + break; + case sc_S: // Sprites + i = PMSpriteStart; + break; + case sc_D: // Digitized + i = PMSoundStart; + break; + case sc_I: // Digitized info + i = ChunksInFile - 1; + break; + case sc_L: // Load all pages + for (j = 0;j < ChunksInFile;j++) + PM_GetPage(j); + break; + case sc_P: +// if (sound != -1) +// SD_PlayDigitized(sound); + break; + case sc_Escape: + done = true; + break; + case sc_Enter: + PM_GetPage(i); + break; + } + } + SD_StopDigitized(); +} +#pragma warn +pia + + + +//=========================================================================== + + +/* +================ += += DebugKeys += +================ +*/ + +int DebugKeys (void) +{ + boolean esc; + int level,i; + + if (Keyboard[sc_B]) // B = border color + { + CenterWindow(24,3); + PrintY+=6; + US_Print(" Border color (0-15):"); + VW_UpdateScreen(); + esc = !US_LineInput (px,py,str,NULL,true,2,0); + if (!esc) + { + level = atoi (str); + if (level>=0 && level<=15) + VW_ColorBorder (level); + } + return 1; + } + + if (Keyboard[sc_C]) // C = count objects + { + CountObjects(); + return 1; + } + + if (Keyboard[sc_E]) // E = quit level + { + if (tedlevel) + Quit (NULL); + playstate = ex_completed; +// gamestate.mapon++; + } + + if (Keyboard[sc_F]) // F = facing spot + { + CenterWindow (14,4); + US_Print ("X:"); + US_PrintUnsigned (player->x); + US_Print ("\nY:"); + US_PrintUnsigned (player->y); + US_Print ("\nA:"); + US_PrintUnsigned (player->angle); + VW_UpdateScreen(); + IN_Ack(); + return 1; + } + + if (Keyboard[sc_G]) // G = god mode + { + CenterWindow (12,2); + if (godmode) + US_PrintCentered ("God mode OFF"); + else + US_PrintCentered ("God mode ON"); + VW_UpdateScreen(); + IN_Ack(); + godmode ^= 1; + return 1; + } + if (Keyboard[sc_H]) // H = hurt self + { + IN_ClearKeysDown (); + TakeDamage (16,NULL); + } + else if (Keyboard[sc_I]) // I = item cheat + { + CenterWindow (12,3); + US_PrintCentered ("Free items!"); + VW_UpdateScreen(); + GivePoints (100000); + HealSelf (99); + if (gamestate.bestweapon 99) + gamestate.ammo = 99; + DrawAmmo (); + IN_Ack (); + return 1; + } + else if (Keyboard[sc_M]) // M = memory info + { + DebugMemory(); + return 1; + } +#ifdef SPEAR + else if (Keyboard[sc_N]) // N = no clip + { + noclip^=1; + CenterWindow (18,3); + if (noclip) + US_PrintCentered ("No clipping ON"); + else + US_PrintCentered ("No clipping OFF"); + VW_UpdateScreen(); + IN_Ack (); + return 1; + } +#endif +#if 0 + else if (Keyboard[sc_O]) // O = overhead + { + ViewMap(); + return 1; + } +#endif + else if (Keyboard[sc_P]) // P = pause with no screen disruptioon + { + PicturePause (); + return 1; + } + else if (Keyboard[sc_Q]) // Q = fast quit + Quit (NULL); + else if (Keyboard[sc_S]) // S = slow motion + { + singlestep^=1; + CenterWindow (18,3); + if (singlestep) + US_PrintCentered ("Slow motion ON"); + else + US_PrintCentered ("Slow motion OFF"); + VW_UpdateScreen(); + IN_Ack (); + return 1; + } + else if (Keyboard[sc_T]) // T = shape test + { + ShapeTest (); + return 1; + } + else if (Keyboard[sc_V]) // V = extra VBLs + { + CenterWindow(30,3); + PrintY+=6; + US_Print(" Add how many extra VBLs(0-8):"); + VW_UpdateScreen(); + esc = !US_LineInput (px,py,str,NULL,true,2,0); + if (!esc) + { + level = atoi (str); + if (level>=0 && level<=8) + extravbls = level; + } + return 1; + } + else if (Keyboard[sc_W]) // W = warp to level + { + CenterWindow(26,3); + PrintY+=6; +#ifndef SPEAR + US_Print(" Warp to which level(1-10):"); +#else + US_Print(" Warp to which level(1-21):"); +#endif + VW_UpdateScreen(); + esc = !US_LineInput (px,py,str,NULL,true,2,0); + if (!esc) + { + level = atoi (str); +#ifndef SPEAR + if (level>0 && level<11) +#else + if (level>0 && level<22) +#endif + { + gamestate.mapon = level-1; + playstate = ex_warped; + } + } + return 1; + } + else if (Keyboard[sc_X]) // X = item cheat + { + CenterWindow (12,3); + US_PrintCentered ("Extra stuff!"); + VW_UpdateScreen(); + // DEBUG: put stuff here + IN_Ack (); + return 1; + } + + return 0; +} + + +#if 0 +/* +=================== += += OverheadRefresh += +=================== +*/ + +void OverheadRefresh (void) +{ + unsigned x,y,endx,endy,sx,sy; + unsigned tile; + + + endx = maporgx+VIEWTILEX; + endy = maporgy+VIEWTILEY; + + for (y=maporgy;y>12)); + LatchDrawChar(sx+8,sy,NUMBERCHARS+((tile&0x0f00)>>8)); + LatchDrawChar(sx,sy+8,NUMBERCHARS+((tile&0x00f0)>>4)); + LatchDrawChar(sx+8,sy+8,NUMBERCHARS+(tile&0x000f)); + } + } + +} +#endif + +#if 0 +/* +=================== += += ViewMap += +=================== +*/ + +void ViewMap (void) +{ + boolean button0held; + + viewtype = actoratview; +// button0held = false; + + + maporgx = player->tilex - VIEWTILEX/2; + if (maporgx<0) + maporgx = 0; + if (maporgx>MAPSIZE-VIEWTILEX) + maporgx=MAPSIZE-VIEWTILEX; + maporgy = player->tiley - VIEWTILEY/2; + if (maporgy<0) + maporgy = 0; + if (maporgy>MAPSIZE-VIEWTILEY) + maporgy=MAPSIZE-VIEWTILEY; + + do + { +// +// let user pan around +// + PollControls (); + if (controlx < 0 && maporgx>0) + maporgx--; + if (controlx > 0 && maporgx0) + maporgy--; + if (controly > 0 && maporgyvisview) + viewtype = mapview; + } + if (!c.button0) + button0held = false; +#endif + + OverheadRefresh (); + + } while (!Keyboard[sc_Escape]); + + IN_ClearKeysDown (); +} +#endif + diff --git a/16/WOLFSRC/WL_DEF.H b/16/WOLFSRC/WL_DEF.H new file mode 100755 index 00000000..d1bc0802 --- /dev/null +++ b/16/WOLFSRC/WL_DEF.H @@ -0,0 +1,1276 @@ +//#define BETA +#define YEAR 1992 +#define MONTH 9 +#define DAY 30 + +#include "ID_HEADS.H" +#include +#include + +#include "WL_MENU.H" + +#ifdef SPANISH +#include "SPANISH.H" +#else +#include "FOREIGN.H" +#endif + +#ifdef SPEAR +#include "F_SPEAR.H" +#endif + +/* +============================================================================= + + MACROS + +============================================================================= +*/ + + +#define COLORBORDER(color) asm{mov dx,STATUS_REGISTER_1;in al,dx;\ + mov dx,ATR_INDEX;mov al,ATR_OVERSCAN;out dx,al;mov al,color;out dx,al;\ + mov al,32;out dx,al}; + +#define MAPSPOT(x,y,plane) (*(mapsegs[plane]+farmapylookup[y]+x)) + +#define SIGN(x) ((x)>0?1:-1) +#define ABS(x) ((int)(x)>0?(x):-(x)) +#define LABS(x) ((long)(x)>0?(x):-(x)) + +/* +============================================================================= + + GLOBAL CONSTANTS + +============================================================================= +*/ + +#define MAXACTORS 150 // max number of nazis, etc / map +#define MAXSTATS 400 // max number of lamps, bonus, etc +#define MAXDOORS 64 // max number of sliding doors +#define MAXWALLTILES 64 // max number of wall tiles + +// +// tile constants +// + +#define ICONARROWS 90 +#define PUSHABLETILE 98 +#define EXITTILE 99 // at end of castle +#define AREATILE 107 // first of NUMAREAS floor tiles +#define NUMAREAS 37 +#define ELEVATORTILE 21 +#define AMBUSHTILE 106 +#define ALTELEVATORTILE 107 + +#define NUMBERCHARS 9 + + +//---------------- + +#define EXTRAPOINTS 40000 + +#define PLAYERSPEED 3000 +#define RUNSPEED 6000 + +#define SCREENSEG 0xa000 + +#define SCREENBWIDE 80 + +#define HEIGHTRATIO 0.50 // also defined in id_mm.c + +#define BORDERCOLOR 3 +#define FLASHCOLOR 5 +#define FLASHTICS 4 + + +#define PLAYERSIZE MINDIST // player radius +#define MINACTORDIST 0x10000l // minimum dist from player center + // to any actor center + +#define NUMLATCHPICS 100 + + +#define PI 3.141592657 + +#define GLOBAL1 (1l<<16) +#define TILEGLOBAL GLOBAL1 +#define PIXGLOBAL (GLOBAL1/64) +#define TILESHIFT 16l +#define UNSIGNEDSHIFT 8 + +#define ANGLES 360 // must be divisable by 4 +#define ANGLEQUAD (ANGLES/4) +#define FINEANGLES 3600 +#define ANG90 (FINEANGLES/4) +#define ANG180 (ANG90*2) +#define ANG270 (ANG90*3) +#define ANG360 (ANG90*4) +#define VANG90 (ANGLES/4) +#define VANG180 (VANG90*2) +#define VANG270 (VANG90*3) +#define VANG360 (VANG90*4) + +#define MINDIST (0x5800l) + + +#define MAXSCALEHEIGHT 256 // largest scale on largest view + +#define MAXVIEWWIDTH 320 + +#define MAPSIZE 64 // maps are 64*64 max +#define NORTH 0 +#define EAST 1 +#define SOUTH 2 +#define WEST 3 + + +#define STATUSLINES 40 + +#define SCREENSIZE (SCREENBWIDE*208) +#define PAGE1START 0 +#define PAGE2START (SCREENSIZE) +#define PAGE3START (SCREENSIZE*2u) +#define FREESTART (SCREENSIZE*3u) + + +#define PIXRADIUS 512 + +#define STARTAMMO 8 + + +// object flag values + +#define FL_SHOOTABLE 1 +#define FL_BONUS 2 +#define FL_NEVERMARK 4 +#define FL_VISABLE 8 +#define FL_ATTACKMODE 16 +#define FL_FIRSTATTACK 32 +#define FL_AMBUSH 64 +#define FL_NONMARK 128 + + +// +// sprite constants +// + +enum { + SPR_DEMO, + SPR_DEATHCAM, +// +// static sprites +// + SPR_STAT_0,SPR_STAT_1,SPR_STAT_2,SPR_STAT_3, + SPR_STAT_4,SPR_STAT_5,SPR_STAT_6,SPR_STAT_7, + + SPR_STAT_8,SPR_STAT_9,SPR_STAT_10,SPR_STAT_11, + SPR_STAT_12,SPR_STAT_13,SPR_STAT_14,SPR_STAT_15, + + SPR_STAT_16,SPR_STAT_17,SPR_STAT_18,SPR_STAT_19, + SPR_STAT_20,SPR_STAT_21,SPR_STAT_22,SPR_STAT_23, + + SPR_STAT_24,SPR_STAT_25,SPR_STAT_26,SPR_STAT_27, + SPR_STAT_28,SPR_STAT_29,SPR_STAT_30,SPR_STAT_31, + + SPR_STAT_32,SPR_STAT_33,SPR_STAT_34,SPR_STAT_35, + SPR_STAT_36,SPR_STAT_37,SPR_STAT_38,SPR_STAT_39, + + SPR_STAT_40,SPR_STAT_41,SPR_STAT_42,SPR_STAT_43, + SPR_STAT_44,SPR_STAT_45,SPR_STAT_46,SPR_STAT_47, + +#ifdef SPEAR + SPR_STAT_48,SPR_STAT_49,SPR_STAT_50,SPR_STAT_51, +#endif + +// +// guard +// + SPR_GRD_S_1,SPR_GRD_S_2,SPR_GRD_S_3,SPR_GRD_S_4, + SPR_GRD_S_5,SPR_GRD_S_6,SPR_GRD_S_7,SPR_GRD_S_8, + + SPR_GRD_W1_1,SPR_GRD_W1_2,SPR_GRD_W1_3,SPR_GRD_W1_4, + SPR_GRD_W1_5,SPR_GRD_W1_6,SPR_GRD_W1_7,SPR_GRD_W1_8, + + SPR_GRD_W2_1,SPR_GRD_W2_2,SPR_GRD_W2_3,SPR_GRD_W2_4, + SPR_GRD_W2_5,SPR_GRD_W2_6,SPR_GRD_W2_7,SPR_GRD_W2_8, + + SPR_GRD_W3_1,SPR_GRD_W3_2,SPR_GRD_W3_3,SPR_GRD_W3_4, + SPR_GRD_W3_5,SPR_GRD_W3_6,SPR_GRD_W3_7,SPR_GRD_W3_8, + + SPR_GRD_W4_1,SPR_GRD_W4_2,SPR_GRD_W4_3,SPR_GRD_W4_4, + SPR_GRD_W4_5,SPR_GRD_W4_6,SPR_GRD_W4_7,SPR_GRD_W4_8, + + SPR_GRD_PAIN_1,SPR_GRD_DIE_1,SPR_GRD_DIE_2,SPR_GRD_DIE_3, + SPR_GRD_PAIN_2,SPR_GRD_DEAD, + + SPR_GRD_SHOOT1,SPR_GRD_SHOOT2,SPR_GRD_SHOOT3, + +// +// dogs +// + SPR_DOG_W1_1,SPR_DOG_W1_2,SPR_DOG_W1_3,SPR_DOG_W1_4, + SPR_DOG_W1_5,SPR_DOG_W1_6,SPR_DOG_W1_7,SPR_DOG_W1_8, + + SPR_DOG_W2_1,SPR_DOG_W2_2,SPR_DOG_W2_3,SPR_DOG_W2_4, + SPR_DOG_W2_5,SPR_DOG_W2_6,SPR_DOG_W2_7,SPR_DOG_W2_8, + + SPR_DOG_W3_1,SPR_DOG_W3_2,SPR_DOG_W3_3,SPR_DOG_W3_4, + SPR_DOG_W3_5,SPR_DOG_W3_6,SPR_DOG_W3_7,SPR_DOG_W3_8, + + SPR_DOG_W4_1,SPR_DOG_W4_2,SPR_DOG_W4_3,SPR_DOG_W4_4, + SPR_DOG_W4_5,SPR_DOG_W4_6,SPR_DOG_W4_7,SPR_DOG_W4_8, + + SPR_DOG_DIE_1,SPR_DOG_DIE_2,SPR_DOG_DIE_3,SPR_DOG_DEAD, + SPR_DOG_JUMP1,SPR_DOG_JUMP2,SPR_DOG_JUMP3, + + + +// +// ss +// + SPR_SS_S_1,SPR_SS_S_2,SPR_SS_S_3,SPR_SS_S_4, + SPR_SS_S_5,SPR_SS_S_6,SPR_SS_S_7,SPR_SS_S_8, + + SPR_SS_W1_1,SPR_SS_W1_2,SPR_SS_W1_3,SPR_SS_W1_4, + SPR_SS_W1_5,SPR_SS_W1_6,SPR_SS_W1_7,SPR_SS_W1_8, + + SPR_SS_W2_1,SPR_SS_W2_2,SPR_SS_W2_3,SPR_SS_W2_4, + SPR_SS_W2_5,SPR_SS_W2_6,SPR_SS_W2_7,SPR_SS_W2_8, + + SPR_SS_W3_1,SPR_SS_W3_2,SPR_SS_W3_3,SPR_SS_W3_4, + SPR_SS_W3_5,SPR_SS_W3_6,SPR_SS_W3_7,SPR_SS_W3_8, + + SPR_SS_W4_1,SPR_SS_W4_2,SPR_SS_W4_3,SPR_SS_W4_4, + SPR_SS_W4_5,SPR_SS_W4_6,SPR_SS_W4_7,SPR_SS_W4_8, + + SPR_SS_PAIN_1,SPR_SS_DIE_1,SPR_SS_DIE_2,SPR_SS_DIE_3, + SPR_SS_PAIN_2,SPR_SS_DEAD, + + SPR_SS_SHOOT1,SPR_SS_SHOOT2,SPR_SS_SHOOT3, + +// +// mutant +// + SPR_MUT_S_1,SPR_MUT_S_2,SPR_MUT_S_3,SPR_MUT_S_4, + SPR_MUT_S_5,SPR_MUT_S_6,SPR_MUT_S_7,SPR_MUT_S_8, + + SPR_MUT_W1_1,SPR_MUT_W1_2,SPR_MUT_W1_3,SPR_MUT_W1_4, + SPR_MUT_W1_5,SPR_MUT_W1_6,SPR_MUT_W1_7,SPR_MUT_W1_8, + + SPR_MUT_W2_1,SPR_MUT_W2_2,SPR_MUT_W2_3,SPR_MUT_W2_4, + SPR_MUT_W2_5,SPR_MUT_W2_6,SPR_MUT_W2_7,SPR_MUT_W2_8, + + SPR_MUT_W3_1,SPR_MUT_W3_2,SPR_MUT_W3_3,SPR_MUT_W3_4, + SPR_MUT_W3_5,SPR_MUT_W3_6,SPR_MUT_W3_7,SPR_MUT_W3_8, + + SPR_MUT_W4_1,SPR_MUT_W4_2,SPR_MUT_W4_3,SPR_MUT_W4_4, + SPR_MUT_W4_5,SPR_MUT_W4_6,SPR_MUT_W4_7,SPR_MUT_W4_8, + + SPR_MUT_PAIN_1,SPR_MUT_DIE_1,SPR_MUT_DIE_2,SPR_MUT_DIE_3, + SPR_MUT_PAIN_2,SPR_MUT_DIE_4,SPR_MUT_DEAD, + + SPR_MUT_SHOOT1,SPR_MUT_SHOOT2,SPR_MUT_SHOOT3,SPR_MUT_SHOOT4, + +// +// officer +// + SPR_OFC_S_1,SPR_OFC_S_2,SPR_OFC_S_3,SPR_OFC_S_4, + SPR_OFC_S_5,SPR_OFC_S_6,SPR_OFC_S_7,SPR_OFC_S_8, + + SPR_OFC_W1_1,SPR_OFC_W1_2,SPR_OFC_W1_3,SPR_OFC_W1_4, + SPR_OFC_W1_5,SPR_OFC_W1_6,SPR_OFC_W1_7,SPR_OFC_W1_8, + + SPR_OFC_W2_1,SPR_OFC_W2_2,SPR_OFC_W2_3,SPR_OFC_W2_4, + SPR_OFC_W2_5,SPR_OFC_W2_6,SPR_OFC_W2_7,SPR_OFC_W2_8, + + SPR_OFC_W3_1,SPR_OFC_W3_2,SPR_OFC_W3_3,SPR_OFC_W3_4, + SPR_OFC_W3_5,SPR_OFC_W3_6,SPR_OFC_W3_7,SPR_OFC_W3_8, + + SPR_OFC_W4_1,SPR_OFC_W4_2,SPR_OFC_W4_3,SPR_OFC_W4_4, + SPR_OFC_W4_5,SPR_OFC_W4_6,SPR_OFC_W4_7,SPR_OFC_W4_8, + + SPR_OFC_PAIN_1,SPR_OFC_DIE_1,SPR_OFC_DIE_2,SPR_OFC_DIE_3, + SPR_OFC_PAIN_2,SPR_OFC_DIE_4,SPR_OFC_DEAD, + + SPR_OFC_SHOOT1,SPR_OFC_SHOOT2,SPR_OFC_SHOOT3, + +#ifndef SPEAR +// +// ghosts +// + SPR_BLINKY_W1,SPR_BLINKY_W2,SPR_PINKY_W1,SPR_PINKY_W2, + SPR_CLYDE_W1,SPR_CLYDE_W2,SPR_INKY_W1,SPR_INKY_W2, + +// +// hans +// + SPR_BOSS_W1,SPR_BOSS_W2,SPR_BOSS_W3,SPR_BOSS_W4, + SPR_BOSS_SHOOT1,SPR_BOSS_SHOOT2,SPR_BOSS_SHOOT3,SPR_BOSS_DEAD, + + SPR_BOSS_DIE1,SPR_BOSS_DIE2,SPR_BOSS_DIE3, + +// +// schabbs +// + SPR_SCHABB_W1,SPR_SCHABB_W2,SPR_SCHABB_W3,SPR_SCHABB_W4, + SPR_SCHABB_SHOOT1,SPR_SCHABB_SHOOT2, + + SPR_SCHABB_DIE1,SPR_SCHABB_DIE2,SPR_SCHABB_DIE3,SPR_SCHABB_DEAD, + SPR_HYPO1,SPR_HYPO2,SPR_HYPO3,SPR_HYPO4, + +// +// fake +// + SPR_FAKE_W1,SPR_FAKE_W2,SPR_FAKE_W3,SPR_FAKE_W4, + SPR_FAKE_SHOOT,SPR_FIRE1,SPR_FIRE2, + + SPR_FAKE_DIE1,SPR_FAKE_DIE2,SPR_FAKE_DIE3,SPR_FAKE_DIE4, + SPR_FAKE_DIE5,SPR_FAKE_DEAD, + +// +// hitler +// + SPR_MECHA_W1,SPR_MECHA_W2,SPR_MECHA_W3,SPR_MECHA_W4, + SPR_MECHA_SHOOT1,SPR_MECHA_SHOOT2,SPR_MECHA_SHOOT3,SPR_MECHA_DEAD, + + SPR_MECHA_DIE1,SPR_MECHA_DIE2,SPR_MECHA_DIE3, + + SPR_HITLER_W1,SPR_HITLER_W2,SPR_HITLER_W3,SPR_HITLER_W4, + SPR_HITLER_SHOOT1,SPR_HITLER_SHOOT2,SPR_HITLER_SHOOT3,SPR_HITLER_DEAD, + + SPR_HITLER_DIE1,SPR_HITLER_DIE2,SPR_HITLER_DIE3,SPR_HITLER_DIE4, + SPR_HITLER_DIE5,SPR_HITLER_DIE6,SPR_HITLER_DIE7, + +// +// giftmacher +// + SPR_GIFT_W1,SPR_GIFT_W2,SPR_GIFT_W3,SPR_GIFT_W4, + SPR_GIFT_SHOOT1,SPR_GIFT_SHOOT2, + + SPR_GIFT_DIE1,SPR_GIFT_DIE2,SPR_GIFT_DIE3,SPR_GIFT_DEAD, +#endif +// +// Rocket, smoke and small explosion +// + SPR_ROCKET_1,SPR_ROCKET_2,SPR_ROCKET_3,SPR_ROCKET_4, + SPR_ROCKET_5,SPR_ROCKET_6,SPR_ROCKET_7,SPR_ROCKET_8, + + SPR_SMOKE_1,SPR_SMOKE_2,SPR_SMOKE_3,SPR_SMOKE_4, + SPR_BOOM_1,SPR_BOOM_2,SPR_BOOM_3, + +// +// Angel of Death's DeathSparks(tm) +// +#ifdef SPEAR + SPR_HROCKET_1,SPR_HROCKET_2,SPR_HROCKET_3,SPR_HROCKET_4, + SPR_HROCKET_5,SPR_HROCKET_6,SPR_HROCKET_7,SPR_HROCKET_8, + + SPR_HSMOKE_1,SPR_HSMOKE_2,SPR_HSMOKE_3,SPR_HSMOKE_4, + SPR_HBOOM_1,SPR_HBOOM_2,SPR_HBOOM_3, + + SPR_SPARK1,SPR_SPARK2,SPR_SPARK3,SPR_SPARK4, +#endif + +#ifndef SPEAR +// +// gretel +// + SPR_GRETEL_W1,SPR_GRETEL_W2,SPR_GRETEL_W3,SPR_GRETEL_W4, + SPR_GRETEL_SHOOT1,SPR_GRETEL_SHOOT2,SPR_GRETEL_SHOOT3,SPR_GRETEL_DEAD, + + SPR_GRETEL_DIE1,SPR_GRETEL_DIE2,SPR_GRETEL_DIE3, + +// +// fat face +// + SPR_FAT_W1,SPR_FAT_W2,SPR_FAT_W3,SPR_FAT_W4, + SPR_FAT_SHOOT1,SPR_FAT_SHOOT2,SPR_FAT_SHOOT3,SPR_FAT_SHOOT4, + + SPR_FAT_DIE1,SPR_FAT_DIE2,SPR_FAT_DIE3,SPR_FAT_DEAD, + +// +// bj +// + SPR_BJ_W1,SPR_BJ_W2,SPR_BJ_W3,SPR_BJ_W4, + SPR_BJ_JUMP1,SPR_BJ_JUMP2,SPR_BJ_JUMP3,SPR_BJ_JUMP4, +#else +// +// THESE ARE FOR 'SPEAR OF DESTINY' +// + +// +// Trans Grosse +// + SPR_TRANS_W1,SPR_TRANS_W2,SPR_TRANS_W3,SPR_TRANS_W4, + SPR_TRANS_SHOOT1,SPR_TRANS_SHOOT2,SPR_TRANS_SHOOT3,SPR_TRANS_DEAD, + + SPR_TRANS_DIE1,SPR_TRANS_DIE2,SPR_TRANS_DIE3, + +// +// Wilhelm +// + SPR_WILL_W1,SPR_WILL_W2,SPR_WILL_W3,SPR_WILL_W4, + SPR_WILL_SHOOT1,SPR_WILL_SHOOT2,SPR_WILL_SHOOT3,SPR_WILL_SHOOT4, + + SPR_WILL_DIE1,SPR_WILL_DIE2,SPR_WILL_DIE3,SPR_WILL_DEAD, + +// +// UberMutant +// + SPR_UBER_W1,SPR_UBER_W2,SPR_UBER_W3,SPR_UBER_W4, + SPR_UBER_SHOOT1,SPR_UBER_SHOOT2,SPR_UBER_SHOOT3,SPR_UBER_SHOOT4, + + SPR_UBER_DIE1,SPR_UBER_DIE2,SPR_UBER_DIE3,SPR_UBER_DIE4, + SPR_UBER_DEAD, + +// +// Death Knight +// + SPR_DEATH_W1,SPR_DEATH_W2,SPR_DEATH_W3,SPR_DEATH_W4, + SPR_DEATH_SHOOT1,SPR_DEATH_SHOOT2,SPR_DEATH_SHOOT3,SPR_DEATH_SHOOT4, + + SPR_DEATH_DIE1,SPR_DEATH_DIE2,SPR_DEATH_DIE3,SPR_DEATH_DIE4, + SPR_DEATH_DIE5,SPR_DEATH_DIE6,SPR_DEATH_DEAD, + +// +// Ghost +// + SPR_SPECTRE_W1,SPR_SPECTRE_W2,SPR_SPECTRE_W3,SPR_SPECTRE_W4, + SPR_SPECTRE_F1,SPR_SPECTRE_F2,SPR_SPECTRE_F3,SPR_SPECTRE_F4, + +// +// Angel of Death +// + SPR_ANGEL_W1,SPR_ANGEL_W2,SPR_ANGEL_W3,SPR_ANGEL_W4, + SPR_ANGEL_SHOOT1,SPR_ANGEL_SHOOT2,SPR_ANGEL_TIRED1,SPR_ANGEL_TIRED2, + + SPR_ANGEL_DIE1,SPR_ANGEL_DIE2,SPR_ANGEL_DIE3,SPR_ANGEL_DIE4, + SPR_ANGEL_DIE5,SPR_ANGEL_DIE6,SPR_ANGEL_DIE7,SPR_ANGEL_DEAD, + +#endif + +// +// player attack frames +// + SPR_KNIFEREADY,SPR_KNIFEATK1,SPR_KNIFEATK2,SPR_KNIFEATK3, + SPR_KNIFEATK4, + + SPR_PISTOLREADY,SPR_PISTOLATK1,SPR_PISTOLATK2,SPR_PISTOLATK3, + SPR_PISTOLATK4, + + SPR_MACHINEGUNREADY,SPR_MACHINEGUNATK1,SPR_MACHINEGUNATK2,MACHINEGUNATK3, + SPR_MACHINEGUNATK4, + + SPR_CHAINREADY,SPR_CHAINATK1,SPR_CHAINATK2,SPR_CHAINATK3, + SPR_CHAINATK4, + + }; + + +/* +============================================================================= + + GLOBAL TYPES + +============================================================================= +*/ + +typedef long fixed; + +typedef enum { + di_north, + di_east, + di_south, + di_west +} controldir_t; + +typedef enum { + dr_normal, + dr_lock1, + dr_lock2, + dr_lock3, + dr_lock4, + dr_elevator +} door_t; + +typedef enum { + ac_badobject = -1, + ac_no, + ac_yes, + ac_allways +} activetype; + +typedef enum { + nothing, + playerobj, + inertobj, + guardobj, + officerobj, + ssobj, + dogobj, + bossobj, + schabbobj, + fakeobj, + mechahitlerobj, + mutantobj, + needleobj, + fireobj, + bjobj, + ghostobj, + realhitlerobj, + gretelobj, + giftobj, + fatobj, + rocketobj, + + spectreobj, + angelobj, + transobj, + uberobj, + willobj, + deathobj, + hrocketobj, + sparkobj +} classtype; + +typedef enum { + dressing, + block, + bo_gibs, + bo_alpo, + bo_firstaid, + bo_key1, + bo_key2, + bo_key3, + bo_key4, + bo_cross, + bo_chalice, + bo_bible, + bo_crown, + bo_clip, + bo_clip2, + bo_machinegun, + bo_chaingun, + bo_food, + bo_fullheal, + bo_25clip, + bo_spear +} stat_t; + +typedef enum { + east, + northeast, + north, + northwest, + west, + southwest, + south, + southeast, + nodir +} dirtype; + + +#define NUMENEMIES 22 +typedef enum { + en_guard, + en_officer, + en_ss, + en_dog, + en_boss, + en_schabbs, + en_fake, + en_hitler, + en_mutant, + en_blinky, + en_clyde, + en_pinky, + en_inky, + en_gretel, + en_gift, + en_fat, + en_spectre, + en_angel, + en_trans, + en_uber, + en_will, + en_death +} enemy_t; + + +typedef struct statestruct +{ + boolean rotate; + int shapenum; // a shapenum of -1 means get from ob->temp1 + int tictime; + void (*think) (),(*action) (); + struct statestruct *next; +} statetype; + + +//--------------------- +// +// trivial actor structure +// +//--------------------- + +typedef struct statstruct +{ + byte tilex,tiley; + byte *visspot; + int shapenum; // if shapenum == -1 the obj has been removed + byte flags; + byte itemnumber; +} statobj_t; + + +//--------------------- +// +// door actor structure +// +//--------------------- + +typedef struct doorstruct +{ + byte tilex,tiley; + boolean vertical; + byte lock; + enum {dr_open,dr_closed,dr_opening,dr_closing} action; + int ticcount; +} doorobj_t; + + +//-------------------- +// +// thinking actor structure +// +//-------------------- + +typedef struct objstruct +{ + activetype active; + int ticcount; + classtype obclass; + statetype *state; + + byte flags; // FL_SHOOTABLE, etc + + long distance; // if negative, wait for that door to open + dirtype dir; + + fixed x,y; + unsigned tilex,tiley; + byte areanumber; + + int viewx; + unsigned viewheight; + fixed transx,transy; // in global coord + + int angle; + int hitpoints; + long speed; + + int temp1,temp2,temp3; + struct objstruct *next,*prev; +} objtype; + + +#define NUMBUTTONS 8 +enum { + bt_nobutton=-1, + bt_attack=0, + bt_strafe, + bt_run, + bt_use, + bt_readyknife, + bt_readypistol, + bt_readymachinegun, + bt_readychaingun +}; + + +#define NUMWEAPONS 5 +typedef enum { + wp_knife, + wp_pistol, + wp_machinegun, + wp_chaingun +} weapontype; + + +typedef enum { + gd_baby, + gd_easy, + gd_medium, + gd_hard +}; + +//--------------- +// +// gamestate structure +// +//--------------- + +typedef struct +{ + int difficulty; + int mapon; + long oldscore,score,nextextra; + int lives; + int health; + int ammo; + int keys; + weapontype bestweapon,weapon,chosenweapon; + + int faceframe; + int attackframe,attackcount,weaponframe; + + int episode,secretcount,treasurecount,killcount, + secrettotal,treasuretotal,killtotal; + long TimeCount; + long killx,killy; + boolean victoryflag; // set during victory animations +} gametype; + + +typedef enum { + ex_stillplaying, + ex_completed, + ex_died, + ex_warped, + ex_resetgame, + ex_loadedgame, + ex_victorious, + ex_abort, + ex_demodone, + ex_secretlevel +} exit_t; + + +/* +============================================================================= + + WL_MAIN DEFINITIONS + +============================================================================= +*/ + +extern boolean MS_CheckParm (char far *string); + +extern char str[80],str2[20]; +extern int tedlevelnum; +extern boolean tedlevel; +extern boolean nospr; +extern boolean IsA386; + +extern byte far *scalermemory; + +extern fixed focallength; +extern unsigned viewangles; +extern unsigned screenofs; +extern int viewwidth; +extern int viewheight; +extern int centerx; +extern int shootdelta; + +extern int dirangle[9]; + +extern boolean startgame,loadedgame,virtualreality; +extern int mouseadjustment; +// +// math tables +// +extern int pixelangle[MAXVIEWWIDTH]; +extern long far finetangent[FINEANGLES/4]; +extern fixed far sintable[],far *costable; + +// +// derived constants +// +extern fixed scale,maxslope; +extern long heightnumerator; +extern int minheightdiv; + +extern char configname[13]; + + + +void HelpScreens (void); +void OrderingInfo (void); +void TEDDeath(void); +void Quit (char *error); +void CalcProjection (long focal); +boolean SetViewSize (unsigned width, unsigned height); +void NewGame (int difficulty,int episode); +void NewViewSize (int width); +boolean LoadTheGame(int file,int x,int y); +boolean SaveTheGame(int file,int x,int y); +void ShowViewSize (int width); +void ShutdownId (void); + + +/* +============================================================================= + + WL_GAME DEFINITIONS + +============================================================================= +*/ + + +extern boolean ingame,fizzlein; +extern unsigned latchpics[NUMLATCHPICS]; +extern gametype gamestate; +extern int doornum; + +extern char demoname[13]; + +extern long spearx,speary; +extern unsigned spearangle; +extern boolean spearflag; + + +void DrawPlayBorder (void); +void ScanInfoPlane (void); +void SetupGameLevel (void); +void NormalScreen (void); +void DrawPlayScreen (void); +void FizzleOut (void); +void GameLoop (void); +void ClearMemory (void); +void PlayDemo (int demonumber); +void RecordDemo (void); +void DrawAllPlayBorder (void); +void DrawHighScores(void); +void DrawAllPlayBorderSides (void); + + +// JAB +#define PlaySoundLocTile(s,tx,ty) PlaySoundLocGlobal(s,(((long)(tx) << TILESHIFT) + (1L << (TILESHIFT - 1))),(((long)ty << TILESHIFT) + (1L << (TILESHIFT - 1)))) +#define PlaySoundLocActor(s,ob) PlaySoundLocGlobal(s,(ob)->x,(ob)->y) +void PlaySoundLocGlobal(word s,fixed gx,fixed gy); +void UpdateSoundLoc(void); + + +/* +============================================================================= + + WL_PLAY DEFINITIONS + +============================================================================= +*/ + +#ifdef SPEAR +extern long funnyticount; // FOR FUNNY BJ FACE +#endif + +extern exit_t playstate; + +extern boolean madenoise; + +extern objtype objlist[MAXACTORS],*new,*obj,*player,*lastobj, + *objfreelist,*killerobj; +extern statobj_t statobjlist[MAXSTATS],*laststatobj; +extern doorobj_t doorobjlist[MAXDOORS],*lastdoorobj; + +extern unsigned farmapylookup[MAPSIZE]; +extern byte *nearmapylookup[MAPSIZE]; + +extern byte tilemap[MAPSIZE][MAPSIZE]; // wall values only +extern byte spotvis[MAPSIZE][MAPSIZE]; +extern objtype *actorat[MAPSIZE][MAPSIZE]; + +#define UPDATESIZE (UPDATEWIDE*UPDATEHIGH) +extern byte update[UPDATESIZE]; + +extern boolean singlestep,godmode,noclip; +extern int extravbls; + +// +// control info +// +extern boolean mouseenabled,joystickenabled,joypadenabled,joystickprogressive; +extern int joystickport; +extern int dirscan[4]; +extern int buttonscan[NUMBUTTONS]; +extern int buttonmouse[4]; +extern int buttonjoy[4]; + +extern boolean buttonheld[NUMBUTTONS]; + +extern int viewsize; + +// +// curent user input +// +extern int controlx,controly; // range from -100 to 100 +extern boolean buttonstate[NUMBUTTONS]; + +extern boolean demorecord,demoplayback; +extern char far *demoptr, far *lastdemoptr; +extern memptr demobuffer; + + + +void InitRedShifts (void); +void FinishPaletteShifts (void); + +void CenterWindow(word w,word h); +void InitActorList (void); +void GetNewActor (void); +void RemoveObj (objtype *gone); +void PollControls (void); +void StopMusic(void); +void StartMusic(void); +void PlayLoop (void); +void StartDamageFlash (int damage); +void StartBonusFlash (void); + +/* +============================================================================= + + WL_INTER + +============================================================================= +*/ + +void IntroScreen (void); +void PreloadGraphics(void); +void LevelCompleted (void); +void CheckHighScore (long score,word other); +void Victory (void); +void ClearSplitVWB (void); + + +/* +============================================================================= + + WL_DEBUG + +============================================================================= +*/ + +int DebugKeys (void); +void PicturePause (void); + + +/* +============================================================================= + + WL_DRAW DEFINITIONS + +============================================================================= +*/ + +extern unsigned screenloc[3]; +extern unsigned freelatch; + +extern long lasttimecount; +extern long frameon; +extern boolean fizzlein; + +extern unsigned wallheight[MAXVIEWWIDTH]; + +extern fixed tileglobal; +extern fixed focallength; +extern fixed mindist; + +// +// math tables +// +extern int pixelangle[MAXVIEWWIDTH]; +extern long far finetangent[FINEANGLES/4]; +extern fixed far sintable[],far *costable; + +// +// derived constants +// +extern fixed scale; +extern long heightnumerator,mindist; + +// +// refresh variables +// +extern fixed viewx,viewy; // the focal point +extern int viewangle; +extern fixed viewsin,viewcos; + +extern long postsource; +extern unsigned postx; +extern unsigned postwidth; + + +extern int horizwall[],vertwall[]; + +extern unsigned pwallpos; + + +fixed FixedByFrac (fixed a, fixed b); +void TransformActor (objtype *ob); +void BuildTables (void); +void ClearScreen (void); +int CalcRotate (objtype *ob); +void DrawScaleds (void); +void CalcTics (void); +void FixOfs (void); +void ThreeDRefresh (void); +void FarScalePost (void); + +/* +============================================================================= + + WL_STATE DEFINITIONS + +============================================================================= +*/ +#define TURNTICS 10 +#define SPDPATROL 512 +#define SPDDOG 1500 + + +extern dirtype opposite[9]; +extern dirtype diagonal[9][9]; + + +void InitHitRect (objtype *ob, unsigned radius); +void SpawnNewObj (unsigned tilex, unsigned tiley, statetype *state); +void NewState (objtype *ob, statetype *state); + +boolean TryWalk (objtype *ob); +void SelectChaseDir (objtype *ob); +void SelectDodgeDir (objtype *ob); +void SelectRunDir (objtype *ob); +void MoveObj (objtype *ob, long move); +boolean SightPlayer (objtype *ob); + +void KillActor (objtype *ob); +void DamageActor (objtype *ob, unsigned damage); + +boolean CheckLine (objtype *ob); +boolean CheckSight (objtype *ob); + + +/* +============================================================================= + + WL_SCALE DEFINITIONS + +============================================================================= +*/ + + +#define COMPSCALECODESTART (65*4) // offset to start of code in comp scaler + +typedef struct +{ + unsigned codeofs[65]; + unsigned width[65]; + byte code[]; +} t_compscale; + +typedef struct +{ + unsigned leftpix,rightpix; + unsigned dataofs[64]; +// table data after dataofs[rightpix-leftpix+1] +} t_compshape; + + +extern t_compscale _seg *scaledirectory[MAXSCALEHEIGHT+1]; +extern long fullscalefarcall[MAXSCALEHEIGHT+1]; + +extern byte bitmasks1[8][8]; +extern byte bitmasks2[8][8]; +extern unsigned wordmasks[8][8]; + +extern byte mapmasks1[4][8]; +extern byte mapmasks2[4][8]; +extern byte mapmasks3[4][8]; + +extern int maxscale,maxscaleshl2; + +extern boolean insetupscaling; + +void SetupScaling (int maxscaleheight); +void ScaleShape (int xcenter, int shapenum, unsigned height); +void SimpleScaleShape (int xcenter, int shapenum, unsigned height); + +/* +============================================================================= + + WL_AGENT DEFINITIONS + +============================================================================= +*/ + +// +// player state info +// +extern boolean running; +extern long thrustspeed; +extern unsigned plux,pluy; // player coordinates scaled to unsigned + +extern int anglefrac; +extern int facecount; + +void SpawnPlayer (int tilex, int tiley, int dir); +void DrawFace (void); +void DrawHealth (void); +void TakeDamage (int points,objtype *attacker); +void HealSelf (int points); +void DrawLevel (void); +void DrawLives (void); +void GiveExtraMan (void); +void DrawScore (void); +void GivePoints (long points); +void DrawWeapon (void); +void DrawKeys (void); +void GiveWeapon (int weapon); +void DrawAmmo (void); +void GiveAmmo (int ammo); +void GiveKey (int key); +void GetBonus (statobj_t *check); + +void Thrust (int angle, long speed); + +/* +============================================================================= + + WL_ACT1 DEFINITIONS + +============================================================================= +*/ + +extern doorobj_t doorobjlist[MAXDOORS],*lastdoorobj; +extern int doornum; + +extern unsigned doorposition[MAXDOORS],pwallstate; + +extern byte far areaconnect[NUMAREAS][NUMAREAS]; + +extern boolean areabyplayer[NUMAREAS]; + +extern unsigned pwallstate; +extern unsigned pwallpos; // amount a pushable wall has been moved (0-63) +extern unsigned pwallx,pwally; +extern int pwalldir; + + +void InitDoorList (void); +void InitStaticList (void); +void SpawnStatic (int tilex, int tiley, int type); +void SpawnDoor (int tilex, int tiley, boolean vertical, int lock); +void MoveDoors (void); +void MovePWalls (void); +void OpenDoor (int door); +void PlaceItemType (int itemtype, int tilex, int tiley); +void PushWall (int checkx, int checky, int dir); +void OperateDoor (int door); +void InitAreas (void); + +/* +============================================================================= + + WL_ACT2 DEFINITIONS + +============================================================================= +*/ + +#define s_nakedbody s_static10 + +extern statetype s_grddie1; +extern statetype s_dogdie1; +extern statetype s_ofcdie1; +extern statetype s_mutdie1; +extern statetype s_ssdie1; +extern statetype s_bossdie1; +extern statetype s_schabbdie1; +extern statetype s_fakedie1; +extern statetype s_mechadie1; +extern statetype s_hitlerdie1; +extern statetype s_greteldie1; +extern statetype s_giftdie1; +extern statetype s_fatdie1; + +extern statetype s_spectredie1; +extern statetype s_angeldie1; +extern statetype s_transdie0; +extern statetype s_uberdie0; +extern statetype s_willdie1; +extern statetype s_deathdie1; + + +extern statetype s_grdchase1; +extern statetype s_dogchase1; +extern statetype s_ofcchase1; +extern statetype s_sschase1; +extern statetype s_mutchase1; +extern statetype s_bosschase1; +extern statetype s_schabbchase1; +extern statetype s_fakechase1; +extern statetype s_mechachase1; +extern statetype s_gretelchase1; +extern statetype s_giftchase1; +extern statetype s_fatchase1; + +extern statetype s_spectrechase1; +extern statetype s_angelchase1; +extern statetype s_transchase1; +extern statetype s_uberchase1; +extern statetype s_willchase1; +extern statetype s_deathchase1; + +extern statetype s_blinkychase1; +extern statetype s_hitlerchase1; + +extern statetype s_grdpain; +extern statetype s_grdpain1; +extern statetype s_ofcpain; +extern statetype s_ofcpain1; +extern statetype s_sspain; +extern statetype s_sspain1; +extern statetype s_mutpain; +extern statetype s_mutpain1; + +extern statetype s_deathcam; + +extern statetype s_schabbdeathcam2; +extern statetype s_hitlerdeathcam2; +extern statetype s_giftdeathcam2; +extern statetype s_fatdeathcam2; + +void SpawnStand (enemy_t which, int tilex, int tiley, int dir); +void SpawnPatrol (enemy_t which, int tilex, int tiley, int dir); +void KillActor (objtype *ob); + +void US_ControlPanel(byte); + +void SpawnDeadGuard (int tilex, int tiley); +void SpawnBoss (int tilex, int tiley); +void SpawnGretel (int tilex, int tiley); +void SpawnTrans (int tilex, int tiley); +void SpawnUber (int tilex, int tiley); +void SpawnWill (int tilex, int tiley); +void SpawnDeath (int tilex, int tiley); +void SpawnAngel (int tilex, int tiley); +void SpawnSpectre (int tilex, int tiley); +void SpawnGhosts (int which, int tilex, int tiley); +void SpawnSchabbs (int tilex, int tiley); +void SpawnGift (int tilex, int tiley); +void SpawnFat (int tilex, int tiley); +void SpawnFakeHitler (int tilex, int tiley); +void SpawnHitler (int tilex, int tiley); + +/* +============================================================================= + + WL_TEXT DEFINITIONS + +============================================================================= +*/ + +extern char helpfilename[],endfilename[]; + +extern void HelpScreens(void); +extern void EndText(void); diff --git a/16/WOLFSRC/WL_DRAW.C b/16/WOLFSRC/WL_DRAW.C new file mode 100755 index 00000000..3c32e39e --- /dev/null +++ b/16/WOLFSRC/WL_DRAW.C @@ -0,0 +1,1419 @@ +// WL_DRAW.C + +#include "WL_DEF.H" +#include +#pragma hdrstop + +//#define DEBUGWALLS +//#define DEBUGTICS + +/* +============================================================================= + + LOCAL CONSTANTS + +============================================================================= +*/ + +// the door is the last picture before the sprites +#define DOORWALL (PMSpriteStart-8) + +#define ACTORSIZE 0x4000 + +/* +============================================================================= + + GLOBAL VARIABLES + +============================================================================= +*/ + + +#ifdef DEBUGWALLS +unsigned screenloc[3]= {0,0,0}; +#else +unsigned screenloc[3]= {PAGE1START,PAGE2START,PAGE3START}; +#endif +unsigned freelatch = FREESTART; + +long lasttimecount; +long frameon; + +unsigned wallheight[MAXVIEWWIDTH]; + +fixed tileglobal = TILEGLOBAL; +fixed mindist = MINDIST; + + +// +// math tables +// +int pixelangle[MAXVIEWWIDTH]; +long far finetangent[FINEANGLES/4]; +fixed far sintable[ANGLES+ANGLES/4],far *costable = sintable+(ANGLES/4); + +// +// refresh variables +// +fixed viewx,viewy; // the focal point +int viewangle; +fixed viewsin,viewcos; + + + +fixed FixedByFrac (fixed a, fixed b); +void TransformActor (objtype *ob); +void BuildTables (void); +void ClearScreen (void); +int CalcRotate (objtype *ob); +void DrawScaleds (void); +void CalcTics (void); +void FixOfs (void); +void ThreeDRefresh (void); + + + +// +// wall optimization variables +// +int lastside; // true for vertical +long lastintercept; +int lasttilehit; + + +// +// ray tracing variables +// +int focaltx,focalty,viewtx,viewty; + +int midangle,angle; +unsigned xpartial,ypartial; +unsigned xpartialup,xpartialdown,ypartialup,ypartialdown; +unsigned xinttile,yinttile; + +unsigned tilehit; +unsigned pixx; + +int xtile,ytile; +int xtilestep,ytilestep; +long xintercept,yintercept; +long xstep,ystep; + +int horizwall[MAXWALLTILES],vertwall[MAXWALLTILES]; + + +/* +============================================================================= + + LOCAL VARIABLES + +============================================================================= +*/ + + +void AsmRefresh (void); // in WL_DR_A.ASM + +/* +============================================================================ + + 3 - D DEFINITIONS + +============================================================================ +*/ + + +//========================================================================== + + +/* +======================== += += FixedByFrac += += multiply a 16/16 bit, 2's complement fixed point number by a 16 bit += fraction, passed as a signed magnitude 32 bit number += +======================== +*/ + +#pragma warn -rvl // I stick the return value in with ASMs + +fixed FixedByFrac (fixed a, fixed b) +{ +// +// setup +// +asm mov si,[WORD PTR b+2] // sign of result = sign of fraction + +asm mov ax,[WORD PTR a] +asm mov cx,[WORD PTR a+2] + +asm or cx,cx +asm jns aok: // negative? +asm neg cx +asm neg ax +asm sbb cx,0 +asm xor si,0x8000 // toggle sign of result +aok: + +// +// multiply cx:ax by bx +// +asm mov bx,[WORD PTR b] +asm mul bx // fraction*fraction +asm mov di,dx // di is low word of result +asm mov ax,cx // +asm mul bx // units*fraction +asm add ax,di +asm adc dx,0 + +// +// put result dx:ax in 2's complement +// +asm test si,0x8000 // is the result negative? +asm jz ansok: +asm neg dx +asm neg ax +asm sbb dx,0 + +ansok:; + +} + +#pragma warn +rvl + +//========================================================================== + +/* +======================== += += TransformActor += += Takes paramaters: += gx,gy : globalx/globaly of point += += globals: += viewx,viewy : point of view += viewcos,viewsin : sin/cos of viewangle += scale : conversion from global value to screen value += += sets: += screenx,transx,transy,screenheight: projected edge location and size += +======================== +*/ + + +// +// transform actor +// +void TransformActor (objtype *ob) +{ + int ratio; + fixed gx,gy,gxt,gyt,nx,ny; + long temp; + +// +// translate point to view centered coordinates +// + gx = ob->x-viewx; + gy = ob->y-viewy; + +// +// calculate newx +// + gxt = FixedByFrac(gx,viewcos); + gyt = FixedByFrac(gy,viewsin); + nx = gxt-gyt-ACTORSIZE; // fudge the shape forward a bit, because + // the midpoint could put parts of the shape + // into an adjacent wall + +// +// calculate newy +// + gxt = FixedByFrac(gx,viewsin); + gyt = FixedByFrac(gy,viewcos); + ny = gyt+gxt; + +// +// calculate perspective ratio +// + ob->transx = nx; + ob->transy = ny; + + if (nxviewheight = 0; + return; + } + + ob->viewx = centerx + ny*scale/nx; // DEBUG: use assembly divide + +// +// calculate height (heightnumerator/(nx>>8)) +// + asm mov ax,[WORD PTR heightnumerator] + asm mov dx,[WORD PTR heightnumerator+2] + asm idiv [WORD PTR nx+1] // nx>>8 + asm mov [WORD PTR temp],ax + asm mov [WORD PTR temp+2],dx + + ob->viewheight = temp; +} + +//========================================================================== + +/* +======================== += += TransformTile += += Takes paramaters: += tx,ty : tile the object is centered in += += globals: += viewx,viewy : point of view += viewcos,viewsin : sin/cos of viewangle += scale : conversion from global value to screen value += += sets: += screenx,transx,transy,screenheight: projected edge location and size += += Returns true if the tile is withing getting distance += +======================== +*/ + +boolean TransformTile (int tx, int ty, int *dispx, int *dispheight) +{ + int ratio; + fixed gx,gy,gxt,gyt,nx,ny; + long temp; + +// +// translate point to view centered coordinates +// + gx = ((long)tx<>8)) +// + asm mov ax,[WORD PTR heightnumerator] + asm mov dx,[WORD PTR heightnumerator+2] + asm idiv [WORD PTR nx+1] // nx>>8 + asm mov [WORD PTR temp],ax + asm mov [WORD PTR temp+2],dx + + *dispheight = temp; + +// +// see if it should be grabbed +// + if (nx-TILEGLOBAL/2 && ny>8)) + // + if (nx>8 +} + + +//========================================================================== + +/* +=================== += += ScalePost += +=================== +*/ + +long postsource; +unsigned postx; +unsigned postwidth; + +void near ScalePost (void) // VGA version +{ + asm mov ax,SCREENSEG + asm mov es,ax + + asm mov bx,[postx] + asm shl bx,1 + asm mov bp,WORD PTR [wallheight+bx] // fractional height (low 3 bits frac) + asm and bp,0xfff8 // bp = heightscaler*4 + asm shr bp,1 + asm cmp bp,[maxscaleshl2] + asm jle heightok + asm mov bp,[maxscaleshl2] +heightok: + asm add bp,OFFSET fullscalefarcall + // + // scale a byte wide strip of wall + // + asm mov bx,[postx] + asm mov di,bx + asm shr di,1 // X in bytes + asm shr di,1 + asm add di,[bufferofs] + + asm and bx,3 + /* begin 8086 hack + asm shl bx,3 + */ + asm push cx + asm mov cl,3 + asm shl bx,cl + asm pop cx + /* end 8086 hack */ + asm add bx,[postwidth] + + asm mov al,BYTE PTR [mapmasks1-1+bx] // -1 because no widths of 0 + asm mov dx,SC_INDEX+1 + asm out dx,al // set bit mask register + asm lds si,DWORD PTR [postsource] + asm call DWORD PTR [bp] // scale the line of pixels + + asm mov al,BYTE PTR [ss:mapmasks2-1+bx] // -1 because no widths of 0 + asm or al,al + asm jz nomore + + // + // draw a second byte for vertical strips that cross two bytes + // + asm inc di + asm out dx,al // set bit mask register + asm call DWORD PTR [bp] // scale the line of pixels + + asm mov al,BYTE PTR [ss:mapmasks3-1+bx] // -1 because no widths of 0 + asm or al,al + asm jz nomore + // + // draw a third byte for vertical strips that cross three bytes + // + asm inc di + asm out dx,al // set bit mask register + asm call DWORD PTR [bp] // scale the line of pixels + + +nomore: + asm mov ax,ss + asm mov ds,ax +} + +void FarScalePost (void) // just so other files can call +{ + ScalePost (); +} + + +/* +==================== += += HitVertWall += += tilehit bit 7 is 0, because it's not a door tile += if bit 6 is 1 and the adjacent tile is a door tile, use door side pic += +==================== +*/ + +void HitVertWall (void) +{ + int wallpic; + unsigned texture; + + texture = (yintercept>>4)&0xfc0; + if (xtilestep == -1) + { + texture = 0xfc0-texture; + xintercept += TILEGLOBAL; + } + wallheight[pixx] = CalcHeight(); + + if (lastside==1 && lastintercept == xtile && lasttilehit == tilehit) + { + // in the same wall type as last time, so check for optimized draw + if (texture == (unsigned)postsource) + { + // wide scale + postwidth++; + wallheight[pixx] = wallheight[pixx-1]; + return; + } + else + { + ScalePost (); + (unsigned)postsource = texture; + postwidth = 1; + postx = pixx; + } + } + else + { + // new wall + if (lastside != -1) // if not the first scaled post + ScalePost (); + + lastside = true; + lastintercept = xtile; + + lasttilehit = tilehit; + postx = pixx; + postwidth = 1; + + if (tilehit & 0x40) + { // check for adjacent doors + ytile = yintercept>>TILESHIFT; + if ( tilemap[xtile-xtilestep][ytile]&0x80 ) + wallpic = DOORWALL+3; + else + wallpic = vertwall[tilehit & ~0x40]; + } + else + wallpic = vertwall[tilehit]; + + *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(wallpic); + (unsigned)postsource = texture; + + } +} + + +/* +==================== += += HitHorizWall += += tilehit bit 7 is 0, because it's not a door tile += if bit 6 is 1 and the adjacent tile is a door tile, use door side pic += +==================== +*/ + +void HitHorizWall (void) +{ + int wallpic; + unsigned texture; + + texture = (xintercept>>4)&0xfc0; + if (ytilestep == -1) + yintercept += TILEGLOBAL; + else + texture = 0xfc0-texture; + wallheight[pixx] = CalcHeight(); + + if (lastside==0 && lastintercept == ytile && lasttilehit == tilehit) + { + // in the same wall type as last time, so check for optimized draw + if (texture == (unsigned)postsource) + { + // wide scale + postwidth++; + wallheight[pixx] = wallheight[pixx-1]; + return; + } + else + { + ScalePost (); + (unsigned)postsource = texture; + postwidth = 1; + postx = pixx; + } + } + else + { + // new wall + if (lastside != -1) // if not the first scaled post + ScalePost (); + + lastside = 0; + lastintercept = ytile; + + lasttilehit = tilehit; + postx = pixx; + postwidth = 1; + + if (tilehit & 0x40) + { // check for adjacent doors + xtile = xintercept>>TILESHIFT; + if ( tilemap[xtile][ytile-ytilestep]&0x80 ) + wallpic = DOORWALL+2; + else + wallpic = horizwall[tilehit & ~0x40]; + } + else + wallpic = horizwall[tilehit]; + + *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(wallpic); + (unsigned)postsource = texture; + } + +} + +//========================================================================== + +/* +==================== += += HitHorizDoor += +==================== +*/ + +void HitHorizDoor (void) +{ + unsigned texture,doorpage,doornum; + + doornum = tilehit&0x7f; + texture = ( (xintercept-doorposition[doornum]) >> 4) &0xfc0; + + wallheight[pixx] = CalcHeight(); + + if (lasttilehit == tilehit) + { + // in the same door as last time, so check for optimized draw + if (texture == (unsigned)postsource) + { + // wide scale + postwidth++; + wallheight[pixx] = wallheight[pixx-1]; + return; + } + else + { + ScalePost (); + (unsigned)postsource = texture; + postwidth = 1; + postx = pixx; + } + } + else + { + if (lastside != -1) // if not the first scaled post + ScalePost (); // draw last post + // first pixel in this door + lastside = 2; + lasttilehit = tilehit; + postx = pixx; + postwidth = 1; + + switch (doorobjlist[doornum].lock) + { + case dr_normal: + doorpage = DOORWALL; + break; + case dr_lock1: + case dr_lock2: + case dr_lock3: + case dr_lock4: + doorpage = DOORWALL+6; + break; + case dr_elevator: + doorpage = DOORWALL+4; + break; + } + + *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(doorpage); + (unsigned)postsource = texture; + } +} + +//========================================================================== + +/* +==================== += += HitVertDoor += +==================== +*/ + +void HitVertDoor (void) +{ + unsigned texture,doorpage,doornum; + + doornum = tilehit&0x7f; + texture = ( (yintercept-doorposition[doornum]) >> 4) &0xfc0; + + wallheight[pixx] = CalcHeight(); + + if (lasttilehit == tilehit) + { + // in the same door as last time, so check for optimized draw + if (texture == (unsigned)postsource) + { + // wide scale + postwidth++; + wallheight[pixx] = wallheight[pixx-1]; + return; + } + else + { + ScalePost (); + (unsigned)postsource = texture; + postwidth = 1; + postx = pixx; + } + } + else + { + if (lastside != -1) // if not the first scaled post + ScalePost (); // draw last post + // first pixel in this door + lastside = 2; + lasttilehit = tilehit; + postx = pixx; + postwidth = 1; + + switch (doorobjlist[doornum].lock) + { + case dr_normal: + doorpage = DOORWALL; + break; + case dr_lock1: + case dr_lock2: + case dr_lock3: + case dr_lock4: + doorpage = DOORWALL+6; + break; + case dr_elevator: + doorpage = DOORWALL+4; + break; + } + + *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(doorpage+1); + (unsigned)postsource = texture; + } +} + +//========================================================================== + + +/* +==================== += += HitHorizPWall += += A pushable wall in action has been hit += +==================== +*/ + +void HitHorizPWall (void) +{ + int wallpic; + unsigned texture,offset; + + texture = (xintercept>>4)&0xfc0; + offset = pwallpos<<10; + if (ytilestep == -1) + yintercept += TILEGLOBAL-offset; + else + { + texture = 0xfc0-texture; + yintercept += offset; + } + + wallheight[pixx] = CalcHeight(); + + if (lasttilehit == tilehit) + { + // in the same wall type as last time, so check for optimized draw + if (texture == (unsigned)postsource) + { + // wide scale + postwidth++; + wallheight[pixx] = wallheight[pixx-1]; + return; + } + else + { + ScalePost (); + (unsigned)postsource = texture; + postwidth = 1; + postx = pixx; + } + } + else + { + // new wall + if (lastside != -1) // if not the first scaled post + ScalePost (); + + lasttilehit = tilehit; + postx = pixx; + postwidth = 1; + + wallpic = horizwall[tilehit&63]; + + *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(wallpic); + (unsigned)postsource = texture; + } + +} + + +/* +==================== += += HitVertPWall += += A pushable wall in action has been hit += +==================== +*/ + +void HitVertPWall (void) +{ + int wallpic; + unsigned texture,offset; + + texture = (yintercept>>4)&0xfc0; + offset = pwallpos<<10; + if (xtilestep == -1) + { + xintercept += TILEGLOBAL-offset; + texture = 0xfc0-texture; + } + else + xintercept += offset; + + wallheight[pixx] = CalcHeight(); + + if (lasttilehit == tilehit) + { + // in the same wall type as last time, so check for optimized draw + if (texture == (unsigned)postsource) + { + // wide scale + postwidth++; + wallheight[pixx] = wallheight[pixx-1]; + return; + } + else + { + ScalePost (); + (unsigned)postsource = texture; + postwidth = 1; + postx = pixx; + } + } + else + { + // new wall + if (lastside != -1) // if not the first scaled post + ScalePost (); + + lasttilehit = tilehit; + postx = pixx; + postwidth = 1; + + wallpic = vertwall[tilehit&63]; + + *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(wallpic); + (unsigned)postsource = texture; + } + +} + +//========================================================================== + +//========================================================================== + +#if 0 +/* +===================== += += ClearScreen += +===================== +*/ + +void ClearScreen (void) +{ + unsigned floor=egaFloor[gamestate.episode*10+mapon], + ceiling=egaCeiling[gamestate.episode*10+mapon]; + + // + // clear the screen + // +asm mov dx,GC_INDEX +asm mov ax,GC_MODE + 256*2 // read mode 0, write mode 2 +asm out dx,ax +asm mov ax,GC_BITMASK + 255*256 +asm out dx,ax + +asm mov dx,40 +asm mov ax,[viewwidth] +asm shr ax,1 +asm shr ax,1 +asm shr ax,1 +asm sub dx,ax // dx = 40-viewwidth/8 + +asm mov bx,[viewwidth] +asm shr bx,1 // bl = viewwidth/16 +asm shr bx,1 +asm shr bx,1 +asm shr bx,1 +asm mov bh,BYTE PTR [viewheight] +asm shr bh,1 // half height + +asm mov ax,[ceiling] +asm mov es,[screenseg] +asm mov di,[bufferofs] + +toploop: +asm mov cl,bl +asm rep stosw +asm add di,dx +asm dec bh +asm jnz toploop + +asm mov bh,BYTE PTR [viewheight] +asm shr bh,1 // half height +asm mov ax,[floor] + +bottomloop: +asm mov cl,bl +asm rep stosw +asm add di,dx +asm dec bh +asm jnz bottomloop + + +asm mov dx,GC_INDEX +asm mov ax,GC_MODE + 256*10 // read mode 1, write mode 2 +asm out dx,ax +asm mov al,GC_BITMASK +asm out dx,al + +} +#endif +//========================================================================== + +unsigned vgaCeiling[]= +{ +#ifndef SPEAR + 0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0xbfbf, + 0x4e4e,0x4e4e,0x4e4e,0x1d1d,0x8d8d,0x4e4e,0x1d1d,0x2d2d,0x1d1d,0x8d8d, + 0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x2d2d,0xdddd,0x1d1d,0x1d1d,0x9898, + + 0x1d1d,0x9d9d,0x2d2d,0xdddd,0xdddd,0x9d9d,0x2d2d,0x4d4d,0x1d1d,0xdddd, + 0x7d7d,0x1d1d,0x2d2d,0x2d2d,0xdddd,0xd7d7,0x1d1d,0x1d1d,0x1d1d,0x2d2d, + 0x1d1d,0x1d1d,0x1d1d,0x1d1d,0xdddd,0xdddd,0x7d7d,0xdddd,0xdddd,0xdddd +#else + 0x6f6f,0x4f4f,0x1d1d,0xdede,0xdfdf,0x2e2e,0x7f7f,0x9e9e,0xaeae,0x7f7f, + 0x1d1d,0xdede,0xdfdf,0xdede,0xdfdf,0xdede,0xe1e1,0xdcdc,0x2e2e,0x1d1d,0xdcdc +#endif +}; + +/* +===================== += += VGAClearScreen += +===================== +*/ + +void VGAClearScreen (void) +{ + unsigned ceiling=vgaCeiling[gamestate.episode*10+mapon]; + + // + // clear the screen + // +asm mov dx,SC_INDEX +asm mov ax,SC_MAPMASK+15*256 // write through all planes +asm out dx,ax + +asm mov dx,80 +asm mov ax,[viewwidth] +asm shr ax,1 +asm shr ax,1 +asm sub dx,ax // dx = 40-viewwidth/2 + +asm mov bx,[viewwidth] +asm shr bx,1 // bl = viewwidth/8 +asm shr bx,1 +asm shr bx,1 +asm mov bh,BYTE PTR [viewheight] +asm shr bh,1 // half height + +asm mov es,[screenseg] +asm mov di,[bufferofs] +asm mov ax,[ceiling] + +toploop: +asm mov cl,bl +asm rep stosw +asm add di,dx +asm dec bh +asm jnz toploop + +asm mov bh,BYTE PTR [viewheight] +asm shr bh,1 // half height +asm mov ax,0x1919 + +bottomloop: +asm mov cl,bl +asm rep stosw +asm add di,dx +asm dec bh +asm jnz bottomloop +} + +//========================================================================== + +/* +===================== += += CalcRotate += +===================== +*/ + +int CalcRotate (objtype *ob) +{ + int angle,viewangle; + + // this isn't exactly correct, as it should vary by a trig value, + // but it is close enough with only eight rotations + + viewangle = player->angle + (centerx - ob->viewx)/8; + + if (ob->obclass == rocketobj || ob->obclass == hrocketobj) + angle = (viewangle-180)- ob->angle; + else + angle = (viewangle-180)- dirangle[ob->dir]; + + angle+=ANGLES/16; + while (angle>=ANGLES) + angle-=ANGLES; + while (angle<0) + angle+=ANGLES; + + if (ob->state->rotate == 2) // 2 rotation pain frame + return 4*(angle/(ANGLES/2)); // seperated by 3 (art layout...) + + return angle/(ANGLES/8); +} + + +/* +===================== += += DrawScaleds += += Draws all objects that are visable += +===================== +*/ + +#define MAXVISABLE 50 + +typedef struct +{ + int viewx, + viewheight, + shapenum; +} visobj_t; + +visobj_t vislist[MAXVISABLE],*visptr,*visstep,*farthest; + +void DrawScaleds (void) +{ + int i,j,least,numvisable,height; + memptr shape; + byte *tilespot,*visspot; + int shapenum; + unsigned spotloc; + + statobj_t *statptr; + objtype *obj; + + visptr = &vislist[0]; + +// +// place static objects +// + for (statptr = &statobjlist[0] ; statptr !=laststatobj ; statptr++) + { + if ((visptr->shapenum = statptr->shapenum) == -1) + continue; // object has been deleted + + if (!*statptr->visspot) + continue; // not visable + + if (TransformTile (statptr->tilex,statptr->tiley + ,&visptr->viewx,&visptr->viewheight) && statptr->flags & FL_BONUS) + { + GetBonus (statptr); + continue; + } + + if (!visptr->viewheight) + continue; // to close to the object + + if (visptr < &vislist[MAXVISABLE-1]) // don't let it overflow + visptr++; + } + +// +// place active objects +// + for (obj = player->next;obj;obj=obj->next) + { + if (!(visptr->shapenum = obj->state->shapenum)) + continue; // no shape + + spotloc = (obj->tilex<<6)+obj->tiley; // optimize: keep in struct? + visspot = &spotvis[0][0]+spotloc; + tilespot = &tilemap[0][0]+spotloc; + + // + // could be in any of the nine surrounding tiles + // + if (*visspot + || ( *(visspot-1) && !*(tilespot-1) ) + || ( *(visspot+1) && !*(tilespot+1) ) + || ( *(visspot-65) && !*(tilespot-65) ) + || ( *(visspot-64) && !*(tilespot-64) ) + || ( *(visspot-63) && !*(tilespot-63) ) + || ( *(visspot+65) && !*(tilespot+65) ) + || ( *(visspot+64) && !*(tilespot+64) ) + || ( *(visspot+63) && !*(tilespot+63) ) ) + { + obj->active = true; + TransformActor (obj); + if (!obj->viewheight) + continue; // too close or far away + + visptr->viewx = obj->viewx; + visptr->viewheight = obj->viewheight; + if (visptr->shapenum == -1) + visptr->shapenum = obj->temp1; // special shape + + if (obj->state->rotate) + visptr->shapenum += CalcRotate (obj); + + if (visptr < &vislist[MAXVISABLE-1]) // don't let it overflow + visptr++; + obj->flags |= FL_VISABLE; + } + else + obj->flags &= ~FL_VISABLE; + } + +// +// draw from back to front +// + numvisable = visptr-&vislist[0]; + + if (!numvisable) + return; // no visable objects + + for (i = 0; iviewheight; + if (height < least) + { + least = height; + farthest = visstep; + } + } + // + // draw farthest + // + ScaleShape(farthest->viewx,farthest->shapenum,farthest->viewheight); + + farthest->viewheight = 32000; + } + +} + +//========================================================================== + +/* +============== += += DrawPlayerWeapon += += Draw the player's hands += +============== +*/ + +int weaponscale[NUMWEAPONS] = {SPR_KNIFEREADY,SPR_PISTOLREADY + ,SPR_MACHINEGUNREADY,SPR_CHAINREADY}; + +void DrawPlayerWeapon (void) +{ + int shapenum; + +#ifndef SPEAR + if (gamestate.victoryflag) + { + if (player->state == &s_deathcam && (TimeCount&32) ) + SimpleScaleShape(viewwidth/2,SPR_DEATHCAM,viewheight+1); + return; + } +#endif + + if (gamestate.weapon != -1) + { + shapenum = weaponscale[gamestate.weapon]+gamestate.weaponframe; + SimpleScaleShape(viewwidth/2,shapenum,viewheight+1); + } + + if (demorecord || demoplayback) + SimpleScaleShape(viewwidth/2,SPR_DEMO,viewheight+1); +} + + +//========================================================================== + + +/* +===================== += += CalcTics += +===================== +*/ + +void CalcTics (void) +{ + long newtime,oldtimecount; + +// +// calculate tics since last refresh for adaptive timing +// + if (lasttimecount > TimeCount) + TimeCount = lasttimecount; // if the game was paused a LONG time + + do + { + newtime = TimeCount; + tics = newtime-lasttimecount; + } while (!tics); // make sure at least one tic passes + + lasttimecount = newtime; + +#ifdef FILEPROFILE + strcpy (scratch,"\tTics:"); + itoa (tics,str,10); + strcat (scratch,str); + strcat (scratch,"\n"); + write (profilehandle,scratch,strlen(scratch)); +#endif + + if (tics>MAXTICS) + { + TimeCount -= (tics-MAXTICS); + tics = MAXTICS; + } +} + + +//========================================================================== + + +/* +======================== += += FixOfs += +======================== +*/ + +void FixOfs (void) +{ + VW_ScreenToScreen (displayofs,bufferofs,viewwidth/8,viewheight); +} + + +//========================================================================== + + +/* +==================== += += WallRefresh += +==================== +*/ + +void WallRefresh (void) +{ +// +// set up variables for this view +// + viewangle = player->angle; + midangle = viewangle*(FINEANGLES/ANGLES); + viewsin = sintable[viewangle]; + viewcos = costable[viewangle]; + viewx = player->x - FixedByFrac(focallength,viewcos); + viewy = player->y + FixedByFrac(focallength,viewsin); + + focaltx = viewx>>TILESHIFT; + focalty = viewy>>TILESHIFT; + + viewtx = player->x >> TILESHIFT; + viewty = player->y >> TILESHIFT; + + xpartialdown = viewx&(TILEGLOBAL-1); + xpartialup = TILEGLOBAL-xpartialdown; + ypartialdown = viewy&(TILEGLOBAL-1); + ypartialup = TILEGLOBAL-ypartialdown; + + lastside = -1; // the first pixel is on a new wall + AsmRefresh (); + ScalePost (); // no more optimization on last post +} + +//========================================================================== + +/* +======================== += += ThreeDRefresh += +======================== +*/ + +void ThreeDRefresh (void) +{ + int tracedir; + +// this wouldn't need to be done except for my debugger/video wierdness + outportb (SC_INDEX,SC_MAPMASK); + +// +// clear out the traced array +// +asm mov ax,ds +asm mov es,ax +asm mov di,OFFSET spotvis +asm xor ax,ax +asm mov cx,2048 // 64*64 / 2 +asm rep stosw + + bufferofs += screenofs; + +// +// follow the walls from there to the right, drawwing as we go +// + VGAClearScreen (); + + WallRefresh (); + +// +// draw all the scaled images +// + DrawScaleds(); // draw scaled stuff + DrawPlayerWeapon (); // draw player's hands + +// +// show screen and time last cycle +// + if (fizzlein) + { + FizzleFade(bufferofs,displayofs+screenofs,viewwidth,viewheight,20,false); + fizzlein = false; + + lasttimecount = TimeCount = 0; // don't make a big tic count + + } + + bufferofs -= screenofs; + displayofs = bufferofs; + + asm cli + asm mov cx,[displayofs] + asm mov dx,3d4h // CRTC address register + asm mov al,0ch // start address high register + asm out dx,al + asm inc dx + asm mov al,ch + asm out dx,al // set the high byte + asm sti + + bufferofs += SCREENSIZE; + if (bufferofs > PAGE3START) + bufferofs = PAGE1START; + + frameon++; + PM_NextFrame(); +} + + +//=========================================================================== + diff --git a/16/WOLFSRC/WL_DR_A.ASM b/16/WOLFSRC/WL_DR_A.ASM new file mode 100755 index 00000000..aec139a1 --- /dev/null +++ b/16/WOLFSRC/WL_DR_A.ASM @@ -0,0 +1,795 @@ + IDEAL + MODEL MEDIUM,C + P286 + +SCREENSEG = 0a000h + +FINEANGLES = 3600 +DEG90 = 900 +DEG180 = 1800 +DEG270 = 2700 +DEG360 = 3600 + +OP_JLE = 07eh +OP_JGE = 07dh + +EXTRN finetangent:DWORD ; far array, starts at offset 0 + +EXTRN HitHorizWall:FAR +EXTRN HitVertWall:FAR +EXTRN HitHorizDoor:FAR +EXTRN HitVertDoor:FAR +EXTRN HitHorizPWall:FAR +EXTRN HitVertPWall:FAR + + +DATASEG + +EXTRN viewwidth:WORD + +EXTRN tilemap:BYTE +EXTRN spotvis:BYTE +EXTRN pixelangle:WORD + + +EXTRN midangle:WORD +EXTRN angle:WORD + +EXTRN focaltx:WORD +EXTRN focalty:WORD +EXTRN viewtx:WORD +EXTRN viewty:WORD +EXTRN viewx:DWORD +EXTRN viewy:DWORD + +EXTRN xpartialup:WORD +EXTRN ypartialup:WORD +EXTRN xpartialdown:WORD +EXTRN ypartialdown:WORD + +EXTRN tilehit:WORD +EXTRN pixx:WORD +EXTRN wallheight:WORD ; array of VIEWWIDTH entries + +EXTRN xtile:WORD +EXTRN ytile:WORD +EXTRN xtilestep:WORD +EXTRN ytilestep:WORD +EXTRN xintercept:DWORD +EXTRN yintercept:DWORD +EXTRN xstep:DWORD +EXTRN ystep:DWORD + +EXTRN doorposition:WORD ; table of door position values + + +EXTRN pwallpos:WORD ; amound a pushable wall has been moved + +CODESEG + +;------------------- +; +; xpartialbyystep +; +; multiplies long [ystep] (possibly negative), by word [xpartial] (in BX) +; +; returns dx:ax +; trashes bx,cx,di +; +;------------------- + +PROC xpartialbyystep NEAR +; +; setup +; + mov ax,[WORD ystep] + mov cx,[WORD ystep+2] + or cx,cx ; is ystep negatice? + jns @@multpos +; +; multiply negative cx:ax by bx +; + neg cx + neg ax + sbb cx,0 + + mul bx ; fraction*fraction + mov di,dx ; di is low word of result + mov ax,cx ; + mul bx ; units*fraction + add ax,di + adc dx,0 + + neg dx + neg ax + sbb dx,0 + ret +; +; multiply positive cx:ax by bx +; +EVEN +@@multpos: + mul bx ; fraction*fraction + mov di,dx ; di is low word of result + mov ax,cx ; + mul bx ; units*fraction + add ax,di + adc dx,0 + + ret + +ENDP + + + +;------------------- +; +; ypartialbyxstep +; +; multiplies long [xstep] (possibly negative), by word [ypartial] (in BP) +; +; returns dx:ax +; trashes cx,di,bp +; +;------------------- + +PROC ypartialbyxstep NEAR +; +; setup +; + mov ax,[WORD xstep] + mov cx,[WORD xstep+2] + or cx,cx ; is ystep negatice? + jns @@multpos +; +; multiply negative cx:ax by bx +; + neg cx + neg ax + sbb cx,0 + + mul bp ; fraction*fraction + mov di,dx ; di is low word of result + mov ax,cx ; + mul bp ; units*fraction + add ax,di + adc dx,0 + + neg dx + neg ax + sbb dx,0 + ret +; +; multiply positive cx:ax by bx +; +EVEN +@@multpos: + mul bp ; fraction*fraction + mov di,dx ; di is low word of result + mov ax,cx ; + mul bp ; units*fraction + add ax,di + adc dx,0 + ret + +ENDP + + +;============================ +; +; AsmRefresh +; +; +;============================ + +PROC AsmRefresh +PUBLIC AsmRefresh + + push si + push di + push bp + + mov [pixx],0 +;--------------------------------------------------------------------------- +; +; Setup to trace a ray through pixx view pixel +; +; CX : angle of the ray through pixx +; ES : points to segment of finetangent array for this block of code +; +; Upon entrance to initialize block +; +; BX : xpartial +; BP : ypartial +; +;--------------------------------------------------------------------------- + EVEN +pixxloop: + mov ax,SEG finetangent + mov es,ax + mov cx,[midangle] ; center of view area + mov bx,[pixx] + shl bx,1 + add cx,[pixelangle+bx] ; delta for this pixel + cmp cx,0 + jge not0 +;---------- +; +; -90 - -1 degree arc +; +;---------- + add cx,FINEANGLES ; -90 is the same as 270 + jmp entry360 + +not0: + cmp cx,DEG90 + jge not90 +;---------- +; +; 0-89 degree arc +; +;---------- +entry90: + mov [xtilestep],1 ; xtilestep = 1 + mov [ytilestep],-1 ; ytilestep = -1 + mov [BYTE cs:horizop],OP_JGE ; patch a jge in + mov [BYTE cs:vertop],OP_JLE ; patch a jle in + mov bx,DEG90-1 + sub bx,cx + ;begin 8086 hack + ;shl bx,2 + shl bx,1 + shl bx,1 + ;end 8086 hack + mov ax,[es:bx] + mov dx,[es:bx+2] + mov [WORD xstep],ax + mov [WORD xstep+2],dx ; xstep = finetangent[DEG90-1-angle] + mov bx,cx + ;begin 8086 hack + ;shl bx,2 + shl bx,1 + shl bx,1 + ;end 8086 hack + mov ax,[es:bx] + mov dx,[es:bx+2] + neg dx + neg ax + sbb dx,0 + mov [WORD ystep],ax + mov [WORD ystep+2],dx ; ystep = -finetangent[angle] + + mov bx,[xpartialup] ; xpartial = xpartialup + mov bp,[ypartialdown] ; ypartial = ypartialdown + jmp initvars + +not90: + cmp cx,DEG180 + jge not180 +;---------- +; +; 90-179 degree arc +; +;---------- + mov ax,-1 + mov [xtilestep],ax ; xtilestep = -1 + mov [ytilestep],ax ; ytilestep = -1 + mov [BYTE cs:horizop],OP_JLE ; patch a jle in + mov [BYTE cs:vertop],OP_JLE ; patch a jle in + + mov bx,cx + ;begin 8086 hack + ;shl bx,2 + shl bx,1 + shl bx,1 + ;end 8086 hack + mov ax,[es:bx-DEG90*4] + mov dx,[es:bx+2-DEG90*4] + neg dx + neg ax + sbb dx,0 + mov [WORD xstep],ax + mov [WORD xstep+2],dx ; xstep = -finetangent[angle-DEG90] + mov bx,DEG180-1 + sub bx,cx + ;begin 8086 hack + ;shl bx,2 + shl bx,1 + shl bx,1 + ;end 8086 hack + mov ax,[es:bx] + mov dx,[es:bx+2] + neg dx + neg ax + sbb dx,0 + mov [WORD ystep],ax + mov [WORD ystep+2],dx ; ystep = -finetangent[DEG180-1-angle] + + mov bx,[xpartialdown] ; xpartial = xpartialdown + mov bp,[ypartialdown] ; ypartial = ypartialdown + jmp initvars + +not180: + cmp cx,DEG270 + jge not270 +;---------- +; +; 180-269 degree arc +; +;---------- + mov [xtilestep],-1 ; xtilestep = -1 + mov [ytilestep],1 ; ytilestep = 1 + mov [BYTE cs:horizop],OP_JLE ; patch a jle in + mov [BYTE cs:vertop],OP_JGE ; patch a jge in + + mov bx,DEG270-1 + sub bx,cx + ;begin 8086 hack + ;shl bx,2 + shl bx,1 + shl bx,1 + ;end 8086 hack + mov ax,[es:bx] + mov dx,[es:bx+2] + neg dx + neg ax + sbb dx,0 + mov [WORD xstep],ax + mov [WORD xstep+2],dx ; xstep = -finetangent[DEG270-1-angle] + mov bx,cx + ;begin 8086 hack + ;shl bx,2 + shl bx,1 + shl bx,1 + ;end 8086 hack + mov ax,[es:bx-DEG180*4] + mov dx,[es:bx+2-DEG180*4] + mov [WORD ystep],ax + mov [WORD ystep+2],dx ; ystep = finetangent[angle-DEG180] + + mov bx,[xpartialdown] ; xpartial = xpartialdown + mov bp,[ypartialup] ; ypartial = ypartialup + jmp initvars + + +not270: + cmp cx,DEG360 + jge not360 +;---------- +; +; 270-359 degree arc +; +;---------- +entry360: + mov ax,1 + mov [xtilestep],ax ; xtilestep = 1 + mov [ytilestep],ax ; ytilestep = 1 + mov [BYTE cs:horizop],OP_JGE ; patch a jge in + mov [BYTE cs:vertop],OP_JGE ; patch a jge in + + mov bx,cx + ;begin 8086 hack + ;shl bx,2 + shl bx,1 + shl bx,1 + ;end 8086 hack + mov ax,[es:bx-DEG270*4] + mov dx,[es:bx+2-DEG270*4] + mov [WORD xstep],ax + mov [WORD xstep+2],dx ; xstep = finetangent[angle-DEG270] + mov bx,DEG360-1 + sub bx,cx + ;begin 8086 hack + ;shl bx,2 + shl bx,1 + shl bx,1 + ;end 8086 hack + mov ax,[es:bx] + mov dx,[es:bx+2] + mov [WORD ystep],ax + mov [WORD ystep+2],dx ; ystep = finetangent[DEG360-1-angle] + + mov bx,[xpartialup] ; xpartial = xpartialup + mov bp,[ypartialup] ; ypartial = ypartialup + jmp initvars + + +not360: +;---------- +; +; 360-449 degree arc +; +;---------- + sub cx,FINEANGLES ; -449 is the same as 89 + jmp entry90 + +;--------------------------------------------------------------------------- +; +; initialise variables for intersection testing +; +;--------------------------------------------------------------------------- +initvars: + call NEAR xpartialbyystep ; xpartial is in BX + add ax,[WORD viewy] + adc dx,[WORD viewy+2] + mov [WORD yintercept],ax + mov [WORD yintercept+2],dx + + mov si,[focaltx] + add si,[xtilestep] + mov [xtile],si ; xtile = focaltx+xtilestep + ;begin 8086 hack + ;shl si,6 + push cx + mov cl,6 + shl si,cl + pop cx + ;end 8086 hack + add si,dx ; xspot = (xtile<<6) + yinttile + + + call NEAR ypartialbyxstep ; ypartial is in BP + add ax,[WORD viewx] + adc dx,[WORD viewx+2] + mov [WORD xintercept],ax + mov cx,dx + + mov bx,[focalty] + add bx,[ytilestep] + mov bp,bx ; ytile = focalty+ytilestep + mov di,dx + ;begin 8086 hack + ;shl di,6 + push cx + mov cl,6 + shl di,cl + pop cx + ;end 8086 hack + add di,bx ; yspot = (xinttile<<6) + ytile + + mov bx,[xtile] + mov dx,[WORD yintercept+2] + mov ax,SCREENSEG + mov es,ax ; faster than mov es,[screenseg] + + +;--------------------------------------------------------------------------- +; +; trace along this angle until we hit a wall +; +; CORE LOOP! +; +; All variables are killed when a wall is hit +; +; AX : scratch +; BX : xtile +; CX : high word of xintercept +; DX : high word of yintercept +; SI : xspot (yinttile<<6)+xtile (index into tilemap and spotvis) +; DI : yspot (xinttile<<6)+ytile (index into tilemap and spotvis) +; BP : ytile +; ES : screenseg +; +;--------------------------------------------------------------------------- + +;----------- +; +; check intersections with vertical walls +; +;----------- + + EVEN +vertcheck: + cmp dx,bp +vertop: ; 0x7e = jle (ytilestep==-1) + jle horizentry ; 0x7d = jge (ytilestep==1) +vertentry: + test [BYTE tilemap+si],0ffh ; tilehit = *((byte *)tilemap+xspot); + jnz hitvert +passvert: + mov [BYTE spotvis+si],1 ; *((byte *)spotvis+xspot) = true; + add bx,[xtilestep] ; xtile+=xtilestep + mov ax,[WORD ystep] + add [WORD yintercept],ax ; yintercept += ystep + adc dx,[WORD ystep+2] + mov si,bx + ;begin 8086 hack + ;shl si,6 + push cx + mov cl,6 + shl si,cl + pop cx + ;end 8086 hack + add si,dx ; xspot = (xtile<<6)+yinttile + jmp vertcheck + + EVEN +hitvert: + mov al,[BYTE tilemap+si] ; tilehit = *((byte *)tilemap+xspot); + mov [BYTE tilehit],al + or al,al ; set flags + jns notvertdoor + jmp vertdoor +notvertdoor: + mov [WORD xintercept],0 + mov [WORD xintercept+2],bx + mov [xtile],bx + mov [WORD yintercept+2],dx + mov [ytile],dx + call FAR HitVertWall + jmp nextpix + + +;----------- +; +; check intersections with horizontal walls +; +;----------- + EVEN +horizcheck: + cmp cx,bx +horizop: ; 0x7e = jle (xtilestep==-1) + jle vertentry ; 0x7d = jge (xtilestep==1) +horizentry: + test [BYTE tilemap+di],0ffh ; tilehit = *((byte *)tilemap+yspot); + jnz hithoriz +passhoriz: + mov [BYTE spotvis+di],1 ; *((byte *)spotvis+yspot) = true; + add bp,[ytilestep] ; ytile+=ytilestep + mov ax,[WORD xstep] + add [WORD xintercept],ax ; xintercept += xstep + adc cx,[WORD xstep+2] + mov di,cx + ;begin 8086 hack + ;shl di,6 + push cx + mov cl,6 + shl di,cl + pop cx + ;end 8086 hack + add di,bp ; yspot = (xinttile<<6)+ytile + jmp horizcheck + + EVEN +hithoriz: + mov al,[BYTE tilemap+di] ; tilehit = *((byte *)tilemap+yspot); + mov [BYTE tilehit],al + or al,al ; set flags + js horizdoor + mov [WORD xintercept+2],cx + mov [xtile],cx + mov [WORD yintercept],0 + mov [WORD yintercept+2],bp + mov [ytile],bp + call FAR HitHorizWall + jmp nextpix + +;--------------------------------------------------------------------------- +; +; next pixel over +; +;--------------------------------------------------------------------------- + +nextpix: + mov ax,[pixx] + inc ax + mov [pixx],ax + cmp ax,[viewwidth] + jge done + jmp pixxloop +done: + pop bp + pop di + pop si + retf + +;=========================================================================== + +;============= +; +; hit a special horizontal wall, so find which coordinate a door would be +; intersected at, and check to see if the door is open past that point +; +;============= +horizdoor: + mov [xtile],bx ; save off live register variables + mov [WORD yintercept+2],dx + + test al,040h ; both high bits set == pushable wall + jnz horizpushwall + + mov bx,ax + and bx,7fh ; strip high bit + shl bx,1 ; index into word width door table + + mov ax,[WORD xstep] + mov dx,[WORD xstep+2] + sar dx,1 + rcr ax,1 ; half a step gets to door position + + add ax,[WORD xintercept] ; add half step to current intercept pos + adc dx,cx ; CX hold high word of xintercept + + cmp cx,dx ; is it still in the same tile? + je hithmid +; +; midpoint is outside tile, so it hit the side of the wall before a door +; +continuehoriz: + mov bx,[xtile] ; reload register variables + mov dx,[WORD yintercept+2] + jmp passhoriz ; continue tracing +; +; the trace hit the door plane at pixel position AX, see if the door is +; closed that much +; +hithmid: + cmp ax,[doorposition+bx] ; position of leading edge of door + jb continuehoriz +; +; draw the door +; + mov [WORD xintercept],ax ; save pixel intercept position + mov [WORD xintercept+2],cx + + mov [WORD yintercept],8000h ; intercept in middle of tile + mov [WORD yintercept+2],bp + + call FAR HitHorizDoor + jmp nextpix + +;============ +; +; hit a sliding horizontal wall +; +;============ + +horizpushwall: + mov ax,[WORD xstep+2] ; multiply xstep by pwallmove (0-63) + mul [pwallpos] + mov bx,ax + mov ax,[WORD xstep] + mul [pwallpos] + add dx,bx + + sar dx,1 ; then divide by 64 to accomplish a + rcr ax,1 ; fixed point multiplication + sar dx,1 + rcr ax,1 + sar dx,1 + rcr ax,1 + sar dx,1 + rcr ax,1 + sar dx,1 + rcr ax,1 + sar dx,1 + rcr ax,1 + + add ax,[WORD xintercept] ; add partial step to current intercept + adc dx,cx ; CX hold high word of xintercept + + cmp cx,dx ; is it still in the same tile? + jne continuehoriz ; no, it hit the side + +; +; draw the pushable wall at the new height +; + mov [WORD xintercept],ax ; save pixel intercept position + mov [WORD xintercept+2],dx + + mov [WORD yintercept+2],bp + mov [WORD yintercept],0 + + call FAR HitHorizPWall + jmp nextpix + + + +;=========================================================================== + +;============= +; +; hit a special vertical wall, so find which coordinate a door would be +; intersected at, and check to see if the door is open past that point +; +;============= +vertdoor: + mov [xtile],bx ; save off live register variables + mov [WORD yintercept+2],dx + + test al,040h ; both high bits set == pushable wall + jnz vertpushwall + + mov bx,ax + and bx,7fh ; strip high bit + shl bx,1 ; index into word width doorposition + + mov ax,[WORD ystep] + mov dx,[WORD ystep+2] + sar dx,1 + rcr ax,1 ; half a step gets to door position + + add ax,[WORD yintercept] ; add half step to current intercept pos + adc dx,[WORD yintercept+2] + + cmp [WORD yintercept+2],dx ; is it still in the same tile? + je hitvmid +; +; midpoint is outside tile, so it hit the side of the wall before a door +; +continuevert: + mov bx,[xtile] ; reload register variables + mov dx,[WORD yintercept+2] + jmp passvert ; continue tracing +; +; the trace hit the door plane at pixel position AX, see if the door is +; closed that much +; +hitvmid: + cmp ax,[doorposition+bx] ; position of leading edge of door + jb continuevert +; +; draw the door +; + mov [WORD yintercept],ax ; save pixel intercept position + mov [WORD xintercept],8000h ; intercept in middle of tile + mov ax,[xtile] + mov [WORD xintercept+2],ax + + call FAR HitVertDoor + jmp nextpix + +;============ +; +; hit a sliding vertical wall +; +;============ + +vertpushwall: + mov ax,[WORD ystep+2] ; multiply ystep by pwallmove (0-63) + mul [pwallpos] + mov bx,ax + mov ax,[WORD ystep] + mul [pwallpos] + add dx,bx + + sar dx,1 ; then divide by 64 to accomplish a + rcr ax,1 ; fixed point multiplication + sar dx,1 + rcr ax,1 + sar dx,1 + rcr ax,1 + sar dx,1 + rcr ax,1 + sar dx,1 + rcr ax,1 + sar dx,1 + rcr ax,1 + + add ax,[WORD yintercept] ; add partial step to current intercept + adc dx,[WORD yintercept+2] + + cmp [WORD yintercept+2],dx ; is it still in the same tile? + jne continuevert ; no, it hit the side + +; +; draw the pushable wall at the new height +; + mov [WORD yintercept],ax ; save pixel intercept position + mov [WORD yintercept+2],dx + + mov bx,[xtile] + mov [WORD xintercept+2],bx + mov [WORD xintercept],0 + + call FAR HitVertPWall + jmp nextpix + + + +ENDP + + +END + + diff --git a/16/WOLFSRC/WL_GAME.C b/16/WOLFSRC/WL_GAME.C new file mode 100755 index 00000000..9f63d9fe --- /dev/null +++ b/16/WOLFSRC/WL_GAME.C @@ -0,0 +1,1484 @@ +// WL_GAME.C + +#include "WL_DEF.H" +#pragma hdrstop + +#ifdef MYPROFILE +#include +#endif + + +/* +============================================================================= + + LOCAL CONSTANTS + +============================================================================= +*/ + + +/* +============================================================================= + + GLOBAL VARIABLES + +============================================================================= +*/ + +boolean ingame,fizzlein; +unsigned latchpics[NUMLATCHPICS]; +gametype gamestate; + +long spearx,speary; +unsigned spearangle; +boolean spearflag; + +// +// ELEVATOR BACK MAPS - REMEMBER (-1)!! +// +int ElevatorBackTo[]={1,1,7,3,5,3}; + +void ScanInfoPlane (void); +void SetupGameLevel (void); +void DrawPlayScreen (void); +void LoadLatchMem (void); +void GameLoop (void); + +/* +============================================================================= + + LOCAL VARIABLES + +============================================================================= +*/ + + + +//=========================================================================== +//=========================================================================== + + +/* +========================== += += SetSoundLoc - Given the location of an object (in terms of global += coordinates, held in globalsoundx and globalsoundy), munges the values += for an approximate distance from the left and right ear, and puts += those values into leftchannel and rightchannel. += += JAB += +========================== +*/ + + fixed globalsoundx,globalsoundy; + int leftchannel,rightchannel; +#define ATABLEMAX 15 +byte righttable[ATABLEMAX][ATABLEMAX * 2] = { +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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} +}; +byte lefttable[ATABLEMAX][ATABLEMAX * 2] = { +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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} +}; + +void +SetSoundLoc(fixed gx,fixed gy) +{ + fixed xt,yt; + int x,y; + +// +// translate point to view centered coordinates +// + gx -= viewx; + gy -= viewy; + +// +// calculate newx +// + xt = FixedByFrac(gx,viewcos); + yt = FixedByFrac(gy,viewsin); + x = (xt - yt) >> TILESHIFT; + +// +// calculate newy +// + xt = FixedByFrac(gx,viewsin); + yt = FixedByFrac(gy,viewcos); + y = (yt + xt) >> TILESHIFT; + + if (y >= ATABLEMAX) + y = ATABLEMAX - 1; + else if (y <= -ATABLEMAX) + y = -ATABLEMAX; + if (x < 0) + x = -x; + if (x >= ATABLEMAX) + x = ATABLEMAX - 1; + leftchannel = lefttable[x][y + ATABLEMAX]; + rightchannel = righttable[x][y + ATABLEMAX]; + +#if 0 + CenterWindow(8,1); + US_PrintSigned(leftchannel); + US_Print(","); + US_PrintSigned(rightchannel); + VW_UpdateScreen(); +#endif +} + +/* +========================== += += SetSoundLocGlobal - Sets up globalsoundx & globalsoundy and then calls += UpdateSoundLoc() to transform that into relative channel volumes. Those += values are then passed to the Sound Manager so that they'll be used for += the next sound played (if possible). += += JAB += +========================== +*/ +void PlaySoundLocGlobal(word s,fixed gx,fixed gy) +{ + SetSoundLoc(gx,gy); + SD_PositionSound(leftchannel,rightchannel); + if (SD_PlaySound(s)) + { + globalsoundx = gx; + globalsoundy = gy; + } +} + +void UpdateSoundLoc(void) +{ + if (SoundPositioned) + { + SetSoundLoc(globalsoundx,globalsoundy); + SD_SetPosition(leftchannel,rightchannel); + } +} + +/* +** JAB End +*/ + + +/* +========================== += += ClearMemory += +========================== +*/ + +void ClearMemory (void) +{ + PM_UnlockMainMem(); + SD_StopDigitized(); + MM_SortMem (); +} + + +/* +========================== += += ScanInfoPlane += += Spawn all actors and mark down special places += +========================== +*/ + +void ScanInfoPlane (void) +{ + unsigned x,y,i,j; + int tile; + unsigned far *start; + + start = mapsegs[1]; + for (y=0;ywidth; + mapheight = mapheaderseg[mapon]->height; + + if (mapwidth != 64 || mapheight != 64) + Quit ("Map not 64*64!"); + + +// +// copy the wall data to a data segment array +// + memset (tilemap,0,sizeof(tilemap)); + memset (actorat,0,sizeof(actorat)); + map = mapsegs[0]; + for (y=0;y= 90 && tile <= 101) + { + // door + switch (tile) + { + case 90: + case 92: + case 94: + case 96: + case 98: + case 100: + SpawnDoor (x,y,1,(tile-90)/2); + break; + case 91: + case 93: + case 95: + case 97: + case 99: + case 101: + SpawnDoor (x,y,0,(tile-91)/2); + break; + } + } + } + +// +// spawn actors +// + ScanInfoPlane (); + +// +// take out the ambush markers +// + map = mapsegs[0]; + for (y=0;y= AREATILE) + tile = *map; + if (*(map-1-mapwidth) >= AREATILE) + tile = *(map-1-mapwidth); + if (*(map-1+mapwidth) >= AREATILE) + tile = *(map-1+mapwidth); + if ( *(map-2) >= AREATILE) + tile = *(map-2); + + *(map-1) = tile; + } + } + + + +// +// have the caching manager load and purge stuff to make sure all marks +// are in memory +// + CA_LoadAllSounds (); + +} + + +//========================================================================== + + +/* +=================== += += DrawPlayBorderSides += += To fix window overwrites += +=================== +*/ + +void DrawPlayBorderSides (void) +{ + int xl,yl; + + xl = 160-viewwidth/2; + yl = (200-STATUSLINES-viewheight)/2; + + VWB_Bar (0,0,xl-1,200-STATUSLINES,127); + VWB_Bar (xl+viewwidth+1,0,xl-2,200-STATUSLINES,127); + + VWB_Vlin (yl-1,yl+viewheight,xl-1,0); + VWB_Vlin (yl-1,yl+viewheight,xl+viewwidth,125); +} + + +/* +=================== += += DrawAllPlayBorderSides += +=================== +*/ + +void DrawAllPlayBorderSides (void) +{ + unsigned i,temp; + + temp = bufferofs; + for (i=0;i<3;i++) + { + bufferofs = screenloc[i]; + DrawPlayBorderSides (); + } + bufferofs = temp; +} + +/* +=================== += += DrawPlayBorder += +=================== +*/ +void DrawAllPlayBorder (void) +{ + unsigned i,temp; + + temp = bufferofs; + for (i=0;i<3;i++) + { + bufferofs = screenloc[i]; + DrawPlayBorder (); + } + bufferofs = temp; +} + +/* +=================== += += DrawPlayBorder += +=================== +*/ + +void DrawPlayBorder (void) +{ + int xl,yl; + + VWB_Bar (0,0,320,200-STATUSLINES,127); + + xl = 160-viewwidth/2; + yl = (200-STATUSLINES-viewheight)/2; + VWB_Bar (xl,yl,viewwidth,viewheight,0); + + VWB_Hlin (xl-1,xl+viewwidth,yl-1,0); + VWB_Hlin (xl-1,xl+viewwidth,yl+viewheight,125); + VWB_Vlin (yl-1,yl+viewheight,xl-1,0); + VWB_Vlin (yl-1,yl+viewheight,xl+viewwidth,125); + VWB_Plot (xl-1,yl+viewheight,124); +} + + + +/* +=================== += += DrawPlayScreen += +=================== +*/ + +void DrawPlayScreen (void) +{ + int i,j,p,m; + unsigned temp; + + VW_FadeOut (); + + temp = bufferofs; + + CA_CacheGrChunk (STATUSBARPIC); + + for (i=0;i<3;i++) + { + bufferofs = screenloc[i]; + DrawPlayBorder (); + VWB_DrawPic (0,200-STATUSLINES,STATUSBARPIC); + } + + bufferofs = temp; + + UNCACHEGRCHUNK (STATUSBARPIC); + + DrawFace (); + DrawHealth (); + DrawLives (); + DrawLevel (); + DrawAmmo (); + DrawKeys (); + DrawWeapon (); + DrawScore (); +} + + + +//========================================================================== + +/* +================== += += StartDemoRecord += +================== +*/ + +#define MAXDEMOSIZE 8192 + +void StartDemoRecord (int levelnumber) +{ + MM_GetPtr (&demobuffer,MAXDEMOSIZE); + MM_SetLock (&demobuffer,true); + demoptr = (char far *)demobuffer; + lastdemoptr = demoptr+MAXDEMOSIZE; + + *demoptr = levelnumber; + demoptr += 4; // leave space for length + demorecord = true; +} + + +/* +================== += += FinishDemoRecord += +================== +*/ + +char demoname[13] = "DEMO?."; + +void FinishDemoRecord (void) +{ + long length,level; + + demorecord = false; + + length = demoptr - (char far *)demobuffer; + + demoptr = ((char far *)demobuffer)+1; + *(unsigned far *)demoptr = length; + + CenterWindow(24,3); + PrintY+=6; + US_Print(" Demo number (0-9):"); + VW_UpdateScreen(); + + if (US_LineInput (px,py,str,NULL,true,2,0)) + { + level = atoi (str); + if (level>=0 && level<=9) + { + demoname[4] = '0'+level; + CA_WriteFile (demoname,(void far *)demobuffer,length); + } + } + + + MM_FreePtr (&demobuffer); +} + +//========================================================================== + +/* +================== += += RecordDemo += += Fades the screen out, then starts a demo. Exits with the screen faded += +================== +*/ + +void RecordDemo (void) +{ + int level,esc; + + CenterWindow(26,3); + PrintY+=6; + CA_CacheGrChunk(STARTFONT); + fontnumber=0; + US_Print(" Demo which level(1-10):"); + VW_UpdateScreen(); + VW_FadeIn (); + esc = !US_LineInput (px,py,str,NULL,true,2,0); + if (esc) + return; + + level = atoi (str); + level--; + + SETFONTCOLOR(0,15); + VW_FadeOut (); + +#ifndef SPEAR + NewGame (gd_hard,level/10); + gamestate.mapon = level%10; +#else + NewGame (gd_hard,0); + gamestate.mapon = level; +#endif + + StartDemoRecord (level); + + DrawPlayScreen (); + VW_FadeIn (); + + startgame = false; + demorecord = true; + + SetupGameLevel (); + StartMusic (); + PM_CheckMainMem (); + fizzlein = true; + + PlayLoop (); + + demoplayback = false; + + StopMusic (); + VW_FadeOut (); + ClearMemory (); + + FinishDemoRecord (); +} + +//========================================================================== + +/* +================== += += PlayDemo += += Fades the screen out, then starts a demo. Exits with the screen faded += +================== +*/ + +void PlayDemo (int demonumber) +{ + int length; + +#ifdef DEMOSEXTERN +// debug: load chunk +#ifndef SPEARDEMO + int dems[4]={T_DEMO0,T_DEMO1,T_DEMO2,T_DEMO3}; +#else + int dems[1]={T_DEMO0}; +#endif + + CA_CacheGrChunk(dems[demonumber]); + demoptr = grsegs[dems[demonumber]]; + MM_SetLock (&grsegs[dems[demonumber]],true); +#else + demoname[4] = '0'+demonumber; + CA_LoadFile (demoname,&demobuffer); + MM_SetLock (&demobuffer,true); + demoptr = (char far *)demobuffer; +#endif + + NewGame (1,0); + gamestate.mapon = *demoptr++; + gamestate.difficulty = gd_hard; + length = *((unsigned far *)demoptr)++; + demoptr++; + lastdemoptr = demoptr-4+length; + + VW_FadeOut (); + + SETFONTCOLOR(0,15); + DrawPlayScreen (); + VW_FadeIn (); + + startgame = false; + demoplayback = true; + + SetupGameLevel (); + StartMusic (); + PM_CheckMainMem (); + fizzlein = true; + + PlayLoop (); + +#ifdef DEMOSEXTERN + UNCACHEGRCHUNK(dems[demonumber]); +#else + MM_FreePtr (&demobuffer); +#endif + + demoplayback = false; + + StopMusic (); + VW_FadeOut (); + ClearMemory (); +} + +//========================================================================== + +/* +================== += += Died += +================== +*/ + +#define DEATHROTATE 2 + +void Died (void) +{ + float fangle; + long dx,dy; + int iangle,curangle,clockwise,counter,change; + + gamestate.weapon = -1; // take away weapon + SD_PlaySound (PLAYERDEATHSND); +// +// swing around to face attacker +// + dx = killerobj->x - player->x; + dy = player->y - killerobj->y; + + fangle = atan2(dy,dx); // returns -pi to pi + if (fangle<0) + fangle = M_PI*2+fangle; + + iangle = fangle/(M_PI*2)*ANGLES; + + if (player->angle > iangle) + { + counter = player->angle - iangle; + clockwise = ANGLES-player->angle + iangle; + } + else + { + clockwise = iangle - player->angle; + counter = player->angle + ANGLES-iangle; + } + + curangle = player->angle; + + if (clockwiseiangle) + curangle -= ANGLES; + do + { + change = tics*DEATHROTATE; + if (curangle + change > iangle) + change = iangle-curangle; + + curangle += change; + player->angle += change; + if (player->angle >= ANGLES) + player->angle -= ANGLES; + + ThreeDRefresh (); + CalcTics (); + } while (curangle != iangle); + } + else + { + // + // rotate counterclockwise + // + if (curangleangle += change; + if (player->angle < 0) + player->angle += ANGLES; + + ThreeDRefresh (); + CalcTics (); + } while (curangle != iangle); + } + +// +// fade to red +// + FinishPaletteShifts (); + + bufferofs += screenofs; + VW_Bar (0,0,viewwidth,viewheight,4); + IN_ClearKeysDown (); + FizzleFade(bufferofs,displayofs+screenofs,viewwidth,viewheight,70,false); + bufferofs -= screenofs; + IN_UserInput(100); + SD_WaitSoundDone (); + + if (tedlevel == false) // SO'S YA DON'T GET KILLED WHILE LAUNCHING! + gamestate.lives--; + + if (gamestate.lives > -1) + { + gamestate.health = 100; + gamestate.weapon = gamestate.bestweapon + = gamestate.chosenweapon = wp_pistol; + gamestate.ammo = STARTAMMO; + gamestate.keys = 0; + gamestate.attackframe = gamestate.attackcount = + gamestate.weaponframe = 0; + + DrawKeys (); + DrawWeapon (); + DrawAmmo (); + DrawHealth (); + DrawFace (); + DrawLives (); + } + +} + +//========================================================================== + +/* +=================== += += GameLoop += +=================== +*/ + +void GameLoop (void) +{ + int i,xl,yl,xh,yh; + char num[20]; + boolean died; +#ifdef MYPROFILE + clock_t start,end; +#endif + +restartgame: + ClearMemory (); + SETFONTCOLOR(0,15); + DrawPlayScreen (); + died = false; +restart: + do + { + if (!loadedgame) + gamestate.score = gamestate.oldscore; + DrawScore(); + + startgame = false; + if (loadedgame) + loadedgame = false; + else + SetupGameLevel (); + +#ifdef SPEAR + if (gamestate.mapon == 20) // give them the key allways + { + gamestate.keys |= 1; + DrawKeys (); + } +#endif + + ingame = true; + StartMusic (); + PM_CheckMainMem (); + if (!died) + PreloadGraphics (); + else + died = false; + + fizzlein = true; + DrawLevel (); + +startplayloop: + PlayLoop (); + +#ifdef SPEAR + if (spearflag) + { + SD_StopSound(); + SD_PlaySound(GETSPEARSND); + if (DigiMode != sds_Off) + { + long lasttimecount = TimeCount; + + while(TimeCount < lasttimecount+150) + //while(DigiPlaying!=false) + SD_Poll(); + } + else + SD_WaitSoundDone(); + + ClearMemory (); + gamestate.oldscore = gamestate.score; + gamestate.mapon = 20; + SetupGameLevel (); + StartMusic (); + PM_CheckMainMem (); + player->x = spearx; + player->y = speary; + player->angle = spearangle; + spearflag = false; + Thrust (0,0); + goto startplayloop; + } +#endif + + StopMusic (); + ingame = false; + + if (demorecord && playstate != ex_warped) + FinishDemoRecord (); + + if (startgame || loadedgame) + goto restartgame; + + switch (playstate) + { + case ex_completed: + case ex_secretlevel: + gamestate.keys = 0; + DrawKeys (); + VW_FadeOut (); + + ClearMemory (); + + LevelCompleted (); // do the intermission +#ifdef SPEARDEMO + if (gamestate.mapon == 1) + { + died = true; // don't "get psyched!" + + VW_FadeOut (); + + ClearMemory (); + + CheckHighScore (gamestate.score,gamestate.mapon+1); + + #pragma warn -sus + #ifndef JAPAN + _fstrcpy(MainMenu[viewscores].string,STR_VS); + #endif + MainMenu[viewscores].routine = CP_ViewScores; + #pragma warn +sus + + return; + } +#endif + +#ifdef JAPDEMO + if (gamestate.mapon == 3) + { + died = true; // don't "get psyched!" + + VW_FadeOut (); + + ClearMemory (); + + CheckHighScore (gamestate.score,gamestate.mapon+1); + + #pragma warn -sus + #ifndef JAPAN + _fstrcpy(MainMenu[viewscores].string,STR_VS); + #endif + MainMenu[viewscores].routine = CP_ViewScores; + #pragma warn +sus + + return; + } +#endif + + gamestate.oldscore = gamestate.score; + +#ifndef SPEAR + // + // COMING BACK FROM SECRET LEVEL + // + if (gamestate.mapon == 9) + gamestate.mapon = ElevatorBackTo[gamestate.episode]; // back from secret + else + // + // GOING TO SECRET LEVEL + // + if (playstate == ex_secretlevel) + gamestate.mapon = 9; +#else + +#define FROMSECRET1 3 +#define FROMSECRET2 11 + + // + // GOING TO SECRET LEVEL + // + if (playstate == ex_secretlevel) + switch(gamestate.mapon) + { + case FROMSECRET1: gamestate.mapon = 18; break; + case FROMSECRET2: gamestate.mapon = 19; break; + } + else + // + // COMING BACK FROM SECRET LEVEL + // + if (gamestate.mapon == 18 || gamestate.mapon == 19) + switch(gamestate.mapon) + { + case 18: gamestate.mapon = FROMSECRET1+1; break; + case 19: gamestate.mapon = FROMSECRET2+1; break; + } +#endif + else + // + // GOING TO NEXT LEVEL + // + gamestate.mapon++; + + + break; + + case ex_died: + Died (); + died = true; // don't "get psyched!" + + if (gamestate.lives > -1) + break; // more lives left + + VW_FadeOut (); + + ClearMemory (); + + CheckHighScore (gamestate.score,gamestate.mapon+1); + + #pragma warn -sus + #ifndef JAPAN + _fstrcpy(MainMenu[viewscores].string,STR_VS); + #endif + MainMenu[viewscores].routine = CP_ViewScores; + #pragma warn +sus + + return; + + case ex_victorious: + +#ifndef SPEAR + VW_FadeOut (); +#else + VL_FadeOut (0,255,0,17,17,300); +#endif + ClearMemory (); + + Victory (); + + ClearMemory (); + + CheckHighScore (gamestate.score,gamestate.mapon+1); + + #pragma warn -sus + #ifndef JAPAN + _fstrcpy(MainMenu[viewscores].string,STR_VS); + #endif + MainMenu[viewscores].routine = CP_ViewScores; + #pragma warn +sus + + return; + + default: + ClearMemory (); + break; + } + + } while (1); + +} + diff --git a/16/WOLFSRC/WL_INTER.C b/16/WOLFSRC/WL_INTER.C new file mode 100755 index 00000000..c74cc9e6 --- /dev/null +++ b/16/WOLFSRC/WL_INTER.C @@ -0,0 +1,1718 @@ +// WL_INTER.C + +#include "WL_DEF.H" +#pragma hdrstop + + +//========================================================================== + +/* +================== += += CLearSplitVWB += +================== +*/ + +void ClearSplitVWB (void) +{ + memset (update,0,sizeof(update)); + WindowX = 0; + WindowY = 0; + WindowW = 320; + WindowH = 160; +} + + +//========================================================================== + +#ifdef SPEAR +#ifndef SPEARDEMO +//////////////////////////////////////////////////////// +// +// End of Spear of Destiny +// +//////////////////////////////////////////////////////// + +void EndScreen (int palette, int screen) +{ + CA_CacheScreen (screen); + VW_UpdateScreen (); + CA_CacheGrChunk (palette); + VL_FadeIn(0,255,grsegs[palette],30); + UNCACHEGRCHUNK (palette); + IN_ClearKeysDown (); + IN_Ack (); + VW_FadeOut (); +} + + +void EndSpear(void) +{ + EndScreen (END1PALETTE, ENDSCREEN11PIC); + + CA_CacheScreen (ENDSCREEN3PIC); + VW_UpdateScreen (); + CA_CacheGrChunk (END3PALETTE); + VL_FadeIn(0,255,grsegs[END3PALETTE],30); + UNCACHEGRCHUNK (END3PALETTE); + fontnumber = 0; + fontcolor = 0xd0; + WindowX = 0; + WindowW = 320; + PrintX = 0; + PrintY = 180; + US_CPrint (STR_ENDGAME1"\n"); + US_CPrint (STR_ENDGAME2); + VW_UpdateScreen (); + IN_StartAck (); + TimeCount = 0; + while (!IN_CheckAck () && TimeCount < 700); + + PrintX = 0; + PrintY = 180; + VWB_Bar(0,180,320,20,0); + US_CPrint (STR_ENDGAME3"\n"); + US_CPrint (STR_ENDGAME4); + VW_UpdateScreen (); + IN_StartAck (); + TimeCount = 0; + while (!IN_CheckAck () && TimeCount < 700); + + VW_FadeOut (); + + EndScreen (END4PALETTE, ENDSCREEN4PIC); + EndScreen (END5PALETTE, ENDSCREEN5PIC); + EndScreen (END6PALETTE, ENDSCREEN6PIC); + EndScreen (END7PALETTE, ENDSCREEN7PIC); + EndScreen (END8PALETTE, ENDSCREEN8PIC); + EndScreen (END9PALETTE, ENDSCREEN9PIC); + + EndScreen (END2PALETTE, ENDSCREEN12PIC); + + MainMenu[savegame].active = 0; +} +#endif +#endif + +//========================================================================== + +/* +================== += += Victory += +================== +*/ + +void Victory (void) +{ +#ifndef SPEARDEMO + long sec; + int i,min,kr,sr,tr,x; + char tempstr[8]; + +#define RATIOX 6 +#define RATIOY 14 +#define TIMEX 14 +#define TIMEY 8 + + +#ifdef SPEAR + StartCPMusic (XTHEEND_MUS); + + CA_CacheGrChunk(BJCOLLAPSE1PIC); + CA_CacheGrChunk(BJCOLLAPSE2PIC); + CA_CacheGrChunk(BJCOLLAPSE3PIC); + CA_CacheGrChunk(BJCOLLAPSE4PIC); + + VWB_Bar(0,0,320,200,VIEWCOLOR); + VWB_DrawPic (124,44,BJCOLLAPSE1PIC); + VW_UpdateScreen (); + VW_FadeIn (); + VW_WaitVBL(2*70); + VWB_DrawPic (124,44,BJCOLLAPSE2PIC); + VW_UpdateScreen (); + VW_WaitVBL(105); + VWB_DrawPic (124,44,BJCOLLAPSE3PIC); + VW_UpdateScreen (); + VW_WaitVBL(105); + VWB_DrawPic (124,44,BJCOLLAPSE4PIC); + VW_UpdateScreen (); + VW_WaitVBL(3*70); + + UNCACHEGRCHUNK(BJCOLLAPSE1PIC); + UNCACHEGRCHUNK(BJCOLLAPSE2PIC); + UNCACHEGRCHUNK(BJCOLLAPSE3PIC); + UNCACHEGRCHUNK(BJCOLLAPSE4PIC); + VL_FadeOut (0,255,0,17,17,5); +#endif + + StartCPMusic (URAHERO_MUS); + ClearSplitVWB (); + CacheLump(LEVELEND_LUMP_START,LEVELEND_LUMP_END); + CA_CacheGrChunk(STARTFONT); + +#ifndef SPEAR + CA_CacheGrChunk(C_TIMECODEPIC); +#endif + + + VWB_Bar (0,0,320,200-STATUSLINES,127); +#ifdef JAPAN +#ifndef JAPDEMO + CA_CacheGrChunk(C_ENDRATIOSPIC); + VWB_DrawPic(0,0,C_ENDRATIOSPIC); + UNCACHEGRCHUNK(C_ENDRATIOSPIC); +#endif +#else + Write(18,2,STR_YOUWIN); + + Write(TIMEX,TIMEY-2,STR_TOTALTIME); + + Write(12,RATIOY-2,"averages"); + + #ifdef SPANISH + Write(RATIOX+2, RATIOY, STR_RATKILL); + Write(RATIOX+2, RATIOY+2, STR_RATSECRET); + Write(RATIOX+2, RATIOY+4,STR_RATTREASURE); + #else + Write(RATIOX+8,RATIOY, STR_RATKILL); + Write(RATIOX+4,RATIOY+2, STR_RATSECRET); + Write(RATIOX, RATIOY+4,STR_RATTREASURE); + #endif + +#endif + +#ifndef JAPDEMO + VWB_DrawPic (8,4,L_BJWINSPIC); +#endif + + +#ifndef SPEAR + for (kr = sr = tr = sec = i = 0;i < 8;i++) +#else + for (kr = sr = tr = sec = i = 0;i < 20;i++) +#endif + { + sec += LevelRatios[i].time; + kr += LevelRatios[i].kill; + sr += LevelRatios[i].secret; + tr += LevelRatios[i].treasure; + } + +#ifndef SPEAR + kr /= 8; + sr /= 8; + tr /= 8; +#else + kr /= 14; + sr /= 14; + tr /= 14; +#endif + + min = sec/60; + sec %= 60; + + if (min > 99) + min = sec = 99; + + i = TIMEX*8+1; + VWB_DrawPic(i,TIMEY*8,L_NUM0PIC+(min/10)); + i += 2*8; + VWB_DrawPic(i,TIMEY*8,L_NUM0PIC+(min%10)); + i += 2*8; + Write(i/8,TIMEY,":"); + i += 1*8; + VWB_DrawPic(i,TIMEY*8,L_NUM0PIC+(sec/10)); + i += 2*8; + VWB_DrawPic(i,TIMEY*8,L_NUM0PIC+(sec%10)); + VW_UpdateScreen (); + + itoa(kr,tempstr,10); + x=RATIOX+24-strlen(tempstr)*2; + Write(x,RATIOY,tempstr); + + itoa(sr,tempstr,10); + x=RATIOX+24-strlen(tempstr)*2; + Write(x,RATIOY+2,tempstr); + + itoa(tr,tempstr,10); + x=RATIOX+24-strlen(tempstr)*2; + Write(x,RATIOY+4,tempstr); + + +#ifndef SPANISH +#ifndef UPLOAD +#ifndef SPEAR + // + // TOTAL TIME VERIFICATION CODE + // + if (gamestate.difficulty>=gd_medium) + { + VWB_DrawPic (30*8,TIMEY*8,C_TIMECODEPIC); + fontnumber = 0; + fontcolor = READHCOLOR; + PrintX = 30*8-3; + PrintY = TIMEY*8+8; + PrintX+=4; + tempstr[0] = (((min/10)^(min%10))^0xa)+'A'; + tempstr[1] = (((sec/10)^(sec%10))^0xa)+'A'; + tempstr[2] = (tempstr[0]^tempstr[1])+'A'; + tempstr[3] = 0; + US_Print(tempstr); + } +#endif +#endif +#endif + + + fontnumber = 1; + + VW_UpdateScreen (); + VW_FadeIn (); + + IN_Ack(); + + #ifndef SPEAR + if (Keyboard[sc_P] && MS_CheckParm("goobers")) + PicturePause(); + #endif + + VW_FadeOut (); + +#ifndef SPEAR + UNCACHEGRCHUNK(C_TIMECODEPIC); +#endif + UnCacheLump(LEVELEND_LUMP_START,LEVELEND_LUMP_END); + +#ifndef SPEAR + EndText(); +#else + EndSpear(); +#endif + +#endif // SPEARDEMO +} + + +//========================================================================== + +#ifndef JAPAN +/* +================== += += PG13 += +================== +*/ + +void PG13 (void) +{ + VW_FadeOut(); + VWB_Bar(0,0,320,200,0x82); // background + + CA_CacheGrChunk (PG13PIC); + VWB_DrawPic (216,110,PG13PIC); + VW_UpdateScreen (); + + UNCACHEGRCHUNK (PG13PIC); + + VW_FadeIn(); + IN_UserInput(TickBase*7); + + VW_FadeOut (); +} +#endif + + +//========================================================================== + +void Write(int x,int y,char *string) +{ + int alpha[]={L_NUM0PIC,L_NUM1PIC,L_NUM2PIC,L_NUM3PIC,L_NUM4PIC,L_NUM5PIC, + L_NUM6PIC,L_NUM7PIC,L_NUM8PIC,L_NUM9PIC,L_COLONPIC,0,0,0,0,0,0,L_APIC,L_BPIC, + L_CPIC,L_DPIC,L_EPIC,L_FPIC,L_GPIC,L_HPIC,L_IPIC,L_JPIC,L_KPIC, + L_LPIC,L_MPIC,L_NPIC,L_OPIC,L_PPIC,L_QPIC,L_RPIC,L_SPIC,L_TPIC, + L_UPIC,L_VPIC,L_WPIC,L_XPIC,L_YPIC,L_ZPIC}; + + int i,ox,nx,ny; + char ch; + + + ox=nx=x*8; + ny=y*8; + for (i=0;i='a') + ch-=('a'-'A'); + ch-='0'; + + switch(string[i]) + { + case '!': + VWB_DrawPic(nx,ny,L_EXPOINTPIC); + nx+=8; + continue; + + case '\'': + VWB_DrawPic(nx,ny,L_APOSTROPHEPIC); + nx+=8; + continue; + + case ' ': break; + case 0x3a: // ':' + + VWB_DrawPic(nx,ny,L_COLONPIC); + nx+=8; + continue; + + case '%': + VWB_DrawPic(nx,ny,L_PERCENTPIC); + break; + + default: + VWB_DrawPic(nx,ny,alpha[ch]); + } + nx+=16; + } +} + + +// +// Breathe Mr. BJ!!! +// +void BJ_Breathe(void) +{ + static int which=0,max=10; + int pics[2]={L_GUYPIC,L_GUY2PIC}; + + + if (TimeCount>max) + { + which^=1; + VWB_DrawPic(0,16,pics[which]); + VW_UpdateScreen(); + TimeCount=0; + max=35; + } +} + + + +/* +================== += += LevelCompleted += += Entered with the screen faded out += Still in split screen mode with the status bar += += Exit with the screen faded out += +================== +*/ + +#ifndef SPEAR +LRstruct LevelRatios[8]; +#else +LRstruct LevelRatios[20]; +#endif + +void LevelCompleted (void) +{ + #define VBLWAIT 30 + #define PAR_AMOUNT 500 + #define PERCENT100AMT 10000 + typedef struct { + float time; + char timestr[6]; + } times; + + int x,i,min,sec,ratio,kr,sr,tr; + unsigned temp; + char tempstr[10]; + long bonus,timeleft=0; + times parTimes[]= + { +#ifndef SPEAR + // + // Episode One Par Times + // + {1.5, "01:30"}, + {2, "02:00"}, + {2, "02:00"}, + {3.5, "03:30"}, + {3, "03:00"}, + {3, "03:00"}, + {2.5, "02:30"}, + {2.5, "02:30"}, + {0, "??:??"}, // Boss level + {0, "??:??"}, // Secret level + + // + // Episode Two Par Times + // + {1.5, "01:30"}, + {3.5, "03:30"}, + {3, "03:00"}, + {2, "02:00"}, + {4, "04:00"}, + {6, "06:00"}, + {1, "01:00"}, + {3, "03:00"}, + {0, "??:??"}, + {0, "??:??"}, + + // + // Episode Three Par Times + // + {1.5, "01:30"}, + {1.5, "01:30"}, + {2.5, "02:30"}, + {2.5, "02:30"}, + {3.5, "03:30"}, + {2.5, "02:30"}, + {2, "02:00"}, + {6, "06:00"}, + {0, "??:??"}, + {0, "??:??"}, + + // + // Episode Four Par Times + // + {2, "02:00"}, + {2, "02:00"}, + {1.5, "01:30"}, + {1, "01:00"}, + {4.5, "04:30"}, + {3.5, "03:30"}, + {2, "02:00"}, + {4.5, "04:30"}, + {0, "??:??"}, + {0, "??:??"}, + + // + // Episode Five Par Times + // + {2.5, "02:30"}, + {1.5, "01:30"}, + {2.5, "02:30"}, + {2.5, "02:30"}, + {4, "04:00"}, + {3, "03:00"}, + {4.5, "04:30"}, + {3.5, "03:30"}, + {0, "??:??"}, + {0, "??:??"}, + + // + // Episode Six Par Times + // + {6.5, "06:30"}, + {4, "04:00"}, + {4.5, "04:30"}, + {6, "06:00"}, + {5, "05:00"}, + {5.5, "05:30"}, + {5.5, "05:30"}, + {8.5, "08:30"}, + {0, "??:??"}, + {0, "??:??"} +#else + // + // SPEAR OF DESTINY TIMES + // + {1.5, "01:30"}, + {3.5, "03:30"}, + {2.75, "02:45"}, + {3.5, "03:30"}, + {0, "??:??"}, // Boss 1 + {4.5, "04:30"}, + {3.25, "03:15"}, + {2.75, "02:45"}, + {4.75, "04:45"}, + {0, "??:??"}, // Boss 2 + {6.5, "06:30"}, + {4.5, "04:30"}, + {2.75, "02:45"}, + {4.5, "04:30"}, + {6, "06:00"}, + {0, "??:??"}, // Boss 3 + {6, "06:00"}, + {0, "??:??"}, // Boss 4 + {0, "??:??"}, // Secret level 1 + {0, "??:??"}, // Secret level 2 +#endif + }; + + + + CacheLump(LEVELEND_LUMP_START,LEVELEND_LUMP_END); + ClearSplitVWB (); // set up for double buffering in split screen + VWB_Bar (0,0,320,200-STATUSLINES,127); + StartCPMusic(ENDLEVEL_MUS); + +// +// do the intermission +// + IN_ClearKeysDown(); + IN_StartAck(); + +#ifdef JAPAN + CA_CacheGrChunk(C_INTERMISSIONPIC); + VWB_DrawPic(0,0,C_INTERMISSIONPIC); + UNCACHEGRCHUNK(C_INTERMISSIONPIC); +#endif + VWB_DrawPic(0,16,L_GUYPIC); + +#ifndef SPEAR + if (mapon<8) +#else + if (mapon != 4 && + mapon != 9 && + mapon != 15 && + mapon < 17) +#endif + { +#ifndef JAPAN + #ifdef SPANISH + Write(14,2,"piso\ncompletado"); + #else + Write(14,2,"floor\ncompleted"); + #endif + + Write(14,7,STR_BONUS" 0"); + Write(16,10,STR_TIME); + Write(16,12,STR_PAR); + + #ifdef SPANISH + Write(11,14, STR_RAT2KILL); + Write(11,16, STR_RAT2SECRET); + Write(11,18,STR_RAT2TREASURE); + #else + Write(9,14, STR_RAT2KILL); + Write(5,16, STR_RAT2SECRET); + Write(1,18,STR_RAT2TREASURE); + #endif + + Write(26,2,itoa(gamestate.mapon+1,tempstr,10)); +#endif + + #ifdef SPANISH + Write(30,12,parTimes[gamestate.episode*10+mapon].timestr); + #else + Write(26,12,parTimes[gamestate.episode*10+mapon].timestr); + #endif + + // + // PRINT TIME + // + sec=gamestate.TimeCount/70; + + if (sec > 99*60) // 99 minutes max + sec = 99*60; + + if (gamestate.TimeCountname); + + // + // level + // + ultoa(s->completed,buffer,10); +#ifndef SPEAR + for (str = buffer;*str;str++) + *str = *str + (129 - '0'); // Used fixed-width numbers (129...) + USL_MeasureString(buffer,&w,&h); + PrintX = (22 * 8)-w; +#else + USL_MeasureString(buffer,&w,&h); + PrintX = 194 - w; +#endif + +#ifndef UPLOAD +#ifndef SPEAR + PrintX -= 6; + itoa(s->episode+1,buffer1,10); + US_Print("E"); + US_Print(buffer1); + US_Print("/L"); +#endif +#endif + +#ifdef SPEAR + if (s->completed == 21) + VWB_DrawPic (PrintX+8,PrintY-1,C_WONSPEARPIC); + else +#endif + US_Print(buffer); + + // + // score + // + ultoa(s->score,buffer,10); +#ifndef SPEAR + for (str = buffer;*str;str++) + *str = *str + (129 - '0'); // Used fixed-width numbers (129...) + USL_MeasureString(buffer,&w,&h); + PrintX = (34 * 8) - 8 - w; +#else + USL_MeasureString(buffer,&w,&h); + PrintX = 292 - w; +#endif + US_Print(buffer); + + #if 0 +#ifndef UPLOAD +#ifndef SPEAR + // + // verification # + // + if (!i) + { + temp=(((s->score >> 28)& 0xf)^ + ((s->score >> 24)& 0xf))+'A'; + temp1=(((s->score >> 20)& 0xf)^ + ((s->score >> 16)& 0xf))+'A'; + temp2=(((s->score >> 12)& 0xf)^ + ((s->score >> 8)& 0xf))+'A'; + temp3=(((s->score >> 4)& 0xf)^ + ((s->score >> 0)& 0xf))+'A'; + + SETFONTCOLOR(0x49,0x29); + PrintX = 35*8; + buffer[0]=temp; + buffer[1]=temp1; + buffer[2]=temp2; + buffer[3]=temp3; + buffer[4]=0; + US_Print(buffer); + SETFONTCOLOR(15,0x29); + } +#endif +#endif + #endif + } + + VW_UpdateScreen (); + +#ifdef SPEAR + UnCacheLump (HIGHSCORES_LUMP_START,HIGHSCORES_LUMP_END); + fontnumber = 0; +#endif +} + +//=========================================================================== + + +/* +======================= += += CheckHighScore += +======================= +*/ + +void CheckHighScore (long score,word other) +{ + word i,j; + int n; + HighScore myscore; + + strcpy(myscore.name,""); + myscore.score = score; + myscore.episode = gamestate.episode; + myscore.completed = other; + + for (i = 0,n = -1;i < MaxScores;i++) + { + if + ( + (myscore.score > Scores[i].score) + || ( + (myscore.score == Scores[i].score) + && (myscore.completed > Scores[i].completed) + ) + ) + { + for (j = MaxScores;--j > i;) + Scores[j] = Scores[j - 1]; + Scores[i] = myscore; + n = i; + break; + } + } + +#ifdef SPEAR + StartCPMusic (XAWARD_MUS); +#else + StartCPMusic (ROSTER_MUS); +#endif + DrawHighScores (); + + VW_FadeIn (); + + if (n != -1) + { + // + // got a high score + // + PrintY = 76 + (16 * n); +#ifndef SPEAR + PrintX = 4*8; + backcolor = BORDCOLOR; + fontcolor = 15; + US_LineInput(PrintX,PrintY,Scores[n].name,nil,true,MaxHighName,100); +#else + PrintX = 16; + fontnumber = 1; + VWB_Bar (PrintX-2,PrintY-2,145,15,0x9c); + VW_UpdateScreen (); + backcolor = 0x9c; + fontcolor = 15; + US_LineInput(PrintX,PrintY,Scores[n].name,nil,true,MaxHighName,130); +#endif + } + else + { + IN_ClearKeysDown (); + IN_UserInput(500); + } + +} + + +#ifndef UPLOAD +#ifndef SPEAR +#ifndef JAPAN +//////////////////////////////////////////////////////// +// +// NON-SHAREWARE NOTICE +// +//////////////////////////////////////////////////////// +void NonShareware(void) +{ + VW_FadeOut(); + + ClearMScreen(); + DrawStripes(10); + + CA_CacheGrChunk(STARTFONT+1); + fontnumber = 1; + + SETFONTCOLOR(READHCOLOR,BKGDCOLOR); + PrintX=110; + PrintY=15; + + #ifdef SPANISH + US_Print("Atencion"); + #else + US_Print("Attention"); + #endif + + SETFONTCOLOR(HIGHLIGHT,BKGDCOLOR); + WindowX=PrintX=40; + PrintY=60; + #ifdef SPANISH + US_Print("Este juego NO es gratis y\n"); + US_Print("NO es Shareware; favor de\n"); + US_Print("no distribuirlo.\n\n"); + #else + US_Print("This game is NOT shareware.\n"); + US_Print("Please do not distribute it.\n"); + US_Print("Thanks.\n\n"); + #endif + US_Print(" Id Software\n"); + + VW_UpdateScreen (); + VW_FadeIn(); + IN_Ack(); +} +#endif +#endif +#endif + +#ifdef SPEAR +#ifndef SPEARDEMO +//////////////////////////////////////////////////////// +// +// COPY PROTECTION FOR FormGen +// +//////////////////////////////////////////////////////// +char far CopyProFailedStrs[][100] = { + STR_COPY1, + STR_COPY2, + + STR_COPY3, + STR_COPY4, + + STR_COPY5, + STR_COPY6, + + STR_COPY7, + STR_COPY8, + + STR_COPY9, + "", + + STR_COPY10, + STR_COPY11, + + STR_COPY12, + "", + + STR_COPY13, + "", + + STR_COPY14, + "" + }, + + far BackDoorStrs[5][16] = { + "a spoon?", + "bite me!", + "joshua", + "pelt", +#ifdef BETA + "beta" +#else + "snoops" +#endif + }, + + far GoodBoyStrs[10][40] = { + "...is the CORRECT ANSWER!", + "", + + "Consider yourself bitten, sir.", + "", + + "Greetings Professor Falken, would you", + "like to play Spear of Destiny?", + + "Do you have any gold spray paint?", + "", + +#ifdef BETA + "Beta testing approved.", +#else + "I wish I had a 21\" monitor...", +#endif + "" + }, + + far bossstrs[4][24] = { + "DEATH KNIGHT", + "BARNACLE WILHELM", + "UBERMUTANTUBER MUTANT", + "TRANS GROSSE" + }, + + far WordStr[5][20] = { + "New Game", + "Sound...F4", + "Control...F6", + "Change View...F5", + "Quit...F10"}, + + far WordCorrect[5][2] = {"3","4","4","5","5"}, + + far MemberStr[10][40] = { + STR_COPY15, + "", + + STR_COPY16, + "", + + STR_COPY17, + STR_COPY18, + + STR_COPY19, + STR_COPY20, + + STR_COPY21, + STR_COPY22}, + + far MemberCorrect[5][24] = { + "adrian carmack", + "john carmackjohn romero", + "tom hall", + "jay wilbur", + "kevin cloud"}, + + far DosMessages[9][80] = { + STR_NOPE1, + STR_NOPE2, + STR_NOPE3, + STR_NOPE4, + STR_NOPE5, + STR_NOPE6, + STR_NOPE7, + STR_NOPE8, + STR_NOPE9}, + + far MiscTitle[4][20] = { + "BLOOD TEST", + "STRAIGHT-LACED", + "QUITE SHAPELY", + "I AM WHAT I AMMO" + }, + + far MiscStr[12][40] = { + STR_MISC1, + STR_MISC2, + "", + + STR_MISC3, + STR_MISC4, + "", + + STR_MISC5, + STR_MISC6, + "", + + STR_MISC7, + STR_MISC8, + STR_MISC9 + }, + + far MiscCorrect[4][5] = {"ss","8",STR_STAR,"45"}; + + +int BackDoor(char *s) +{ + int i; + + + strlwr(s); + + for (i=0;i<5;i++) + if (!_fstrcmp(s,BackDoorStrs[i])) + { + SETFONTCOLOR(14,15); + fontnumber = 0; + PrintY = 175; + VWB_DrawPic (0,20*8,COPYPROTBOXPIC); + US_CPrint(GoodBoyStrs[i*2]); + US_CPrint(GoodBoyStrs[i*2+1]); + VW_UpdateScreen(); + return 1; + } + + return 0; +} + + +void CopyProtection(void) +{ +#define TYPEBOX_Y 177 +#define TYPEBOX_BKGD 0x9c +#define PRINTCOLOR HIGHLIGHT + + int i,match,whichboss,bossnum,try,whichline,enemypicked[4]={0,0,0,0}, + bosses[4] = { BOSSPIC1PIC,BOSSPIC2PIC,BOSSPIC3PIC,BOSSPIC4PIC }, + whichone,whichpicked[4]={0,0,0,0},quiztype,whichmem, + memberpicked[5]={0,0,0,0,0},wordpicked[5]={0,0,0,0,0},whichword; + + char inputbuffer[20], + message[80]; + + enum + { + debriefing, + checkmanual, + staffquiz, + miscquiz, + + totaltypes + }; + + + + try = 0; + VW_FadeOut(); + CA_CacheGrChunk(C_BACKDROPPIC); + CacheLump(COPYPROT_LUMP_START,COPYPROT_LUMP_END); + CA_CacheGrChunk(STARTFONT+1); + CA_LoadAllSounds(); + StartCPMusic(COPYPRO_MUS); + US_InitRndT(true); + + while (try<3) + { + fontnumber = 1; + SETFONTCOLOR(PRINTCOLOR-2,15); + VWB_DrawPic (0,0,C_BACKDROPPIC); + VWB_DrawPic (0,0,COPYPROTTOPPIC); + VWB_DrawPic (0,20*8,COPYPROTBOXPIC); + WindowX = WindowY = 0; + WindowW = 320; + WindowH = 200; + PrintY = 65; + + quiztype = US_RndT()%totaltypes; + switch(quiztype) + { + // + // BOSSES QUIZ + // + case debriefing: + PrintX = 0; + US_Print(STR_DEBRIEF); + SETFONTCOLOR(PRINTCOLOR,15); + + while (enemypicked[whichboss = US_RndT()&3]); + enemypicked[whichboss] = 1; + bossnum = bosses[whichboss]; + VWB_DrawPic(128,60,bossnum); + fontnumber = 0; + PrintY = 130; + US_CPrint(STR_ENEMY1"\n"); + US_CPrint(STR_ENEMY2"\n\n"); + + VW_UpdateScreen(); + VW_FadeIn(); + + PrintX = 100; + fontcolor = 15; + backcolor = TYPEBOX_BKGD; + inputbuffer[0] = 0; + PrintY = TYPEBOX_Y; + fontnumber = 1; + US_LineInput(PrintX,PrintY,inputbuffer,nil,true,20,100); + + match = 0; + for (i=0;i<_fstrlen(bossstrs[whichboss]);i++) + if (!_fstrnicmp(inputbuffer,bossstrs[whichboss]+i,strlen(inputbuffer)) && + strlen(inputbuffer)>3) + match = 1; + + match += BackDoor(inputbuffer); + break; + + // + // MANUAL CHECK + // + case checkmanual: + while (wordpicked[whichword = US_RndT()%5]); + wordpicked[whichword] = 1; + US_CPrint(STR_CHECKMAN); + SETFONTCOLOR(PRINTCOLOR,15); + PrintY += 25; + US_CPrint(STR_MAN1); + US_CPrint(STR_MAN2); + _fstrcpy(message,STR_MAN3" \""); + _fstrcat(message,WordStr[whichword]); + _fstrcat(message,"\" "STR_MAN4); + US_CPrint(message); + VW_UpdateScreen(); + VW_FadeIn(); + + PrintX = 146; + fontcolor = 15; + backcolor = TYPEBOX_BKGD; + inputbuffer[0] = 0; + PrintY = TYPEBOX_Y; + US_LineInput(PrintX,PrintY,inputbuffer,nil,true,6,100); + + strlwr(inputbuffer); + match = 1-(_fstrcmp(inputbuffer,WordCorrect[whichword])!=0); + match += BackDoor(inputbuffer); + break; + + // + // STAFF QUIZ + // + case staffquiz: + while (memberpicked[whichmem = US_RndT()%5]); + memberpicked[whichmem] = 1; + US_CPrint(STR_ID1); + SETFONTCOLOR(PRINTCOLOR,15); + PrintY += 25; + US_CPrint(MemberStr[whichmem*2]); + US_CPrint(MemberStr[whichmem*2+1]); + VW_UpdateScreen(); + VW_FadeIn(); + + PrintX = 100; + fontcolor = 15; + backcolor = TYPEBOX_BKGD; + inputbuffer[0] = 0; + PrintY = TYPEBOX_Y; + US_LineInput(PrintX,PrintY,inputbuffer,nil,true,20,120); + + strlwr(inputbuffer); + match = 0; + for (i=0;i<_fstrlen(MemberCorrect[whichmem]);i++) + if (!_fstrnicmp(inputbuffer,MemberCorrect[whichmem]+i,strlen(inputbuffer)) && + strlen(inputbuffer)>2) + match = 1; + match += BackDoor(inputbuffer); + break; + + // + // MISCELLANEOUS QUESTIONS + // + case miscquiz: + while (whichpicked[whichone = US_RndT()&3]); + whichpicked[whichone] = 1; + US_CPrint(MiscTitle[whichone]); + SETFONTCOLOR(PRINTCOLOR,15); + PrintY += 25; + US_CPrint(MiscStr[whichone*3]); + US_CPrint(MiscStr[whichone*3+1]); + US_CPrint(MiscStr[whichone*3+2]); + VW_UpdateScreen(); + VW_FadeIn(); + + PrintX = 146; + fontcolor = 15; + backcolor = TYPEBOX_BKGD; + inputbuffer[0] = 0; + PrintY = TYPEBOX_Y; + US_LineInput(PrintX,PrintY,inputbuffer,nil,true,6,100); + + strlwr(inputbuffer); + match = 1-(_fstrcmp(inputbuffer,MiscCorrect[whichone])!=0); + match += BackDoor(inputbuffer); + break; + } + + // + // IF NO MATCH, WE'VE GOT A (MINOR) PROBLEM! + // + + if (!match) + { + whichline = 2*(US_RndT()%9); + SETFONTCOLOR(14,15); + fontnumber = 0; + PrintY = 175; + VWB_DrawPic (0,20*8,COPYPROTBOXPIC); + US_CPrint(CopyProFailedStrs[whichline]); + US_CPrint(CopyProFailedStrs[whichline+1]); + + VW_UpdateScreen(); + SD_PlaySound(NOWAYSND); + IN_UserInput(TickBase*3); + VW_FadeOut(); + try++; + } + else + { + int start; + + + SD_PlaySound(BONUS1UPSND); + SD_WaitSoundDone(); + UNCACHEGRCHUNK (STARTFONT+1); + UNCACHEGRCHUNK (C_BACKDROPPIC); + UnCacheLump (COPYPROT_LUMP_START,COPYPROT_LUMP_END); + + switch(SoundMode) + { + case sdm_Off: return; + case sdm_PC: start = STARTPCSOUNDS; break; + case sdm_AdLib: start = STARTADLIBSOUNDS; + } + + for (i=0;i +#include "WL_DEF.H" +#pragma hdrstop + + +/* +============================================================================= + + WOLFENSTEIN 3-D + + An Id Software production + + by John Carmack + +============================================================================= +*/ + +/* +============================================================================= + + LOCAL CONSTANTS + +============================================================================= +*/ + + +#define FOCALLENGTH (0x5700l) // in global coordinates +#define VIEWGLOBAL 0x10000 // globals visable flush to wall + +#define VIEWWIDTH 256 // size of view window +#define VIEWHEIGHT 144 + +/* +============================================================================= + + GLOBAL VARIABLES + +============================================================================= +*/ + +char str[80],str2[20]; +int tedlevelnum; +boolean tedlevel; +boolean nospr; +boolean IsA386; +int dirangle[9] = {0,ANGLES/8,2*ANGLES/8,3*ANGLES/8,4*ANGLES/8, + 5*ANGLES/8,6*ANGLES/8,7*ANGLES/8,ANGLES}; + +// +// proejection variables +// +fixed focallength; +unsigned screenofs; +int viewwidth; +int viewheight; +int centerx; +int shootdelta; // pixels away from centerx a target can be +fixed scale,maxslope; +long heightnumerator; +int minheightdiv; + + +void Quit (char *error); + +boolean startgame,loadedgame,virtualreality; +int mouseadjustment; + +char configname[13]="CONFIG."; + + +/* +============================================================================= + + LOCAL VARIABLES + +============================================================================= +*/ + + +/* +==================== += += ReadConfig += +==================== +*/ + +void ReadConfig(void) +{ + int file; + SDMode sd; + SMMode sm; + SDSMode sds; + + + if ( (file = open(configname,O_BINARY | O_RDONLY)) != -1) + { + // + // valid config file + // + read(file,Scores,sizeof(HighScore) * MaxScores); + + read(file,&sd,sizeof(sd)); + read(file,&sm,sizeof(sm)); + read(file,&sds,sizeof(sds)); + + read(file,&mouseenabled,sizeof(mouseenabled)); + read(file,&joystickenabled,sizeof(joystickenabled)); + read(file,&joypadenabled,sizeof(joypadenabled)); + read(file,&joystickprogressive,sizeof(joystickprogressive)); + read(file,&joystickport,sizeof(joystickport)); + + read(file,&dirscan,sizeof(dirscan)); + read(file,&buttonscan,sizeof(buttonscan)); + read(file,&buttonmouse,sizeof(buttonmouse)); + read(file,&buttonjoy,sizeof(buttonjoy)); + + read(file,&viewsize,sizeof(viewsize)); + read(file,&mouseadjustment,sizeof(mouseadjustment)); + + close(file); + + if (sd == sdm_AdLib && !AdLibPresent && !SoundBlasterPresent) + { + sd = sdm_PC; + sd = smm_Off; + } + + if ((sds == sds_SoundBlaster && !SoundBlasterPresent) || + (sds == sds_SoundSource && !SoundSourcePresent)) + sds = sds_Off; + + if (!MousePresent) + mouseenabled = false; + if (!JoysPresent[joystickport]) + joystickenabled = false; + + MainMenu[6].active=1; + MainItems.curpos=0; + } + else + { + // + // no config file, so select by hardware + // + if (SoundBlasterPresent || AdLibPresent) + { + sd = sdm_AdLib; + sm = smm_AdLib; + } + else + { + sd = sdm_PC; + sm = smm_Off; + } + + if (SoundBlasterPresent) + sds = sds_SoundBlaster; + else if (SoundSourcePresent) + sds = sds_SoundSource; + else + sds = sds_Off; + + if (MousePresent) + mouseenabled = true; + + joystickenabled = false; + joypadenabled = false; + joystickport = 0; + joystickprogressive = false; + + viewsize = 15; + mouseadjustment=5; + } + + SD_SetMusicMode (sm); + SD_SetSoundMode (sd); + SD_SetDigiDevice (sds); + +} + + +/* +==================== += += WriteConfig += +==================== +*/ + +void WriteConfig(void) +{ + int file; + + file = open(configname,O_CREAT | O_BINARY | O_WRONLY, + S_IREAD | S_IWRITE | S_IFREG); + + if (file != -1) + { + write(file,Scores,sizeof(HighScore) * MaxScores); + + write(file,&SoundMode,sizeof(SoundMode)); + write(file,&MusicMode,sizeof(MusicMode)); + write(file,&DigiMode,sizeof(DigiMode)); + + write(file,&mouseenabled,sizeof(mouseenabled)); + write(file,&joystickenabled,sizeof(joystickenabled)); + write(file,&joypadenabled,sizeof(joypadenabled)); + write(file,&joystickprogressive,sizeof(joystickprogressive)); + write(file,&joystickport,sizeof(joystickport)); + + write(file,&dirscan,sizeof(dirscan)); + write(file,&buttonscan,sizeof(buttonscan)); + write(file,&buttonmouse,sizeof(buttonmouse)); + write(file,&buttonjoy,sizeof(buttonjoy)); + + write(file,&viewsize,sizeof(viewsize)); + write(file,&mouseadjustment,sizeof(mouseadjustment)); + + close(file); + } +} + + +//=========================================================================== + + +/* +======================== += += Patch386 += += Patch ldiv to use 32 bit instructions += +======================== +*/ + +char *JHParmStrings[] = {"no386",nil}; +void Patch386 (void) +{ +extern void far jabhack2(void); +extern int far CheckIs386(void); + + int i; + + for (i = 1;i < _argc;i++) + if (US_CheckParm(_argv[i],JHParmStrings) == 0) + { + IsA386 = false; + return; + } + + if (CheckIs386()) + { + IsA386 = true; + jabhack2(); + } + else + IsA386 = false; +} + +//=========================================================================== + +/* +===================== += += NewGame += += Set up new game to start from the beginning += +===================== +*/ + +void NewGame (int difficulty,int episode) +{ + memset (&gamestate,0,sizeof(gamestate)); + gamestate.difficulty = difficulty; + gamestate.weapon = gamestate.bestweapon + = gamestate.chosenweapon = wp_pistol; + gamestate.health = 100; + gamestate.ammo = STARTAMMO; + gamestate.lives = 3; + gamestate.nextextra = EXTRAPOINTS; + gamestate.episode=episode; + + startgame = true; +} + +//=========================================================================== + +void DiskFlopAnim(int x,int y) +{ + static char which=0; + if (!x && !y) + return; + VWB_DrawPic(x,y,C_DISKLOADING1PIC+which); + VW_UpdateScreen(); + which^=1; +} + + +long DoChecksum(byte far *source,unsigned size,long checksum) +{ + unsigned i; + + for (i=0;inext) + size += sizeof(*ob); + size += sizeof(nullobj); + + size += sizeof(gamestate) + + sizeof(LRstruct)*8 + + sizeof(tilemap) + + sizeof(actorat) + + sizeof(laststatobj) + + sizeof(statobjlist) + + sizeof(doorposition) + + sizeof(pwallstate) + + sizeof(pwallx) + + sizeof(pwally) + + sizeof(pwalldir) + + sizeof(pwallpos); + + if (avail < size) + { + Message(STR_NOSPACE1"\n" + STR_NOSPACE2); + return false; + } + + checksum = 0; + + + DiskFlopAnim(x,y); + CA_FarWrite (file,(void far *)&gamestate,sizeof(gamestate)); + checksum = DoChecksum((byte far *)&gamestate,sizeof(gamestate),checksum); + + DiskFlopAnim(x,y); +#ifdef SPEAR + CA_FarWrite (file,(void far *)&LevelRatios[0],sizeof(LRstruct)*20); + checksum = DoChecksum((byte far *)&LevelRatios[0],sizeof(LRstruct)*20,checksum); +#else + CA_FarWrite (file,(void far *)&LevelRatios[0],sizeof(LRstruct)*8); + checksum = DoChecksum((byte far *)&LevelRatios[0],sizeof(LRstruct)*8,checksum); +#endif + + DiskFlopAnim(x,y); + CA_FarWrite (file,(void far *)tilemap,sizeof(tilemap)); + checksum = DoChecksum((byte far *)tilemap,sizeof(tilemap),checksum); + DiskFlopAnim(x,y); + CA_FarWrite (file,(void far *)actorat,sizeof(actorat)); + checksum = DoChecksum((byte far *)actorat,sizeof(actorat),checksum); + + CA_FarWrite (file,(void far *)areaconnect,sizeof(areaconnect)); + CA_FarWrite (file,(void far *)areabyplayer,sizeof(areabyplayer)); + + for (ob = player ; ob ; ob=ob->next) + { + DiskFlopAnim(x,y); + CA_FarWrite (file,(void far *)ob,sizeof(*ob)); + } + nullobj.active = ac_badobject; // end of file marker + DiskFlopAnim(x,y); + CA_FarWrite (file,(void far *)&nullobj,sizeof(nullobj)); + + + + DiskFlopAnim(x,y); + CA_FarWrite (file,(void far *)&laststatobj,sizeof(laststatobj)); + checksum = DoChecksum((byte far *)&laststatobj,sizeof(laststatobj),checksum); + DiskFlopAnim(x,y); + CA_FarWrite (file,(void far *)statobjlist,sizeof(statobjlist)); + checksum = DoChecksum((byte far *)statobjlist,sizeof(statobjlist),checksum); + + DiskFlopAnim(x,y); + CA_FarWrite (file,(void far *)doorposition,sizeof(doorposition)); + checksum = DoChecksum((byte far *)doorposition,sizeof(doorposition),checksum); + DiskFlopAnim(x,y); + CA_FarWrite (file,(void far *)doorobjlist,sizeof(doorobjlist)); + checksum = DoChecksum((byte far *)doorobjlist,sizeof(doorobjlist),checksum); + + DiskFlopAnim(x,y); + CA_FarWrite (file,(void far *)&pwallstate,sizeof(pwallstate)); + checksum = DoChecksum((byte far *)&pwallstate,sizeof(pwallstate),checksum); + CA_FarWrite (file,(void far *)&pwallx,sizeof(pwallx)); + checksum = DoChecksum((byte far *)&pwallx,sizeof(pwallx),checksum); + CA_FarWrite (file,(void far *)&pwally,sizeof(pwally)); + checksum = DoChecksum((byte far *)&pwally,sizeof(pwally),checksum); + CA_FarWrite (file,(void far *)&pwalldir,sizeof(pwalldir)); + checksum = DoChecksum((byte far *)&pwalldir,sizeof(pwalldir),checksum); + CA_FarWrite (file,(void far *)&pwallpos,sizeof(pwallpos)); + checksum = DoChecksum((byte far *)&pwallpos,sizeof(pwallpos),checksum); + + // + // WRITE OUT CHECKSUM + // + CA_FarWrite (file,(void far *)&checksum,sizeof(checksum)); + + return(true); +} + +//=========================================================================== + +/* +================== += += LoadTheGame += +================== +*/ + +boolean LoadTheGame(int file,int x,int y) +{ + long checksum,oldchecksum; + objtype *ob,nullobj; + + + checksum = 0; + + DiskFlopAnim(x,y); + CA_FarRead (file,(void far *)&gamestate,sizeof(gamestate)); + checksum = DoChecksum((byte far *)&gamestate,sizeof(gamestate),checksum); + + DiskFlopAnim(x,y); +#ifdef SPEAR + CA_FarRead (file,(void far *)&LevelRatios[0],sizeof(LRstruct)*20); + checksum = DoChecksum((byte far *)&LevelRatios[0],sizeof(LRstruct)*20,checksum); +#else + CA_FarRead (file,(void far *)&LevelRatios[0],sizeof(LRstruct)*8); + checksum = DoChecksum((byte far *)&LevelRatios[0],sizeof(LRstruct)*8,checksum); +#endif + + DiskFlopAnim(x,y); + SetupGameLevel (); + + DiskFlopAnim(x,y); + CA_FarRead (file,(void far *)tilemap,sizeof(tilemap)); + checksum = DoChecksum((byte far *)tilemap,sizeof(tilemap),checksum); + DiskFlopAnim(x,y); + CA_FarRead (file,(void far *)actorat,sizeof(actorat)); + checksum = DoChecksum((byte far *)actorat,sizeof(actorat),checksum); + + CA_FarRead (file,(void far *)areaconnect,sizeof(areaconnect)); + CA_FarRead (file,(void far *)areabyplayer,sizeof(areabyplayer)); + + + + InitActorList (); + DiskFlopAnim(x,y); + CA_FarRead (file,(void far *)player,sizeof(*player)); + + while (1) + { + DiskFlopAnim(x,y); + CA_FarRead (file,(void far *)&nullobj,sizeof(nullobj)); + if (nullobj.active == ac_badobject) + break; + GetNewActor (); + // don't copy over the links + memcpy (new,&nullobj,sizeof(nullobj)-4); + } + + + + DiskFlopAnim(x,y); + CA_FarRead (file,(void far *)&laststatobj,sizeof(laststatobj)); + checksum = DoChecksum((byte far *)&laststatobj,sizeof(laststatobj),checksum); + DiskFlopAnim(x,y); + CA_FarRead (file,(void far *)statobjlist,sizeof(statobjlist)); + checksum = DoChecksum((byte far *)statobjlist,sizeof(statobjlist),checksum); + + DiskFlopAnim(x,y); + CA_FarRead (file,(void far *)doorposition,sizeof(doorposition)); + checksum = DoChecksum((byte far *)doorposition,sizeof(doorposition),checksum); + DiskFlopAnim(x,y); + CA_FarRead (file,(void far *)doorobjlist,sizeof(doorobjlist)); + checksum = DoChecksum((byte far *)doorobjlist,sizeof(doorobjlist),checksum); + + DiskFlopAnim(x,y); + CA_FarRead (file,(void far *)&pwallstate,sizeof(pwallstate)); + checksum = DoChecksum((byte far *)&pwallstate,sizeof(pwallstate),checksum); + CA_FarRead (file,(void far *)&pwallx,sizeof(pwallx)); + checksum = DoChecksum((byte far *)&pwallx,sizeof(pwallx),checksum); + CA_FarRead (file,(void far *)&pwally,sizeof(pwally)); + checksum = DoChecksum((byte far *)&pwally,sizeof(pwally),checksum); + CA_FarRead (file,(void far *)&pwalldir,sizeof(pwalldir)); + checksum = DoChecksum((byte far *)&pwalldir,sizeof(pwalldir),checksum); + CA_FarRead (file,(void far *)&pwallpos,sizeof(pwallpos)); + checksum = DoChecksum((byte far *)&pwallpos,sizeof(pwallpos),checksum); + + CA_FarRead (file,(void far *)&oldchecksum,sizeof(oldchecksum)); + + if (oldchecksum != checksum) + { + Message(STR_SAVECHT1"\n" + STR_SAVECHT2"\n" + STR_SAVECHT3"\n" + STR_SAVECHT4); + + IN_ClearKeysDown(); + IN_Ack(); + + gamestate.score = 0; + gamestate.lives = 1; + gamestate.weapon = + gamestate.chosenweapon = + gamestate.bestweapon = wp_pistol; + gamestate.ammo = 8; + } + + return true; +} + +//=========================================================================== + +/* +========================== += += ShutdownId += += Shuts down all ID_?? managers += +========================== +*/ + +void ShutdownId (void) +{ + US_Shutdown (); + SD_Shutdown (); + PM_Shutdown (); + IN_Shutdown (); + VW_Shutdown (); + CA_Shutdown (); + MM_Shutdown (); +} + + +//=========================================================================== + +/* +================== += += BuildTables += += Calculates: += += scale projection constant += sintable/costable overlapping fractional tables += +================== +*/ + +const float radtoint = (float)FINEANGLES/2/PI; + +void BuildTables (void) +{ + int i; + float angle,anglestep; + double tang; + fixed value; + + +// +// calculate fine tangents +// + + for (i=0;i>2 +// + heightnumerator = (TILEGLOBAL*scale)>>6; + minheightdiv = heightnumerator/0x7fff +1; + +// +// calculate the angle offset from view angle of each pixel's ray +// + + for (i=0;i>= 8; +} + + + +//=========================================================================== + +/* +=================== += += SetupWalls += += Map tile values to scaled pics += +=================== +*/ + +void SetupWalls (void) +{ + int i; + + for (i=1;i=0) + { + if (lastsong >= 0) + MusicMenu[start+lastsong].active = 1; + + StartCPMusic(songs[start + which]); + MusicMenu[start+which].active = 2; + DrawMenu (&MusicItems,&MusicMenu[start]); + VW_UpdateScreen(); + lastsong = which; + } + } while(which>=0); + + MenuFadeOut(); + IN_ClearKeysDown(); +#ifdef SPEAR + UnCacheLump (BACKDROP_LUMP_START,BACKDROP_LUMP_END); +#else + UnCacheLump (CONTROLS_LUMP_START,CONTROLS_LUMP_END); +#endif +} +#endif + + +/* +========================== += += InitGame += += Load a few things right away += +========================== +*/ + +void InitGame (void) +{ + int i,x,y; + unsigned *blockstart; + + if (MS_CheckParm ("virtual")) + virtualreality = true; + else + virtualreality = false; + + MM_Startup (); // so the signon screen can be freed + + SignonScreen (); + + VW_Startup (); + IN_Startup (); + PM_Startup (); + PM_UnlockMainMem (); + SD_Startup (); + CA_Startup (); + US_Startup (); + + +#ifndef SPEAR + if (mminfo.mainmem < 235000L) +#else + if (mminfo.mainmem < 257000L && !MS_CheckParm("debugmode")) +#endif + { + memptr screen; + + CA_CacheGrChunk (ERRORSCREEN); + screen = grsegs[ERRORSCREEN]; + ShutdownId(); + movedata ((unsigned)screen,7+7*160,0xb800,0,17*160); + gotoxy (1,23); + exit(1); + } + + +// +// build some tables +// + InitDigiMap (); + + for (i=0;i YEAR || + (d.month >= MONTH && d.day >= DAY)) + { + printf("Sorry, BETA-TESTING is over. Thanks for you help.\n"); + exit(1); + } +#endif + + CheckForEpisodes(); + + Patch386 (); + + InitGame (); + + DemoLoop(); + + Quit("Demo loop exited???"); +} + diff --git a/16/WOLFSRC/WL_MENU.C b/16/WOLFSRC/WL_MENU.C new file mode 100755 index 00000000..7d1521cb --- /dev/null +++ b/16/WOLFSRC/WL_MENU.C @@ -0,0 +1,3986 @@ +//////////////////////////////////////////////////////////////////// +// +// WL_MENU.C +// by John Romero (C) 1992 Id Software, Inc. +// +//////////////////////////////////////////////////////////////////// +#include "wl_def.h" +#pragma hdrstop + +// +// PRIVATE PROTOTYPES +// +void CP_ReadThis(void); + +#ifdef SPEAR +#define STARTITEM newgame + +#else +#ifdef GOODTIMES +#define STARTITEM newgame + +#else +#define STARTITEM readthis +#endif +#endif + +char far endStrings[9][80]= +{ +#ifndef SPEAR + {"Dost thou wish to\nleave with such hasty\nabandon?"}, + {"Chickening out...\nalready?"}, + {"Press N for more carnage.\nPress Y to be a weenie."}, + {"So, you think you can\nquit this easily, huh?"}, + {"Press N to save the world.\nPress Y to abandon it in\nits hour of need."}, + {"Press N if you are brave.\nPress Y to cower in shame."}, + {"Heroes, press N.\nWimps, press Y."}, + {"You are at an intersection.\nA sign says, 'Press Y to quit.'\n>"}, + {"For guns and glory, press N.\nFor work and worry, press Y."} +#else + ENDSTR1, + ENDSTR2, + ENDSTR3, + ENDSTR4, + ENDSTR5, + ENDSTR6, + ENDSTR7, + ENDSTR8, + ENDSTR9 +#endif +}; + +CP_iteminfo + MainItems={MENU_X,MENU_Y,10,STARTITEM,24}, + SndItems={SM_X,SM_Y1,12,0,52}, + LSItems={LSM_X,LSM_Y,10,0,24}, + CtlItems={CTL_X,CTL_Y,6,-1,56}, + CusItems={8,CST_Y+13*2,9,-1,0}, + NewEitems={NE_X,NE_Y,11,0,88}, + NewItems={NM_X,NM_Y,4,2,24}; + +#pragma warn -sus +CP_itemtype far +MainMenu[]= +{ +#ifdef JAPAN + {1,"",CP_NewGame}, + {1,"",CP_Sound}, + {1,"",CP_Control}, + {1,"",CP_LoadGame}, + {0,"",CP_SaveGame}, + {1,"",CP_ChangeView}, + {2,"",CP_ReadThis}, + {1,"",CP_ViewScores}, + {1,"",0}, + {1,"",0} +#else + + {1,STR_NG,CP_NewGame}, + {1,STR_SD,CP_Sound}, + {1,STR_CL,CP_Control}, + {1,STR_LG,CP_LoadGame}, + {0,STR_SG,CP_SaveGame}, + {1,STR_CV,CP_ChangeView}, + +#ifndef GOODTIMES +#ifndef SPEAR + + #ifdef SPANISH + {2,"Ve esto!",CP_ReadThis}, + #else + {2,"Read This!",CP_ReadThis}, + #endif + +#endif +#endif + + {1,STR_VS,CP_ViewScores}, + {1,STR_BD,0}, + {1,STR_QT,0} +#endif +}, + +far SndMenu[]= +{ +#ifdef JAPAN + {1,"",0}, + {1,"",0}, + {1,"",0}, + {0,"",0}, + {0,"",0}, + {1,"",0}, + {1,"",0}, + {1,"",0}, + {0,"",0}, + {0,"",0}, + {1,"",0}, + {1,"",0}, +#else + {1,STR_NONE,0}, + {1,STR_PC,0}, + {1,STR_ALSB,0}, + {0,"",0}, + {0,"",0}, + {1,STR_NONE,0}, + {1,STR_DISNEY,0}, + {1,STR_SB,0}, + {0,"",0}, + {0,"",0}, + {1,STR_NONE,0}, + {1,STR_ALSB,0} +#endif +}, + +far CtlMenu[]= +{ +#ifdef JAPAN + {0,"",0}, + {0,"",0}, + {0,"",0}, + {0,"",0}, + {0,"",MouseSensitivity}, + {1,"",CustomControls} +#else + {0,STR_MOUSEEN,0}, + {0,STR_JOYEN,0}, + {0,STR_PORT2,0}, + {0,STR_GAMEPAD,0}, + {0,STR_SENS,MouseSensitivity}, + {1,STR_CUSTOM,CustomControls} +#endif +}, + +#pragma warn +sus + +#ifndef SPEAR +far NewEmenu[]= +{ +#ifdef JAPAN +#ifdef JAPDEMO + {1,"",0}, + {0,"",0}, + {0,"",0}, + {0,"",0}, + {0,"",0}, + {0,"",0}, + {0,"",0}, + {0,"",0}, + {0,"",0}, + {0,"",0}, + {0,"",0}, + {0,"",0}, +#else + {1,"",0}, + {0,"",0}, + {1,"",0}, + {0,"",0}, + {1,"",0}, + {0,"",0}, + {1,"",0}, + {0,"",0}, + {1,"",0}, + {0,"",0}, + {1,"",0}, + {0,"",0} +#endif +#else + #ifdef SPANISH + {1,"Episodio 1\n" + "Fuga desde Wolfenstein",0}, + {0,"",0}, + {3,"Episodio 2\n" + "Operacion Eisenfaust",0}, + {0,"",0}, + {3,"Episodio 3\n" + "Muere, Fuhrer, Muere!",0}, + {0,"",0}, + {3,"Episodio 4\n" + "Un Negro Secreto",0}, + {0,"",0}, + {3,"Episodio 5\n" + "Huellas del Loco",0}, + {0,"",0}, + {3,"Episodio 6\n" + "Confrontacion",0} + #else + {1,"Episode 1\n" + "Escape from Wolfenstein",0}, + {0,"",0}, + {3,"Episode 2\n" + "Operation: Eisenfaust",0}, + {0,"",0}, + {3,"Episode 3\n" + "Die, Fuhrer, Die!",0}, + {0,"",0}, + {3,"Episode 4\n" + "A Dark Secret",0}, + {0,"",0}, + {3,"Episode 5\n" + "Trail of the Madman",0}, + {0,"",0}, + {3,"Episode 6\n" + "Confrontation",0} + #endif +#endif +}, +#endif + + +far NewMenu[]= +{ +#ifdef JAPAN + {1,"",0}, + {1,"",0}, + {1,"",0}, + {1,"",0} +#else + {1,STR_DADDY,0}, + {1,STR_HURTME,0}, + {1,STR_BRINGEM,0}, + {1,STR_DEATH,0} +#endif +}, + +far LSMenu[]= +{ + {1,"",0}, + {1,"",0}, + {1,"",0}, + {1,"",0}, + {1,"",0}, + {1,"",0}, + {1,"",0}, + {1,"",0}, + {1,"",0}, + {1,"",0} +}, + +far CusMenu[]= +{ + {1,"",0}, + {0,"",0}, + {0,"",0}, + {1,"",0}, + {0,"",0}, + {0,"",0}, + {1,"",0}, + {0,"",0}, + {1,"",0} +} +; + + +int color_hlite[]={ + DEACTIVE, + HIGHLIGHT, + READHCOLOR, + 0x67 + }, + + color_norml[]={ + DEACTIVE, + TEXTCOLOR, + READCOLOR, + 0x6b + }; + +int EpisodeSelect[6]={1}; + + +int SaveGamesAvail[10],StartGame,SoundStatus=1,pickquick; +char SaveGameNames[10][32],SaveName[13]="SAVEGAM?."; + + +//////////////////////////////////////////////////////////////////// +// +// INPUT MANAGER SCANCODE TABLES +// +//////////////////////////////////////////////////////////////////// +static byte + *ScanNames[] = // Scan code names with single chars + { + "?","?","1","2","3","4","5","6","7","8","9","0","-","+","?","?", + "Q","W","E","R","T","Y","U","I","O","P","[","]","|","?","A","S", + "D","F","G","H","J","K","L",";","\"","?","?","?","Z","X","C","V", + "B","N","M",",",".","/","?","?","?","?","?","?","?","?","?","?", + "?","?","?","?","?","?","?","?","\xf","?","-","\x15","5","\x11","+","?", + "\x13","?","?","?","?","?","?","?","?","?","?","?","?","?","?","?", + "?","?","?","?","?","?","?","?","?","?","?","?","?","?","?","?", + "?","?","?","?","?","?","?","?","?","?","?","?","?","?","?","?" + }, // DEBUG - consolidate these + far ExtScanCodes[] = // Scan codes with >1 char names + { + 1,0xe,0xf,0x1d,0x2a,0x39,0x3a,0x3b,0x3c,0x3d,0x3e, + 0x3f,0x40,0x41,0x42,0x43,0x44,0x57,0x59,0x46,0x1c,0x36, + 0x37,0x38,0x47,0x49,0x4f,0x51,0x52,0x53,0x45,0x48, + 0x50,0x4b,0x4d,0x00 + }, + *ExtScanNames[] = // Names corresponding to ExtScanCodes + { + "Esc","BkSp","Tab","Ctrl","LShft","Space","CapsLk","F1","F2","F3","F4", + "F5","F6","F7","F8","F9","F10","F11","F12","ScrlLk","Enter","RShft", + "PrtSc","Alt","Home","PgUp","End","PgDn","Ins","Del","NumLk","Up", + "Down","Left","Right","" + }; + + +//////////////////////////////////////////////////////////////////// +// +// Wolfenstein Control Panel! Ta Da! +// +//////////////////////////////////////////////////////////////////// +void US_ControlPanel(byte scancode) +{ + int which,i,start; + + + if (ingame) + if (CP_CheckQuick(scancode)) + return; + + StartCPMusic(MENUSONG); + SetupControlPanel(); + + // + // F-KEYS FROM WITHIN GAME + // + switch(scancode) + { + case sc_F1: + #ifdef SPEAR + BossKey(); + #else + #ifdef GOODTIMES + BossKey(); + #else + HelpScreens(); + #endif + #endif + goto finishup; + + case sc_F2: + CP_SaveGame(0); + goto finishup; + + case sc_F3: + CP_LoadGame(0); + goto finishup; + + case sc_F4: + CP_Sound(); + goto finishup; + + case sc_F5: + CP_ChangeView(); + goto finishup; + + case sc_F6: + CP_Control(); + goto finishup; + + finishup: + CleanupControlPanel(); + #ifdef SPEAR + UnCacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); + #endif + return; + } + +#ifdef SPEAR + CacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); +#endif + + DrawMainMenu(); + MenuFadeIn(); + StartGame=0; + + // + // MAIN MENU LOOP + // + do + { + which=HandleMenu(&MainItems,&MainMenu[0],NULL); + + #ifdef SPEAR + #ifndef SPEARDEMO + // + // EASTER EGG FOR SPEAR OF DESTINY! + // + if (Keyboard[sc_I] && Keyboard[sc_D]) + { + VW_FadeOut(); + StartCPMusic (XJAZNAZI_MUS); + UnCacheLump(OPTIONS_LUMP_START,OPTIONS_LUMP_END); + UnCacheLump(BACKDROP_LUMP_START,BACKDROP_LUMP_END); + MM_SortMem (); + ClearMemory (); + + + CA_CacheGrChunk (IDGUYS1PIC); + VWB_DrawPic(0,0,IDGUYS1PIC); + UNCACHEGRCHUNK(IDGUYS1PIC); + + CA_CacheGrChunk (IDGUYS2PIC); + VWB_DrawPic(0,80,IDGUYS2PIC); + UNCACHEGRCHUNK(IDGUYS2PIC); + + VW_UpdateScreen(); + + CA_CacheGrChunk (IDGUYSPALETTE); + VL_FadeIn(0,255,grsegs[IDGUYSPALETTE],30); + UNCACHEGRCHUNK(IDGUYSPALETTE); + + while (Keyboard[sc_I] || Keyboard[sc_D]); + IN_ClearKeysDown(); + IN_Ack(); + + VW_FadeOut(); + + CacheLump(BACKDROP_LUMP_START,BACKDROP_LUMP_END); + CacheLump(OPTIONS_LUMP_START,OPTIONS_LUMP_END); + DrawMainMenu(); + StartCPMusic (MENUSONG); + MenuFadeIn(); + } + #endif + #endif + + switch(which) + { + case viewscores: + if (MainMenu[viewscores].routine == NULL) + if (CP_EndGame()) + StartGame=1; + + DrawMainMenu(); + MenuFadeIn(); + break; + + case backtodemo: + #ifdef SPEAR + if (!ingame) + { + // + // DEALLOCATE ALL SOUNDS! + // + switch (SoundMode) + { + case sdm_PC: + start = STARTPCSOUNDS; + break; + case sdm_AdLib: + start = STARTADLIBSOUNDS; + break; + } + + if (SoundMode != sdm_Off) + for (i=0;i"); + while (!Keyboard[sc_Escape]) + IN_ClearKeysDown(); + + SD_MusicOn(); + VL_SetVGAPlaneMode (); + VL_TestPaletteSet (); + VL_SetPalette (&gamepal); + LoadLatchMem(); +} +#endif +#endif + +//////////////////////////////////////////////////////////////////// +// +// CHECK QUICK-KEYS & QUIT (WHILE IN A GAME) +// +//////////////////////////////////////////////////////////////////// +int CP_CheckQuick(unsigned scancode) +{ + switch(scancode) + { + // + // END GAME + // + case sc_F7: + CA_CacheGrChunk(STARTFONT+1); + + WindowH=160; + #ifdef JAPAN + if (GetYorN(7,8,C_JAPQUITPIC)) + #else + if (Confirm(ENDGAMESTR)) + #endif + { + playstate = ex_died; + pickquick = gamestate.lives = 0; + } + + DrawAllPlayBorder(); + WindowH=200; + fontnumber=0; + MainMenu[savegame].active = 0; + return 1; + + // + // QUICKSAVE + // + case sc_F8: + if (SaveGamesAvail[LSItems.curpos] && pickquick) + { + CA_CacheGrChunk(STARTFONT+1); + fontnumber = 1; + Message(STR_SAVING"..."); + CP_SaveGame(1); + fontnumber=0; + } + else + { + #ifndef SPEAR + CA_CacheGrChunk(STARTFONT+1); + CA_CacheGrChunk(C_CURSOR1PIC); + CA_CacheGrChunk(C_CURSOR2PIC); + CA_CacheGrChunk(C_DISKLOADING1PIC); + CA_CacheGrChunk(C_DISKLOADING2PIC); + CA_CacheGrChunk(C_SAVEGAMEPIC); + CA_CacheGrChunk(C_MOUSELBACKPIC); + #else + CacheLump (BACKDROP_LUMP_START,BACKDROP_LUMP_END); + CA_CacheGrChunk(C_CURSOR1PIC); + #endif + + VW_FadeOut (); + + StartCPMusic(MENUSONG); + pickquick=CP_SaveGame(0); + + SETFONTCOLOR(0,15); + IN_ClearKeysDown(); + DrawPlayScreen (); + + if (!startgame && !loadedgame) + { + VW_FadeIn (); + StartMusic (); + } + + if (loadedgame) + playstate = ex_abort; + lasttimecount = TimeCount; + + if (MousePresent) + Mouse(MDelta); // Clear accumulated mouse movement + + PM_CheckMainMem (); + + #ifndef SPEAR + UNCACHEGRCHUNK(C_CURSOR1PIC); + UNCACHEGRCHUNK(C_CURSOR2PIC); + UNCACHEGRCHUNK(C_DISKLOADING1PIC); + UNCACHEGRCHUNK(C_DISKLOADING2PIC); + UNCACHEGRCHUNK(C_SAVEGAMEPIC); + UNCACHEGRCHUNK(C_MOUSELBACKPIC); + #else + UnCacheLump (BACKDROP_LUMP_START,BACKDROP_LUMP_END); + #endif + } + return 1; + + // + // QUICKLOAD + // + case sc_F9: + if (SaveGamesAvail[LSItems.curpos] && pickquick) + { + char string[100]=STR_LGC; + + + CA_CacheGrChunk(STARTFONT+1); + fontnumber = 1; + + strcat(string,SaveGameNames[LSItems.curpos]); + strcat(string,"\"?"); + + if (Confirm(string)) + CP_LoadGame(1); + + DrawAllPlayBorder(); + fontnumber=0; + } + else + { + #ifndef SPEAR + CA_CacheGrChunk(STARTFONT+1); + CA_CacheGrChunk(C_CURSOR1PIC); + CA_CacheGrChunk(C_CURSOR2PIC); + CA_CacheGrChunk(C_DISKLOADING1PIC); + CA_CacheGrChunk(C_DISKLOADING2PIC); + CA_CacheGrChunk(C_LOADGAMEPIC); + CA_CacheGrChunk(C_MOUSELBACKPIC); + #else + CA_CacheGrChunk(C_CURSOR1PIC); + CacheLump (BACKDROP_LUMP_START,BACKDROP_LUMP_END); + #endif + + VW_FadeOut (); + + StartCPMusic(MENUSONG); + pickquick=CP_LoadGame(0); + + SETFONTCOLOR(0,15); + IN_ClearKeysDown(); + DrawPlayScreen (); + + if (!startgame && !loadedgame) + { + VW_FadeIn (); + StartMusic (); + } + + if (loadedgame) + playstate = ex_abort; + + lasttimecount = TimeCount; + + if (MousePresent) + Mouse(MDelta); // Clear accumulated mouse movement + PM_CheckMainMem (); + + #ifndef SPEAR + UNCACHEGRCHUNK(C_CURSOR1PIC); + UNCACHEGRCHUNK(C_CURSOR2PIC); + UNCACHEGRCHUNK(C_DISKLOADING1PIC); + UNCACHEGRCHUNK(C_DISKLOADING2PIC); + UNCACHEGRCHUNK(C_LOADGAMEPIC); + UNCACHEGRCHUNK(C_MOUSELBACKPIC); + #else + UnCacheLump (BACKDROP_LUMP_START,BACKDROP_LUMP_END); + #endif + } + return 1; + + // + // QUIT + // + case sc_F10: + CA_CacheGrChunk(STARTFONT+1); + + WindowX=WindowY=0; + WindowW=320; + WindowH=160; + #ifdef JAPAN + if (GetYorN(7,8,C_QUITMSGPIC)) + #else + #ifdef SPANISH + if (Confirm(ENDGAMESTR)) + #else + if (Confirm(endStrings[US_RndT()&0x7+(US_RndT()&1)])) + #endif + #endif + { + int i; + + + VW_UpdateScreen(); + SD_MusicOff(); + SD_StopSound(); + MenuFadeOut(); + + // + // SHUT-UP THE ADLIB + // + for (i=1;i<=0xf5;i++) + alOut(i,0); + Quit(NULL); + } + + DrawAllPlayBorder(); + WindowH=200; + fontnumber=0; + return 1; + } + + return 0; +} + + +//////////////////////////////////////////////////////////////////// +// +// END THE CURRENT GAME +// +//////////////////////////////////////////////////////////////////// +int CP_EndGame(void) +{ +#ifdef JAPAN + if (!GetYorN(7,8,C_JAPQUITPIC)) +#else + if (!Confirm(ENDGAMESTR)) +#endif + return 0; + + pickquick = gamestate.lives = 0; + playstate = ex_died; + + #pragma warn -sus + MainMenu[savegame].active = 0; + MainMenu[viewscores].routine=CP_ViewScores; + #ifndef JAPAN + _fstrcpy(MainMenu[viewscores].string,STR_VS); + #endif + #pragma warn +sus + + return 1; +} + + +//////////////////////////////////////////////////////////////////// +// +// VIEW THE HIGH SCORES +// +//////////////////////////////////////////////////////////////////// +void CP_ViewScores(void) +{ + fontnumber=0; + +#ifdef SPEAR + UnCacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); + StartCPMusic (XAWARD_MUS); +#else + StartCPMusic (ROSTER_MUS); +#endif + + DrawHighScores (); + VW_UpdateScreen (); + MenuFadeIn(); + fontnumber=1; + + IN_Ack(); + + StartCPMusic(MENUSONG); + MenuFadeOut(); + +#ifdef SPEAR + CacheLump (BACKDROP_LUMP_START,BACKDROP_LUMP_END); + CacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); +#endif +} + + +//////////////////////////////////////////////////////////////////// +// +// START A NEW GAME +// +//////////////////////////////////////////////////////////////////// +void CP_NewGame(void) +{ + int which,episode; + +#ifdef SPEAR + UnCacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); +#endif + + +#ifndef SPEAR +firstpart: + + DrawNewEpisode(); + do + { + which=HandleMenu(&NewEitems,&NewEmenu[0],NULL); + switch(which) + { + case -1: + MenuFadeOut(); + return; + + default: + if (!EpisodeSelect[which/2]) + { + SD_PlaySound (NOWAYSND); + Message("Please select \"Read This!\"\n" + "from the Options menu to\n" + "find out how to order this\n" + "episode from Apogee."); + IN_ClearKeysDown(); + IN_Ack(); + DrawNewEpisode(); + which = 0; + } + else + { + episode = which/2; + which = 1; + } + break; + } + + } while (!which); + + ShootSnd(); + + // + // ALREADY IN A GAME? + // + if (ingame) + #ifdef JAPAN + if (!GetYorN(7,8,C_JAPNEWGAMEPIC)) + #else + if (!Confirm(CURGAME)) + #endif + { + MenuFadeOut(); + return; + } + + MenuFadeOut(); + +#else + episode = 0; + + // + // ALREADY IN A GAME? + // + CacheLump (NEWGAME_LUMP_START,NEWGAME_LUMP_END); + DrawNewGame(); + if (ingame) + if (!Confirm(CURGAME)) + { + MenuFadeOut(); + UnCacheLump (NEWGAME_LUMP_START,NEWGAME_LUMP_END); + CacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); + return; + } + +#endif + + DrawNewGame(); + which=HandleMenu(&NewItems,&NewMenu[0],DrawNewGameDiff); + if (which<0) + { + MenuFadeOut(); + #ifndef SPEAR + goto firstpart; + #else + UnCacheLump (NEWGAME_LUMP_START,NEWGAME_LUMP_END); + CacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); + return; + #endif + } + + ShootSnd(); + NewGame(which,episode); + StartGame=1; + MenuFadeOut(); + + // + // CHANGE "READ THIS!" TO NORMAL COLOR + // + #ifndef SPEAR + #ifndef GOODTIMES + MainMenu[readthis].active=1; + #endif + #endif + + pickquick = 0; + +#ifdef SPEAR + UnCacheLump (NEWGAME_LUMP_START,NEWGAME_LUMP_END); + CacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); +#endif +} + + +#ifndef SPEAR +///////////////////// +// +// DRAW NEW EPISODE MENU +// +void DrawNewEpisode(void) +{ + int i; + +#ifdef JAPAN + CA_CacheScreen(S_EPISODEPIC); +#else + ClearMScreen(); + VWB_DrawPic(112,184,C_MOUSELBACKPIC); + + DrawWindow(NE_X-4,NE_Y-4,NE_W+8,NE_H+8,BKGDCOLOR); + SETFONTCOLOR(READHCOLOR,BKGDCOLOR); + PrintY=2; + WindowX=0; + #ifdef SPANISH + US_CPrint("Cual episodio jugar?"); + #else + US_CPrint("Which episode to play?"); + #endif +#endif + + SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR); + DrawMenu(&NewEitems,&NewEmenu[0]); + + for (i=0;i<6;i++) + VWB_DrawPic(NE_X+32,NE_Y+i*26,C_EPISODE1PIC+i); + + VW_UpdateScreen(); + MenuFadeIn(); + WaitKeyUp(); +} +#endif + +///////////////////// +// +// DRAW NEW GAME MENU +// +void DrawNewGame(void) +{ +#ifdef JAPAN + CA_CacheScreen(S_SKILLPIC); +#else + ClearMScreen(); + VWB_DrawPic(112,184,C_MOUSELBACKPIC); + + SETFONTCOLOR(READHCOLOR,BKGDCOLOR); + PrintX=NM_X+20; + PrintY=NM_Y-32; + +#ifndef SPEAR + #ifdef SPANISH + US_Print("Eres macho?"); + #else + US_Print("How tough are you?"); + #endif +#else + VWB_DrawPic (PrintX,PrintY,C_HOWTOUGHPIC); +#endif + + DrawWindow(NM_X-5,NM_Y-10,NM_W,NM_H,BKGDCOLOR); +#endif + + DrawMenu(&NewItems,&NewMenu[0]); + DrawNewGameDiff(NewItems.curpos); + VW_UpdateScreen(); + MenuFadeIn(); + WaitKeyUp(); +} + + +//////////////////////// +// +// DRAW NEW GAME GRAPHIC +// +void DrawNewGameDiff(int w) +{ + VWB_DrawPic(NM_X+185,NM_Y+7,w+C_BABYMODEPIC); +} + + +//////////////////////////////////////////////////////////////////// +// +// HANDLE SOUND MENU +// +//////////////////////////////////////////////////////////////////// +void CP_Sound(void) +{ + int which,i; + + +#ifdef SPEAR + UnCacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); + CacheLump (SOUND_LUMP_START,SOUND_LUMP_END); +#endif + + DrawSoundMenu(); + MenuFadeIn(); + WaitKeyUp(); + + do + { + which=HandleMenu(&SndItems,&SndMenu[0],NULL); + // + // HANDLE MENU CHOICES + // + switch(which) + { + // + // SOUND EFFECTS + // + case 0: + if (SoundMode!=sdm_Off) + { + SD_WaitSoundDone(); + SD_SetSoundMode(sdm_Off); + DrawSoundMenu(); + } + break; + case 1: + if (SoundMode!=sdm_PC) + { + SD_WaitSoundDone(); + SD_SetSoundMode(sdm_PC); + CA_LoadAllSounds(); + DrawSoundMenu(); + ShootSnd(); + } + break; + case 2: + if (SoundMode!=sdm_AdLib) + { + SD_WaitSoundDone(); + SD_SetSoundMode(sdm_AdLib); + CA_LoadAllSounds(); + DrawSoundMenu(); + ShootSnd(); + } + break; + + // + // DIGITIZED SOUND + // + case 5: + if (DigiMode!=sds_Off) + { + SD_SetDigiDevice(sds_Off); + DrawSoundMenu(); + } + break; + case 6: + if (DigiMode!=sds_SoundSource) + { + SD_SetDigiDevice(sds_SoundSource); + DrawSoundMenu(); + ShootSnd(); + } + break; + case 7: + if (DigiMode!=sds_SoundBlaster) + { + SD_SetDigiDevice(sds_SoundBlaster); + DrawSoundMenu(); + ShootSnd(); + } + break; + + // + // MUSIC + // + case 10: + if (MusicMode!=smm_Off) + { + SD_SetMusicMode(smm_Off); + DrawSoundMenu(); + ShootSnd(); + } + break; + case 11: + if (MusicMode!=smm_AdLib) + { + SD_SetMusicMode(smm_AdLib); + DrawSoundMenu(); + ShootSnd(); + StartCPMusic(MENUSONG); + } + break; + } + } while(which>=0); + + MenuFadeOut(); + +#ifdef SPEAR + UnCacheLump (SOUND_LUMP_START,SOUND_LUMP_END); + CacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); +#endif +} + + +////////////////////// +// +// DRAW THE SOUND MENU +// +void DrawSoundMenu(void) +{ + int i,on; + + +#ifdef JAPAN + CA_CacheScreen(S_SOUNDPIC); +#else + // + // DRAW SOUND MENU + // + ClearMScreen(); + VWB_DrawPic(112,184,C_MOUSELBACKPIC); + + DrawWindow(SM_X-8,SM_Y1-3,SM_W,SM_H1,BKGDCOLOR); + DrawWindow(SM_X-8,SM_Y2-3,SM_W,SM_H2,BKGDCOLOR); + DrawWindow(SM_X-8,SM_Y3-3,SM_W,SM_H3,BKGDCOLOR); +#endif + + // + // IF NO ADLIB, NON-CHOOSENESS! + // + if (!AdLibPresent && !SoundBlasterPresent) + { + SndMenu[2].active=SndMenu[10].active=SndMenu[11].active=0; + } + + if (!SoundSourcePresent) + SndMenu[6].active=0; + + if (!SoundBlasterPresent) + SndMenu[7].active=0; + + if (!SoundSourcePresent && !SoundBlasterPresent) + SndMenu[5].active=0; + + DrawMenu(&SndItems,&SndMenu[0]); +#ifndef JAPAN + VWB_DrawPic(100,SM_Y1-20,C_FXTITLEPIC); + VWB_DrawPic(100,SM_Y2-20,C_DIGITITLEPIC); + VWB_DrawPic(100,SM_Y3-20,C_MUSICTITLEPIC); +#endif + + for (i=0;i=0 && SaveGamesAvail[which]) + { + ShootSnd(); + name[7]=which+'0'; + + handle=open(name,O_BINARY); + lseek(handle,32,SEEK_SET); + + DrawLSAction(0); + loadedgame=true; + + LoadTheGame(handle,LSA_X+8,LSA_Y+5); + close(handle); + + StartGame=1; + ShootSnd(); + // + // CHANGE "READ THIS!" TO NORMAL COLOR + // + + #ifndef SPEAR + #ifndef GOODTIMES + MainMenu[readthis].active=1; + #endif + #endif + + exit=1; + break; + } + + } while(which>=0); + + MenuFadeOut(); + +#ifdef SPEAR + UnCacheLump (LOADSAVE_LUMP_START,LOADSAVE_LUMP_END); + CacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); +#endif + + return exit; +} + + +/////////////////////////////////// +// +// HIGHLIGHT CURRENT SELECTED ENTRY +// +void TrackWhichGame(int w) +{ + static int lastgameon=0; + + PrintLSEntry(lastgameon,TEXTCOLOR); + PrintLSEntry(w,HIGHLIGHT); + + lastgameon=w; +} + + +//////////////////////////// +// +// DRAW THE LOAD/SAVE SCREEN +// +void DrawLoadSaveScreen(int loadsave) +{ + #define DISKX 100 + #define DISKY 0 + + int i; + + + ClearMScreen(); + fontnumber=1; + VWB_DrawPic(112,184,C_MOUSELBACKPIC); + DrawWindow(LSM_X-10,LSM_Y-5,LSM_W,LSM_H,BKGDCOLOR); + DrawStripes(10); + + if (!loadsave) + VWB_DrawPic(60,0,C_LOADGAMEPIC); + else + VWB_DrawPic(60,0,C_SAVEGAMEPIC); + + for (i=0;i<10;i++) + PrintLSEntry(i,TEXTCOLOR); + + DrawMenu(&LSItems,&LSMenu[0]); + VW_UpdateScreen(); + MenuFadeIn(); + WaitKeyUp(); +} + + +/////////////////////////////////////////// +// +// PRINT LOAD/SAVE GAME ENTRY W/BOX OUTLINE +// +void PrintLSEntry(int w,int color) +{ + SETFONTCOLOR(color,BKGDCOLOR); + DrawOutline(LSM_X+LSItems.indent,LSM_Y+w*13,LSM_W-LSItems.indent-15,11,color,color); + PrintX=LSM_X+LSItems.indent+2; + PrintY=LSM_Y+w*13+1; + fontnumber=0; + + if (SaveGamesAvail[w]) + US_Print(SaveGameNames[w]); + else + US_Print(" - "STR_EMPTY" -"); + + fontnumber=1; +} + + +//////////////////////////////////////////////////////////////////// +// +// SAVE CURRENT GAME +// +//////////////////////////////////////////////////////////////////// +int CP_SaveGame(int quick) +{ + int handle,which,exit=0; + unsigned nwritten; + char name[13],input[32]; + + + strcpy(name,SaveName); + + // + // QUICKSAVE? + // + if (quick) + { + which=LSItems.curpos; + + if (SaveGamesAvail[which]) + { + name[7]=which+'0'; + unlink(name); + handle=creat(name,S_IREAD|S_IWRITE); + + strcpy(input,&SaveGameNames[which][0]); + + _dos_write(handle,(void far *)input,32,&nwritten); + lseek(handle,32,SEEK_SET); + SaveTheGame(handle,0,0); + close(handle); + + return 1; + } + } + + +#ifdef SPEAR + UnCacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); + CacheLump (LOADSAVE_LUMP_START,LOADSAVE_LUMP_END); +#endif + + DrawLoadSaveScreen(1); + + do + { + which=HandleMenu(&LSItems,&LSMenu[0],TrackWhichGame); + if (which>=0) + { + // + // OVERWRITE EXISTING SAVEGAME? + // + if (SaveGamesAvail[which]) + #ifdef JAPAN + if (!GetYorN(7,8,C_JAPSAVEOVERPIC)) + #else + if (!Confirm(GAMESVD)) + #endif + { + DrawLoadSaveScreen(1); + continue; + } + else + { + DrawLoadSaveScreen(1); + PrintLSEntry(which,HIGHLIGHT); + VW_UpdateScreen(); + } + + ShootSnd(); + + strcpy(input,&SaveGameNames[which][0]); + name[7]=which+'0'; + + fontnumber=0; + if (!SaveGamesAvail[which]) + VWB_Bar(LSM_X+LSItems.indent+1,LSM_Y+which*13+1,LSM_W-LSItems.indent-16,10,BKGDCOLOR); + VW_UpdateScreen(); + + if (US_LineInput(LSM_X+LSItems.indent+2,LSM_Y+which*13+1,input,input,true,31,LSM_W-LSItems.indent-30)) + { + SaveGamesAvail[which]=1; + strcpy(&SaveGameNames[which][0],input); + + unlink(name); + handle=creat(name,S_IREAD|S_IWRITE); + _dos_write(handle,(void far *)input,32,&nwritten); + lseek(handle,32,SEEK_SET); + + DrawLSAction(1); + SaveTheGame(handle,LSA_X+8,LSA_Y+5); + + close(handle); + + ShootSnd(); + exit=1; + } + else + { + VWB_Bar(LSM_X+LSItems.indent+1,LSM_Y+which*13+1,LSM_W-LSItems.indent-16,10,BKGDCOLOR); + PrintLSEntry(which,HIGHLIGHT); + VW_UpdateScreen(); + SD_PlaySound(ESCPRESSEDSND); + continue; + } + + fontnumber=1; + break; + } + + } while(which>=0); + + MenuFadeOut(); + +#ifdef SPEAR + UnCacheLump (LOADSAVE_LUMP_START,LOADSAVE_LUMP_END); + CacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); +#endif + + return exit; +} + + +//////////////////////////////////////////////////////////////////// +// +// CALIBRATE JOYSTICK +// +//////////////////////////////////////////////////////////////////// +int CalibrateJoystick(void) +{ + #define CALX 85 + #define CALY 40 + #define CALW 158 + #define CALH 140 + + unsigned xmin,ymin,xmax,ymax,jb; + + + + #ifdef JAPAN + VWB_DrawPic(CALX,CALY,C_JOY0PIC); + #else + DrawWindow(CALX-5,CALY-5,CALW,CALH,TEXTCOLOR); + DrawOutline(CALX-5,CALY-5,CALW,CALH,0,HIGHLIGHT); + SETFONTCOLOR(0,TEXTCOLOR); + + WindowX = PrintX = CALX; + WindowW = CALW; + WindowH = CALH; + WindowY = PrintY = CALY; + US_Print(" "STR_CALIB"\n "STR_JOYST"\n"); + VWB_DrawPic(CALX+40,CALY+30,C_JOY1PIC); + PrintY = CALY+80; + US_Print(STR_MOVEJOY); + SETFONTCOLOR(BKGDCOLOR,TEXTCOLOR); + US_Print(" "STR_ESCEXIT); + #endif + VW_UpdateScreen(); + + do + { + jb=IN_JoyButtons(); + if (Keyboard[sc_Escape]) + return 0; + #ifndef SPEAR + if (Keyboard[sc_Tab] && Keyboard[sc_P] && MS_CheckParm("goobers")) + PicturePause(); + #endif + + } while(!(jb&1)); + + SD_PlaySound(SHOOTSND); + IN_GetJoyAbs(joystickport,&xmin,&ymin); + + + #ifdef JAPAN + VWB_DrawPic(CALX,CALY,C_JOY1PIC); + #else + DrawWindow(CALX-5,CALY-5,CALW,CALH,TEXTCOLOR); + DrawOutline(CALX-5,CALY-5,CALW,CALH,0,HIGHLIGHT); + SETFONTCOLOR(0,TEXTCOLOR); + + PrintX = CALX; + PrintY = CALY; + US_Print(" "STR_CALIB"\n "STR_JOYST"\n"); + VWB_DrawPic(CALX+40,CALY+30,C_JOY2PIC); + PrintY = CALY+80; + US_Print(STR_MOVEJOY2); + SETFONTCOLOR(BKGDCOLOR,TEXTCOLOR); + US_Print(" "STR_ESCEXIT); + #endif + VW_UpdateScreen(); + + do + { + jb=IN_JoyButtons(); + if (Keyboard[sc_Escape]) + return 0; + #ifndef SPEAR + if (Keyboard[sc_Tab] && Keyboard[sc_P] && MS_CheckParm("goobers")) + PicturePause(); + #endif + } while(!(jb&2)); + + IN_GetJoyAbs(joystickport,&xmax,&ymax); + SD_PlaySound(SHOOTSND); + + while (IN_JoyButtons()); + + // + // ASSIGN ACTUAL VALUES HERE + // + if ((xmin != xmax) && (ymin != ymax)) + IN_SetupJoy(joystickport,xmin,xmax,ymin,ymax); + else + return 0; + + return 1; +} + + +//////////////////////////////////////////////////////////////////// +// +// DEFINE CONTROLS +// +//////////////////////////////////////////////////////////////////// +void CP_Control(void) +{ + #define CTL_SPC 70 + enum {MOUSEENABLE,JOYENABLE,USEPORT2,PADENABLE,MOUSESENS,CUSTOMIZE}; + int i,which; + + +#ifdef SPEAR + UnCacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); + CacheLump (CONTROL_LUMP_START,CONTROL_LUMP_END); +#endif + + DrawCtlScreen(); + MenuFadeIn(); + WaitKeyUp(); + + do + { + which=HandleMenu(&CtlItems,&CtlMenu[0],NULL); + switch(which) + { + case MOUSEENABLE: + mouseenabled^=1; + _CX=_DX=CENTER; + Mouse(4); + DrawCtlScreen(); + CusItems.curpos=-1; + ShootSnd(); + break; + + case JOYENABLE: + joystickenabled^=1; + if (joystickenabled) + if (!CalibrateJoystick()) + joystickenabled = 0; + DrawCtlScreen(); + CusItems.curpos=-1; + ShootSnd(); + break; + + case USEPORT2: + joystickport^=1; + DrawCtlScreen(); + ShootSnd(); + break; + + case PADENABLE: + joypadenabled^=1; + DrawCtlScreen(); + ShootSnd(); + break; + + case MOUSESENS: + case CUSTOMIZE: + DrawCtlScreen(); + MenuFadeIn(); + WaitKeyUp(); + break; + } + } while(which>=0); + + MenuFadeOut(); + +#ifdef SPEAR + UnCacheLump (CONTROL_LUMP_START,CONTROL_LUMP_END); + CacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); +#endif +} + + +//////////////////////////////// +// +// DRAW MOUSE SENSITIVITY SCREEN +// +void DrawMouseSens(void) +{ +#ifdef JAPAN + CA_CacheScreen(S_MOUSESENSPIC); +#else + ClearMScreen(); + VWB_DrawPic(112,184,C_MOUSELBACKPIC); + #ifdef SPANISH + DrawWindow(10,80,300,43,BKGDCOLOR); + #else + DrawWindow(10,80,300,30,BKGDCOLOR); + #endif + + WindowX=0; + WindowW=320; + PrintY=82; + SETFONTCOLOR(READCOLOR,BKGDCOLOR); + US_CPrint(STR_MOUSEADJ); + + SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR); + #ifdef SPANISH + PrintX=14; + PrintY=95+13; + US_Print(STR_SLOW); + PrintX=252; + US_Print(STR_FAST); + #else + PrintX=14; + PrintY=95; + US_Print(STR_SLOW); + PrintX=269; + US_Print(STR_FAST); + #endif +#endif + + VWB_Bar(60,97,200,10,TEXTCOLOR); + DrawOutline(60,97,200,10,0,HIGHLIGHT); + DrawOutline(60+20*mouseadjustment,97,20,10,0,READCOLOR); + VWB_Bar(61+20*mouseadjustment,98,19,9,READHCOLOR); + + VW_UpdateScreen(); + MenuFadeIn(); +} + + +/////////////////////////// +// +// ADJUST MOUSE SENSITIVITY +// +void MouseSensitivity(void) +{ + ControlInfo ci; + int exit=0,oldMA; + + + oldMA=mouseadjustment; + DrawMouseSens(); + do + { + ReadAnyControl(&ci); + switch(ci.dir) + { + case dir_North: + case dir_West: + if (mouseadjustment) + { + mouseadjustment--; + VWB_Bar(60,97,200,10,TEXTCOLOR); + DrawOutline(60,97,200,10,0,HIGHLIGHT); + DrawOutline(60+20*mouseadjustment,97,20,10,0,READCOLOR); + VWB_Bar(61+20*mouseadjustment,98,19,9,READHCOLOR); + VW_UpdateScreen(); + SD_PlaySound(MOVEGUN1SND); + while(Keyboard[sc_LeftArrow]); + WaitKeyUp(); + } + break; + + case dir_South: + case dir_East: + if (mouseadjustment<9) + { + mouseadjustment++; + VWB_Bar(60,97,200,10,TEXTCOLOR); + DrawOutline(60,97,200,10,0,HIGHLIGHT); + DrawOutline(60+20*mouseadjustment,97,20,10,0,READCOLOR); + VWB_Bar(61+20*mouseadjustment,98,19,9,READHCOLOR); + VW_UpdateScreen(); + SD_PlaySound(MOVEGUN1SND); + while(Keyboard[sc_RightArrow]); + WaitKeyUp(); + } + break; + } + + #ifndef SPEAR + if (Keyboard[sc_Tab] && Keyboard[sc_P] && MS_CheckParm("goobers")) + #else + if (Keyboard[sc_Tab] && Keyboard[sc_P] && MS_CheckParm("debugmode")) + #endif + PicturePause(); + + if (ci.button0 || Keyboard[sc_Space] || Keyboard[sc_Enter]) + exit=1; + else + if (ci.button1 || Keyboard[sc_Escape]) + exit=2; + + } while(!exit); + + if (exit==2) + { + mouseadjustment=oldMA; + SD_PlaySound(ESCPRESSEDSND); + } + else + SD_PlaySound(SHOOTSND); + + WaitKeyUp(); + MenuFadeOut(); +} + + +/////////////////////////// +// +// DRAW CONTROL MENU SCREEN +// +void DrawCtlScreen(void) +{ + int i,x,y; + + +#ifdef JAPAN + CA_CacheScreen(S_CONTROLPIC); +#else + ClearMScreen(); + DrawStripes(10); + VWB_DrawPic(80,0,C_CONTROLPIC); + VWB_DrawPic(112,184,C_MOUSELBACKPIC); + DrawWindow(CTL_X-8,CTL_Y-5,CTL_W,CTL_H,BKGDCOLOR); +#endif + WindowX=0; + WindowW=320; + SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR); + + if (JoysPresent[0]) + CtlMenu[1].active= + CtlMenu[2].active= + CtlMenu[3].active=1; + + CtlMenu[2].active=CtlMenu[3].active=joystickenabled; + + if (MousePresent) + { + CtlMenu[4].active= + CtlMenu[0].active=1; + } + + CtlMenu[4].active=mouseenabled; + + + DrawMenu(&CtlItems,&CtlMenu[0]); + + + x=CTL_X+CtlItems.indent-24; + y=CTL_Y+3; + if (mouseenabled) + VWB_DrawPic(x,y,C_SELECTEDPIC); + else + VWB_DrawPic(x,y,C_NOTSELECTEDPIC); + + y=CTL_Y+16; + if (joystickenabled) + VWB_DrawPic(x,y,C_SELECTEDPIC); + else + VWB_DrawPic(x,y,C_NOTSELECTEDPIC); + + y=CTL_Y+29; + if (joystickport) + VWB_DrawPic(x,y,C_SELECTEDPIC); + else + VWB_DrawPic(x,y,C_NOTSELECTEDPIC); + + y=CTL_Y+42; + if (joypadenabled) + VWB_DrawPic(x,y,C_SELECTEDPIC); + else + VWB_DrawPic(x,y,C_NOTSELECTEDPIC); + + // + // PICK FIRST AVAILABLE SPOT + // + if (CtlItems.curpos<0 || !CtlMenu[CtlItems.curpos].active) + for (i=0;i<6;i++) + if (CtlMenu[i].active) + { + CtlItems.curpos=i; + break; + } + + DrawMenuGun(&CtlItems); + VW_UpdateScreen(); +} + + +//////////////////////////////////////////////////////////////////// +// +// CUSTOMIZE CONTROLS +// +//////////////////////////////////////////////////////////////////// +enum {FIRE,STRAFE,RUN,OPEN}; +char mbarray[4][3]={"b0","b1","b2","b3"}, + order[4]={RUN,OPEN,FIRE,STRAFE}; + + +void CustomControls(void) +{ + int which; + + + DrawCustomScreen(); + do + { + which=HandleMenu(&CusItems,&CusMenu[0],FixupCustom); + switch(which) + { + case 0: + DefineMouseBtns(); + DrawCustMouse(1); + break; + case 3: + DefineJoyBtns(); + DrawCustJoy(0); + break; + case 6: + DefineKeyBtns(); + DrawCustKeybd(0); + break; + case 8: + DefineKeyMove(); + DrawCustKeys(0); + } + } while(which>=0); + + + + MenuFadeOut(); +} + + +//////////////////////// +// +// DEFINE THE MOUSE BUTTONS +// +void DefineMouseBtns(void) +{ + CustomCtrls mouseallowed={0,1,1,1}; + EnterCtrlData(2,&mouseallowed,DrawCustMouse,PrintCustMouse,MOUSE); +} + + +//////////////////////// +// +// DEFINE THE JOYSTICK BUTTONS +// +void DefineJoyBtns(void) +{ + CustomCtrls joyallowed={1,1,1,1}; + EnterCtrlData(5,&joyallowed,DrawCustJoy,PrintCustJoy,JOYSTICK); +} + + +//////////////////////// +// +// DEFINE THE KEYBOARD BUTTONS +// +void DefineKeyBtns(void) +{ + CustomCtrls keyallowed={1,1,1,1}; + EnterCtrlData(8,&keyallowed,DrawCustKeybd,PrintCustKeybd,KEYBOARDBTNS); +} + + +//////////////////////// +// +// DEFINE THE KEYBOARD BUTTONS +// +void DefineKeyMove(void) +{ + CustomCtrls keyallowed={1,1,1,1}; + EnterCtrlData(10,&keyallowed,DrawCustKeys,PrintCustKeys,KEYBOARDMOVE); +} + + +//////////////////////// +// +// ENTER CONTROL DATA FOR ANY TYPE OF CONTROL +// +enum {FWRD,RIGHT,BKWD,LEFT}; +int moveorder[4]={LEFT,RIGHT,FWRD,BKWD}; + +void EnterCtrlData(int index,CustomCtrls *cust,void (*DrawRtn)(int),void (*PrintRtn)(int),int type) +{ + int j,exit,tick,redraw,which,x,picked; + ControlInfo ci; + + + ShootSnd(); + PrintY=CST_Y+13*index; + IN_ClearKeysDown(); + exit=0; + redraw=1; + // + // FIND FIRST SPOT IN ALLOWED ARRAY + // + for (j=0;j<4;j++) + if (cust->allowed[j]) + { + which=j; + break; + } + + do + { + if (redraw) + { + x=CST_START+CST_SPC*which; + DrawWindow(5,PrintY-1,310,13,BKGDCOLOR); + + DrawRtn(1); + DrawWindow(x-2,PrintY,CST_SPC,11,TEXTCOLOR); + DrawOutline(x-2,PrintY,CST_SPC,11,0,HIGHLIGHT); + SETFONTCOLOR(0,TEXTCOLOR); + PrintRtn(which); + PrintX=x; + SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR); + VW_UpdateScreen(); + WaitKeyUp(); + redraw=0; + } + + ReadAnyControl(&ci); + + if (type==MOUSE || type==JOYSTICK) + if (IN_KeyDown(sc_Enter)||IN_KeyDown(sc_Control)||IN_KeyDown(sc_Alt)) + { + IN_ClearKeysDown(); + ci.button0=ci.button1=false; + } + + // + // CHANGE BUTTON VALUE? + // + if ((ci.button0|ci.button1|ci.button2|ci.button3)|| + ((type==KEYBOARDBTNS||type==KEYBOARDMOVE) && LastScan==sc_Enter)) + { + tick=TimeCount=picked=0; + SETFONTCOLOR(0,TEXTCOLOR); + + do + { + int button,result=0; + + + if (type==KEYBOARDBTNS||type==KEYBOARDMOVE) + IN_ClearKeysDown(); + + // + // FLASH CURSOR + // + if (TimeCount>10) + { + switch(tick) + { + case 0: + VWB_Bar(x,PrintY+1,CST_SPC-2,10,TEXTCOLOR); + break; + case 1: + PrintX=x; + US_Print("?"); + SD_PlaySound(HITWALLSND); + } + tick^=1; + TimeCount=0; + VW_UpdateScreen(); + } + + // + // WHICH TYPE OF INPUT DO WE PROCESS? + // + switch(type) + { + case MOUSE: + Mouse(3); + button=_BX; + switch(button) + { + case 1: result=1; break; + case 2: result=2; break; + case 4: result=3; break; + } + + if (result) + { + int z; + + + for (z=0;z<4;z++) + if (order[which]==buttonmouse[z]) + { + buttonmouse[z]=bt_nobutton; + break; + } + + buttonmouse[result-1]=order[which]; + picked=1; + SD_PlaySound(SHOOTDOORSND); + } + break; + + case JOYSTICK: + if (ci.button0) result=1; + else + if (ci.button1) result=2; + else + if (ci.button2) result=3; + else + if (ci.button3) result=4; + + if (result) + { + int z; + + + for (z=0;z<4;z++) + if (order[which]==buttonjoy[z]) + { + buttonjoy[z]=bt_nobutton; + break; + } + + buttonjoy[result-1]=order[which]; + picked=1; + SD_PlaySound(SHOOTDOORSND); + } + break; + + case KEYBOARDBTNS: + if (LastScan) + { + buttonscan[order[which]]=LastScan; + picked=1; + ShootSnd(); + IN_ClearKeysDown(); + } + break; + + case KEYBOARDMOVE: + if (LastScan) + { + dirscan[moveorder[which]]=LastScan; + picked=1; + ShootSnd(); + IN_ClearKeysDown(); + } + break; + } + + // + // EXIT INPUT? + // + if (IN_KeyDown(sc_Escape)) + { + picked=1; + continue; + } + + } while(!picked); + + SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR); + redraw=1; + WaitKeyUp(); + continue; + } + + if (ci.button1 || IN_KeyDown(sc_Escape)) + exit=1; + + // + // MOVE TO ANOTHER SPOT? + // + switch(ci.dir) + { + case dir_West: + do + { + which--; + if (which<0) + which=3; + } while(!cust->allowed[which]); + redraw=1; + SD_PlaySound(MOVEGUN1SND); + while(ReadAnyControl(&ci),ci.dir!=dir_None); + IN_ClearKeysDown(); + break; + + case dir_East: + do + { + which++; + if (which>3) + which=0; + } while(!cust->allowed[which]); + redraw=1; + SD_PlaySound(MOVEGUN1SND); + while(ReadAnyControl(&ci),ci.dir!=dir_None); + IN_ClearKeysDown(); + break; + case dir_North: + case dir_South: + exit=1; + } + } while(!exit); + + SD_PlaySound(ESCPRESSEDSND); + WaitKeyUp(); + DrawWindow(5,PrintY-1,310,13,BKGDCOLOR); +} + + +//////////////////////// +// +// FIXUP GUN CURSOR OVERDRAW SHIT +// +void FixupCustom(int w) +{ + static int lastwhich=-1; + int y=CST_Y+26+w*13; + + + VWB_Hlin(7,32,y-1,DEACTIVE); + VWB_Hlin(7,32,y+12,BORD2COLOR); +#ifndef SPEAR + VWB_Hlin(7,32,y-2,BORDCOLOR); + VWB_Hlin(7,32,y+13,BORDCOLOR); +#else + VWB_Hlin(7,32,y-2,BORD2COLOR); + VWB_Hlin(7,32,y+13,BORD2COLOR); +#endif + + switch(w) + { + case 0: DrawCustMouse(1); break; + case 3: DrawCustJoy(1); break; + case 6: DrawCustKeybd(1); break; + case 8: DrawCustKeys(1); + } + + + if (lastwhich>=0) + { + y=CST_Y+26+lastwhich*13; + VWB_Hlin(7,32,y-1,DEACTIVE); + VWB_Hlin(7,32,y+12,BORD2COLOR); +#ifndef SPEAR + VWB_Hlin(7,32,y-2,BORDCOLOR); + VWB_Hlin(7,32,y+13,BORDCOLOR); +#else + VWB_Hlin(7,32,y-2,BORD2COLOR); + VWB_Hlin(7,32,y+13,BORD2COLOR); +#endif + + if (lastwhich!=w) + switch(lastwhich) + { + case 0: DrawCustMouse(0); break; + case 3: DrawCustJoy(0); break; + case 6: DrawCustKeybd(0); break; + case 8: DrawCustKeys(0); + } + } + + lastwhich=w; +} + + +//////////////////////// +// +// DRAW CUSTOMIZE SCREEN +// +void DrawCustomScreen(void) +{ + int i; + + +#ifdef JAPAN + CA_CacheScreen(S_CUSTOMPIC); + fontnumber=1; + + PrintX=CST_START; + PrintY = CST_Y+26; + DrawCustMouse(0); + + PrintX=CST_START; + US_Print("\n\n\n"); + DrawCustJoy(0); + + PrintX=CST_START; + US_Print("\n\n\n"); + DrawCustKeybd(0); + + PrintX=CST_START; + US_Print("\n\n\n"); + DrawCustKeys(0); +#else + ClearMScreen(); + WindowX=0; + WindowW=320; + VWB_DrawPic(112,184,C_MOUSELBACKPIC); + DrawStripes(10); + VWB_DrawPic(80,0,C_CUSTOMIZEPIC); + + // + // MOUSE + // + SETFONTCOLOR(READCOLOR,BKGDCOLOR); + WindowX=0; + WindowW=320; + +#ifndef SPEAR + PrintY=CST_Y; + US_CPrint("Mouse\n"); +#else + PrintY = CST_Y+13; + VWB_DrawPic (128,48,C_MOUSEPIC); +#endif + + SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR); + #ifdef SPANISH + PrintX=CST_START-16; + US_Print(STR_CRUN); + PrintX=CST_START-16+CST_SPC*1; + US_Print(STR_COPEN); + PrintX=CST_START-16+CST_SPC*2; + US_Print(STR_CFIRE); + PrintX=CST_START-16+CST_SPC*3; + US_Print(STR_CSTRAFE"\n"); + #else + PrintX=CST_START; + US_Print(STR_CRUN); + PrintX=CST_START+CST_SPC*1; + US_Print(STR_COPEN); + PrintX=CST_START+CST_SPC*2; + US_Print(STR_CFIRE); + PrintX=CST_START+CST_SPC*3; + US_Print(STR_CSTRAFE"\n"); + #endif + + DrawWindow(5,PrintY-1,310,13,BKGDCOLOR); + DrawCustMouse(0); + US_Print("\n"); + + + // + // JOYSTICK/PAD + // +#ifndef SPEAR + SETFONTCOLOR(READCOLOR,BKGDCOLOR); + US_CPrint("Joystick/Gravis GamePad\n"); +#else + PrintY += 13; + VWB_DrawPic (40,88,C_JOYSTICKPIC); +#endif + +#ifdef SPEAR + VWB_DrawPic (112,120,C_KEYBOARDPIC); +#endif + + SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR); + #ifdef SPANISH + PrintX=CST_START-16; + US_Print(STR_CRUN); + PrintX=CST_START-16+CST_SPC*1; + US_Print(STR_COPEN); + PrintX=CST_START-16+CST_SPC*2; + US_Print(STR_CFIRE); + PrintX=CST_START-16+CST_SPC*3; + US_Print(STR_CSTRAFE"\n"); + #else + PrintX=CST_START; + US_Print(STR_CRUN); + PrintX=CST_START+CST_SPC*1; + US_Print(STR_COPEN); + PrintX=CST_START+CST_SPC*2; + US_Print(STR_CFIRE); + PrintX=CST_START+CST_SPC*3; + US_Print(STR_CSTRAFE"\n"); + #endif + DrawWindow(5,PrintY-1,310,13,BKGDCOLOR); + DrawCustJoy(0); + US_Print("\n"); + + + // + // KEYBOARD + // +#ifndef SPEAR + SETFONTCOLOR(READCOLOR,BKGDCOLOR); + US_CPrint("Keyboard\n"); +#else + PrintY += 13; +#endif + SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR); + #ifdef SPANISH + PrintX=CST_START-16; + US_Print(STR_CRUN); + PrintX=CST_START-16+CST_SPC*1; + US_Print(STR_COPEN); + PrintX=CST_START-16+CST_SPC*2; + US_Print(STR_CFIRE); + PrintX=CST_START-16+CST_SPC*3; + US_Print(STR_CSTRAFE"\n"); + #else + PrintX=CST_START; + US_Print(STR_CRUN); + PrintX=CST_START+CST_SPC*1; + US_Print(STR_COPEN); + PrintX=CST_START+CST_SPC*2; + US_Print(STR_CFIRE); + PrintX=CST_START+CST_SPC*3; + US_Print(STR_CSTRAFE"\n"); + #endif + DrawWindow(5,PrintY-1,310,13,BKGDCOLOR); + DrawCustKeybd(0); + US_Print("\n"); + + + // + // KEYBOARD MOVE KEYS + // + SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR); + #ifdef SPANISH + PrintX=4; + US_Print(STR_LEFT); + US_Print("/"); + US_Print(STR_RIGHT); + US_Print("/"); + US_Print(STR_FRWD); + US_Print("/"); + US_Print(STR_BKWD"\n"); + #else + PrintX=CST_START; + US_Print(STR_LEFT); + PrintX=CST_START+CST_SPC*1; + US_Print(STR_RIGHT); + PrintX=CST_START+CST_SPC*2; + US_Print(STR_FRWD); + PrintX=CST_START+CST_SPC*3; + US_Print(STR_BKWD"\n"); + #endif + DrawWindow(5,PrintY-1,310,13,BKGDCOLOR); + DrawCustKeys(0); +#endif + // + // PICK STARTING POINT IN MENU + // + if (CusItems.curpos<0) + for (i=0;i19) + newview=19; + ShowViewSize(newview); + VW_UpdateScreen(); + SD_PlaySound(HITWALLSND); + TicDelay(10); + break; + } + + #ifndef SPEAR + if (Keyboard[sc_Tab] && Keyboard[sc_P] && MS_CheckParm("goobers")) + #else + if (Keyboard[sc_Tab] && Keyboard[sc_P] && MS_CheckParm("debugmode")) + #endif + PicturePause(); + + if (ci.button0 || Keyboard[sc_Enter]) + exit=1; + else + if (ci.button1 || Keyboard[sc_Escape]) + { + viewwidth=oldview*16; + SD_PlaySound(ESCPRESSEDSND); + MenuFadeOut(); + return; + } + + } while(!exit); + + + if (oldview!=newview) + { + SD_PlaySound (SHOOTSND); + Message(STR_THINK"..."); + NewViewSize(newview); + } + + ShootSnd(); + MenuFadeOut(); +} + + +///////////////////////////// +// +// DRAW THE CHANGEVIEW SCREEN +// +void DrawChangeView(int view) +{ +#ifdef JAPAN + CA_CacheScreen(S_CHANGEPIC); + + ShowViewSize(view); +#else + VWB_Bar(0,160,320,40,VIEWCOLOR); + ShowViewSize(view); + + PrintY=161; + WindowX=0; + WindowY=320; + SETFONTCOLOR(HIGHLIGHT,BKGDCOLOR); + + US_CPrint(STR_SIZE1"\n"); + US_CPrint(STR_SIZE2"\n"); + US_CPrint(STR_SIZE3); +#endif + VW_UpdateScreen(); + + MenuFadeIn(); +} + + +//////////////////////////////////////////////////////////////////// +// +// QUIT THIS INFERNAL GAME! +// +//////////////////////////////////////////////////////////////////// +void CP_Quit(void) +{ + int i; + + + #ifdef JAPAN + if (GetYorN(7,11,C_QUITMSGPIC)) + #else + + #ifdef SPANISH + if (Confirm(ENDGAMESTR)) + #else + if (Confirm(endStrings[US_RndT()&0x7+(US_RndT()&1)])) + #endif + + #endif + { + VW_UpdateScreen(); + SD_MusicOff(); + SD_StopSound(); + MenuFadeOut(); + // + // SHUT-UP THE ADLIB + // + for (i=1;i<=0xf5;i++) + alOut(i,0); + Quit(NULL); + } + + DrawMainMenu(); +} + + +//////////////////////////////////////////////////////////////////// +// +// HANDLE INTRO SCREEN (SYSTEM CONFIG) +// +//////////////////////////////////////////////////////////////////// +void IntroScreen(void) +{ +#ifdef SPEAR + +#define MAINCOLOR 0x4f +#define EMSCOLOR 0x4f +#define XMSCOLOR 0x4f + +#else + +#define MAINCOLOR 0x6c +#define EMSCOLOR 0x6c +#define XMSCOLOR 0x6c + +#endif +#define FILLCOLOR 14 + + long memory,emshere,xmshere; + int i,num,ems[10]={100,200,300,400,500,600,700,800,900,1000}, + xms[10]={100,200,300,400,500,600,700,800,900,1000}, + main[10]={32,64,96,128,160,192,224,256,288,320}; + + + // + // DRAW MAIN MEMORY + // + memory=(1023l+mminfo.nearheap+mminfo.farheap)/1024l; + for (i=0;i<10;i++) + if (memory>=main[i]) + VWB_Bar(49,163-8*i,6,5,MAINCOLOR-i); + + + // + // DRAW EMS MEMORY + // + if (EMSPresent) + { + emshere=4l*EMSPagesAvail; + for (i=0;i<10;i++) + if (emshere>=ems[i]) + VWB_Bar(89,163-8*i,6,5,EMSCOLOR-i); + } + + // + // DRAW XMS MEMORY + // + if (XMSPresent) + { + xmshere=4l*XMSPagesAvail; + for (i=0;i<10;i++) + if (xmshere>=xms[i]) + VWB_Bar(129,163-8*i,6,5,XMSCOLOR-i); + } + + // + // FILL BOXES + // + if (MousePresent) + VWB_Bar(164,82,12,2,FILLCOLOR); + + if (JoysPresent[0] || JoysPresent[1]) + VWB_Bar(164,105,12,2,FILLCOLOR); + + if (AdLibPresent && !SoundBlasterPresent) + VWB_Bar(164,128,12,2,FILLCOLOR); + + if (SoundBlasterPresent) + VWB_Bar(164,151,12,2,FILLCOLOR); + + if (SoundSourcePresent) + VWB_Bar(164,174,12,2,FILLCOLOR); +} + + +//////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////// +// +// SUPPORT ROUTINES +// +//////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////// +// +// Clear Menu screens to dark red +// +//////////////////////////////////////////////////////////////////// +void ClearMScreen(void) +{ +#ifndef SPEAR + VWB_Bar(0,0,320,200,BORDCOLOR); +#else + VWB_DrawPic(0,0,C_BACKDROPPIC); +#endif +} + + +//////////////////////////////////////////////////////////////////// +// +// Un/Cache a LUMP of graphics +// +//////////////////////////////////////////////////////////////////// +void CacheLump(int lumpstart,int lumpend) +{ + int i; + + for (i=lumpstart;i<=lumpend;i++) + CA_CacheGrChunk(i); +} + + +void UnCacheLump(int lumpstart,int lumpend) +{ + int i; + + for (i=lumpstart;i<=lumpend;i++) + if (grsegs[i]) + UNCACHEGRCHUNK(i); +} + + +//////////////////////////////////////////////////////////////////// +// +// Draw a window for a menu +// +//////////////////////////////////////////////////////////////////// +void DrawWindow(int x,int y,int w,int h,int wcolor) +{ + VWB_Bar(x,y,w,h,wcolor); + DrawOutline(x,y,w,h,BORD2COLOR,DEACTIVE); +} + + +void DrawOutline(int x,int y,int w,int h,int color1,int color2) +{ + VWB_Hlin(x,x+w,y,color2); + VWB_Vlin(y,y+h,x,color2); + VWB_Hlin(x,x+w,y+h,color1); + VWB_Vlin(y,y+h,x+w,color1); +} + + +//////////////////////////////////////////////////////////////////// +// +// Setup Control Panel stuff - graphics, etc. +// +//////////////////////////////////////////////////////////////////// +void SetupControlPanel(void) +{ + struct ffblk f; + char name[13]; + int which,i; + + + // + // CACHE GRAPHICS & SOUNDS + // + CA_CacheGrChunk(STARTFONT+1); +#ifndef SPEAR + CacheLump(CONTROLS_LUMP_START,CONTROLS_LUMP_END); +#else + CacheLump(BACKDROP_LUMP_START,BACKDROP_LUMP_END); +#endif + + SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR); + fontnumber=1; + WindowH=200; + + if (!ingame) + CA_LoadAllSounds(); + else + MainMenu[savegame].active=1; + + // + // SEE WHICH SAVE GAME FILES ARE AVAILABLE & READ STRING IN + // + strcpy(name,SaveName); + if (!findfirst(name,&f,0)) + do + { + which=f.ff_name[7]-'0'; + if (which<10) + { + int handle; + char temp[32]; + + SaveGamesAvail[which]=1; + handle=open(f.ff_name,O_BINARY); + read(handle,temp,32); + close(handle); + strcpy(&SaveGameNames[which][0],temp); + } + } while(!findnext(&f)); + + // + // CENTER MOUSE + // + _CX=_DX=CENTER; + Mouse(4); +} + + +//////////////////////////////////////////////////////////////////// +// +// Clean up all the Control Panel stuff +// +//////////////////////////////////////////////////////////////////// +void CleanupControlPanel(void) +{ +#ifndef SPEAR + UnCacheLump(CONTROLS_LUMP_START,CONTROLS_LUMP_END); +#else + UnCacheLump (BACKDROP_LUMP_START,BACKDROP_LUMP_END); +#endif + + fontnumber = 0; +} + + +//////////////////////////////////////////////////////////////////// +// +// Handle moving gun around a menu +// +//////////////////////////////////////////////////////////////////// +int HandleMenu(CP_iteminfo *item_i,CP_itemtype far *items,void (*routine)(int w)) +{ + char key; + static int redrawitem=1,lastitem=-1; + int i,x,y,basey,exit,which,shape,timer; + ControlInfo ci; + + + which=item_i->curpos; + x=item_i->x&-8; + basey=item_i->y-2; + y=basey+which*13; + + VWB_DrawPic(x,y,C_CURSOR1PIC); + SetTextColor(items+which,1); + if (redrawitem) + { + PrintX=item_i->x+item_i->indent; + PrintY=item_i->y+which*13; + US_Print((items+which)->string); + } + // + // CALL CUSTOM ROUTINE IF IT IS NEEDED + // + if (routine) + routine(which); + VW_UpdateScreen(); + + shape=C_CURSOR1PIC; + timer=8; + exit=0; + TimeCount=0; + IN_ClearKeysDown(); + + + do + { + // + // CHANGE GUN SHAPE + // + if (TimeCount>timer) + { + TimeCount=0; + if (shape==C_CURSOR1PIC) + { + shape=C_CURSOR2PIC; + timer=8; + } + else + { + shape=C_CURSOR1PIC; + timer=70; + } + VWB_DrawPic(x,y,shape); + if (routine) + routine(which); + VW_UpdateScreen(); + } + + CheckPause(); + + // + // SEE IF ANY KEYS ARE PRESSED FOR INITIAL CHAR FINDING + // + key=LastASCII; + if (key) + { + int ok=0; + + // + // CHECK FOR SCREEN CAPTURE + // + #ifndef SPEAR + if (Keyboard[sc_Tab] && Keyboard[sc_P] && MS_CheckParm("goobers")) + #else + if (Keyboard[sc_Tab] && Keyboard[sc_P] && MS_CheckParm("debugmode")) + #endif + PicturePause(); + + + if (key>='a') + key-='a'-'A'; + + for (i=which+1;iamount;i++) + if ((items+i)->active && (items+i)->string[0]==key) + { + EraseGun(item_i,items,x,y,which); + which=i; + DrawGun(item_i,items,x,&y,which,basey,routine); + ok=1; + IN_ClearKeysDown(); + break; + } + + // + // DIDN'T FIND A MATCH FIRST TIME THRU. CHECK AGAIN. + // + if (!ok) + { + for (i=0;iactive && (items+i)->string[0]==key) + { + EraseGun(item_i,items,x,y,which); + which=i; + DrawGun(item_i,items,x,&y,which,basey,routine); + IN_ClearKeysDown(); + break; + } + } + } + + // + // GET INPUT + // + ReadAnyControl(&ci); + switch(ci.dir) + { + //////////////////////////////////////////////// + // + // MOVE UP + // + case dir_North: + + EraseGun(item_i,items,x,y,which); + + // + // ANIMATE HALF-STEP + // + if (which && (items+which-1)->active) + { + y-=6; + DrawHalfStep(x,y); + } + + // + // MOVE TO NEXT AVAILABLE SPOT + // + do + { + if (!which) + which=item_i->amount-1; + else + which--; + } while(!(items+which)->active); + + DrawGun(item_i,items,x,&y,which,basey,routine); + // + // WAIT FOR BUTTON-UP OR DELAY NEXT MOVE + // + TicDelay(20); + break; + + //////////////////////////////////////////////// + // + // MOVE DOWN + // + case dir_South: + + EraseGun(item_i,items,x,y,which); + // + // ANIMATE HALF-STEP + // + if (which!=item_i->amount-1 && (items+which+1)->active) + { + y+=6; + DrawHalfStep(x,y); + } + + do + { + if (which==item_i->amount-1) + which=0; + else + which++; + } while(!(items+which)->active); + + DrawGun(item_i,items,x,&y,which,basey,routine); + + // + // WAIT FOR BUTTON-UP OR DELAY NEXT MOVE + // + TicDelay(20); + break; + } + + if (ci.button0 || + Keyboard[sc_Space] || + Keyboard[sc_Enter]) + exit=1; + + if (ci.button1 || + Keyboard[sc_Escape]) + exit=2; + + } while(!exit); + + + IN_ClearKeysDown(); + + // + // ERASE EVERYTHING + // + if (lastitem!=which) + { + VWB_Bar(x-1,y,25,16,BKGDCOLOR); + PrintX=item_i->x+item_i->indent; + PrintY=item_i->y+which*13; + US_Print((items+which)->string); + redrawitem=1; + } + else + redrawitem=0; + + if (routine) + routine(which); + VW_UpdateScreen(); + + item_i->curpos=which; + + lastitem=which; + switch(exit) + { + case 1: + // + // CALL THE ROUTINE + // + if ((items+which)->routine!=NULL) + { + ShootSnd(); + MenuFadeOut(); + (items+which)->routine(0); + } + return which; + + case 2: + SD_PlaySound(ESCPRESSEDSND); + return -1; + } + + return 0; // JUST TO SHUT UP THE ERROR MESSAGES! +} + + +// +// ERASE GUN & DE-HIGHLIGHT STRING +// +void EraseGun(CP_iteminfo *item_i,CP_itemtype far *items,int x,int y,int which) +{ + VWB_Bar(x-1,y,25,16,BKGDCOLOR); + SetTextColor(items+which,0); + + PrintX=item_i->x+item_i->indent; + PrintY=item_i->y+which*13; + US_Print((items+which)->string); + VW_UpdateScreen(); +} + + +// +// DRAW HALF STEP OF GUN TO NEXT POSITION +// +void DrawHalfStep(int x,int y) +{ + VWB_DrawPic(x,y,C_CURSOR1PIC); + VW_UpdateScreen(); + SD_PlaySound(MOVEGUN1SND); + TimeCount=0; + while(TimeCount<8); +} + + +// +// DRAW GUN AT NEW POSITION +// +void DrawGun(CP_iteminfo *item_i,CP_itemtype far *items,int x,int *y,int which,int basey,void (*routine)(int w)) +{ + VWB_Bar(x-1,*y,25,16,BKGDCOLOR); + *y=basey+which*13; + VWB_DrawPic(x,*y,C_CURSOR1PIC); + SetTextColor(items+which,1); + + PrintX=item_i->x+item_i->indent; + PrintY=item_i->y+which*13; + US_Print((items+which)->string); + + // + // CALL CUSTOM ROUTINE IF IT IS NEEDED + // + if (routine) + routine(which); + VW_UpdateScreen(); + SD_PlaySound(MOVEGUN2SND); +} + +//////////////////////////////////////////////////////////////////// +// +// DELAY FOR AN AMOUNT OF TICS OR UNTIL CONTROLS ARE INACTIVE +// +//////////////////////////////////////////////////////////////////// +void TicDelay(int count) +{ + ControlInfo ci; + + + TimeCount=0; + do + { + ReadAnyControl(&ci); + } while(TimeCountcurpos; + + + WindowX=PrintX=item_i->x+item_i->indent; + WindowY=PrintY=item_i->y; + WindowW=320; + WindowH=200; + + for (i=0;iamount;i++) + { + SetTextColor(items+i,which==i); + + PrintY=item_i->y+i*13; + if ((items+i)->active) + US_Print((items+i)->string); + else + { + SETFONTCOLOR(DEACTIVE,BKGDCOLOR); + US_Print((items+i)->string); + SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR); + } + + US_Print("\n"); + } +} + + +//////////////////////////////////////////////////////////////////// +// +// SET TEXT COLOR (HIGHLIGHT OR NO) +// +//////////////////////////////////////////////////////////////////// +void SetTextColor(CP_itemtype far *items,int hlight) +{ + if (hlight) + {SETFONTCOLOR(color_hlite[items->active],BKGDCOLOR);} + else + {SETFONTCOLOR(color_norml[items->active],BKGDCOLOR);} +} + + +//////////////////////////////////////////////////////////////////// +// +// WAIT FOR CTRLKEY-UP OR BUTTON-UP +// +//////////////////////////////////////////////////////////////////// +void WaitKeyUp(void) +{ + ControlInfo ci; + while(ReadAnyControl(&ci), ci.button0| + ci.button1| + ci.button2| + ci.button3| + Keyboard[sc_Space]| + Keyboard[sc_Enter]| + Keyboard[sc_Escape]); +} + + +//////////////////////////////////////////////////////////////////// +// +// READ KEYBOARD, JOYSTICK AND MOUSE FOR INPUT +// +//////////////////////////////////////////////////////////////////// +void ReadAnyControl(ControlInfo *ci) +{ + int mouseactive=0; + + + IN_ReadControl(0,ci); + + if (mouseenabled) + { + int mousey,mousex; + + + // READ MOUSE MOTION COUNTERS + // RETURN DIRECTION + // HOME MOUSE + // CHECK MOUSE BUTTONS + + Mouse(3); + mousex=_CX; + mousey=_DX; + + if (mouseydir=dir_North; + _CX=_DX=CENTER; + Mouse(4); + mouseactive=1; + } + else + if (mousey>CENTER+SENSITIVE) + { + ci->dir=dir_South; + _CX=_DX=CENTER; + Mouse(4); + mouseactive=1; + } + + if (mousexdir=dir_West; + _CX=_DX=CENTER; + Mouse(4); + mouseactive=1; + } + else + if (mousex>CENTER+SENSITIVE) + { + ci->dir=dir_East; + _CX=_DX=CENTER; + Mouse(4); + mouseactive=1; + } + + if (IN_MouseButtons()) + { + ci->button0=IN_MouseButtons()&1; + ci->button1=IN_MouseButtons()&2; + ci->button2=IN_MouseButtons()&4; + ci->button3=false; + mouseactive=1; + } + } + + if (joystickenabled && !mouseactive) + { + int jx,jy,jb; + + + INL_GetJoyDelta(joystickport,&jx,&jy); + if (jy<-SENSITIVE) + ci->dir=dir_North; + else + if (jy>SENSITIVE) + ci->dir=dir_South; + + if (jx<-SENSITIVE) + ci->dir=dir_West; + else + if (jx>SENSITIVE) + ci->dir=dir_East; + + jb=IN_JoyButtons(); + if (jb) + { + ci->button0=jb&1; + ci->button1=jb&2; + if (joypadenabled) + { + ci->button2=jb&4; + ci->button3=jb&8; + } + else + ci->button2=ci->button3=false; + } + } +} + + +//////////////////////////////////////////////////////////////////// +// +// DRAW DIALOG AND CONFIRM YES OR NO TO QUESTION +// +//////////////////////////////////////////////////////////////////// +int Confirm(char far *string) +{ + int xit=0,i,x,y,tick=0,time,whichsnd[2]={ESCPRESSEDSND,SHOOTSND}; + + + Message(string); + IN_ClearKeysDown(); + + // + // BLINK CURSOR + // + x=PrintX; + y=PrintY; + TimeCount=0; + + do + { + if (TimeCount>=10) + { + switch(tick) + { + case 0: + VWB_Bar(x,y,8,13,TEXTCOLOR); + break; + case 1: + PrintX=x; + PrintY=y; + US_Print("_"); + } + VW_UpdateScreen(); + tick^=1; + TimeCount=0; + } + + #ifndef SPEAR + if (Keyboard[sc_Tab] && Keyboard[sc_P] && MS_CheckParm("goobers")) + PicturePause(); + #endif + + #ifdef SPANISH + } while(!Keyboard[sc_S] && !Keyboard[sc_N] && !Keyboard[sc_Escape]); + #else + } while(!Keyboard[sc_Y] && !Keyboard[sc_N] && !Keyboard[sc_Escape]); + #endif + + #ifdef SPANISH + if (Keyboard[sc_S]) + { + xit=1; + ShootSnd(); + } + + while(Keyboard[sc_S] || Keyboard[sc_N] || Keyboard[sc_Escape]); + + #else + + if (Keyboard[sc_Y]) + { + xit=1; + ShootSnd(); + } + + while(Keyboard[sc_Y] || Keyboard[sc_N] || Keyboard[sc_Escape]); + #endif + + IN_ClearKeysDown(); + SD_PlaySound(whichsnd[xit]); + return xit; +} + +#ifdef JAPAN +//////////////////////////////////////////////////////////////////// +// +// DRAW MESSAGE & GET Y OR N +// +//////////////////////////////////////////////////////////////////// +int GetYorN(int x,int y,int pic) +{ + int xit=0,whichsnd[2]={ESCPRESSEDSND,SHOOTSND}; + + + CA_CacheGrChunk(pic); + VWB_DrawPic(x * 8,y * 8,pic); + UNCACHEGRCHUNK(pic); + VW_UpdateScreen(); + IN_ClearKeysDown(); + + do + { + #ifndef SPEAR + if (Keyboard[sc_Tab] && Keyboard[sc_P] && MS_CheckParm("goobers")) + PicturePause(); + #endif + + #ifdef SPANISH + } while(!Keyboard[sc_S] && !Keyboard[sc_N] && !Keyboard[sc_Escape]); + #else + } while(!Keyboard[sc_Y] && !Keyboard[sc_N] && !Keyboard[sc_Escape]); + #endif + + #ifdef SPANISH + if (Keyboard[sc_S]) + { + xit=1; + ShootSnd(); + } + + while(Keyboard[sc_S] || Keyboard[sc_N] || Keyboard[sc_Escape]); + + #else + + if (Keyboard[sc_Y]) + { + xit=1; + ShootSnd(); + } + + while(Keyboard[sc_Y] || Keyboard[sc_N] || Keyboard[sc_Escape]); + #endif + + IN_ClearKeysDown(); + SD_PlaySound(whichsnd[xit]); + return xit; +} +#endif + + +//////////////////////////////////////////////////////////////////// +// +// PRINT A MESSAGE IN A WINDOW +// +//////////////////////////////////////////////////////////////////// +void Message(char far *string) +{ + int h=0,w=0,mw=0,i,x,y,time; + fontstruct _seg *font; + + + CA_CacheGrChunk (STARTFONT+1); + fontnumber=1; + font=grsegs[STARTFONT+fontnumber]; + h=font->height; + for (i=0;i<_fstrlen(string);i++) + if (string[i]=='\n') + { + if (w>mw) + mw=w; + w=0; + h+=font->height; + } + else + w+=font->width[string[i]]; + + if (w+10>mw) + mw=w+10; + + PrintY=(WindowH/2)-h/2; + PrintX=WindowX=160-mw/2; + + DrawWindow(WindowX-5,PrintY-5,mw+10,h+10,TEXTCOLOR); + DrawOutline(WindowX-5,PrintY-5,mw+10,h+10,0,HIGHLIGHT); + SETFONTCOLOR(0,TEXTCOLOR); + US_Print(string); + VW_UpdateScreen(); +} + + +//////////////////////////////////////////////////////////////////// +// +// THIS MAY BE FIXED A LITTLE LATER... +// +//////////////////////////////////////////////////////////////////// +static int lastmusic; + +void StartCPMusic(int song) +{ + musicnames chunk; + + if (audiosegs[STARTMUSIC + lastmusic]) // JDC + MM_FreePtr ((memptr *)&audiosegs[STARTMUSIC + lastmusic]); + lastmusic = song; + + SD_MusicOff(); + chunk = song; + + MM_BombOnError (false); + CA_CacheAudioChunk(STARTMUSIC + chunk); + MM_BombOnError (true); + if (mmerror) + mmerror = false; + else + { + MM_SetLock(&((memptr)audiosegs[STARTMUSIC + chunk]),true); + SD_StartMusic((MusicGroup far *)audiosegs[STARTMUSIC + chunk]); + } +} + +void FreeMusic (void) +{ + if (audiosegs[STARTMUSIC + lastmusic]) // JDC + MM_FreePtr ((memptr *)&audiosegs[STARTMUSIC + lastmusic]); +} + + +/////////////////////////////////////////////////////////////////////////// +// +// IN_GetScanName() - Returns a string containing the name of the +// specified scan code +// +/////////////////////////////////////////////////////////////////////////// +byte * +IN_GetScanName(ScanCode scan) +{ + byte **p; + ScanCode far *s; + + for (s = ExtScanCodes,p = ExtScanNames;*s;p++,s++) + if (*s == scan) + return(*p); + + return(ScanNames[scan]); +} + + +/////////////////////////////////////////////////////////////////////////// +// +// CHECK FOR PAUSE KEY (FOR MUSIC ONLY) +// +/////////////////////////////////////////////////////////////////////////// +void CheckPause(void) +{ + if (Paused) + { + switch(SoundStatus) + { + case 0: SD_MusicOn(); break; + case 1: SD_MusicOff(); break; + } + + SoundStatus^=1; + VW_WaitVBL(3); + IN_ClearKeysDown(); + Paused=false; + } +} + + +/////////////////////////////////////////////////////////////////////////// +// +// DRAW GUN CURSOR AT CORRECT POSITION IN MENU +// +/////////////////////////////////////////////////////////////////////////// +void DrawMenuGun(CP_iteminfo *iteminfo) +{ + int x,y; + + + x=iteminfo->x; + y=iteminfo->y+iteminfo->curpos*13-2; + VWB_DrawPic(x,y,C_CURSOR1PIC); +} + + +/////////////////////////////////////////////////////////////////////////// +// +// DRAW SCREEN TITLE STRIPES +// +/////////////////////////////////////////////////////////////////////////// +void DrawStripes(int y) +{ +#ifndef SPEAR + VWB_Bar(0,y,320,24,0); + VWB_Hlin(0,319,y+22,STRIPE); +#else + VWB_Bar(0,y,320,22,0); + VWB_Hlin(0,319,y+23,0); +#endif +} + +void ShootSnd(void) +{ + SD_PlaySound(SHOOTSND); +} + + +/////////////////////////////////////////////////////////////////////////// +// +// CHECK FOR EPISODES +// +/////////////////////////////////////////////////////////////////////////// +void CheckForEpisodes(void) +{ + struct ffblk f; + +// +// JAPANESE VERSION +// +#ifdef JAPAN +#ifdef JAPDEMO + if (!findfirst("*.WJ1",&f,FA_ARCH)) + { + strcpy(extension,"WJ1"); +#else + if (!findfirst("*.WJ6",&f,FA_ARCH)) + { + strcpy(extension,"WJ6"); +#endif + strcat(configname,extension); + strcat(SaveName,extension); + strcat(PageFileName,extension); + strcat(audioname,extension); + strcat(demoname,extension); + EpisodeSelect[1] = + EpisodeSelect[2] = + EpisodeSelect[3] = + EpisodeSelect[4] = + EpisodeSelect[5] = 1; + } + else + Quit("NO JAPANESE WOLFENSTEIN 3-D DATA FILES to be found!"); +#else + +// +// ENGLISH +// +#ifndef UPLOAD +#ifndef SPEAR + if (!findfirst("*.WL6",&f,FA_ARCH)) + { + strcpy(extension,"WL6"); + NewEmenu[2].active = + NewEmenu[4].active = + NewEmenu[6].active = + NewEmenu[8].active = + NewEmenu[10].active = + EpisodeSelect[1] = + EpisodeSelect[2] = + EpisodeSelect[3] = + EpisodeSelect[4] = + EpisodeSelect[5] = 1; + } + else + if (!findfirst("*.WL3",&f,FA_ARCH)) + { + strcpy(extension,"WL3"); + NewEmenu[2].active = + NewEmenu[4].active = + EpisodeSelect[1] = + EpisodeSelect[2] = 1; + } + else +#endif +#endif + + + +#ifdef SPEAR +#ifndef SPEARDEMO + if (!findfirst("*.SOD",&f,FA_ARCH)) + { + strcpy(extension,"SOD"); + } + else + Quit("NO SPEAR OF DESTINY DATA FILES TO BE FOUND!"); +#else + if (!findfirst("*.SDM",&f,FA_ARCH)) + { + strcpy(extension,"SDM"); + } + else + Quit("NO SPEAR OF DESTINY DEMO DATA FILES TO BE FOUND!"); +#endif + +#else + if (!findfirst("*.WL1",&f,FA_ARCH)) + { + strcpy(extension,"WL1"); + } + else + Quit("NO WOLFENSTEIN 3-D DATA FILES to be found!"); +#endif + + strcat(configname,extension); + strcat(SaveName,extension); + strcat(PageFileName,extension); + strcat(audioname,extension); + strcat(demoname,extension); +#ifndef SPEAR +#ifndef GOODTIMES + strcat(helpfilename,extension); +#endif + strcat(endfilename,extension); +#endif +#endif +} diff --git a/16/WOLFSRC/WL_SCALE.C b/16/WOLFSRC/WL_SCALE.C new file mode 100755 index 00000000..9c1e102f --- /dev/null +++ b/16/WOLFSRC/WL_SCALE.C @@ -0,0 +1,741 @@ +// WL_SCALE.C + +#include "WL_DEF.H" +#pragma hdrstop + +#define OP_RETF 0xcb + +/* +============================================================================= + + GLOBALS + +============================================================================= +*/ + +t_compscale _seg *scaledirectory[MAXSCALEHEIGHT+1]; +long fullscalefarcall[MAXSCALEHEIGHT+1]; + +int maxscale,maxscaleshl2; + +boolean insetupscaling; + +/* +============================================================================= + + LOCALS + +============================================================================= +*/ + +t_compscale _seg *work; +unsigned BuildCompScale (int height, memptr *finalspot); + +int stepbytwo; + +//=========================================================================== + +/* +============== += += BadScale += +============== +*/ + +void far BadScale (void) +{ + Quit ("BadScale called!"); +} + + +/* +========================== += += SetupScaling += +========================== +*/ + +void SetupScaling (int maxscaleheight) +{ + int i,x,y; + byte far *dest; + + insetupscaling = true; + + maxscaleheight/=2; // one scaler every two pixels + + maxscale = maxscaleheight-1; + maxscaleshl2 = maxscale<<2; + +// +// free up old scalers +// + for (i=1;i=stepbytwo) + i += 2; + } + memset (scaledirectory,0,sizeof(scaledirectory)); + + MM_SortMem (); + +// +// build the compiled scalers +// + stepbytwo = viewheight/2; // save space by double stepping + MM_GetPtr (&(memptr)work,20000); + + for (i=1;i<=maxscaleheight;i++) + { + BuildCompScale (i*2,&(memptr)scaledirectory[i]); + if (i>=stepbytwo) + i+= 2; + } + MM_FreePtr (&(memptr)work); + +// +// compact memory and lock down scalers +// + MM_SortMem (); + for (i=1;i<=maxscaleheight;i++) + { + MM_SetLock (&(memptr)scaledirectory[i],true); + fullscalefarcall[i] = (unsigned)scaledirectory[i]; + fullscalefarcall[i] <<=16; + fullscalefarcall[i] += scaledirectory[i]->codeofs[0]; + if (i>=stepbytwo) + { + scaledirectory[i+1] = scaledirectory[i]; + fullscalefarcall[i+1] = fullscalefarcall[i]; + scaledirectory[i+2] = scaledirectory[i]; + fullscalefarcall[i+2] = fullscalefarcall[i]; + i+=2; + } + } + scaledirectory[0] = scaledirectory[1]; + fullscalefarcall[0] = fullscalefarcall[1]; + +// +// check for oversize wall drawing +// + for (i=maxscaleheight;icode[0]; + toppix = (viewheight-height)/2; + fix = 0; + + for (src=0;src<=64;src++) + { + startpix = fix>>16; + fix += step; + endpix = fix>>16; + + if (endpix>startpix) + work->width[src] = endpix-startpix; + else + work->width[src] = 0; + +// +// mark the start of the code +// + work->codeofs[src] = FP_OFF(code); + +// +// compile some code if the source pixel generates any screen pixels +// + startpix+=toppix; + endpix+=toppix; + + if (startpix == endpix || endpix < 0 || startpix >= viewheight || src == 64) + continue; + + // + // mov al,[si+src] + // + *code++ = 0x8a; + *code++ = 0x44; + *code++ = src; + + for (;startpix= viewheight) + break; // off the bottom of the view area + if (startpix < 0) + continue; // not into the view area + + // + // mov [es:di+heightofs],al + // + *code++ = 0x26; + *code++ = 0x88; + *code++ = 0x85; + *((unsigned far *)code)++ = startpix*SCREENBWIDE; + } + + } + +// +// retf +// + *code++ = 0xcb; + + totalsize = FP_OFF(code); + MM_GetPtr (finalspot,totalsize); + _fmemcpy ((byte _seg *)(*finalspot),(byte _seg *)work,totalsize); + + return totalsize; +} + + +/* +======================= += += ScaleLine += += linescale should have the high word set to the segment of the scaler += +======================= +*/ + +extern int slinex,slinewidth; +extern unsigned far *linecmds; +extern long linescale; +extern unsigned maskword; + +byte mask1,mask2,mask3; + + +void near ScaleLine (void) +{ +asm mov cx,WORD PTR [linescale+2] +asm mov es,cx // segment of scaler + +asm mov bp,WORD PTR [linecmds] +asm mov dx,SC_INDEX+1 // to set SC_MAPMASK + +asm mov bx,[slinex] +asm mov di,bx +asm shr di,1 // X in bytes +asm shr di,1 +asm add di,[bufferofs] +asm and bx,3 +/* begin 8086 hack +asm shl bx,3 +*/ +asm push cx +asm mov cl,3 +asm shl bx,cl +asm pop cx +/* end 8086 hack */ +asm add bx,[slinewidth] // bx = (pixel*8+pixwidth) +asm mov al,BYTE [mapmasks3-1+bx] // -1 because pixwidth of 1 is first +asm mov ds,WORD PTR [linecmds+2] +asm or al,al +asm jz notthreebyte // scale across three bytes +asm jmp threebyte +notthreebyte: +asm mov al,BYTE PTR ss:[mapmasks2-1+bx] // -1 because pixwidth of 1 is first +asm or al,al +asm jnz twobyte // scale across two bytes + +// +// one byte scaling +// +asm mov al,BYTE PTR ss:[mapmasks1-1+bx] // -1 because pixwidth of 1 is first +asm out dx,al // set map mask register + +scalesingle: + +asm mov bx,[ds:bp] // table location of rtl to patch +asm or bx,bx +asm jz linedone // 0 signals end of segment list +asm mov bx,[es:bx] +asm mov dl,[es:bx] // save old value +asm mov BYTE PTR es:[bx],OP_RETF // patch a RETF in +asm mov si,[ds:bp+4] // table location of entry spot +asm mov ax,[es:si] +asm mov WORD PTR ss:[linescale],ax // call here to start scaling +asm mov si,[ds:bp+2] // corrected top of shape for this segment +asm add bp,6 // next segment list + +asm mov ax,SCREENSEG +asm mov es,ax +asm call ss:[linescale] // scale the segment of pixels + +asm mov es,cx // segment of scaler +asm mov BYTE PTR es:[bx],dl // unpatch the RETF +asm jmp scalesingle // do the next segment + + +// +// done +// +linedone: +asm mov ax,ss +asm mov ds,ax +return; + +// +// two byte scaling +// +twobyte: +asm mov ss:[mask2],al +asm mov al,BYTE PTR ss:[mapmasks1-1+bx] // -1 because pixwidth of 1 is first +asm mov ss:[mask1],al + +scaledouble: + +asm mov bx,[ds:bp] // table location of rtl to patch +asm or bx,bx +asm jz linedone // 0 signals end of segment list +asm mov bx,[es:bx] +asm mov cl,[es:bx] // save old value +asm mov BYTE PTR es:[bx],OP_RETF // patch a RETF in +asm mov si,[ds:bp+4] // table location of entry spot +asm mov ax,[es:si] +asm mov WORD PTR ss:[linescale],ax // call here to start scaling +asm mov si,[ds:bp+2] // corrected top of shape for this segment +asm add bp,6 // next segment list + +asm mov ax,SCREENSEG +asm mov es,ax +asm mov al,ss:[mask1] +asm out dx,al // set map mask register +asm call ss:[linescale] // scale the segment of pixels +asm inc di +asm mov al,ss:[mask2] +asm out dx,al // set map mask register +asm call ss:[linescale] // scale the segment of pixels +asm dec di + +asm mov es,WORD PTR ss:[linescale+2] // segment of scaler +asm mov BYTE PTR es:[bx],cl // unpatch the RETF +asm jmp scaledouble // do the next segment + + +// +// three byte scaling +// +threebyte: +asm mov ss:[mask3],al +asm mov al,BYTE PTR ss:[mapmasks2-1+bx] // -1 because pixwidth of 1 is first +asm mov ss:[mask2],al +asm mov al,BYTE PTR ss:[mapmasks1-1+bx] // -1 because pixwidth of 1 is first +asm mov ss:[mask1],al + +scaletriple: + +asm mov bx,[ds:bp] // table location of rtl to patch +asm or bx,bx +asm jz linedone // 0 signals end of segment list +asm mov bx,[es:bx] +asm mov cl,[es:bx] // save old value +asm mov BYTE PTR es:[bx],OP_RETF // patch a RETF in +asm mov si,[ds:bp+4] // table location of entry spot +asm mov ax,[es:si] +asm mov WORD PTR ss:[linescale],ax // call here to start scaling +asm mov si,[ds:bp+2] // corrected top of shape for this segment +asm add bp,6 // next segment list + +asm mov ax,SCREENSEG +asm mov es,ax +asm mov al,ss:[mask1] +asm out dx,al // set map mask register +asm call ss:[linescale] // scale the segment of pixels +asm inc di +asm mov al,ss:[mask2] +asm out dx,al // set map mask register +asm call ss:[linescale] // scale the segment of pixels +asm inc di +asm mov al,ss:[mask3] +asm out dx,al // set map mask register +asm call ss:[linescale] // scale the segment of pixels +asm dec di +asm dec di + +asm mov es,WORD PTR ss:[linescale+2] // segment of scaler +asm mov BYTE PTR es:[bx],cl // unpatch the RETF +asm jmp scaletriple // do the next segment + + +} + + +/* +======================= += += ScaleShape += += Draws a compiled shape at [scale] pixels high += += each vertical line of the shape has a pointer to segment data: += end of segment pixel*2 (0 terminates line) used to patch rtl in scaler += top of virtual line with segment in proper place += start of segment pixel*2, used to jsl into compiled scaler += += += Setup for call += -------------- += GC_MODE read mode 1, write mode 2 += GC_COLORDONTCARE set to 0, so all reads from video memory return 0xff += GC_INDEX pointing at GC_BITMASK += +======================= +*/ + +static long longtemp; + +void ScaleShape (int xcenter, int shapenum, unsigned height) +{ + t_compshape _seg *shape; + t_compscale _seg *comptable; + unsigned scale,srcx,stopx,tempx; + int t; + unsigned far *cmdptr; + boolean leftvis,rightvis; + + + shape = PM_GetSpritePage (shapenum); + + scale = height>>3; // low three bits are fractional + if (!scale || scale>maxscale) + return; // too close or far away + comptable = scaledirectory[scale]; + + *(((unsigned *)&linescale)+1)=(unsigned)comptable; // seg of far call + *(((unsigned *)&linecmds)+1)=(unsigned)shape; // seg of shape + +// +// scale to the left (from pixel 31 to shape->leftpix) +// + srcx = 32; + slinex = xcenter; + stopx = shape->leftpix; + cmdptr = &shape->dataofs[31-stopx]; + + while ( --srcx >=stopx && slinex>0) + { + (unsigned)linecmds = *cmdptr--; + if ( !(slinewidth = comptable->width[srcx]) ) + continue; + + if (slinewidth == 1) + { + slinex--; + if (slinex= height) + continue; // obscured by closer wall + ScaleLine (); + } + continue; + } + + // + // handle multi pixel lines + // + if (slinex>viewwidth) + { + slinex -= slinewidth; + slinewidth = viewwidth-slinex; + if (slinewidth<1) + continue; // still off the right side + } + else + { + if (slinewidth>slinex) + slinewidth = slinex; + slinex -= slinewidth; + } + + + leftvis = (wallheight[slinex] < height); + rightvis = (wallheight[slinex+slinewidth-1] < height); + + if (leftvis) + { + if (rightvis) + ScaleLine (); + else + { + while (wallheight[slinex+slinewidth-1] >= height) + slinewidth--; + ScaleLine (); + } + } + else + { + if (!rightvis) + continue; // totally obscured + + while (wallheight[slinex] >= height) + { + slinex++; + slinewidth--; + } + ScaleLine (); + break; // the rest of the shape is gone + } + } + + +// +// scale to the right +// + slinex = xcenter; + stopx = shape->rightpix; + if (shape->leftpix<31) + { + srcx = 31; + cmdptr = &shape->dataofs[32-shape->leftpix]; + } + else + { + srcx = shape->leftpix-1; + cmdptr = &shape->dataofs[0]; + } + slinewidth = 0; + + while ( ++srcx <= stopx && (slinex+=slinewidth)width[srcx]) ) + continue; + + if (slinewidth == 1) + { + if (slinex>=0 && wallheight[slinex] < height) + { + ScaleLine (); + } + continue; + } + + // + // handle multi pixel lines + // + if (slinex<0) + { + if (slinewidth <= -slinex) + continue; // still off the left edge + + slinewidth += slinex; + slinex = 0; + } + else + { + if (slinex + slinewidth > viewwidth) + slinewidth = viewwidth-slinex; + } + + + leftvis = (wallheight[slinex] < height); + rightvis = (wallheight[slinex+slinewidth-1] < height); + + if (leftvis) + { + if (rightvis) + { + ScaleLine (); + } + else + { + while (wallheight[slinex+slinewidth-1] >= height) + slinewidth--; + ScaleLine (); + break; // the rest of the shape is gone + } + } + else + { + if (rightvis) + { + while (wallheight[slinex] >= height) + { + slinex++; + slinewidth--; + } + ScaleLine (); + } + else + continue; // totally obscured + } + } +} + + + +/* +======================= += += SimpleScaleShape += += NO CLIPPING, height in pixels += += Draws a compiled shape at [scale] pixels high += += each vertical line of the shape has a pointer to segment data: += end of segment pixel*2 (0 terminates line) used to patch rtl in scaler += top of virtual line with segment in proper place += start of segment pixel*2, used to jsl into compiled scaler += += += Setup for call += -------------- += GC_MODE read mode 1, write mode 2 += GC_COLORDONTCARE set to 0, so all reads from video memory return 0xff += GC_INDEX pointing at GC_BITMASK += +======================= +*/ + +void SimpleScaleShape (int xcenter, int shapenum, unsigned height) +{ + t_compshape _seg *shape; + t_compscale _seg *comptable; + unsigned scale,srcx,stopx,tempx; + int t; + unsigned far *cmdptr; + boolean leftvis,rightvis; + + + shape = PM_GetSpritePage (shapenum); + + scale = height>>1; + comptable = scaledirectory[scale]; + + *(((unsigned *)&linescale)+1)=(unsigned)comptable; // seg of far call + *(((unsigned *)&linecmds)+1)=(unsigned)shape; // seg of shape + +// +// scale to the left (from pixel 31 to shape->leftpix) +// + srcx = 32; + slinex = xcenter; + stopx = shape->leftpix; + cmdptr = &shape->dataofs[31-stopx]; + + while ( --srcx >=stopx ) + { + (unsigned)linecmds = *cmdptr--; + if ( !(slinewidth = comptable->width[srcx]) ) + continue; + + slinex -= slinewidth; + ScaleLine (); + } + + +// +// scale to the right +// + slinex = xcenter; + stopx = shape->rightpix; + if (shape->leftpix<31) + { + srcx = 31; + cmdptr = &shape->dataofs[32-shape->leftpix]; + } + else + { + srcx = shape->leftpix-1; + cmdptr = &shape->dataofs[0]; + } + slinewidth = 0; + + while ( ++srcx <= stopx ) + { + (unsigned)linecmds = *cmdptr++; + if ( !(slinewidth = comptable->width[srcx]) ) + continue; + + ScaleLine (); + slinex+=slinewidth; + } +} + + + + +// +// bit mask tables for drawing scaled strips up to eight pixels wide +// +// down here so the STUPID inline assembler doesn't get confused! +// + + +byte mapmasks1[4][8] = { +{1 ,3 ,7 ,15,15,15,15,15}, +{2 ,6 ,14,14,14,14,14,14}, +{4 ,12,12,12,12,12,12,12}, +{8 ,8 ,8 ,8 ,8 ,8 ,8 ,8} }; + +byte mapmasks2[4][8] = { +{0 ,0 ,0 ,0 ,1 ,3 ,7 ,15}, +{0 ,0 ,0 ,1 ,3 ,7 ,15,15}, +{0 ,0 ,1 ,3 ,7 ,15,15,15}, +{0 ,1 ,3 ,7 ,15,15,15,15} }; + +byte mapmasks3[4][8] = { +{0 ,0 ,0 ,0 ,0 ,0 ,0 ,0}, +{0 ,0 ,0 ,0 ,0 ,0 ,0 ,1}, +{0 ,0 ,0 ,0 ,0 ,0 ,1 ,3}, +{0 ,0 ,0 ,0 ,0 ,1 ,3 ,7} }; + + +unsigned wordmasks[8][8] = { +{0x0080,0x00c0,0x00e0,0x00f0,0x00f8,0x00fc,0x00fe,0x00ff}, +{0x0040,0x0060,0x0070,0x0078,0x007c,0x007e,0x007f,0x807f}, +{0x0020,0x0030,0x0038,0x003c,0x003e,0x003f,0x803f,0xc03f}, +{0x0010,0x0018,0x001c,0x001e,0x001f,0x801f,0xc01f,0xe01f}, +{0x0008,0x000c,0x000e,0x000f,0x800f,0xc00f,0xe00f,0xf00f}, +{0x0004,0x0006,0x0007,0x8007,0xc007,0xe007,0xf007,0xf807}, +{0x0002,0x0003,0x8003,0xc003,0xe003,0xf003,0xf803,0xfc03}, +{0x0001,0x8001,0xc001,0xe001,0xf001,0xf801,0xfc01,0xfe01} }; + +int slinex,slinewidth; +unsigned far *linecmds; +long linescale; +unsigned maskword; + diff --git a/16/WOLFSRC/WL_STATE.C b/16/WOLFSRC/WL_STATE.C new file mode 100755 index 00000000..ad534ba9 --- /dev/null +++ b/16/WOLFSRC/WL_STATE.C @@ -0,0 +1,1480 @@ +// WL_STATE.C + +#include "WL_DEF.H" +#pragma hdrstop + +/* +============================================================================= + + LOCAL CONSTANTS + +============================================================================= +*/ + + +/* +============================================================================= + + GLOBAL VARIABLES + +============================================================================= +*/ + + +dirtype opposite[9] = + {west,southwest,south,southeast,east,northeast,north,northwest,nodir}; + +dirtype diagonal[9][9] = +{ +/* east */ {nodir,nodir,northeast,nodir,nodir,nodir,southeast,nodir,nodir}, + {nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir}, +/* north */ {northeast,nodir,nodir,nodir,northwest,nodir,nodir,nodir,nodir}, + {nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir}, +/* west */ {nodir,nodir,northwest,nodir,nodir,nodir,southwest,nodir,nodir}, + {nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir}, +/* south */ {southeast,nodir,nodir,nodir,southwest,nodir,nodir,nodir,nodir}, + {nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir}, + {nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir} +}; + + + +void SpawnNewObj (unsigned tilex, unsigned tiley, statetype *state); +void NewState (objtype *ob, statetype *state); + +boolean TryWalk (objtype *ob); +void MoveObj (objtype *ob, long move); + +void KillActor (objtype *ob); +void DamageActor (objtype *ob, unsigned damage); + +boolean CheckLine (objtype *ob); +void FirstSighting (objtype *ob); +boolean CheckSight (objtype *ob); + +/* +============================================================================= + + LOCAL VARIABLES + +============================================================================= +*/ + + + +//=========================================================================== + + +/* +=================== += += SpawnNewObj += += Spaws a new actor at the given TILE coordinates, with the given state, and += the given size in GLOBAL units. += += new = a pointer to an initialized new actor += +=================== +*/ + +void SpawnNewObj (unsigned tilex, unsigned tiley, statetype *state) +{ + GetNewActor (); + new->state = state; + if (state->tictime) + new->ticcount = US_RndT () % state->tictime; + else + new->ticcount = 0; + + new->tilex = tilex; + new->tiley = tiley; + new->x = ((long)tilex<y = ((long)tiley<dir = nodir; + + actorat[tilex][tiley] = new; + new->areanumber = + *(mapsegs[0] + farmapylookup[new->tiley]+new->tilex) - AREATILE; +} + + + +/* +=================== += += NewState += += Changes ob to a new state, setting ticcount to the max for that state += +=================== +*/ + +void NewState (objtype *ob, statetype *state) +{ + ob->state = state; + ob->ticcount = state->tictime; +} + + + +/* +============================================================================= + + ENEMY TILE WORLD MOVEMENT CODE + +============================================================================= +*/ + + +/* +================================== += += TryWalk += += Attempts to move ob in its current (ob->dir) direction. += += If blocked by either a wall or an actor returns FALSE += += If move is either clear or blocked only by a door, returns TRUE and sets += += ob->tilex = new destination += ob->tiley += ob->areanumber = the floor tile number (0-(NUMAREAS-1)) of destination += ob->distance = TILEGLOBAl, or -doornumber if a door is blocking the way += += If a door is in the way, an OpenDoor call is made to start it opening. += The actor code should wait until += doorobjlist[-ob->distance].action = dr_open, meaning the door has been += fully opened += +================================== +*/ + +#define CHECKDIAG(x,y) \ +{ \ + temp=(unsigned)actorat[x][y]; \ + if (temp) \ + { \ + if (temp<256) \ + return false; \ + if (((objtype *)temp)->flags&FL_SHOOTABLE) \ + return false; \ + } \ +} + +#define CHECKSIDE(x,y) \ +{ \ + temp=(unsigned)actorat[x][y]; \ + if (temp) \ + { \ + if (temp<128) \ + return false; \ + if (temp<256) \ + doornum = temp&63; \ + else if (((objtype *)temp)->flags&FL_SHOOTABLE)\ + return false; \ + } \ +} + + +boolean TryWalk (objtype *ob) +{ + int doornum; + unsigned temp; + + doornum = -1; + + if (ob->obclass == inertobj) + { + switch (ob->dir) + { + case north: + ob->tiley--; + break; + + case northeast: + ob->tilex++; + ob->tiley--; + break; + + case east: + ob->tilex++; + break; + + case southeast: + ob->tilex++; + ob->tiley++; + break; + + case south: + ob->tiley++; + break; + + case southwest: + ob->tilex--; + ob->tiley++; + break; + + case west: + ob->tilex--; + break; + + case northwest: + ob->tilex--; + ob->tiley--; + break; + } + } + else + switch (ob->dir) + { + case north: + if (ob->obclass == dogobj || ob->obclass == fakeobj) + { + CHECKDIAG(ob->tilex,ob->tiley-1); + } + else + { + CHECKSIDE(ob->tilex,ob->tiley-1); + } + ob->tiley--; + break; + + case northeast: + CHECKDIAG(ob->tilex+1,ob->tiley-1); + CHECKDIAG(ob->tilex+1,ob->tiley); + CHECKDIAG(ob->tilex,ob->tiley-1); + ob->tilex++; + ob->tiley--; + break; + + case east: + if (ob->obclass == dogobj || ob->obclass == fakeobj) + { + CHECKDIAG(ob->tilex+1,ob->tiley); + } + else + { + CHECKSIDE(ob->tilex+1,ob->tiley); + } + ob->tilex++; + break; + + case southeast: + CHECKDIAG(ob->tilex+1,ob->tiley+1); + CHECKDIAG(ob->tilex+1,ob->tiley); + CHECKDIAG(ob->tilex,ob->tiley+1); + ob->tilex++; + ob->tiley++; + break; + + case south: + if (ob->obclass == dogobj || ob->obclass == fakeobj) + { + CHECKDIAG(ob->tilex,ob->tiley+1); + } + else + { + CHECKSIDE(ob->tilex,ob->tiley+1); + } + ob->tiley++; + break; + + case southwest: + CHECKDIAG(ob->tilex-1,ob->tiley+1); + CHECKDIAG(ob->tilex-1,ob->tiley); + CHECKDIAG(ob->tilex,ob->tiley+1); + ob->tilex--; + ob->tiley++; + break; + + case west: + if (ob->obclass == dogobj || ob->obclass == fakeobj) + { + CHECKDIAG(ob->tilex-1,ob->tiley); + } + else + { + CHECKSIDE(ob->tilex-1,ob->tiley); + } + ob->tilex--; + break; + + case northwest: + CHECKDIAG(ob->tilex-1,ob->tiley-1); + CHECKDIAG(ob->tilex-1,ob->tiley); + CHECKDIAG(ob->tilex,ob->tiley-1); + ob->tilex--; + ob->tiley--; + break; + + case nodir: + return false; + + default: + Quit ("Walk: Bad dir"); + } + + if (doornum != -1) + { + OpenDoor (doornum); + ob->distance = -doornum-1; + return true; + } + + + ob->areanumber = + *(mapsegs[0] + farmapylookup[ob->tiley]+ob->tilex) - AREATILE; + + ob->distance = TILEGLOBAL; + return true; +} + + + +/* +================================== += += SelectDodgeDir += += Attempts to choose and initiate a movement for ob that sends it towards += the player while dodging += += If there is no possible move (ob is totally surrounded) += += ob->dir = nodir += += Otherwise += += ob->dir = new direction to follow += ob->distance = TILEGLOBAL or -doornumber += ob->tilex = new destination += ob->tiley += ob->areanumber = the floor tile number (0-(NUMAREAS-1)) of destination += +================================== +*/ + +void SelectDodgeDir (objtype *ob) +{ + int deltax,deltay,i; + unsigned absdx,absdy; + dirtype dirtry[5]; + dirtype turnaround,tdir; + + if (ob->flags & FL_FIRSTATTACK) + { + // + // turning around is only ok the very first time after noticing the + // player + // + turnaround = nodir; + ob->flags &= ~FL_FIRSTATTACK; + } + else + turnaround=opposite[ob->dir]; + + deltax = player->tilex - ob->tilex; + deltay = player->tiley - ob->tiley; + +// +// arange 5 direction choices in order of preference +// the four cardinal directions plus the diagonal straight towards +// the player +// + + if (deltax>0) + { + dirtry[1]= east; + dirtry[3]= west; + } + else + { + dirtry[1]= west; + dirtry[3]= east; + } + + if (deltay>0) + { + dirtry[2]= south; + dirtry[4]= north; + } + else + { + dirtry[2]= north; + dirtry[4]= south; + } + +// +// randomize a bit for dodging +// + absdx = abs(deltax); + absdy = abs(deltay); + + if (absdx > absdy) + { + tdir = dirtry[1]; + dirtry[1] = dirtry[2]; + dirtry[2] = tdir; + tdir = dirtry[3]; + dirtry[3] = dirtry[4]; + dirtry[4] = tdir; + } + + if (US_RndT() < 128) + { + tdir = dirtry[1]; + dirtry[1] = dirtry[2]; + dirtry[2] = tdir; + tdir = dirtry[3]; + dirtry[3] = dirtry[4]; + dirtry[4] = tdir; + } + + dirtry[0] = diagonal [ dirtry[1] ] [ dirtry[2] ]; + +// +// try the directions util one works +// + for (i=0;i<5;i++) + { + if ( dirtry[i] == nodir || dirtry[i] == turnaround) + continue; + + ob->dir = dirtry[i]; + if (TryWalk(ob)) + return; + } + +// +// turn around only as a last resort +// + if (turnaround != nodir) + { + ob->dir = turnaround; + + if (TryWalk(ob)) + return; + } + + ob->dir = nodir; +} + + +/* +============================ += += SelectChaseDir += += As SelectDodgeDir, but doesn't try to dodge += +============================ +*/ + +void SelectChaseDir (objtype *ob) +{ + int deltax,deltay,i; + dirtype d[3]; + dirtype tdir, olddir, turnaround; + + + olddir=ob->dir; + turnaround=opposite[olddir]; + + deltax=player->tilex - ob->tilex; + deltay=player->tiley - ob->tiley; + + d[1]=nodir; + d[2]=nodir; + + if (deltax>0) + d[1]= east; + else if (deltax<0) + d[1]= west; + if (deltay>0) + d[2]=south; + else if (deltay<0) + d[2]=north; + + if (abs(deltay)>abs(deltax)) + { + tdir=d[1]; + d[1]=d[2]; + d[2]=tdir; + } + + if (d[1]==turnaround) + d[1]=nodir; + if (d[2]==turnaround) + d[2]=nodir; + + + if (d[1]!=nodir) + { + ob->dir=d[1]; + if (TryWalk(ob)) + return; /*either moved forward or attacked*/ + } + + if (d[2]!=nodir) + { + ob->dir=d[2]; + if (TryWalk(ob)) + return; + } + +/* there is no direct path to the player, so pick another direction */ + + if (olddir!=nodir) + { + ob->dir=olddir; + if (TryWalk(ob)) + return; + } + + if (US_RndT()>128) /*randomly determine direction of search*/ + { + for (tdir=north;tdir<=west;tdir++) + { + if (tdir!=turnaround) + { + ob->dir=tdir; + if ( TryWalk(ob) ) + return; + } + } + } + else + { + for (tdir=west;tdir>=north;tdir--) + { + if (tdir!=turnaround) + { + ob->dir=tdir; + if ( TryWalk(ob) ) + return; + } + } + } + + if (turnaround != nodir) + { + ob->dir=turnaround; + if (ob->dir != nodir) + { + if ( TryWalk(ob) ) + return; + } + } + + ob->dir = nodir; // can't move +} + + +/* +============================ += += SelectRunDir += += Run Away from player += +============================ +*/ + +void SelectRunDir (objtype *ob) +{ + int deltax,deltay,i; + dirtype d[3]; + dirtype tdir, olddir, turnaround; + + + deltax=player->tilex - ob->tilex; + deltay=player->tiley - ob->tiley; + + if (deltax<0) + d[1]= east; + else + d[1]= west; + if (deltay<0) + d[2]=south; + else + d[2]=north; + + if (abs(deltay)>abs(deltax)) + { + tdir=d[1]; + d[1]=d[2]; + d[2]=tdir; + } + + ob->dir=d[1]; + if (TryWalk(ob)) + return; /*either moved forward or attacked*/ + + ob->dir=d[2]; + if (TryWalk(ob)) + return; + +/* there is no direct path to the player, so pick another direction */ + + if (US_RndT()>128) /*randomly determine direction of search*/ + { + for (tdir=north;tdir<=west;tdir++) + { + ob->dir=tdir; + if ( TryWalk(ob) ) + return; + } + } + else + { + for (tdir=west;tdir>=north;tdir--) + { + ob->dir=tdir; + if ( TryWalk(ob) ) + return; + } + } + + ob->dir = nodir; // can't move +} + + +/* +================= += += MoveObj += += Moves ob be move global units in ob->dir direction += Actors are not allowed to move inside the player += Does NOT check to see if the move is tile map valid += += ob->x = adjusted for new position += ob->y += +================= +*/ + +void MoveObj (objtype *ob, long move) +{ + long deltax,deltay; + + switch (ob->dir) + { + case north: + ob->y -= move; + break; + case northeast: + ob->x += move; + ob->y -= move; + break; + case east: + ob->x += move; + break; + case southeast: + ob->x += move; + ob->y += move; + break; + case south: + ob->y += move; + break; + case southwest: + ob->x -= move; + ob->y += move; + break; + case west: + ob->x -= move; + break; + case northwest: + ob->x -= move; + ob->y -= move; + break; + + case nodir: + return; + + default: + Quit ("MoveObj: bad dir!"); + } + +// +// check to make sure it's not on top of player +// + if (areabyplayer[ob->areanumber]) + { + deltax = ob->x - player->x; + if (deltax < -MINACTORDIST || deltax > MINACTORDIST) + goto moveok; + deltay = ob->y - player->y; + if (deltay < -MINACTORDIST || deltay > MINACTORDIST) + goto moveok; + + if (ob->obclass == ghostobj || ob->obclass == spectreobj) + TakeDamage (tics*2,ob); + + // + // back up + // + switch (ob->dir) + { + case north: + ob->y += move; + break; + case northeast: + ob->x -= move; + ob->y += move; + break; + case east: + ob->x -= move; + break; + case southeast: + ob->x -= move; + ob->y -= move; + break; + case south: + ob->y -= move; + break; + case southwest: + ob->x += move; + ob->y -= move; + break; + case west: + ob->x += move; + break; + case northwest: + ob->x += move; + ob->y += move; + break; + + case nodir: + return; + } + return; + } +moveok: + ob->distance -=move; +} + +/* +============================================================================= + + STUFF + +============================================================================= +*/ + +/* +=============== += += DropItem += += Tries to drop a bonus item somewhere in the tiles surrounding the += given tilex/tiley += +=============== +*/ + +void DropItem (stat_t itemtype, int tilex, int tiley) +{ + int x,y,xl,xh,yl,yh; + +// +// find a free spot to put it in +// + if (!actorat[tilex][tiley]) + { + PlaceItemType (itemtype, tilex,tiley); + return; + } + + xl = tilex-1; + xh = tilex+1; + yl = tiley-1; + yh = tiley+1; + + for (x=xl ; x<= xh ; x++) + for (y=yl ; y<= yh ; y++) + if (!actorat[x][y]) + { + PlaceItemType (itemtype, x,y); + return; + } +} + + + +/* +=============== += += KillActor += +=============== +*/ + +void KillActor (objtype *ob) +{ + int tilex,tiley; + + tilex = ob->tilex = ob->x >> TILESHIFT; // drop item on center + tiley = ob->tiley = ob->y >> TILESHIFT; + + switch (ob->obclass) + { + case guardobj: + GivePoints (100); + NewState (ob,&s_grddie1); + PlaceItemType (bo_clip2,tilex,tiley); + break; + + case officerobj: + GivePoints (400); + NewState (ob,&s_ofcdie1); + PlaceItemType (bo_clip2,tilex,tiley); + break; + + case mutantobj: + GivePoints (700); + NewState (ob,&s_mutdie1); + PlaceItemType (bo_clip2,tilex,tiley); + break; + + case ssobj: + GivePoints (500); + NewState (ob,&s_ssdie1); + if (gamestate.bestweapon < wp_machinegun) + PlaceItemType (bo_machinegun,tilex,tiley); + else + PlaceItemType (bo_clip2,tilex,tiley); + break; + + case dogobj: + GivePoints (200); + NewState (ob,&s_dogdie1); + break; + +#ifndef SPEAR + case bossobj: + GivePoints (5000); + NewState (ob,&s_bossdie1); + PlaceItemType (bo_key1,tilex,tiley); + break; + + case gretelobj: + GivePoints (5000); + NewState (ob,&s_greteldie1); + PlaceItemType (bo_key1,tilex,tiley); + break; + + case giftobj: + GivePoints (5000); + gamestate.killx = player->x; + gamestate.killy = player->y; + NewState (ob,&s_giftdie1); + break; + + case fatobj: + GivePoints (5000); + gamestate.killx = player->x; + gamestate.killy = player->y; + NewState (ob,&s_fatdie1); + break; + + case schabbobj: + GivePoints (5000); + gamestate.killx = player->x; + gamestate.killy = player->y; + NewState (ob,&s_schabbdie1); + A_DeathScream(ob); + break; + case fakeobj: + GivePoints (2000); + NewState (ob,&s_fakedie1); + break; + + case mechahitlerobj: + GivePoints (5000); + NewState (ob,&s_mechadie1); + break; + case realhitlerobj: + GivePoints (5000); + gamestate.killx = player->x; + gamestate.killy = player->y; + NewState (ob,&s_hitlerdie1); + A_DeathScream(ob); + break; +#else + case spectreobj: + GivePoints (200); + NewState (ob,&s_spectredie1); + break; + + case angelobj: + GivePoints (5000); + NewState (ob,&s_angeldie1); + break; + + case transobj: + GivePoints (5000); + NewState (ob,&s_transdie0); + PlaceItemType (bo_key1,tilex,tiley); + break; + + case uberobj: + GivePoints (5000); + NewState (ob,&s_uberdie0); + PlaceItemType (bo_key1,tilex,tiley); + break; + + case willobj: + GivePoints (5000); + NewState (ob,&s_willdie1); + PlaceItemType (bo_key1,tilex,tiley); + break; + + case deathobj: + GivePoints (5000); + NewState (ob,&s_deathdie1); + PlaceItemType (bo_key1,tilex,tiley); + break; +#endif + } + + gamestate.killcount++; + ob->flags &= ~FL_SHOOTABLE; + actorat[ob->tilex][ob->tiley] = NULL; + ob->flags |= FL_NONMARK; +} + + + +/* +=================== += += DamageActor += += Called when the player succesfully hits an enemy. += += Does damage points to enemy ob, either putting it into a stun frame or += killing it. += +=================== +*/ + +void DamageActor (objtype *ob, unsigned damage) +{ + madenoise = true; + +// +// do double damage if shooting a non attack mode actor +// + if ( !(ob->flags & FL_ATTACKMODE) ) + damage <<= 1; + + ob->hitpoints -= damage; + + if (ob->hitpoints<=0) + KillActor (ob); + else + { + if (! (ob->flags & FL_ATTACKMODE) ) + FirstSighting (ob); // put into combat mode + + switch (ob->obclass) // dogs only have one hit point + { + case guardobj: + if (ob->hitpoints&1) + NewState (ob,&s_grdpain); + else + NewState (ob,&s_grdpain1); + break; + + case officerobj: + if (ob->hitpoints&1) + NewState (ob,&s_ofcpain); + else + NewState (ob,&s_ofcpain1); + break; + + case mutantobj: + if (ob->hitpoints&1) + NewState (ob,&s_mutpain); + else + NewState (ob,&s_mutpain1); + break; + + case ssobj: + if (ob->hitpoints&1) + NewState (ob,&s_sspain); + else + NewState (ob,&s_sspain1); + + break; + + } + } +} + +/* +============================================================================= + + CHECKSIGHT + +============================================================================= +*/ + + +/* +===================== += += CheckLine += += Returns true if a straight line between the player and ob is unobstructed += +===================== +*/ + +boolean CheckLine (objtype *ob) +{ + int x1,y1,xt1,yt1,x2,y2,xt2,yt2; + int x,y; + int xdist,ydist,xstep,ystep; + int temp; + int partial,delta; + long ltemp; + int xfrac,yfrac,deltafrac; + unsigned value,intercept; + + x1 = ob->x >> UNSIGNEDSHIFT; // 1/256 tile precision + y1 = ob->y >> UNSIGNEDSHIFT; + xt1 = x1 >> 8; + yt1 = y1 >> 8; + + x2 = plux; + y2 = pluy; + xt2 = player->tilex; + yt2 = player->tiley; + + + xdist = abs(xt2-xt1); + + if (xdist > 0) + { + if (xt2 > xt1) + { + partial = 256-(x1&0xff); + xstep = 1; + } + else + { + partial = x1&0xff; + xstep = -1; + } + + deltafrac = abs(x2-x1); + delta = y2-y1; + ltemp = ((long)delta<<8)/deltafrac; + if (ltemp > 0x7fffl) + ystep = 0x7fff; + else if (ltemp < -0x7fffl) + ystep = -0x7fff; + else + ystep = ltemp; + yfrac = y1 + (((long)ystep*partial) >>8); + + x = xt1+xstep; + xt2 += xstep; + do + { + y = yfrac>>8; + yfrac += ystep; + + value = (unsigned)tilemap[x][y]; + x += xstep; + + if (!value) + continue; + + if (value<128 || value>256) + return false; + + // + // see if the door is open enough + // + value &= ~0x80; + intercept = yfrac-ystep/2; + + if (intercept>doorposition[value]) + return false; + + } while (x != xt2); + } + + ydist = abs(yt2-yt1); + + if (ydist > 0) + { + if (yt2 > yt1) + { + partial = 256-(y1&0xff); + ystep = 1; + } + else + { + partial = y1&0xff; + ystep = -1; + } + + deltafrac = abs(y2-y1); + delta = x2-x1; + ltemp = ((long)delta<<8)/deltafrac; + if (ltemp > 0x7fffl) + xstep = 0x7fff; + else if (ltemp < -0x7fffl) + xstep = -0x7fff; + else + xstep = ltemp; + xfrac = x1 + (((long)xstep*partial) >>8); + + y = yt1 + ystep; + yt2 += ystep; + do + { + x = xfrac>>8; + xfrac += xstep; + + value = (unsigned)tilemap[x][y]; + y += ystep; + + if (!value) + continue; + + if (value<128 || value>256) + return false; + + // + // see if the door is open enough + // + value &= ~0x80; + intercept = xfrac-xstep/2; + + if (intercept>doorposition[value]) + return false; + } while (y != yt2); + } + + return true; +} + + + +/* +================ += += CheckSight += += Checks a straight line between player and current object += += If the sight is ok, check alertness and angle to see if they notice += += returns true if the player has been spoted += +================ +*/ + +#define MINSIGHT 0x18000l + +boolean CheckSight (objtype *ob) +{ + long deltax,deltay; + +// +// don't bother tracing a line if the area isn't connected to the player's +// + if (!areabyplayer[ob->areanumber]) + return false; + +// +// if the player is real close, sight is automatic +// + deltax = player->x - ob->x; + deltay = player->y - ob->y; + + if (deltax > -MINSIGHT && deltax < MINSIGHT + && deltay > -MINSIGHT && deltay < MINSIGHT) + return true; + +// +// see if they are looking in the right direction +// + switch (ob->dir) + { + case north: + if (deltay > 0) + return false; + break; + + case east: + if (deltax < 0) + return false; + break; + + case south: + if (deltay < 0) + return false; + break; + + case west: + if (deltax > 0) + return false; + break; + } + +// +// trace a line to check for blocking tiles (corners) +// + return CheckLine (ob); + +} + + + +/* +=============== += += FirstSighting += += Puts an actor into attack mode and possibly reverses the direction += if the player is behind it += +=============== +*/ + +void FirstSighting (objtype *ob) +{ +// +// react to the player +// + switch (ob->obclass) + { + case guardobj: + PlaySoundLocActor(HALTSND,ob); + NewState (ob,&s_grdchase1); + ob->speed *= 3; // go faster when chasing player + break; + + case officerobj: + PlaySoundLocActor(SPIONSND,ob); + NewState (ob,&s_ofcchase1); + ob->speed *= 5; // go faster when chasing player + break; + + case mutantobj: + NewState (ob,&s_mutchase1); + ob->speed *= 3; // go faster when chasing player + break; + + case ssobj: + PlaySoundLocActor(SCHUTZADSND,ob); + NewState (ob,&s_sschase1); + ob->speed *= 4; // go faster when chasing player + break; + + case dogobj: + PlaySoundLocActor(DOGBARKSND,ob); + NewState (ob,&s_dogchase1); + ob->speed *= 2; // go faster when chasing player + break; + +#ifndef SPEAR + case bossobj: + SD_PlaySound(GUTENTAGSND); + NewState (ob,&s_bosschase1); + ob->speed = SPDPATROL*3; // go faster when chasing player + break; + + case gretelobj: + SD_PlaySound(KEINSND); + NewState (ob,&s_gretelchase1); + ob->speed *= 3; // go faster when chasing player + break; + + case giftobj: + SD_PlaySound(EINESND); + NewState (ob,&s_giftchase1); + ob->speed *= 3; // go faster when chasing player + break; + + case fatobj: + SD_PlaySound(ERLAUBENSND); + NewState (ob,&s_fatchase1); + ob->speed *= 3; // go faster when chasing player + break; + + case schabbobj: + SD_PlaySound(SCHABBSHASND); + NewState (ob,&s_schabbchase1); + ob->speed *= 3; // go faster when chasing player + break; + + case fakeobj: + SD_PlaySound(TOT_HUNDSND); + NewState (ob,&s_fakechase1); + ob->speed *= 3; // go faster when chasing player + break; + + case mechahitlerobj: + SD_PlaySound(DIESND); + NewState (ob,&s_mechachase1); + ob->speed *= 3; // go faster when chasing player + break; + + case realhitlerobj: + SD_PlaySound(DIESND); + NewState (ob,&s_hitlerchase1); + ob->speed *= 5; // go faster when chasing player + break; + + case ghostobj: + NewState (ob,&s_blinkychase1); + ob->speed *= 2; // go faster when chasing player + break; +#else + + case spectreobj: + SD_PlaySound(GHOSTSIGHTSND); + NewState (ob,&s_spectrechase1); + ob->speed = 800; // go faster when chasing player + break; + + case angelobj: + SD_PlaySound(ANGELSIGHTSND); + NewState (ob,&s_angelchase1); + ob->speed = 1536; // go faster when chasing player + break; + + case transobj: + SD_PlaySound(TRANSSIGHTSND); + NewState (ob,&s_transchase1); + ob->speed = 1536; // go faster when chasing player + break; + + case uberobj: + NewState (ob,&s_uberchase1); + ob->speed = 3000; // go faster when chasing player + break; + + case willobj: + SD_PlaySound(WILHELMSIGHTSND); + NewState (ob,&s_willchase1); + ob->speed = 2048; // go faster when chasing player + break; + + case deathobj: + SD_PlaySound(KNIGHTSIGHTSND); + NewState (ob,&s_deathchase1); + ob->speed = 2048; // go faster when chasing player + break; + +#endif + } + + if (ob->distance < 0) + ob->distance = 0; // ignore the door opening command + + ob->flags |= FL_ATTACKMODE|FL_FIRSTATTACK; +} + + + +/* +=============== += += SightPlayer += += Called by actors that ARE NOT chasing the player. If the player += is detected (by sight, noise, or proximity), the actor is put into += it's combat frame and true is returned. += += Incorporates a random reaction delay += +=============== +*/ + +boolean SightPlayer (objtype *ob) +{ + if (ob->flags & FL_ATTACKMODE) + Quit ("An actor in ATTACKMODE called SightPlayer!"); + + if (ob->temp2) + { + // + // count down reaction time + // + ob->temp2 -= tics; + if (ob->temp2 > 0) + return false; + ob->temp2 = 0; // time to react + } + else + { + if (!areabyplayer[ob->areanumber]) + return false; + + if (ob->flags & FL_AMBUSH) + { + if (!CheckSight (ob)) + return false; + ob->flags &= ~FL_AMBUSH; + } + else + { + if (!madenoise && !CheckSight (ob)) + return false; + } + + + switch (ob->obclass) + { + case guardobj: + ob->temp2 = 1+US_RndT()/4; + break; + case officerobj: + ob->temp2 = 2; + break; + case mutantobj: + ob->temp2 = 1+US_RndT()/6; + break; + case ssobj: + ob->temp2 = 1+US_RndT()/6; + break; + case dogobj: + ob->temp2 = 1+US_RndT()/8; + break; + + case bossobj: + case schabbobj: + case fakeobj: + case mechahitlerobj: + case realhitlerobj: + case gretelobj: + case giftobj: + case fatobj: + case spectreobj: + case angelobj: + case transobj: + case uberobj: + case willobj: + case deathobj: + ob->temp2 = 1; + break; + } + return false; + } + + FirstSighting (ob); + + return true; +} + + diff --git a/16/WOLFSRC/WL_TEXT.C b/16/WOLFSRC/WL_TEXT.C new file mode 100755 index 00000000..1df86b83 --- /dev/null +++ b/16/WOLFSRC/WL_TEXT.C @@ -0,0 +1,859 @@ +// WL_TEXT.C + +#include "WL_DEF.H" +#pragma hdrstop + +/* +============================================================================= + +TEXT FORMATTING COMMANDS +------------------------ +^C Change text color +^E[enter] End of layout (all pages) +^G,,[enter] Draw a graphic and push margins +^P[enter] start new page, must be the first chars in a layout +^L,[ENTER] Locate to a specific spot, x in pixels, y in lines + +============================================================================= +*/ + +/* +============================================================================= + + LOCAL CONSTANTS + +============================================================================= +*/ + +#define BACKCOLOR 0x11 + + +#define WORDLIMIT 80 +#define FONTHEIGHT 10 +#define TOPMARGIN 16 +#define BOTTOMMARGIN 32 +#define LEFTMARGIN 16 +#define RIGHTMARGIN 16 +#define PICMARGIN 8 +#define TEXTROWS ((200-TOPMARGIN-BOTTOMMARGIN)/FONTHEIGHT) +#define SPACEWIDTH 7 +#define SCREENPIXWIDTH 320 +#define SCREENMID (SCREENPIXWIDTH/2) + +/* +============================================================================= + + LOCAL VARIABLES + +============================================================================= +*/ + +int pagenum,numpages; + +unsigned leftmargin[TEXTROWS],rightmargin[TEXTROWS]; +char far *text; +unsigned rowon; + +int picx,picy,picnum,picdelay; +boolean layoutdone; + +//=========================================================================== + +#ifndef JAPAN +/* +===================== += += RipToEOL += +===================== +*/ + +void RipToEOL (void) +{ + while (*text++ != '\n') // scan to end of line + ; +} + + +/* +===================== += += ParseNumber += +===================== +*/ + +int ParseNumber (void) +{ + char ch; + char num[80],*numptr; + +// +// scan until a number is found +// + ch = *text; + while (ch < '0' || ch >'9') + ch = *++text; + +// +// copy the number out +// + numptr = num; + do + { + *numptr++ = ch; + ch = *++text; + } while (ch >= '0' && ch <= '9'); + *numptr = 0; + + return atoi (num); +} + + + +/* +===================== += += ParsePicCommand += += Call with text pointing just after a ^P += Upon exit text points to the start of next line += +===================== +*/ + +void ParsePicCommand (void) +{ + picy=ParseNumber(); + picx=ParseNumber(); + picnum=ParseNumber(); + RipToEOL (); +} + + +void ParseTimedCommand (void) +{ + picy=ParseNumber(); + picx=ParseNumber(); + picnum=ParseNumber(); + picdelay=ParseNumber(); + RipToEOL (); +} + + +/* +===================== += += TimedPicCommand += += Call with text pointing just after a ^P += Upon exit text points to the start of next line += +===================== +*/ + +void TimedPicCommand (void) +{ + ParseTimedCommand (); + +// +// update the screen, and wait for time delay +// + VW_UpdateScreen (); + +// +// wait for time +// + TimeCount = 0; + while (TimeCount < picdelay) + ; + +// +// draw pic +// + VWB_DrawPic (picx&~7,picy,picnum); +} + + +/* +===================== += += HandleCommand += +===================== +*/ + +void HandleCommand (void) +{ + int i,margin,top,bottom; + int picwidth,picheight,picmid; + + switch (toupper(*++text)) + { + case 'B': + picy=ParseNumber(); + picx=ParseNumber(); + picwidth=ParseNumber(); + picheight=ParseNumber(); + VWB_Bar(picx,picy,picwidth,picheight,BACKCOLOR); + RipToEOL(); + break; + case ';': // comment + RipToEOL(); + break; + case 'P': // ^P is start of next page, ^E is end of file + case 'E': + layoutdone = true; + text--; // back up to the '^' + break; + + case 'C': // ^c changes text color + i = toupper(*++text); + if (i>='0' && i<='9') + fontcolor = i-'0'; + else if (i>='A' && i<='F') + fontcolor = i-'A'+10; + + fontcolor *= 16; + i = toupper(*++text); + if (i>='0' && i<='9') + fontcolor += i-'0'; + else if (i>='A' && i<='F') + fontcolor += i-'A'+10; + text++; + break; + + case '>': + px = 160; + text++; + break; + + case 'L': + py=ParseNumber(); + rowon = (py-TOPMARGIN)/FONTHEIGHT; + py = TOPMARGIN+rowon*FONTHEIGHT; + px=ParseNumber(); + while (*text++ != '\n') // scan to end of line + ; + break; + + case 'T': // ^Tyyy,xxx,ppp,ttt waits ttt tics, then draws pic + TimedPicCommand (); + break; + + case 'G': // ^Gyyy,xxx,ppp draws graphic + ParsePicCommand (); + VWB_DrawPic (picx&~7,picy,picnum); + picwidth = pictable[picnum-STARTPICS].width; + picheight = pictable[picnum-STARTPICS].height; + // + // adjust margins + // + picmid = picx + picwidth/2; + if (picmid > SCREENMID) + margin = picx-PICMARGIN; // new right margin + else + margin = picx+picwidth+PICMARGIN; // new left margin + + top = (picy-TOPMARGIN)/FONTHEIGHT; + if (top<0) + top = 0; + bottom = (picy+picheight-TOPMARGIN)/FONTHEIGHT; + if (bottom>=TEXTROWS) + bottom = TEXTROWS-1; + + for (i=top;i<=bottom;i++) + if (picmid > SCREENMID) + rightmargin[i] = margin; + else + leftmargin[i] = margin; + + // + // adjust this line if needed + // + if (px < leftmargin[rowon]) + px = leftmargin[rowon]; + break; + } +} + + +/* +===================== += += NewLine += +===================== +*/ + +void NewLine (void) +{ + char ch; + + if (++rowon == TEXTROWS) + { + // + // overflowed the page, so skip until next page break + // + layoutdone = true; + do + { + if (*text == '^') + { + ch = toupper(*(text+1)); + if (ch == 'E' || ch == 'P') + { + layoutdone = true; + return; + } + } + text++; + + } while (1); + + } + px = leftmargin[rowon]; + py+= FONTHEIGHT; +} + + + +/* +===================== += += HandleCtrls += +===================== +*/ + +void HandleCtrls (void) +{ + char ch; + + ch = *text++; // get the character and advance + + if (ch == '\n') + { + NewLine (); + return; + } + +} + + +/* +===================== += += HandleWord += +===================== +*/ + +void HandleWord (void) +{ + char word[WORDLIMIT]; + int i,wordindex; + unsigned wwidth,wheight,newpos; + + + // + // copy the next word into [word] + // + word[0] = *text++; + wordindex = 1; + while (*text>32) + { + word[wordindex] = *text++; + if (++wordindex == WORDLIMIT) + Quit ("PageLayout: Word limit exceeded"); + } + word[wordindex] = 0; // stick a null at end for C + + // + // see if it fits on this line + // + VW_MeasurePropString (word,&wwidth,&wheight); + + while (px+wwidth > rightmargin[rowon]) + { + NewLine (); + if (layoutdone) + return; // overflowed page + } + + // + // print it + // + newpos = px+wwidth; + VWB_DrawPropString (word); + px = newpos; + + // + // suck up any extra spaces + // + while (*text == ' ') + { + px += SPACEWIDTH; + text++; + } +} + +/* +===================== += += PageLayout += += Clears the screen, draws the pics on the page, and word wraps the text. += Returns a pointer to the terminating command += +===================== +*/ + +void PageLayout (boolean shownumber) +{ + int i,oldfontcolor; + char ch; + + oldfontcolor = fontcolor; + + fontcolor = 0; + +// +// clear the screen +// + VWB_Bar (0,0,320,200,BACKCOLOR); + VWB_DrawPic (0,0,H_TOPWINDOWPIC); + VWB_DrawPic (0,8,H_LEFTWINDOWPIC); + VWB_DrawPic (312,8,H_RIGHTWINDOWPIC); + VWB_DrawPic (8,176,H_BOTTOMINFOPIC); + + + for (i=0;i1) + { + #ifndef JAPAN + BackPage (); + BackPage (); + #else + pagenum--; + #endif + newpage = true; + } + break; + + case sc_Enter: + case sc_DownArrow: + case sc_PgDn: + case sc_RightArrow: // the text allready points at next page + if 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 RJBoVVZ_B|wEhH)P{{RI5maYH* literal 0 HcmV?d00001 diff --git a/16/WOLFSRC/WOLF.OBR b/16/WOLFSRC/WOLF.OBR new file mode 100755 index 0000000000000000000000000000000000000000..d51eda791f38af94fa3c32e2693aa06180bfceeb GIT binary patch literal 467 zcmZ=N$}cZYEm8OzGjwq-kxRFVDb7eN&r6Rf&Mz%WPK_xj&PdJ4i7ANBP0Y;GOJ+EO0@AG*&S2L7 zRj3HGRu_nkpcv!;D0e^@( TgOrg7Kq2~os0?m-Xg)6E|yI*Cl$t-(U5wyHC%Y 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 Jn#5m${ukqkHp~D3 literal 0 HcmV?d00001 diff --git a/16/WOLFSRC/WOLFGTV.H b/16/WOLFSRC/WOLFGTV.H new file mode 100755 index 00000000..05abb0e5 --- /dev/null +++ b/16/WOLFSRC/WOLFGTV.H @@ -0,0 +1,10 @@ +//#define SPEAR +//#define JAPAN +#define GOODTIMES +#define ARTSEXTERN +#define DEMOSEXTERN +//#define MYPROFILE +//#define DEBCHECK +#define CARMACIZED +//#define UPLOAD + \ No newline at end of file diff --git a/16/WOLFSRC/WOLFHACK.C b/16/WOLFSRC/WOLFHACK.C new file mode 100755 index 00000000..343d3b9f --- /dev/null +++ b/16/WOLFSRC/WOLFHACK.C @@ -0,0 +1,186 @@ +// WOLFHACK.C + +#include "WL_DEF.H" + +#define MAXVIEWHEIGHT 200 + +int spanstart[MAXVIEWHEIGHT/2]; + +fixed stepscale[MAXVIEWHEIGHT/2]; +fixed basedist[MAXVIEWHEIGHT/2]; + +extern char far planepics[8192]; // 4k of ceiling, 4k of floor + +int halfheight = 0; + +byte far *planeylookup[MAXVIEWHEIGHT/2]; +unsigned mirrorofs[MAXVIEWHEIGHT/2]; + +fixed psin, pcos; + +fixed FixedMul (fixed a, fixed b) +{ + return (a>>8)*(b>>8); +} + + +int mr_rowofs; +int mr_count; +int mr_xstep; +int mr_ystep; +int mr_xfrac; +int mr_yfrac; +int mr_dest; + + +/* +============== += += DrawSpans += += Height ranges from 0 (infinity) to viewheight/2 (nearest) +============== +*/ + +void DrawSpans (int x1, int x2, int height) +{ + fixed length; + int ofs; + int prestep; + fixed startxfrac, startyfrac; + + int x, startx, count, plane, startplane; + byte far *toprow, far *dest; + + toprow = planeylookup[height]+bufferofs; + mr_rowofs = mirrorofs[height]; + + mr_xstep = (psin<<1)/height; + mr_ystep = (pcos<<1)/height; + + length = basedist[height]; + startxfrac = (viewx + FixedMul(length,pcos)); + startyfrac = (viewy - FixedMul(length,psin)); + +// draw two spans simultaniously + + plane = startplane = x1&3; + prestep = viewwidth/2 - x1; + do + { + outportb (SC_INDEX+1,1<>2)*prestep; + mr_yfrac = startyfrac - (mr_ystep>>2)*prestep; + + startx = x1>>2; + mr_dest = (unsigned)toprow + startx; + mr_count = ((x2-plane)>>2) - startx + 1; + x1++; + prestep--; + if (mr_count) + MapRow (); + plane = (plane+1)&3; + } while (plane != startplane); + +} + + + + +/* +=================== += += SetPlaneViewSize += +=================== +*/ + +void SetPlaneViewSize (void) +{ + int x,y; + byte far *dest, far *src; + + halfheight = viewheight>>1; + + + for (y=0 ; y0) + basedist[y] = GLOBAL1/2*scale/y; + } + + src = PM_GetPage(0); + dest = planepics; + for (x=0 ; x<4096 ; x++) + { + *dest = *src++; + dest += 2; + } + src = PM_GetPage(1); + dest = planepics+1; + for (x=0 ; x<4096 ; x++) + { + *dest = *src++; + dest += 2; + } + +} + + +/* +=================== += += DrawPlanes += +=================== +*/ + +void DrawPlanes (void) +{ + int height, lastheight; + int x; + + if (viewheight>>1 != halfheight) + SetPlaneViewSize (); // screen size has changed + + + psin = viewsin; + if (psin < 0) + psin = -(psin&0xffff); + pcos = viewcos; + if (pcos < 0) + pcos = -(pcos&0xffff); + +// +// loop over all columns +// + lastheight = halfheight; + + for (x=0 ; x>3; + if (height < lastheight) + { // more starts + do + { + spanstart[--lastheight] = x; + } while (lastheight > height); + } + else if (height > lastheight) + { // draw spans + if (height > halfheight) + height = halfheight; + for ( ; lastheight < height ; lastheight++) + DrawSpans (spanstart[lastheight], x-1, lastheight); + } + } + + height = halfheight; + for ( ; lastheight < height ; lastheight++) + DrawSpans (spanstart[lastheight], x-1, lastheight); +} + diff --git a/16/WOLFSRC/WOLFJVER.H b/16/WOLFSRC/WOLFJVER.H new file mode 100755 index 00000000..c5510ba7 --- /dev/null +++ b/16/WOLFSRC/WOLFJVER.H @@ -0,0 +1,8 @@ +//#define SPEAR +#define JAPAN +#define ARTSEXTERN +#define DEMOSEXTERN +//#define MYPROFILE +//#define DEBCHECK +#define CARMACIZED +//#define UPLOAD diff --git a/16/WOLFSRC/WOLFVER.H b/16/WOLFSRC/WOLFVER.H new file mode 100755 index 00000000..1208b35d --- /dev/null +++ b/16/WOLFSRC/WOLFVER.H @@ -0,0 +1,7 @@ +//#define SPEAR +#define ARTSEXTERN +#define DEMOSEXTERN +//#define MYPROFILE +//#define DEBCHECK +#define CARMACIZED +//#define UPLOAD diff --git a/16/WOLFSRC/id_vh.c b/16/WOLFSRC/id_vh.c new file mode 100755 index 00000000..696a3e1f --- /dev/null +++ b/16/WOLFSRC/id_vh.c @@ -0,0 +1,547 @@ +// ID_VH.C + +#include "ID_HEADS.H" + +#define SCREENWIDTH 80 +#define CHARWIDTH 2 +#define TILEWIDTH 4 +#define GRPLANES 4 +#define BYTEPIXELS 4 + +#define SCREENXMASK (~3) +#define SCREENXPLUS (3) +#define SCREENXDIV (4) + +#define VIEWWIDTH 80 + +#define PIXTOBLOCK 4 // 16 pixels to an update block + +#define UNCACHEGRCHUNK(chunk) {MM_FreePtr(&grsegs[chunk]);grneeded[chunk]&=~ca_levelbit;} + +byte update[UPDATEHIGH][UPDATEWIDE]; + +//========================================================================== + +pictabletype _seg *pictable; + + +int px,py; +byte fontcolor,backcolor; +int fontnumber; +int bufferwidth,bufferheight; + + +//========================================================================== + +void VWL_UpdateScreenBlocks (void); + +//========================================================================== + +void VW_DrawPropString (char far *string) +{ + fontstruct far *font; + int width,step,height,i; + byte far *source, far *dest, far *origdest; + byte ch,mask; + + font = (fontstruct far *)grsegs[STARTFONT+fontnumber]; + height = bufferheight = font->height; + dest = origdest = MK_FP(SCREENSEG,bufferofs+ylookup[py]+(px>>2)); + mask = 1<<(px&3); + + + while ((ch = *string++)!=0) + { + width = step = font->width[ch]; + source = ((byte far *)font)+font->location[ch]; + while (width--) + { + VGAMAPMASK(mask); + +asm mov ah,[BYTE PTR fontcolor] +asm mov bx,[step] +asm mov cx,[height] +asm mov dx,[linewidth] +asm lds si,[source] +asm les di,[dest] + +vertloop: +asm mov al,[si] +asm or al,al +asm je next +asm mov [es:di],ah // draw color + +next: +asm add si,bx +asm add di,dx +asm loop vertloop +asm mov ax,ss +asm mov ds,ax + + source++; + px++; + mask <<= 1; + if (mask == 16) + { + mask = 1; + dest++; + } + } + } +bufferheight = height; +bufferwidth = ((dest+1)-origdest)*4; +} + + +void VW_DrawColorPropString (char far *string) +{ + fontstruct far *font; + int width,step,height,i; + byte far *source, far *dest, far *origdest; + byte ch,mask; + + font = (fontstruct far *)grsegs[STARTFONT+fontnumber]; + height = bufferheight = font->height; + dest = origdest = MK_FP(SCREENSEG,bufferofs+ylookup[py]+(px>>2)); + mask = 1<<(px&3); + + + while ((ch = *string++)!=0) + { + width = step = font->width[ch]; + source = ((byte far *)font)+font->location[ch]; + while (width--) + { + VGAMAPMASK(mask); + +asm mov ah,[BYTE PTR fontcolor] +asm mov bx,[step] +asm mov cx,[height] +asm mov dx,[linewidth] +asm lds si,[source] +asm les di,[dest] + +vertloop: +asm mov al,[si] +asm or al,al +asm je next +asm mov [es:di],ah // draw color + +next: +asm add si,bx +asm add di,dx + +asm rcr cx,1 // inc font color +asm jc cont +asm inc ah + +cont: +asm rcl cx,1 +asm loop vertloop +asm mov ax,ss +asm mov ds,ax + + source++; + px++; + mask <<= 1; + if (mask == 16) + { + mask = 1; + dest++; + } + } + } +bufferheight = height; +bufferwidth = ((dest+1)-origdest)*4; +} + + +//========================================================================== + + +/* +================= += += VL_MungePic += +================= +*/ + +void VL_MungePic (byte far *source, unsigned width, unsigned height) +{ + unsigned x,y,plane,size,pwidth; + byte _seg *temp, far *dest, far *srcline; + + size = width*height; + + if (width&3) + MS_Quit ("VL_MungePic: Not divisable by 4!"); + +// +// copy the pic to a temp buffer +// + MM_GetPtr (&(memptr)temp,size); + _fmemcpy (temp,source,size); + +// +// munge it back into the original buffer +// + dest = source; + pwidth = width/4; + + for (plane=0;plane<4;plane++) + { + srcline = temp; + for (y=0;yheight; + for (*width = 0;*string;string++) + *width += font->width[*((byte far *)string)]; // proportional width +} + +void VW_MeasurePropString (char far *string, word *width, word *height) +{ + VWL_MeasureString(string,width,height,(fontstruct _seg *)grsegs[STARTFONT+fontnumber]); +} + +void VW_MeasureMPropString (char far *string, word *width, word *height) +{ + VWL_MeasureString(string,width,height,(fontstruct _seg *)grsegs[STARTFONTM+fontnumber]); +} + + + +/* +============================================================================= + + Double buffer management routines + +============================================================================= +*/ + + +/* +======================= += += VW_MarkUpdateBlock += += Takes a pixel bounded block and marks the tiles in bufferblocks += Returns 0 if the entire block is off the buffer screen += +======================= +*/ + +int VW_MarkUpdateBlock (int x1, int y1, int x2, int y2) +{ + int x,y,xt1,yt1,xt2,yt2,nextline; + byte *mark; + + xt1 = x1>>PIXTOBLOCK; + yt1 = y1>>PIXTOBLOCK; + + xt2 = x2>>PIXTOBLOCK; + yt2 = y2>>PIXTOBLOCK; + + if (xt1<0) + xt1=0; + else if (xt1>=UPDATEWIDE) + return 0; + + if (yt1<0) + yt1=0; + else if (yt1>UPDATEHIGH) + return 0; + + if (xt2<0) + return 0; + else if (xt2>=UPDATEWIDE) + xt2 = UPDATEWIDE-1; + + if (yt2<0) + return 0; + else if (yt2>=UPDATEHIGH) + yt2 = UPDATEHIGH-1; + + mark = updateptr + uwidthtable[yt1] + xt1; + nextline = UPDATEWIDE - (xt2-xt1) - 1; + + for (y=yt1;y<=yt2;y++) + { + for (x=xt1;x<=xt2;x++) + *mark++ = 1; // this tile will need to be updated + + mark += nextline; + } + + return 1; +} + +void VWB_DrawTile8 (int x, int y, int tile) +{ + if (VW_MarkUpdateBlock (x,y,x+7,y+7)) + LatchDrawChar(x,y,tile); +} + +void VWB_DrawTile8M (int x, int y, int tile) +{ + if (VW_MarkUpdateBlock (x,y,x+7,y+7)) + VL_MemToScreen (((byte far *)grsegs[STARTTILE8M])+tile*64,8,8,x,y); +} + + +void VWB_DrawPic (int x, int y, int chunknum) +{ + int picnum = chunknum - STARTPICS; + unsigned width,height; + + x &= ~7; + + width = pictable[picnum].width; + height = pictable[picnum].height; + + if (VW_MarkUpdateBlock (x,y,x+width-1,y+height-1)) + VL_MemToScreen (grsegs[chunknum],width,height,x,y); +} + + + +void VWB_DrawPropString (char far *string) +{ + int x; + x=px; + VW_DrawPropString (string); + VW_MarkUpdateBlock(x,py,px-1,py+bufferheight-1); +} + + +void VWB_Bar (int x, int y, int width, int height, int color) +{ + if (VW_MarkUpdateBlock (x,y,x+width,y+height-1) ) + VW_Bar (x,y,width,height,color); +} + +void VWB_Plot (int x, int y, int color) +{ + if (VW_MarkUpdateBlock (x,y,x,y)) + VW_Plot(x,y,color); +} + +void VWB_Hlin (int x1, int x2, int y, int color) +{ + if (VW_MarkUpdateBlock (x1,y,x2,y)) + VW_Hlin(x1,x2,y,color); +} + +void VWB_Vlin (int y1, int y2, int x, int color) +{ + if (VW_MarkUpdateBlock (x,y1,x,y2)) + VW_Vlin(y1,y2,x,color); +} + +void VW_UpdateScreen (void) +{ + VH_UpdateScreen (); +} + + +/* +============================================================================= + + WOLFENSTEIN STUFF + +============================================================================= +*/ + +/* +===================== += += LatchDrawPic += +===================== +*/ + +void LatchDrawPic (unsigned x, unsigned y, unsigned picnum) +{ + unsigned wide, height, source; + + wide = pictable[picnum-STARTPICS].width; + height = pictable[picnum-STARTPICS].height; + source = latchpics[2+picnum-LATCHPICS_LUMP_START]; + + VL_LatchToScreen (source,wide/4,height,x*8,y); +} + + +//========================================================================== + +/* +=================== += += LoadLatchMem += +=================== +*/ + +void LoadLatchMem (void) +{ + int i,j,p,m,width,height,start,end; + byte far *src; + unsigned destoff; + +// +// tile 8s +// + latchpics[0] = freelatch; + CA_CacheGrChunk (STARTTILE8); + src = (byte _seg *)grsegs[STARTTILE8]; + destoff = freelatch; + + for (i=0;iwidth || y>height) + continue; + drawofs = source+ylookup[y] + (x>>2); + + // + // copy one pixel + // + mask = x&3; + VGAREADMAP(mask); + mask = maskb[mask]; + VGAMAPMASK(mask); + + asm mov di,[drawofs] + asm mov al,[es:di] + asm add di,[pagedelta] + asm mov [es:di],al + + if (rndval == 1) // entire sequence has been completed + return false; + } + frame++; + while (TimeCount 64) + controlx += (joyx-64)*JOYSCALE*tics; + else if (joyx < -64) + controlx -= (-joyx-64)*JOYSCALE*tics; + if (joyy > 64) + controlx += (joyy-64)*JOYSCALE*tics; + else if (joyy < -64) + controly -= (-joyy-64)*JOYSCALE*tics; + } + else if (buttonstate[bt_run]) + { + if (joyx > 64) + controlx += RUNMOVE*tics; + else if (joyx < -64) + controlx -= RUNMOVE*tics; + if (joyy > 64) + controly += RUNMOVE*tics; + else if (joyy < -64) + controly -= RUNMOVE*tics; + } + else + { + if (joyx > 64) + controlx += BASEMOVE*tics; + else if (joyx < -64) + controlx -= BASEMOVE*tics; + if (joyy > 64) + controly += BASEMOVE*tics; + else if (joyy < -64) + controly -= BASEMOVE*tics; + } +} + + +/* +=================== += += PollControls += += Gets user or demo input, call once each frame += += controlx set between -100 and 100 per tic += controly += buttonheld[] the state of the buttons LAST frame += buttonstate[] the state of the buttons THIS frame += +=================== +*/ + +void PollControls (void) +{ + int max,min,i; + byte buttonbits; + +// +// get timing info for last frame +// + if (demoplayback) + { + while (TimeCount>= 1; + } + + controlx = *demoptr++; + controly = *demoptr++; + + if (demoptr == lastdemoptr) + playstate = ex_completed; // demo is done + + controlx *= (int)tics; + controly *= (int)tics; + + return; + } + + +// +// get button states +// + PollKeyboardButtons (); + + if (mouseenabled) + PollMouseButtons (); + + if (joystickenabled) + PollJoystickButtons (); + +// +// get movements +// + PollKeyboardMove (); + + if (mouseenabled) + PollMouseMove (); + + if (joystickenabled) + PollJoystickMove (); + +// +// bound movement to a maximum +// + max = 100*tics; + min = -max; + if (controlx > max) + controlx = max; + else if (controlx < min) + controlx = min; + + if (controly > max) + controly = max; + else if (controly < min) + controly = min; + + if (demorecord) + { + // + // save info out to demo buffer + // + controlx /= (int)tics; + controly /= (int)tics; + + buttonbits = 0; + + for (i=NUMBUTTONS-1;i>=0;i--) + { + buttonbits <<= 1; + if (buttonstate[i]) + buttonbits |= 1; + } + + *demoptr++ = buttonbits; + *demoptr++ = controlx; + *demoptr++ = controly; + + if (demoptr >= lastdemoptr) + Quit ("Demo buffer overflowed!"); + + controlx *= (int)tics; + controly *= (int)tics; + } +} + + + +//========================================================================== + + + +/////////////////////////////////////////////////////////////////////////// +// +// CenterWindow() - Generates a window of a given width & height in the +// middle of the screen +// +/////////////////////////////////////////////////////////////////////////// + +#define MAXX 320 +#define MAXY 160 + +void CenterWindow(word w,word h) +{ + FixOfs (); + US_DrawWindow(((MAXX / 8) - w) / 2,((MAXY / 8) - h) / 2,w,h); +} + +//=========================================================================== + + +/* +===================== += += CheckKeys += +===================== +*/ + +void CheckKeys (void) +{ + int i; + byte scan; + unsigned temp; + + + if (screenfaded || demoplayback) // don't do anything with a faded screen + return; + + scan = LastScan; + + + #ifdef SPEAR + // + // SECRET CHEAT CODE: TAB-G-F10 + // + if (Keyboard[sc_Tab] && + Keyboard[sc_G] && + Keyboard[sc_F10]) + { + WindowH = 160; + if (godmode) + { + Message ("God mode OFF"); + SD_PlaySound (NOBONUSSND); + } + else + { + Message ("God mode ON"); + SD_PlaySound (ENDBONUS2SND); + } + + IN_Ack(); + godmode ^= 1; + DrawAllPlayBorderSides (); + IN_ClearKeysDown(); + return; + } + #endif + + + // + // SECRET CHEAT CODE: 'MLI' + // + if (Keyboard[sc_M] && + Keyboard[sc_L] && + Keyboard[sc_I]) + { + gamestate.health = 100; + gamestate.ammo = 99; + gamestate.keys = 3; + gamestate.score = 0; + gamestate.TimeCount += 42000L; + GiveWeapon (wp_chaingun); + + DrawWeapon(); + DrawHealth(); + DrawKeys(); + DrawAmmo(); + DrawScore(); + + ClearMemory (); + CA_CacheGrChunk (STARTFONT+1); + ClearSplitVWB (); + VW_ScreenToScreen (displayofs,bufferofs,80,160); + + Message(STR_CHEATER1"\n" + STR_CHEATER2"\n\n" + STR_CHEATER3"\n" + STR_CHEATER4"\n" + STR_CHEATER5); + + UNCACHEGRCHUNK(STARTFONT+1); + PM_CheckMainMem (); + IN_ClearKeysDown(); + IN_Ack(); + + DrawAllPlayBorder (); + } + + // + // OPEN UP DEBUG KEYS + // +#ifndef SPEAR + if (Keyboard[sc_BackSpace] && + Keyboard[sc_LShift] && + Keyboard[sc_Alt] && + MS_CheckParm("goobers")) +#else + if (Keyboard[sc_BackSpace] && + Keyboard[sc_LShift] && + Keyboard[sc_Alt] && + MS_CheckParm("debugmode")) +#endif + { + ClearMemory (); + CA_CacheGrChunk (STARTFONT+1); + ClearSplitVWB (); + VW_ScreenToScreen (displayofs,bufferofs,80,160); + + Message("Debugging keys are\nnow available!"); + UNCACHEGRCHUNK(STARTFONT+1); + PM_CheckMainMem (); + IN_ClearKeysDown(); + IN_Ack(); + + DrawAllPlayBorderSides (); + DebugOk=1; + } + + // + // TRYING THE KEEN CHEAT CODE! + // + if (Keyboard[sc_B] && + Keyboard[sc_A] && + Keyboard[sc_T]) + { + ClearMemory (); + CA_CacheGrChunk (STARTFONT+1); + ClearSplitVWB (); + VW_ScreenToScreen (displayofs,bufferofs,80,160); + + Message("Commander Keen is also\n" + "available from Apogee, but\n" + "then, you already know\n" + "that - right, Cheatmeister?!"); + + UNCACHEGRCHUNK(STARTFONT+1); + PM_CheckMainMem (); + IN_ClearKeysDown(); + IN_Ack(); + + DrawAllPlayBorder (); + } + +// +// pause key weirdness can't be checked as a scan code +// + if (Paused) + { + bufferofs = displayofs; + LatchDrawPic (20-4,80-2*8,PAUSEDPIC); + SD_MusicOff(); + IN_Ack(); + IN_ClearKeysDown (); + SD_MusicOn(); + Paused = false; + if (MousePresent) + Mouse(MDelta); // Clear accumulated mouse movement + return; + } + + +// +// F1-F7/ESC to enter control panel +// + if ( +#ifndef DEBCHECK + scan == sc_F10 || +#endif + scan == sc_F9 || + scan == sc_F7 || + scan == sc_F8) // pop up quit dialog + { + ClearMemory (); + ClearSplitVWB (); + VW_ScreenToScreen (displayofs,bufferofs,80,160); + US_ControlPanel(scan); + + DrawAllPlayBorderSides (); + + if (scan == sc_F9) + StartMusic (); + + PM_CheckMainMem (); + SETFONTCOLOR(0,15); + IN_ClearKeysDown(); + return; + } + + if ( (scan >= sc_F1 && scan <= sc_F9) || scan == sc_Escape) + { + StopMusic (); + ClearMemory (); + VW_FadeOut (); + + US_ControlPanel(scan); + + SETFONTCOLOR(0,15); + IN_ClearKeysDown(); + DrawPlayScreen (); + if (!startgame && !loadedgame) + { + VW_FadeIn (); + StartMusic (); + } + if (loadedgame) + playstate = ex_abort; + lasttimecount = TimeCount; + if (MousePresent) + Mouse(MDelta); // Clear accumulated mouse movement + PM_CheckMainMem (); + return; + } + +// +// TAB-? debug keys +// + if (Keyboard[sc_Tab] && DebugOk) + { + CA_CacheGrChunk (STARTFONT); + fontnumber=0; + SETFONTCOLOR(0,15); + DebugKeys(); + if (MousePresent) + Mouse(MDelta); // Clear accumulated mouse movement + lasttimecount = TimeCount; + return; + } + +} + + +//=========================================================================== + +/* +############################################################################# + + The objlist data structure + +############################################################################# + +objlist containt structures for every actor currently playing. The structure +is accessed as a linked list starting at *player, ending when ob->next == +NULL. GetNewObj inserts a new object at the end of the list, meaning that +if an actor spawn another actor, the new one WILL get to think and react the +same frame. RemoveObj unlinks the given object and returns it to the free +list, but does not damage the objects ->next pointer, so if the current object +removes itself, a linked list following loop can still safely get to the +next element. + + + +############################################################################# +*/ + + +/* +========================= += += InitActorList += += Call to clear out the actor object lists returning them all to the free += list. Allocates a special spot for the player. += +========================= +*/ + +int objcount; + +void InitActorList (void) +{ + int i; + +// +// init the actor lists +// + for (i=0;iprev; + memset (new,0,sizeof(*new)); + + if (lastobj) + lastobj->next = new; + new->prev = lastobj; // new->next is allready NULL from memset + + new->active = false; + lastobj = new; + + objcount++; +} + +//=========================================================================== + +/* +========================= += += RemoveObj += += Add the given object back into the free list, and unlink it from it's += neighbors += +========================= +*/ + +void RemoveObj (objtype *gone) +{ + objtype **spotat; + + if (gone == player) + Quit ("RemoveObj: Tried to remove the player!"); + + gone->state = NULL; + +// +// fix the next object's back link +// + if (gone == lastobj) + lastobj = (objtype *)gone->prev; + else + gone->next->prev = gone->prev; + +// +// fix the previous object's forward link +// + gone->prev->next = gone->next; + +// +// add it back in to the free list +// + gone->prev = objfreelist; + objfreelist = gone; + + objcount--; +} + +/* +============================================================================= + + MUSIC STUFF + +============================================================================= +*/ + + +/* +================= += += StopMusic += +================= +*/ + +void StopMusic(void) +{ + int i; + + SD_MusicOff(); + for (i = 0;i < LASTMUSIC;i++) + if (audiosegs[STARTMUSIC + i]) + { + MM_SetPurge(&((memptr)audiosegs[STARTMUSIC + i]),3); + MM_SetLock(&((memptr)audiosegs[STARTMUSIC + i]),false); + } +} + +//========================================================================== + + +/* +================= += += StartMusic += +================= +*/ + +void StartMusic(void) +{ + musicnames chunk; + + SD_MusicOff(); + chunk = songs[gamestate.mapon+gamestate.episode*10]; + +// if ((chunk == -1) || (MusicMode != smm_AdLib)) +//DEBUG control panel return; + + MM_BombOnError (false); + CA_CacheAudioChunk(STARTMUSIC + chunk); + MM_BombOnError (true); + if (mmerror) + mmerror = false; + else + { + MM_SetLock(&((memptr)audiosegs[STARTMUSIC + chunk]),true); + SD_StartMusic((MusicGroup far *)audiosegs[STARTMUSIC + chunk]); + } +} + + +/* +============================================================================= + + PALETTE SHIFTING STUFF + +============================================================================= +*/ + +#define NUMREDSHIFTS 6 +#define REDSTEPS 8 + +#define NUMWHITESHIFTS 3 +#define WHITESTEPS 20 +#define WHITETICS 6 + + +byte far redshifts[NUMREDSHIFTS][768]; +byte far whiteshifts[NUMREDSHIFTS][768]; + +int damagecount,bonuscount; +boolean palshifted; + +extern byte far gamepal; + +/* +===================== += += InitRedShifts += +===================== +*/ + +void InitRedShifts (void) +{ + byte far *workptr, far *baseptr; + int i,j,delta; + + +// +// fade through intermediate frames +// + for (i=1;i<=NUMREDSHIFTS;i++) + { + workptr = (byte far *)&redshifts[i-1][0]; + baseptr = &gamepal; + + for (j=0;j<=255;j++) + { + delta = 64-*baseptr; + *workptr++ = *baseptr++ + delta * i / REDSTEPS; + delta = -*baseptr; + *workptr++ = *baseptr++ + delta * i / REDSTEPS; + delta = -*baseptr; + *workptr++ = *baseptr++ + delta * i / REDSTEPS; + } + } + + for (i=1;i<=NUMWHITESHIFTS;i++) + { + workptr = (byte far *)&whiteshifts[i-1][0]; + baseptr = &gamepal; + + for (j=0;j<=255;j++) + { + delta = 64-*baseptr; + *workptr++ = *baseptr++ + delta * i / WHITESTEPS; + delta = 62-*baseptr; + *workptr++ = *baseptr++ + delta * i / WHITESTEPS; + delta = 0-*baseptr; + *workptr++ = *baseptr++ + delta * i / WHITESTEPS; + } + } +} + + +/* +===================== += += ClearPaletteShifts += +===================== +*/ + +void ClearPaletteShifts (void) +{ + bonuscount = damagecount = 0; +} + + +/* +===================== += += StartBonusFlash += +===================== +*/ + +void StartBonusFlash (void) +{ + bonuscount = NUMWHITESHIFTS*WHITETICS; // white shift palette +} + + +/* +===================== += += StartDamageFlash += +===================== +*/ + +void StartDamageFlash (int damage) +{ + damagecount += damage; +} + + +/* +===================== += += UpdatePaletteShifts += +===================== +*/ + +void UpdatePaletteShifts (void) +{ + int red,white; + + if (bonuscount) + { + white = bonuscount/WHITETICS +1; + if (white>NUMWHITESHIFTS) + white = NUMWHITESHIFTS; + bonuscount -= tics; + if (bonuscount < 0) + bonuscount = 0; + } + else + white = 0; + + + if (damagecount) + { + red = damagecount/10 +1; + if (red>NUMREDSHIFTS) + red = NUMREDSHIFTS; + + damagecount -= tics; + if (damagecount < 0) + damagecount = 0; + } + else + red = 0; + + if (red) + { + VW_WaitVBL(1); + VL_SetPalette (redshifts[red-1]); + palshifted = true; + } + else if (white) + { + VW_WaitVBL(1); + VL_SetPalette (whiteshifts[white-1]); + palshifted = true; + } + else if (palshifted) + { + VW_WaitVBL(1); + VL_SetPalette (&gamepal); // back to normal + palshifted = false; + } +} + + +/* +===================== += += FinishPaletteShifts += += Resets palette to normal if needed += +===================== +*/ + +void FinishPaletteShifts (void) +{ + if (palshifted) + { + palshifted = 0; + VW_WaitVBL(1); + VL_SetPalette (&gamepal); + } +} + + +/* +============================================================================= + + CORE PLAYLOOP + +============================================================================= +*/ + + +/* +===================== += += DoActor += +===================== +*/ + +void DoActor (objtype *ob) +{ + void (*think)(objtype *); + + if (!ob->active && !areabyplayer[ob->areanumber]) + return; + + if (!(ob->flags&(FL_NONMARK|FL_NEVERMARK)) ) + actorat[ob->tilex][ob->tiley] = NULL; + +// +// non transitional object +// + + if (!ob->ticcount) + { + think = ob->state->think; + if (think) + { + think (ob); + if (!ob->state) + { + RemoveObj (ob); + return; + } + } + + if (ob->flags&FL_NEVERMARK) + return; + + if ( (ob->flags&FL_NONMARK) && actorat[ob->tilex][ob->tiley]) + return; + + actorat[ob->tilex][ob->tiley] = ob; + return; + } + +// +// transitional object +// + ob->ticcount-=tics; + while ( ob->ticcount <= 0) + { + think = ob->state->action; // end of state action + if (think) + { + think (ob); + if (!ob->state) + { + RemoveObj (ob); + return; + } + } + + ob->state = ob->state->next; + + if (!ob->state) + { + RemoveObj (ob); + return; + } + + if (!ob->state->tictime) + { + ob->ticcount = 0; + goto think; + } + + ob->ticcount += ob->state->tictime; + } + +think: + // + // think + // + think = ob->state->think; + if (think) + { + think (ob); + if (!ob->state) + { + RemoveObj (ob); + return; + } + } + + if (ob->flags&FL_NEVERMARK) + return; + + if ( (ob->flags&FL_NONMARK) && actorat[ob->tilex][ob->tiley]) + return; + + actorat[ob->tilex][ob->tiley] = ob; +} + +//========================================================================== + + +/* +=================== += += PlayLoop += +=================== +*/ +long funnyticount; + + +void PlayLoop (void) +{ + int give; + int helmetangle; + + playstate = TimeCount = lasttimecount = 0; + frameon = 0; + running = false; + anglefrac = 0; + facecount = 0; + funnyticount = 0; + memset (buttonstate,0,sizeof(buttonstate)); + ClearPaletteShifts (); + + if (MousePresent) + Mouse(MDelta); // Clear accumulated mouse movement + + if (demoplayback) + IN_StartAck (); + + do + { + if (virtualreality) + { + helmetangle = peek (0x40,0xf0); + player->angle += helmetangle; + if (player->angle >= ANGLES) + player->angle -= ANGLES; + } + + + PollControls(); + +// +// actor thinking +// + madenoise = false; + + MoveDoors (); + MovePWalls (); + + for (obj = player;obj;obj = obj->next) + DoActor (obj); + + UpdatePaletteShifts (); + + ThreeDRefresh (); + + // + // MAKE FUNNY FACE IF BJ DOESN'T MOVE FOR AWHILE + // + #ifdef SPEAR + funnyticount += tics; + if (funnyticount > 30l*70) + { + funnyticount = 0; + StatusDrawPic (17,4,BJWAITING1PIC+(US_RndT()&1)); + facecount = 0; + } + #endif + + gamestate.TimeCount+=tics; + + SD_Poll (); + UpdateSoundLoc(); // JAB + + if (screenfaded) + VW_FadeIn (); + + CheckKeys(); + +// +// debug aids +// + if (singlestep) + { + VW_WaitVBL(14); + lasttimecount = TimeCount; + } + if (extravbls) + VW_WaitVBL(extravbls); + + if (demoplayback) + { + if (IN_CheckAck ()) + { + IN_ClearKeysDown (); + playstate = ex_abort; + } + } + + + if (virtualreality) + { + player->angle -= helmetangle; + if (player->angle < 0) + player->angle += ANGLES; + } + + }while (!playstate && !startgame); + + if (playstate != ex_died) + FinishPaletteShifts (); +} + diff --git a/16/sod8086/WOLF3D.SYM b/16/sod8086/WOLF3D.SYM new file mode 100755 index 0000000000000000000000000000000000000000..42dc7e28d8d3acde2ab45f01549f9380106ebc35 GIT binary patch literal 738039 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 32 Kbytes + cld +@@EnvLoop: + repnz scasb + jcxz InitFailed ; Bad environment !!! +IFDEF __BOSS__ + jmp InitOK +InitFailed: jmp near ptr _abort +InitOK: +ENDIF + + inc bx ; BX = Nb environment variables + cmp es:[di], al + jne @@EnvLoop ; Next variable ... + or ch, 10000000b + neg cx + mov _envLng@, cx ; Save Environment size + mov cx, dPtrSize / 2 + shl bx, cl + add bx, dPtrSize * 4 + and bx, not ((dPtrSize * 4) - 1) + mov _envSize@, bx ; Save Environment Variables Nb. + +IFNDEF __BOSS__ + +; Determine the amount of memory that we need to keep + +IFDEF _DSSTACK_ + mov dx, ds +ELSE + mov dx, ss +ENDIF + sub bp, dx ; BP = remaining size in paragraphs +IF LDATA + mov di, seg __stklen + mov es, di + mov di, es:__stklen ; DI = Requested stack size +ELSE + mov di, __stklen ; DI = Requested stack size +ENDIF +; +; Make sure that the requested stack size is at least MINSTACK words. +; + cmp di, 2*MINSTACK ; requested stack big enough ? + jae AskedStackOK + mov di, 2*MINSTACK ; no --> use minimal value +IF LDATA + mov es:__stklen, di ; override requested stack size +ELSE + mov __stklen, di ; override requested stack size +ENDIF + +AskedStackOK label near +IFDEF _DSSTACK_ + add di, offset DGROUP: edata@ + jb InitFailed ; DATA segment can NOT be > 64 Kbytes +ENDIF +IF LDATA EQ false + add di, __heaplen + jb InitFailed ; DATA segment can NOT be > 64 Kbytes +ENDIF + mov cl, 4 + shr di, cl ; $$$ Do not destroy CL $$$ + inc di ; DI = DS size in paragraphs + cmp bp, di +IF LDATA EQ false + jb InitFailed ; Not enough memory + cmp __stklen, 0 + je ExpandDS ; Expand DS up to 64 Kb + cmp __heaplen, 0 + jne ExcessOfMemory ; Much more available than needed +ExpandDS label near + mov di, 1000h + cmp bp, di + ja ExcessOfMemory ; Enough to run the program + mov di, bp + jmp short ExcessOfMemory ; Enough to run the program +ELSE + jnb ExcessOfMemory ; Much more available than needed +ENDIF + +; All initialization errors arrive here + +InitFailed label near + jmp near ptr _abort + +; Return to DOS the amount of memory in excess +; Set far heap base and pointer + +ExcessOfMemory label near + mov bx, di + add bx, dx + mov word ptr _heapbase@ + 2, bx + mov word ptr _brklvl@ + 2, bx + mov ax, _psp@ + sub bx, ax ; BX = Number of paragraphs to keep + mov es, ax ; ES = Program Segment Prefix address + mov ah, 04Ah + push di ; preserve DI + int 021h ; this call clobbers SI,DI,BP !!!!!! + pop di ; restore DI + + shl di, cl ; $$$ CX is still equal to 4 $$$ + + cli ; req'd for pre-1983 88/86s + mov ss, dx ; Set the program stack + mov sp, di + sti + +IFNDEF _DSSTACK_ + mov ax, seg __stklen + mov es, ax + mov es:__stklen, di ; If separate stack segment, save size +ENDIF + +ENDIF ; __BOSS__ + +IFNDEF __HUGE__ + +; Reset uninitialized data area + + xor ax, ax + mov es, cs:DGROUP@@ + mov di, offset DGROUP: bdata@ + mov cx, offset DGROUP: edata@ + sub cx, di + cld + rep stosb +ENDIF + +; If default number of file handles have changed then tell DOS + cmp __nfile, 20 + jbe @@NoChange + + cmp _osmajor@, 3 ; Check for >= DOS 3.3 + jb @@NoChange + ja @@DoChange + cmp _osminor@, 1Eh + jb @@NoChange +@@DoChange: + mov ax, 5801h ; Set last fit allocation + mov bx, 2 + int 21h + jc @@BadInit + + mov ah, 67h ; Expand handle table + mov bx, __nfile + int 21h + jc @@BadInit + + mov ah, 48h ; Allocate 16 bytes to find new + mov bx, 1 ; top of memory address + int 21h + jc @@BadInit + inc ax ; Adjust address to point after block + mov word ptr _heaptop@ + 2, ax + + dec ax ; Change back and release block + mov es, ax + mov ah, 49h + int 21h + jc @@BadInit + + mov ax, 5801h ; Set first fit allocation + mov bx, 0 + int 21h + jnc @@NoChange + +@@BadInit: jmp near ptr _abort + +@@NoChange: + +; Prepare main arguments + + mov ah, 0 + int 1ah ; get current BIOS time in ticks + mov word ptr _StartTime@,dx ; save it for clock() fn + mov word ptr _StartTime@+2,cx + or al,al ; was midnight flag set? + jz @@NotMidnight + mov ax,40h ; set BIOS midnight flag + mov es,ax ; at 40:70 + mov bx,70h + mov byte ptr es:[bx],1 + +@@NotMidnight: + xor bp,bp ; set BP to 0 for overlay mgr + + mov es, cs:DGROUP@@ + mov si,offset DGROUP:InitStart ;si = start of table + mov di,offset DGROUP:InitEnd ;di = end of table + call StartExit + +; ExitCode = main(argc,argv,envp); + +IF LDATA + push word ptr __C0environ+2 + push word ptr __C0environ + push word ptr __C0argv+2 + push word ptr __C0argv +ELSE + push word ptr __C0environ + push word ptr __C0argv +ENDIF + push __C0argc + call _main + +; Flush and close streams and files + + push ax + call _exit + +;--------------------------------------------------------------------------- +; _cleanup() call all #pragma exit cleanup routines. +; _checknull() check for null pointer zapping copyright message +; _terminate(int) exit program with error code +; +; These functions are called by exit(), _exit(), _cexit(), +; and _c_exit(). +;--------------------------------------------------------------------------- + +; Call cleanup routines + +__cleanup PROC DIST + PUBLIC __cleanup + + mov es, cs:DGROUP@@ + push si + push di + mov si,offset DGROUP:ExitStart + mov di,offset DGROUP:ExitEnd + call StartExit + pop di + pop si + ret +__cleanup ENDP + +; Check for null pointers before exit + +__checknull PROC DIST + PUBLIC __checknull + +IF LDATA EQ false + IFNDEF __TINY__ + push si + push di + mov es, cs:DGROUP@@ + xor ax, ax + mov si, ax + mov cx, lgth_CopyRight +ComputeChecksum label near + add al, es:[si] + adc ah, 0 + inc si + loop ComputeChecksum + sub ax, CheckSum + jz @@SumOk + mov cx, lgth_NullCheck + mov dx, offset DGROUP: NullCheck + call ErrorDisplay +@@SumOK: pop di + pop si + ENDIF +ENDIF + ret +__checknull ENDP + +; Exit to DOS + +__terminate PROC DIST + PUBLIC __terminate + mov bp,sp + mov ah,4Ch + mov al,[bp+cPtrSize] + int 21h ; Exit to DOS +__terminate ENDP + +STARTX ENDP + + SUBTTL Vector save/restore & default Zero divide routines + PAGE +;[]------------------------------------------------------------[] +;| | +;| Interrupt Save/Restore routines and default divide by zero | +;| handler. | +;| | +;[]------------------------------------------------------------[] + +ZeroDivision PROC FAR + mov cx, lgth_ZeroDivMSG + mov dx, offset DGROUP: ZeroDivMSG + jmp MsgExit3 +ZeroDivision ENDP + +;-------------------------------------------------------------------------- +; savevectors() +; +; Save vectors for 0, 4, 5 & 6 interrupts. This is for extended +; signal()/raise() support as the signal functions can steal these +; vectors during runtime. +;-------------------------------------------------------------------------- +SaveVectors PROC NEAR + push ds +; Save INT 0 + mov ax, 3500h + int 021h + mov word ptr _Int0Vector@, bx + mov word ptr _Int0Vector@+2, es +; Save INT 4 + mov ax, 3504h + int 021h + mov word ptr _Int4Vector@, bx + mov word ptr _Int4Vector@+2, es +; Save INT 5 + mov ax, 3505h + int 021h + mov word ptr _Int5Vector@, bx + mov word ptr _Int5Vector@+2, es +; Save INT 6 + mov ax, 3506h + int 021h + mov word ptr _Int6Vector@, bx + mov word ptr _Int6Vector@+2, es +; +; Install default divide by zero handler. +; + mov ax, 2500h + mov dx, cs + mov ds, dx + mov dx, offset ZeroDivision + int 21h + + pop ds + ret +SaveVectors ENDP + +;-------------------------------------------------------------------------- +; _restorezero() puts back all the vectors that SaveVectors took. +; +;NOTE : TSRs must BE AWARE that signal() functions which take these +; vectors will be deactivated if the keep() function is executed. +; If a TSR wants to use the signal functions when it is active it +; will have to save/restore these vectors itself when activated and +; deactivated. +;-------------------------------------------------------------------------- +__restorezero PROC DIST + PUBLIC __restorezero +IFDEF __HUGE__ + push ds + mov ds, cs: DGROUP@@ +ENDIF + push ds + mov ax, 2500h + lds dx, _Int0Vector@ + int 21h + pop ds + + push ds + mov ax, 2504h + lds dx, _Int4Vector@ + int 21h + pop ds + + push ds + mov ax, 2505h + lds dx, _Int5Vector@ + int 21h + pop ds + +IFNDEF __HUGE__ + push ds +ENDIF + mov ax, 2506h + lds dx, _Int6Vector@ + int 21h + pop ds + + ret + ENDP + +;------------------------------------------------------------------ +; Loop through a startup/exit (SE) table, +; calling functions in order of priority. +; ES:SI is assumed to point to the beginning of the SE table +; ES:DI is assumed to point to the end of the SE table +; First 64 priorities are reserved by Borland +;------------------------------------------------------------------ +PNEAR EQU 0 +PFAR EQU 1 +NOTUSED EQU 0ffh + +SE STRUC +calltype db ? ; 0=near,1=far,ff=not used +priority db ? ; 0=highest,ff=lowest +addrlow dw ? +addrhigh dw ? +SE ENDS + +StartExit proc near +@@Start: cmp si,offset DGROUP:InitStart ; startup or exit? + je @@StartLow ; it's startup + xor ah,ah ; start with high priority + jmp short @@SaveEnd +@@StartLow: mov ah,0ffh ;start with lowest priority +@@SaveEnd: mov dx,di ;set sentinel to end of table + mov bx,si ;bx = start of table + +@@TopOfTable: cmp bx,di ;and the end of the table? + je @@EndOfTable ;yes, exit the loop + cmp es:[bx.calltype],NOTUSED;check the call type + je @@Next + cmp si,offset DGROUP:InitStart ; startup or exit? + je @@CompareHigh ; it's startup + cmp ah,es:[bx.priority] ; it's exit + jmp short @@CheckPrior ; if priority too low, skip +@@CompareHigh: cmp es:[bx.priority],ah ;check the priority +@@CheckPrior: ja @@Next ;too high? skip + mov ah,es:[bx.priority] ;keep priority + mov dx,bx ;keep index in dx +@@Next: add bx,SIZE SE ;bx = next item in table + jmp @@TopOfTable + +@@EndOfTable: cmp dx,di ;did we exhaust the table? + je @@Done ;yes, quit + mov bx,dx ;bx = highest priority item + cmp es:[bx.calltype],PNEAR ;is it near or far? + mov es:[bx.calltype],NOTUSED;wipe the call type + push es ;save es + je @@NearCall + +@@FarCall: call DWORD PTR es:[bx.addrlow] + pop es ;restore es + jmp short @@Start + +@@NearCall: call WORD PTR es:[bx.addrlow] + pop es ;restore es + jmp short @@Start + +@@Done: ret + endp + +;------------------------------------------------------------------ + +ErrorDisplay PROC NEAR + mov ah, 040h + mov bx, 2 + int 021h + ret +ErrorDisplay ENDP + +_abort PROC DIST + PUBLIC _abort + mov cx, lgth_abortMSG + mov dx, offset DGROUP: abortMSG +MsgExit3 label near + mov ds, cs: DGROUP@@ + call ErrorDisplay +CallExit3 label near + mov ax, 3 + push ax + call __exit ; _exit(3); + ENDP + +; The DGROUP@ variable is used to reload DS with DGROUP + +PubSym@ DGROUP@, , __PASCAL__ + +IFDEF __BOSS__ +PubSym@ CSalias@,, __PASCAL__ +ENDIF + + +; __MMODEL is used to determine the memory model or the default +; pointer types at run time. + + public __MMODEL +__MMODEL dw MMODEL + +_TEXT ENDS + + SUBTTL Start Up Data Area + PAGE +;[]------------------------------------------------------------[] +;| Start Up Data Area | +;| | +;| WARNING Do not move any variables in the data | +;| segment unless you're absolutely sure | +;| that it does not matter. | +;[]------------------------------------------------------------[] + +_DATA SEGMENT + +; Magic symbol used by the debug info to locate the data segment + public DATASEG@ +DATASEG@ label byte + +; The CopyRight string must NOT be moved or changed without +; changing the null pointer check logic + +CopyRight db 4 dup(0) + db 'Borland C++ - Copyright 1991 Borland Intl.',0 +lgth_CopyRight equ $ - CopyRight + +IF LDATA EQ false +IFNDEF __TINY__ +CheckSum equ 00D5Ch +NullCheck db 'Null pointer assignment', 13, 10 +lgth_NullCheck equ $ - NullCheck +ENDIF +ENDIF + +ZeroDivMSG db 'Divide error', 13, 10 +lgth_ZeroDivMSG equ $ - ZeroDivMSG + +abortMSG db 'Abnormal program termination', 13, 10 +lgth_abortMSG equ $ - abortMSG + +; JAB - Added string for no 286 +no286MSG db 'Sorry, this program requires a 286 or better.', 13, 10 +lgth_no286MSG equ $ - no286MSG +; JAB - End of modifications + +; +; Interrupt vector save areas +; +; Interrupt vectors 0,4,5 & 6 are saved at startup and then restored +; when the program terminates. The signal/raise functions might +; steal these vectors during execution. +; +; Note: These vectors save area must not be altered +; without changing the save/restore logic. +; +PubSym@ _Int0Vector

, __CDECL__ +PubSym@ _Int4Vector
, __CDECL__ +PubSym@ _Int5Vector
, __CDECL__ +PubSym@ _Int6Vector
, __CDECL__ +; +; Miscellaneous variables +; +PubSym@ _C0argc, , __CDECL__ +dPtrPub@ _C0argv, 0, __CDECL__ +dPtrPub@ _C0environ, 0, __CDECL__ +PubSym@ _envLng, , __CDECL__ +PubSym@ _envseg, , __CDECL__ +PubSym@ _envSize, , __CDECL__ +PubSym@ _psp, , __CDECL__ +PubSym@ _version,
, __CDECL__ +PubSym@ _brklvl,
, __CDECL__ +PubSym@ _heaptop,
, __CDECL__ + +; If stack in DS and Large data model then override location of __emu + +IFDEF _DSSTACK_ +IF LDATA +public __emu +__emu db 044h DUP (0) + db 0CCh DUP (?) +ENDIF +ENDIF + +_DATA ENDS + + +_CVTSEG SEGMENT +PubSym@ _RealCvtVector,
, __CDECL__ +PubSym@ _Int4Vector
, __CDECL__ +PubSym@ _Int5Vector
, __CDECL__ +PubSym@ _Int6Vector
, __CDECL__ +; +; Miscellaneous variables +; +PubSym@ _C0argc, , __CDECL__ +dPtrPub@ _C0argv, 0, __CDECL__ +dPtrPub@ _C0environ, 0, __CDECL__ +PubSym@ _envLng, , __CDECL__ +PubSym@ _envseg, , __CDECL__ +PubSym@ _envSize, , __CDECL__ +PubSym@ _psp, , __CDECL__ +PubSym@ _version,
, __CDECL__ +PubSym@ _brklvl,
, __CDECL__ +PubSym@ _heaptop,
, __CDECL__ + +; If stack in DS and Large data model then override location of __emu + +IFDEF _DSSTACK_ +IF LDATA +public __emu +__emu db 044h DUP (0) + db 0CCh DUP (?) +ENDIF +ENDIF + +_DATA ENDS + + +_CVTSEG SEGMENT +PubSym@ _RealCvtVector,
, sName + ENDM + +dPtrPub@ MACRO Sym, VALUE, sName ;; Global Data Pointer +PubSym@ Sym,
, sName + ENDM + +dPtrExt@ MACRO Sym, sName ;; External Data Pointer +ExtSym@ Sym, DWORD, sName + ENDM +ELSE +DPTR_ equ WORD PTR +dPtrSize equ 2 +LES_ equ MOV +ES_ equ DS: +SS_ equ DS: +LDS_ equ MOV + +pushDS_ MACRO + ENDM + +popDS_ MACRO + ENDM + +PushPtr MACRO dPtrOff, dPtrSeg + PUSH dPtrOff + ENDM + +dPtr@ MACRO Sym, VALUE, sName ;; Static Data pointer +Static@ Sym, , sName + ENDM + +dPtrPub@ MACRO Sym, VALUE, sName ;; Global Data Pointer +PubSym@ Sym, , sName + ENDM + +dPtrExt@ MACRO Sym, sName ;; External Data Pointer +ExtSym@ Sym, WORD, sName + ENDM +ENDIF + PAGE +;[]------------------------------------------------------------[] +;| | +;| Macros which are Code Size Dependent | +;| | +;[]------------------------------------------------------------[] + +IF LPROG +CPTR_ equ DWORD PTR +cPtrSize equ 4 + +Proc@ MACRO Sym, sName ;; Open a Static function +Static@ Sym, , sName + ENDM + +PubProc@ MACRO Sym, sName ;; Open a Public function +PubSym@ Sym, , sName + ENDM + +ExtProc@ MACRO Sym, sName ;; External Function +ExtSym@ Sym, FAR, sName + ENDM + +cPtr@ MACRO Sym, VALUE, sName ;; Static Function pointer +Static@ Sym,
, sName + ENDM + +cPtrPub@ MACRO Sym, VALUE, sName;; Global Function Pointer +PubSym@ Sym,
, sName + ENDM + +cPtrExt@ MACRO Sym, sName ;; External Function Pointer +ExtSym@ Sym, DWORD, sName + ENDM +ELSE +CPTR_ equ WORD PTR +cPtrSize equ 2 + +Proc@ MACRO Sym, sName ;; Open a Static function +Static@ Sym, , sName + ENDM + +PubProc@ MACRO Sym, sName ;; Open a Public function +PubSym@ Sym, , sName + ENDM + +ExtProc@ MACRO Sym, sName ;; External Function +ExtSym@ Sym, NEAR, sName + ENDM + +cPtr@ MACRO Sym, VALUE, sName ;; Static Function pointer +Static@ Sym, , sName + ENDM + +cPtrPub@ MACRO Sym, VALUE, sName ;; Global Function Pointer +PubSym@ Sym, , sName + ENDM + +cPtrExt@ MACRO Sym, sName ;; External Function Pointer +ExtSym@ Sym, WORD, sName + ENDM +ENDIF + +EndProc@ MACRO Sym, sName ;; Close a function +Static@ Sym, ENDP, sName + ENDM + + PAGE +;[]------------------------------------------------------------[] +;| | +;| Miscellaneous Definitions | +;| | +;[]------------------------------------------------------------[] + +;*** Set up some macros for procedure parameters and export/import + +nearCall STRUC +nearBP dw ? +nearIP dw ? +nearParam dw ? +nearCall ENDS + +farCall STRUC +farBP dw ? +farCSIP dd ? +aParam dw ? +farCall ENDS + +;*** Next, we define some convenient structures to access the parts +; of larger objects. + +_twoBytes STRUC +BY0 db ? +BY1 db ? +_twoBytes ENDS + +_fourWords STRUC +W0 dw ? +W1 dw ? +W2 dw ? +W3 dw ? +_fourWords ENDS + +_twoDwords STRUC +DD0 dd ? +DD1 dd ? +_twoDwords ENDS + +_aFloat STRUC +double dq ? +_aFloat ENDS + +; How to invoke MSDOS. + +MSDOS@ MACRO + int 21h + ENDM + PAGE + +; The next section concerns the use of registers. SI and DI are used +; for register variables, and must be conserved. + +; Registers AX, BX, CX, DX will not be preserved across function calls. + +; Firstly, the registers to be conserved through function calls, including +; the setup of local variables. + +link@ MACRO _si,_di,_ES,locals + push bp + mov bp, sp + IFNB + lea sp, locals + ENDIF + IFNB <_si> + push si + ENDIF + IFNB <_di> + push di + ENDIF +ENDM + +unLink@ MACRO _si,_di,_ES,locals + IFNB <_di> + pop di + ENDIF + IFNB <_si> + pop si + ENDIF + IFNB + mov sp, bp + ENDIF + pop bp +ENDM + +.LIST diff --git a/16/sod8086/sdmver.h b/16/sod8086/sdmver.h new file mode 100755 index 00000000..e5f48728 --- /dev/null +++ b/16/sod8086/sdmver.h @@ -0,0 +1,8 @@ +#define SPEAR +#define SPEARDEMO +#define ARTSEXTERN +#define DEMOSEXTERN +#define CARMACIZED +//#define MYPROFILE +//#define DEBCHECK +//#define UPLOAD diff --git a/16/sod8086/sharemsg.h b/16/sod8086/sharemsg.h new file mode 100755 index 00000000..39c27974 --- /dev/null +++ b/16/sod8086/sharemsg.h @@ -0,0 +1,9 @@ +"This game is shareware.\n" +"Share it with everyone.\n" +"Thanks.\n\n" +" Id Software\n" + +"This game is NOT shareware.\n" +"Please do not distribute it.\n" +"Thanks.\n\n" +" Id Software\n" diff --git a/16/sod8086/spanish.h b/16/sod8086/spanish.h new file mode 100755 index 00000000..361ca499 --- /dev/null +++ b/16/sod8086/spanish.h @@ -0,0 +1,112 @@ +#define QUITSUR "Estas seguro que quieres\n"\ + "parar este gran juego?" + +#define CURGAME "Ahora estas en\n"\ + "un juego. Si continuas\n"\ + "borras el juego viejo. O.K.?" + +#define GAMESVD "Ya hay un juego\n"\ + "guardado en esta posicion.\n"\ + "sobre-escribir?" + +#define ENDGAMESTR "Estas seguro que quieres\n"\ + "terminar el juego que\n"\ + "estas jugando? (S o N):" + +#define STR_NG "Juego nuevo" +#define STR_SD "Sonido" +#define STR_CL "Control" +#define STR_LG "Cargar juego" +#define STR_SG "Guardar juego" +#define STR_CV "Cambiar vista" +#define STR_VS "Ver anotacion" +#define STR_EG "Abandonar" +#define STR_BD "Regresar al demo" +#define STR_QT "Parar" + +#define STR_LOADING "Cargando" +#define STR_SAVING "Guardando" + +#define STR_GAME "Regresar, jugar" +#define STR_DEMO "Regresar al Demo" +#define STR_LGC "Cargar juego llamado\n\"" +#define STR_EMPTY "vacio" +#define STR_CALIB "Calibrar" +#define STR_JOYST "Joystick" +#define STR_MOVEJOY "Mover joystick a\n"\ + "arriba izq y\n"\ + "oprimir boton 0\n" +#define STR_MOVEJOY2 "Mover joystick a\n"\ + "abajo derecha y\n"\ + "oprimir boton 1\n" +#define STR_ESCEXIT "ESC para salir" +#define STR_NONE "Ninguno" +#define STR_PC "P.C. bocina" +#define STR_ALSB "AdLib/Sound Blaster" +#define STR_DISNEY "Disney Sound Source" +#define STR_SB "Sound Blaster" + +#define STR_MOUSEEN "Raton activado" +#define STR_JOYEN "Joystick activado" +#define STR_PORT2 "Use joystick puerto 2" +#define STR_GAMEPAD "Gravis Gamepad Activada" +#define STR_SENS "Raton Sensibilidad" +#define STR_CUSTOM "Modificar controles" +#define STR_DADDY "Papi puedo jugar?" +#define STR_HURTME "No me hieras." +#define STR_BRINGEM "­Echamelos!" +#define STR_DEATH "La muerte encarnada" + +#define STR_MOUSEADJ "Raton ajustar sensibilidad" +#define STR_SLOW "Lento" +#define STR_FAST "Rapido" + +#define STR_CRUN "Corre" +#define STR_COPEN "Abre" +#define STR_CFIRE "Fuego" +#define STR_CSTRAFE "Ametrallar" + +#define STR_LEFT "Izquierda" +#define STR_RIGHT "Derecha" +#define STR_FRWD "Adelante" +#define STR_BKWD "Atras" +#define STR_THINK "Pensando" + +#define STR_SIZE1 "Use flechas para ajustar" +#define STR_SIZE2 "Enter para aceptar" +#define STR_SIZE3 "Esc para cancelar" + +#define STR_YOUWIN "Tu ganas" + +#define STR_TOTALTIME "Tiempo total" + +#define STR_RATKILL "Muertes %" +#define STR_RATSECRET "Secreto %" +#define STR_RATTREASURE "Tesoros %" + +#define STR_BONUS "Bono" +#define STR_TIME "Tiempo" +#define STR_PAR "Par" + +#define STR_RAT2KILL "Muertes %" // ratio = promedio +#define STR_RAT2SECRET "Secreto %" +#define STR_RAT2TREASURE "Tesoros %" + +#define STR_DEFEATED "Derrotado!" + +#define STR_CHEATER1 "Ahora tienes 100% salud" +#define STR_CHEATER2 "99 balas y dos llaves" +#define STR_CHEATER3 "Notar que has basicamente" +#define STR_CHEATER4 "eliminado tus chances de" +#define STR_CHEATER5 "obtener puntos altos" + +#define STR_NOSPACE1 "No hay suficiente espacio" +#define STR_NOSPACE2 "en tu disco para guardar juego" + +#define STR_SAVECHT1 "Tu archivo para guardar juego es" +#define STR_SAVECHT2 "diremos,\"corrupto\"." +#define STR_SAVECHT3 "Pero te dire, sigue y" +#define STR_SAVECHT4 "de todos modos juega" + +#define STR_SEEAGAIN "Veamos eso de nuevo" + diff --git a/16/sod8086/spanver.h b/16/sod8086/spanver.h new file mode 100755 index 00000000..b0f3f62b --- /dev/null +++ b/16/sod8086/spanver.h @@ -0,0 +1,8 @@ +//#define SPEAR +#define SPANISH +#define ARTSEXTERN +#define DEMOSEXTERN +//#define MYPROFILE +//#define DEBCHECK +#define CARMACIZED +//#define UPLOAD diff --git a/16/sod8086/sv.exe b/16/sod8086/sv.exe new file mode 100755 index 0000000000000000000000000000000000000000..72d3ff022660dc7c8740c9a819fd7559621977cf GIT binary patch literal 6746 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 literal 0 HcmV?d00001 diff --git a/16/sod8086/version.h b/16/sod8086/version.h new file mode 100755 index 00000000..b964b80b --- /dev/null +++ b/16/sod8086/version.h @@ -0,0 +1,7 @@ +#define SPEAR +#define ARTSEXTERN +#define DEMOSEXTERN +#define CARMACIZED +//#define MYPROFILE +//#define DEBCHECK +//#define UPLOAD diff --git a/16/sod8086/wf3dver.h b/16/sod8086/wf3dver.h new file mode 100755 index 00000000..05abb0e5 --- /dev/null +++ b/16/sod8086/wf3dver.h @@ -0,0 +1,10 @@ +//#define SPEAR +//#define JAPAN +#define GOODTIMES +#define ARTSEXTERN +#define DEMOSEXTERN +//#define MYPROFILE +//#define DEBCHECK +#define CARMACIZED +//#define UPLOAD + \ No newline at end of file diff --git a/16/sod8086/whack_a.asm b/16/sod8086/whack_a.asm new file mode 100755 index 00000000..45fd0980 --- /dev/null +++ b/16/sod8086/whack_a.asm @@ -0,0 +1,112 @@ +; WOLFHACK.ASM + +.386C +IDEAL +MODEL MEDIUM,C + + +;============================================================================ + +DATASEG + +EXTRN mr_rowofs:WORD +EXTRN mr_count:WORD +EXTRN mr_xstep:WORD +EXTRN mr_ystep:WORD +EXTRN mr_xfrac:WORD +EXTRN mr_yfrac:WORD +EXTRN mr_dest:WORD + +FARDATA + +planepics db 8192 dup(?) ; // 4k of ceiling, 4k of floor +PUBLIC planepics + + +;============================================================================ + +CODESEG + +;============================ +; +; MapRow +; +; +;============================ + +PROC MapRow +PUBLIC MapRow + push esi + push edi + push ebp + push ds + + mov bp,[mr_rowofs] + mov cx,[mr_count] + mov dx,[mr_ystep] + ;begin 8086 hack + ;shl edx,16 + push cx + mov cl,16 + shl edx,cl + pop cx + ;end 8086 hack + mov dx,[mr_xstep] + mov si,[mr_yfrac] + ;begin 8086 hack + ;shl esi,16 + push cx + mov cl,16 + shl esi,cl + pop cx + ;end 8086 hack + mov si,[mr_xfrac] + mov di,[mr_dest] + mov ax,SEG planepics + mov ds,ax + mov ax,0a000h + mov es,ax + mov ax,1111111111110b + +; eax color lookup +; ebx scratch offset and pixel values +; ecx loop counter +; edx packed x / y step values +; esi packed x / y fractional values +; edi write pointer +; ebp toprow to bottomrow delta +; es: screenseg +; ds: pictures + +; mov al,[esi] +; mov al,[eax] +; mov [edi],al + +; mov ax,[_variable+ebx+2] + + +pixelloop: + shld ebx,esi,22 ; shift y units in + shld ebx,esi,7 ; shift x units in and one extra bit + and bx,63*65*2 ; mask off extra top bits and 0 low bit + add esi,edx ; position += step + mov al,[bx] + mov al,[eax] + mov [es:di],al ; write ceiling pixel + mov al,[bx+1] + mov al,[eax] + mov [es:di+bp],al ; write floor pixel + inc di + loop pixelloop + + pop ds + pop ebp + pop edi + pop esi + + retf + +ENDP + +END + diff --git a/16/sod8086/wl_act1.c b/16/sod8086/wl_act1.c new file mode 100755 index 00000000..10d84e4e --- /dev/null +++ b/16/sod8086/wl_act1.c @@ -0,0 +1,900 @@ +// WL_ACT1.C + +#include "WL_DEF.H" +#pragma hdrstop + +/* +============================================================================= + + STATICS + +============================================================================= +*/ + + +statobj_t statobjlist[MAXSTATS],*laststatobj; + + +struct +{ + int picnum; + stat_t type; +} statinfo[] = +{ +{SPR_STAT_0}, // puddle spr1v +{SPR_STAT_1,block}, // Green Barrel " +{SPR_STAT_2,block}, // Table/chairs " +{SPR_STAT_3,block}, // Floor lamp " +{SPR_STAT_4}, // Chandelier " +{SPR_STAT_5,block}, // Hanged man " +{SPR_STAT_6,bo_alpo}, // Bad food " +{SPR_STAT_7,block}, // Red pillar " +// +// NEW PAGE +// +{SPR_STAT_8,block}, // Tree spr2v +{SPR_STAT_9}, // Skeleton flat " +{SPR_STAT_10,block}, // Sink " (SOD:gibs) +{SPR_STAT_11,block}, // Potted plant " +{SPR_STAT_12,block}, // Urn " +{SPR_STAT_13,block}, // Bare table " +{SPR_STAT_14}, // Ceiling light " +#ifndef SPEAR +{SPR_STAT_15}, // Kitchen stuff " +#else +{SPR_STAT_15,block}, // Gibs! +#endif +// +// NEW PAGE +// +{SPR_STAT_16,block}, // suit of armor spr3v +{SPR_STAT_17,block}, // Hanging cage " +{SPR_STAT_18,block}, // SkeletoninCage " +{SPR_STAT_19}, // Skeleton relax " +{SPR_STAT_20,bo_key1}, // Key 1 " +{SPR_STAT_21,bo_key2}, // Key 2 " +{SPR_STAT_22,block}, // stuff (SOD:gibs) +{SPR_STAT_23}, // stuff +// +// NEW PAGE +// +{SPR_STAT_24,bo_food}, // Good food spr4v +{SPR_STAT_25,bo_firstaid}, // First aid " +{SPR_STAT_26,bo_clip}, // Clip " +{SPR_STAT_27,bo_machinegun}, // Machine gun " +{SPR_STAT_28,bo_chaingun}, // Gatling gun " +{SPR_STAT_29,bo_cross}, // Cross " +{SPR_STAT_30,bo_chalice}, // Chalice " +{SPR_STAT_31,bo_bible}, // Bible " +// +// NEW PAGE +// +{SPR_STAT_32,bo_crown}, // crown spr5v +{SPR_STAT_33,bo_fullheal}, // one up " +{SPR_STAT_34,bo_gibs}, // gibs " +{SPR_STAT_35,block}, // barrel " +{SPR_STAT_36,block}, // well " +{SPR_STAT_37,block}, // Empty well " +{SPR_STAT_38,bo_gibs}, // Gibs 2 " +{SPR_STAT_39,block}, // flag " +// +// NEW PAGE +// +#ifndef SPEAR +{SPR_STAT_40,block}, // Call Apogee spr7v +#else +{SPR_STAT_40}, // Red light +#endif +// +// NEW PAGE +// +{SPR_STAT_41}, // junk " +{SPR_STAT_42}, // junk " +{SPR_STAT_43}, // junk " +#ifndef SPEAR +{SPR_STAT_44}, // pots " +#else +{SPR_STAT_44,block}, // Gibs! +#endif +{SPR_STAT_45,block}, // stove " (SOD:gibs) +{SPR_STAT_46,block}, // spears " (SOD:gibs) +{SPR_STAT_47}, // vines " +// +// NEW PAGE +// +#ifdef SPEAR +{SPR_STAT_48,block}, // marble pillar +{SPR_STAT_49,bo_25clip}, // bonus 25 clip +{SPR_STAT_50,block}, // truck +{SPR_STAT_51,bo_spear}, // SPEAR OF DESTINY! +#endif + +{SPR_STAT_26,bo_clip2}, // Clip " +{-1} // terminator +}; + +/* +=============== += += InitStaticList += +=============== +*/ + +void InitStaticList (void) +{ + laststatobj = &statobjlist[0]; +} + + + +/* +=============== += += SpawnStatic += +=============== +*/ + +void SpawnStatic (int tilex, int tiley, int type) +{ + laststatobj->shapenum = statinfo[type].picnum; + laststatobj->tilex = tilex; + laststatobj->tiley = tiley; + laststatobj->visspot = &spotvis[tilex][tiley]; + + switch (statinfo[type].type) + { + case block: + (unsigned)actorat[tilex][tiley] = 1; // consider it a blocking tile + case dressing: + laststatobj->flags = 0; + break; + + case bo_cross: + case bo_chalice: + case bo_bible: + case bo_crown: + case bo_fullheal: + if (!loadedgame) + gamestate.treasuretotal++; + + case bo_firstaid: + case bo_key1: + case bo_key2: + case bo_key3: + case bo_key4: + case bo_clip: + case bo_25clip: + case bo_machinegun: + case bo_chaingun: + case bo_food: + case bo_alpo: + case bo_gibs: + case bo_spear: + laststatobj->flags = FL_BONUS; + laststatobj->itemnumber = statinfo[type].type; + break; + } + + laststatobj++; + + if (laststatobj == &statobjlist[MAXSTATS]) + Quit ("Too many static objects!\n"); +} + + +/* +=============== += += PlaceItemType += += Called during game play to drop actors' items. It finds the proper += item number based on the item type (bo_???). If there are no free item += spots, nothing is done. += +=============== +*/ + +void PlaceItemType (int itemtype, int tilex, int tiley) +{ + int type; + statobj_t *spot; + +// +// find the item number +// + for (type=0 ; ; type++) + { + if (statinfo[type].picnum == -1) // end of list + Quit ("PlaceItemType: couldn't find type!"); + if (statinfo[type].type == itemtype) + break; + } + +// +// find a spot in statobjlist to put it in +// + for (spot=&statobjlist[0] ; ; spot++) + { + if (spot==laststatobj) + { + if (spot == &statobjlist[MAXSTATS]) + return; // no free spots + laststatobj++; // space at end + break; + } + + if (spot->shapenum == -1) // -1 is a free spot + break; + } +// +// place it +// + spot->shapenum = statinfo[type].picnum; + spot->tilex = tilex; + spot->tiley = tiley; + spot->visspot = &spotvis[tilex][tiley]; + spot->flags = FL_BONUS; + spot->itemnumber = statinfo[type].type; +} + + + +/* +============================================================================= + + DOORS + +doorobjlist[] holds most of the information for the doors + +doorposition[] holds the amount the door is open, ranging from 0 to 0xffff + this is directly accessed by AsmRefresh during rendering + +The number of doors is limited to 64 because a spot in tilemap holds the + door number in the low 6 bits, with the high bit meaning a door center + and bit 6 meaning a door side tile + +Open doors conect two areas, so sounds will travel between them and sight + will be checked when the player is in a connected area. + +Areaconnect is incremented/decremented by each door. If >0 they connect + +Every time a door opens or closes the areabyplayer matrix gets recalculated. + An area is true if it connects with the player's current spor. + +============================================================================= +*/ + +#define DOORWIDTH 0x7800 +#define OPENTICS 300 + +doorobj_t doorobjlist[MAXDOORS],*lastdoorobj; +int doornum; + +unsigned doorposition[MAXDOORS]; // leading edge of door 0=closed + // 0xffff = fully open + +byte far areaconnect[NUMAREAS][NUMAREAS]; + +boolean areabyplayer[NUMAREAS]; + + +/* +============== += += ConnectAreas += += Scans outward from playerarea, marking all connected areas += +============== +*/ + +void RecursiveConnect (int areanumber) +{ + int i; + + for (i=0;iareanumber] = true; + RecursiveConnect (player->areanumber); +} + + +void InitAreas (void) +{ + memset (areabyplayer,0,sizeof(areabyplayer)); + areabyplayer[player->areanumber] = true; +} + + + +/* +=============== += += InitDoorList += +=============== +*/ + +void InitDoorList (void) +{ + memset (areabyplayer,0,sizeof(areabyplayer)); + _fmemset (areaconnect,0,sizeof(areaconnect)); + + lastdoorobj = &doorobjlist[0]; + doornum = 0; +} + + +/* +=============== += += SpawnDoor += +=============== +*/ + +void SpawnDoor (int tilex, int tiley, boolean vertical, int lock) +{ + int areanumber; + unsigned far *map; + + if (doornum==64) + Quit ("64+ doors on level!"); + + doorposition[doornum] = 0; // doors start out fully closed + lastdoorobj->tilex = tilex; + lastdoorobj->tiley = tiley; + lastdoorobj->vertical = vertical; + lastdoorobj->lock = lock; + lastdoorobj->action = dr_closed; + + (unsigned)actorat[tilex][tiley] = doornum | 0x80; // consider it a solid wall + +// +// make the door tile a special tile, and mark the adjacent tiles +// for door sides +// + tilemap[tilex][tiley] = doornum | 0x80; + map = mapsegs[0] + farmapylookup[tiley]+tilex; + if (vertical) + { + *map = *(map-1); // set area number + tilemap[tilex][tiley-1] |= 0x40; + tilemap[tilex][tiley+1] |= 0x40; + } + else + { + *map = *(map-mapwidth); // set area number + tilemap[tilex-1][tiley] |= 0x40; + tilemap[tilex+1][tiley] |= 0x40; + } + + doornum++; + lastdoorobj++; +} + +//=========================================================================== + +/* +===================== += += OpenDoor += +===================== +*/ + +void OpenDoor (int door) +{ + if (doorobjlist[door].action == dr_open) + doorobjlist[door].ticcount = 0; // reset open time + else + doorobjlist[door].action = dr_opening; // start it opening +} + + +/* +===================== += += CloseDoor += +===================== +*/ + +void CloseDoor (int door) +{ + int tilex,tiley,area; + objtype *check; + +// +// don't close on anything solid +// + tilex = doorobjlist[door].tilex; + tiley = doorobjlist[door].tiley; + + if (actorat[tilex][tiley]) + return; + + if (player->tilex == tilex && player->tiley == tiley) + return; + + if (doorobjlist[door].vertical) + { + if ( player->tiley == tiley ) + { + if ( ((player->x+MINDIST) >>TILESHIFT) == tilex ) + return; + if ( ((player->x-MINDIST) >>TILESHIFT) == tilex ) + return; + } + check = actorat[tilex-1][tiley]; + if (check && ((check->x+MINDIST) >> TILESHIFT) == tilex ) + return; + check = actorat[tilex+1][tiley]; + if (check && ((check->x-MINDIST) >> TILESHIFT) == tilex ) + return; + } + else if (!doorobjlist[door].vertical) + { + if (player->tilex == tilex) + { + if ( ((player->y+MINDIST) >>TILESHIFT) == tiley ) + return; + if ( ((player->y-MINDIST) >>TILESHIFT) == tiley ) + return; + } + check = actorat[tilex][tiley-1]; + if (check && ((check->y+MINDIST) >> TILESHIFT) == tiley ) + return; + check = actorat[tilex][tiley+1]; + if (check && ((check->y-MINDIST) >> TILESHIFT) == tiley ) + return; + } + + +// +// play door sound if in a connected area +// + area = *(mapsegs[0] + farmapylookup[doorobjlist[door].tiley] + +doorobjlist[door].tilex)-AREATILE; + if (areabyplayer[area]) + { + PlaySoundLocTile(CLOSEDOORSND,doorobjlist[door].tilex,doorobjlist[door].tiley); // JAB + } + + doorobjlist[door].action = dr_closing; +// +// make the door space solid +// + (unsigned)actorat[tilex][tiley] + = door | 0x80; +} + + + +/* +===================== += += OperateDoor += += The player wants to change the door's direction += +===================== +*/ + +void OperateDoor (int door) +{ + int lock; + + lock = doorobjlist[door].lock; + if (lock >= dr_lock1 && lock <= dr_lock4) + { + if ( ! (gamestate.keys & (1 << (lock-dr_lock1) ) ) ) + { + SD_PlaySound (NOWAYSND); // locked + return; + } + } + + switch (doorobjlist[door].action) + { + case dr_closed: + case dr_closing: + OpenDoor (door); + break; + case dr_open: + case dr_opening: + CloseDoor (door); + break; + } +} + + +//=========================================================================== + +/* +=============== += += DoorOpen += += Close the door after three seconds += +=============== +*/ + +void DoorOpen (int door) +{ + if ( (doorobjlist[door].ticcount += tics) >= OPENTICS) + CloseDoor (door); +} + + + +/* +=============== += += DoorOpening += +=============== +*/ + +void DoorOpening (int door) +{ + int area1,area2; + unsigned far *map; + long position; + + position = doorposition[door]; + if (!position) + { + // + // door is just starting to open, so connect the areas + // + map = mapsegs[0] + farmapylookup[doorobjlist[door].tiley] + +doorobjlist[door].tilex; + + if (doorobjlist[door].vertical) + { + area1 = *(map+1); + area2 = *(map-1); + } + else + { + area1 = *(map-mapwidth); + area2 = *(map+mapwidth); + } + area1 -= AREATILE; + area2 -= AREATILE; + areaconnect[area1][area2]++; + areaconnect[area2][area1]++; + ConnectAreas (); + if (areabyplayer[area1]) + { + PlaySoundLocTile(OPENDOORSND,doorobjlist[door].tilex,doorobjlist[door].tiley); // JAB + } + } + +// +// slide the door by an adaptive amount +// + position += tics<<10; + if (position >= 0xffff) + { + // + // door is all the way open + // + position = 0xffff; + doorobjlist[door].ticcount = 0; + doorobjlist[door].action = dr_open; + actorat[doorobjlist[door].tilex][doorobjlist[door].tiley] = 0; + } + + doorposition[door] = position; +} + + +/* +=============== += += DoorClosing += +=============== +*/ + +void DoorClosing (int door) +{ + int area1,area2,move; + unsigned far *map; + long position; + int tilex,tiley; + + tilex = doorobjlist[door].tilex; + tiley = doorobjlist[door].tiley; + + if ( ((unsigned)actorat[tilex][tiley] != (door | 0x80)) + || (player->tilex == tilex && player->tiley == tiley) ) + { // something got inside the door + OpenDoor (door); + return; + }; + + position = doorposition[door]; + +// +// slide the door by an adaptive amount +// + position -= tics<<10; + if (position <= 0) + { + // + // door is closed all the way, so disconnect the areas + // + position = 0; + + doorobjlist[door].action = dr_closed; + + map = mapsegs[0] + farmapylookup[doorobjlist[door].tiley] + +doorobjlist[door].tilex; + + if (doorobjlist[door].vertical) + { + area1 = *(map+1); + area2 = *(map-1); + } + else + { + area1 = *(map-mapwidth); + area2 = *(map+mapwidth); + } + area1 -= AREATILE; + area2 -= AREATILE; + areaconnect[area1][area2]--; + areaconnect[area2][area1]--; + + ConnectAreas (); + } + + doorposition[door] = position; +} + + + + +/* +===================== += += MoveDoors += += Called from PlayLoop += +===================== +*/ + +void MoveDoors (void) +{ + int door; + + if (gamestate.victoryflag) // don't move door during victory sequence + return; + + for (door = 0 ; door < doornum ; door++) + switch (doorobjlist[door].action) + { + case dr_open: + DoorOpen (door); + break; + + case dr_opening: + DoorOpening(door); + break; + + case dr_closing: + DoorClosing(door); + break; + } +} + + +/* +============================================================================= + + PUSHABLE WALLS + +============================================================================= +*/ + +unsigned pwallstate; +unsigned pwallpos; // amount a pushable wall has been moved (0-63) +unsigned pwallx,pwally; +int pwalldir; + +/* +=============== += += PushWall += +=============== +*/ + +void PushWall (int checkx, int checky, int dir) +{ + int oldtile; + + if (pwallstate) + return; + + + oldtile = tilemap[checkx][checky]; + if (!oldtile) + return; + + switch (dir) + { + case di_north: + if (actorat[checkx][checky-1]) + { + SD_PlaySound (NOWAYSND); + return; + } + (unsigned)actorat[checkx][checky-1] = + tilemap[checkx][checky-1] = oldtile; + break; + + case di_east: + if (actorat[checkx+1][checky]) + { + SD_PlaySound (NOWAYSND); + return; + } + (unsigned)actorat[checkx+1][checky] = + tilemap[checkx+1][checky] = oldtile; + break; + + case di_south: + if (actorat[checkx][checky+1]) + { + SD_PlaySound (NOWAYSND); + return; + } + (unsigned)actorat[checkx][checky+1] = + tilemap[checkx][checky+1] = oldtile; + break; + + case di_west: + if (actorat[checkx-1][checky]) + { + SD_PlaySound (NOWAYSND); + return; + } + (unsigned)actorat[checkx-1][checky] = + tilemap[checkx-1][checky] = oldtile; + break; + } + + gamestate.secretcount++; + pwallx = checkx; + pwally = checky; + pwalldir = dir; + pwallstate = 1; + pwallpos = 0; + tilemap[pwallx][pwally] |= 0xc0; + *(mapsegs[1]+farmapylookup[pwally]+pwallx) = 0; // remove P tile info + + SD_PlaySound (PUSHWALLSND); +} + + + +/* +================= += += MovePWalls += +================= +*/ + +void MovePWalls (void) +{ + int oldblock,oldtile; + + if (!pwallstate) + return; + + oldblock = pwallstate/128; + + pwallstate += tics; + + if (pwallstate/128 != oldblock) + { + // block crossed into a new block + oldtile = tilemap[pwallx][pwally] & 63; + + // + // the tile can now be walked into + // + tilemap[pwallx][pwally] = 0; + (unsigned)actorat[pwallx][pwally] = 0; + *(mapsegs[0]+farmapylookup[pwally]+pwallx) = player->areanumber+AREATILE; + + // + // see if it should be pushed farther + // + if (pwallstate>256) + { + // + // the block has been pushed two tiles + // + pwallstate = 0; + return; + } + else + { + switch (pwalldir) + { + case di_north: + pwally--; + if (actorat[pwallx][pwally-1]) + { + pwallstate = 0; + return; + } + (unsigned)actorat[pwallx][pwally-1] = + tilemap[pwallx][pwally-1] = oldtile; + break; + + case di_east: + pwallx++; + if (actorat[pwallx+1][pwally]) + { + pwallstate = 0; + return; + } + (unsigned)actorat[pwallx+1][pwally] = + tilemap[pwallx+1][pwally] = oldtile; + break; + + case di_south: + pwally++; + if (actorat[pwallx][pwally+1]) + { + pwallstate = 0; + return; + } + (unsigned)actorat[pwallx][pwally+1] = + tilemap[pwallx][pwally+1] = oldtile; + break; + + case di_west: + pwallx--; + if (actorat[pwallx-1][pwally]) + { + pwallstate = 0; + return; + } + (unsigned)actorat[pwallx-1][pwally] = + tilemap[pwallx-1][pwally] = oldtile; + break; + } + + tilemap[pwallx][pwally] = oldtile | 0xc0; + } + } + + + pwallpos = (pwallstate/2)&63; + +} + diff --git a/16/sod8086/wl_act2.c b/16/sod8086/wl_act2.c new file mode 100755 index 00000000..1574c8b4 --- /dev/null +++ b/16/sod8086/wl_act2.c @@ -0,0 +1,3872 @@ +// WL_ACT2.C + +#include "WL_DEF.H" +#pragma hdrstop + +/* +============================================================================= + + LOCAL CONSTANTS + +============================================================================= +*/ + +#define PROJECTILESIZE 0xc000l + +#define BJRUNSPEED 2048 +#define BJJUMPSPEED 680 + + +/* +============================================================================= + + GLOBAL VARIABLES + +============================================================================= +*/ + + + +/* +============================================================================= + + LOCAL VARIABLES + +============================================================================= +*/ + + +dirtype dirtable[9] = {northwest,north,northeast,west,nodir,east, + southwest,south,southeast}; + +int starthitpoints[4][NUMENEMIES] = + // + // BABY MODE + // + { + {25, // guards + 50, // officer + 100, // SS + 1, // dogs + 850, // Hans + 850, // Schabbs + 200, // fake hitler + 800, // mecha hitler + 45, // mutants + 25, // ghosts + 25, // ghosts + 25, // ghosts + 25, // ghosts + + 850, // Gretel + 850, // Gift + 850, // Fat + 5, // en_spectre, + 1450, // en_angel, + 850, // en_trans, + 1050, // en_uber, + 950, // en_will, + 1250 // en_death + }, + // + // DON'T HURT ME MODE + // + {25, // guards + 50, // officer + 100, // SS + 1, // dogs + 950, // Hans + 950, // Schabbs + 300, // fake hitler + 950, // mecha hitler + 55, // mutants + 25, // ghosts + 25, // ghosts + 25, // ghosts + 25, // ghosts + + 950, // Gretel + 950, // Gift + 950, // Fat + 10, // en_spectre, + 1550, // en_angel, + 950, // en_trans, + 1150, // en_uber, + 1050, // en_will, + 1350 // en_death + }, + // + // BRING 'EM ON MODE + // + {25, // guards + 50, // officer + 100, // SS + 1, // dogs + + 1050, // Hans + 1550, // Schabbs + 400, // fake hitler + 1050, // mecha hitler + + 55, // mutants + 25, // ghosts + 25, // ghosts + 25, // ghosts + 25, // ghosts + + 1050, // Gretel + 1050, // Gift + 1050, // Fat + 15, // en_spectre, + 1650, // en_angel, + 1050, // en_trans, + 1250, // en_uber, + 1150, // en_will, + 1450 // en_death + }, + // + // DEATH INCARNATE MODE + // + {25, // guards + 50, // officer + 100, // SS + 1, // dogs + + 1200, // Hans + 2400, // Schabbs + 500, // fake hitler + 1200, // mecha hitler + + 65, // mutants + 25, // ghosts + 25, // ghosts + 25, // ghosts + 25, // ghosts + + 1200, // Gretel + 1200, // Gift + 1200, // Fat + 25, // en_spectre, + 2000, // en_angel, + 1200, // en_trans, + 1400, // en_uber, + 1300, // en_will, + 1600 // en_death + }} + ; + +void A_StartDeathCam (objtype *ob); + + +void T_Path (objtype *ob); +void T_Shoot (objtype *ob); +void T_Bite (objtype *ob); +void T_DogChase (objtype *ob); +void T_Chase (objtype *ob); +void T_Projectile (objtype *ob); +void T_Stand (objtype *ob); + +void A_DeathScream (objtype *ob); + +extern statetype s_rocket; +extern statetype s_smoke1; +extern statetype s_smoke2; +extern statetype s_smoke3; +extern statetype s_smoke4; +extern statetype s_boom2; +extern statetype s_boom3; + +void A_Smoke (objtype *ob); + +statetype s_rocket = {true,SPR_ROCKET_1,3,T_Projectile,A_Smoke,&s_rocket}; +statetype s_smoke1 = {false,SPR_SMOKE_1,3,NULL,NULL,&s_smoke2}; +statetype s_smoke2 = {false,SPR_SMOKE_2,3,NULL,NULL,&s_smoke3}; +statetype s_smoke3 = {false,SPR_SMOKE_3,3,NULL,NULL,&s_smoke4}; +statetype s_smoke4 = {false,SPR_SMOKE_4,3,NULL,NULL,NULL}; + +statetype s_boom1 = {false,SPR_BOOM_1,6,NULL,NULL,&s_boom2}; +statetype s_boom2 = {false,SPR_BOOM_2,6,NULL,NULL,&s_boom3}; +statetype s_boom3 = {false,SPR_BOOM_3,6,NULL,NULL,NULL}; + +#ifdef SPEAR + +extern statetype s_hrocket; +extern statetype s_hsmoke1; +extern statetype s_hsmoke2; +extern statetype s_hsmoke3; +extern statetype s_hsmoke4; +extern statetype s_hboom2; +extern statetype s_hboom3; + +void A_Smoke (objtype *ob); + +statetype s_hrocket = {true,SPR_HROCKET_1,3,T_Projectile,A_Smoke,&s_hrocket}; +statetype s_hsmoke1 = {false,SPR_HSMOKE_1,3,NULL,NULL,&s_hsmoke2}; +statetype s_hsmoke2 = {false,SPR_HSMOKE_2,3,NULL,NULL,&s_hsmoke3}; +statetype s_hsmoke3 = {false,SPR_HSMOKE_3,3,NULL,NULL,&s_hsmoke4}; +statetype s_hsmoke4 = {false,SPR_HSMOKE_4,3,NULL,NULL,NULL}; + +statetype s_hboom1 = {false,SPR_HBOOM_1,6,NULL,NULL,&s_hboom2}; +statetype s_hboom2 = {false,SPR_HBOOM_2,6,NULL,NULL,&s_hboom3}; +statetype s_hboom3 = {false,SPR_HBOOM_3,6,NULL,NULL,NULL}; + +#endif + +void T_Schabb (objtype *ob); +void T_SchabbThrow (objtype *ob); +void T_Fake (objtype *ob); +void T_FakeFire (objtype *ob); +void T_Ghosts (objtype *ob); + +void A_Slurpie (objtype *ob); +void A_HitlerMorph (objtype *ob); +void A_MechaSound (objtype *ob); + +/* +================= += += A_Smoke += +================= +*/ + +void A_Smoke (objtype *ob) +{ + GetNewActor (); +#ifdef SPEAR + if (ob->obclass == hrocketobj) + new->state = &s_hsmoke1; + else +#endif + new->state = &s_smoke1; + new->ticcount = 6; + + new->tilex = ob->tilex; + new->tiley = ob->tiley; + new->x = ob->x; + new->y = ob->y; + new->obclass = inertobj; + new->active = true; + + new->flags = FL_NEVERMARK; +} + + +/* +=================== += += ProjectileTryMove += += returns true if move ok +=================== +*/ + +#define PROJSIZE 0x2000 + +boolean ProjectileTryMove (objtype *ob) +{ + int xl,yl,xh,yh,x,y; + objtype *check; + long deltax,deltay; + + xl = (ob->x-PROJSIZE) >>TILESHIFT; + yl = (ob->y-PROJSIZE) >>TILESHIFT; + + xh = (ob->x+PROJSIZE) >>TILESHIFT; + yh = (ob->y+PROJSIZE) >>TILESHIFT; + +// +// check for solid walls +// + for (y=yl;y<=yh;y++) + for (x=xl;x<=xh;x++) + { + check = actorat[x][y]; + if (check && checkspeed*tics; + + deltax = FixedByFrac(speed,costable[ob->angle]); + deltay = -FixedByFrac(speed,sintable[ob->angle]); + + if (deltax>0x10000l) + deltax = 0x10000l; + if (deltay>0x10000l) + deltay = 0x10000l; + + ob->x += deltax; + ob->y += deltay; + + deltax = LABS(ob->x - player->x); + deltay = LABS(ob->y - player->y); + + if (!ProjectileTryMove (ob)) + { + if (ob->obclass == rocketobj) + { + PlaySoundLocActor(MISSILEHITSND,ob); + ob->state = &s_boom1; + } +#ifdef SPEAR + else if (ob->obclass == hrocketobj) + { + PlaySoundLocActor(MISSILEHITSND,ob); + ob->state = &s_hboom1; + } +#endif + else + ob->state = NULL; // mark for removal + + return; + } + + if (deltax < PROJECTILESIZE && deltay < PROJECTILESIZE) + { // hit the player + switch (ob->obclass) + { + case needleobj: + damage = (US_RndT() >>3) + 20; + break; + case rocketobj: + case hrocketobj: + case sparkobj: + damage = (US_RndT() >>3) + 30; + break; + case fireobj: + damage = (US_RndT() >>3); + break; + } + + TakeDamage (damage,ob); + ob->state = NULL; // mark for removal + return; + } + + ob->tilex = ob->x >> TILESHIFT; + ob->tiley = ob->y >> TILESHIFT; + +} + + + + +/* +============================================================================= + + GUARD + +============================================================================= +*/ + +// +// guards +// + +extern statetype s_grdstand; + +extern statetype s_grdpath1; +extern statetype s_grdpath1s; +extern statetype s_grdpath2; +extern statetype s_grdpath3; +extern statetype s_grdpath3s; +extern statetype s_grdpath4; + +extern statetype s_grdpain; +extern statetype s_grdpain1; + +extern statetype s_grdgiveup; + +extern statetype s_grdshoot1; +extern statetype s_grdshoot2; +extern statetype s_grdshoot3; +extern statetype s_grdshoot4; + +extern statetype s_grdchase1; +extern statetype s_grdchase1s; +extern statetype s_grdchase2; +extern statetype s_grdchase3; +extern statetype s_grdchase3s; +extern statetype s_grdchase4; + +extern statetype s_grddie1; +extern statetype s_grddie1d; +extern statetype s_grddie2; +extern statetype s_grddie3; +extern statetype s_grddie4; + +statetype s_grdstand = {true,SPR_GRD_S_1,0,T_Stand,NULL,&s_grdstand}; + +statetype s_grdpath1 = {true,SPR_GRD_W1_1,20,T_Path,NULL,&s_grdpath1s}; +statetype s_grdpath1s = {true,SPR_GRD_W1_1,5,NULL,NULL,&s_grdpath2}; +statetype s_grdpath2 = {true,SPR_GRD_W2_1,15,T_Path,NULL,&s_grdpath3}; +statetype s_grdpath3 = {true,SPR_GRD_W3_1,20,T_Path,NULL,&s_grdpath3s}; +statetype s_grdpath3s = {true,SPR_GRD_W3_1,5,NULL,NULL,&s_grdpath4}; +statetype s_grdpath4 = {true,SPR_GRD_W4_1,15,T_Path,NULL,&s_grdpath1}; + +statetype s_grdpain = {2,SPR_GRD_PAIN_1,10,NULL,NULL,&s_grdchase1}; +statetype s_grdpain1 = {2,SPR_GRD_PAIN_2,10,NULL,NULL,&s_grdchase1}; + +statetype s_grdshoot1 = {false,SPR_GRD_SHOOT1,20,NULL,NULL,&s_grdshoot2}; +statetype s_grdshoot2 = {false,SPR_GRD_SHOOT2,20,NULL,T_Shoot,&s_grdshoot3}; +statetype s_grdshoot3 = {false,SPR_GRD_SHOOT3,20,NULL,NULL,&s_grdchase1}; + +statetype s_grdchase1 = {true,SPR_GRD_W1_1,10,T_Chase,NULL,&s_grdchase1s}; +statetype s_grdchase1s = {true,SPR_GRD_W1_1,3,NULL,NULL,&s_grdchase2}; +statetype s_grdchase2 = {true,SPR_GRD_W2_1,8,T_Chase,NULL,&s_grdchase3}; +statetype s_grdchase3 = {true,SPR_GRD_W3_1,10,T_Chase,NULL,&s_grdchase3s}; +statetype s_grdchase3s = {true,SPR_GRD_W3_1,3,NULL,NULL,&s_grdchase4}; +statetype s_grdchase4 = {true,SPR_GRD_W4_1,8,T_Chase,NULL,&s_grdchase1}; + +statetype s_grddie1 = {false,SPR_GRD_DIE_1,15,NULL,A_DeathScream,&s_grddie2}; +statetype s_grddie2 = {false,SPR_GRD_DIE_2,15,NULL,NULL,&s_grddie3}; +statetype s_grddie3 = {false,SPR_GRD_DIE_3,15,NULL,NULL,&s_grddie4}; +statetype s_grddie4 = {false,SPR_GRD_DEAD,0,NULL,NULL,&s_grddie4}; + + +#ifndef SPEAR +// +// ghosts +// +extern statetype s_blinkychase1; +extern statetype s_blinkychase2; +extern statetype s_inkychase1; +extern statetype s_inkychase2; +extern statetype s_pinkychase1; +extern statetype s_pinkychase2; +extern statetype s_clydechase1; +extern statetype s_clydechase2; + +statetype s_blinkychase1 = {false,SPR_BLINKY_W1,10,T_Ghosts,NULL,&s_blinkychase2}; +statetype s_blinkychase2 = {false,SPR_BLINKY_W2,10,T_Ghosts,NULL,&s_blinkychase1}; + +statetype s_inkychase1 = {false,SPR_INKY_W1,10,T_Ghosts,NULL,&s_inkychase2}; +statetype s_inkychase2 = {false,SPR_INKY_W2,10,T_Ghosts,NULL,&s_inkychase1}; + +statetype s_pinkychase1 = {false,SPR_PINKY_W1,10,T_Ghosts,NULL,&s_pinkychase2}; +statetype s_pinkychase2 = {false,SPR_PINKY_W2,10,T_Ghosts,NULL,&s_pinkychase1}; + +statetype s_clydechase1 = {false,SPR_CLYDE_W1,10,T_Ghosts,NULL,&s_clydechase2}; +statetype s_clydechase2 = {false,SPR_CLYDE_W2,10,T_Ghosts,NULL,&s_clydechase1}; +#endif + +// +// dogs +// + +extern statetype s_dogpath1; +extern statetype s_dogpath1s; +extern statetype s_dogpath2; +extern statetype s_dogpath3; +extern statetype s_dogpath3s; +extern statetype s_dogpath4; + +extern statetype s_dogjump1; +extern statetype s_dogjump2; +extern statetype s_dogjump3; +extern statetype s_dogjump4; +extern statetype s_dogjump5; + +extern statetype s_dogchase1; +extern statetype s_dogchase1s; +extern statetype s_dogchase2; +extern statetype s_dogchase3; +extern statetype s_dogchase3s; +extern statetype s_dogchase4; + +extern statetype s_dogdie1; +extern statetype s_dogdie1d; +extern statetype s_dogdie2; +extern statetype s_dogdie3; +extern statetype s_dogdead; + +statetype s_dogpath1 = {true,SPR_DOG_W1_1,20,T_Path,NULL,&s_dogpath1s}; +statetype s_dogpath1s = {true,SPR_DOG_W1_1,5,NULL,NULL,&s_dogpath2}; +statetype s_dogpath2 = {true,SPR_DOG_W2_1,15,T_Path,NULL,&s_dogpath3}; +statetype s_dogpath3 = {true,SPR_DOG_W3_1,20,T_Path,NULL,&s_dogpath3s}; +statetype s_dogpath3s = {true,SPR_DOG_W3_1,5,NULL,NULL,&s_dogpath4}; +statetype s_dogpath4 = {true,SPR_DOG_W4_1,15,T_Path,NULL,&s_dogpath1}; + +statetype s_dogjump1 = {false,SPR_DOG_JUMP1,10,NULL,NULL,&s_dogjump2}; +statetype s_dogjump2 = {false,SPR_DOG_JUMP2,10,NULL,T_Bite,&s_dogjump3}; +statetype s_dogjump3 = {false,SPR_DOG_JUMP3,10,NULL,NULL,&s_dogjump4}; +statetype s_dogjump4 = {false,SPR_DOG_JUMP1,10,NULL,NULL,&s_dogjump5}; +statetype s_dogjump5 = {false,SPR_DOG_W1_1,10,NULL,NULL,&s_dogchase1}; + +statetype s_dogchase1 = {true,SPR_DOG_W1_1,10,T_DogChase,NULL,&s_dogchase1s}; +statetype s_dogchase1s = {true,SPR_DOG_W1_1,3,NULL,NULL,&s_dogchase2}; +statetype s_dogchase2 = {true,SPR_DOG_W2_1,8,T_DogChase,NULL,&s_dogchase3}; +statetype s_dogchase3 = {true,SPR_DOG_W3_1,10,T_DogChase,NULL,&s_dogchase3s}; +statetype s_dogchase3s = {true,SPR_DOG_W3_1,3,NULL,NULL,&s_dogchase4}; +statetype s_dogchase4 = {true,SPR_DOG_W4_1,8,T_DogChase,NULL,&s_dogchase1}; + +statetype s_dogdie1 = {false,SPR_DOG_DIE_1,15,NULL,A_DeathScream,&s_dogdie2}; +statetype s_dogdie2 = {false,SPR_DOG_DIE_2,15,NULL,NULL,&s_dogdie3}; +statetype s_dogdie3 = {false,SPR_DOG_DIE_3,15,NULL,NULL,&s_dogdead}; +statetype s_dogdead = {false,SPR_DOG_DEAD,15,NULL,NULL,&s_dogdead}; + + +// +// officers +// + +extern statetype s_ofcstand; + +extern statetype s_ofcpath1; +extern statetype s_ofcpath1s; +extern statetype s_ofcpath2; +extern statetype s_ofcpath3; +extern statetype s_ofcpath3s; +extern statetype s_ofcpath4; + +extern statetype s_ofcpain; +extern statetype s_ofcpain1; + +extern statetype s_ofcgiveup; + +extern statetype s_ofcshoot1; +extern statetype s_ofcshoot2; +extern statetype s_ofcshoot3; +extern statetype s_ofcshoot4; + +extern statetype s_ofcchase1; +extern statetype s_ofcchase1s; +extern statetype s_ofcchase2; +extern statetype s_ofcchase3; +extern statetype s_ofcchase3s; +extern statetype s_ofcchase4; + +extern statetype s_ofcdie1; +extern statetype s_ofcdie2; +extern statetype s_ofcdie3; +extern statetype s_ofcdie4; +extern statetype s_ofcdie5; + +statetype s_ofcstand = {true,SPR_OFC_S_1,0,T_Stand,NULL,&s_ofcstand}; + +statetype s_ofcpath1 = {true,SPR_OFC_W1_1,20,T_Path,NULL,&s_ofcpath1s}; +statetype s_ofcpath1s = {true,SPR_OFC_W1_1,5,NULL,NULL,&s_ofcpath2}; +statetype s_ofcpath2 = {true,SPR_OFC_W2_1,15,T_Path,NULL,&s_ofcpath3}; +statetype s_ofcpath3 = {true,SPR_OFC_W3_1,20,T_Path,NULL,&s_ofcpath3s}; +statetype s_ofcpath3s = {true,SPR_OFC_W3_1,5,NULL,NULL,&s_ofcpath4}; +statetype s_ofcpath4 = {true,SPR_OFC_W4_1,15,T_Path,NULL,&s_ofcpath1}; + +statetype s_ofcpain = {2,SPR_OFC_PAIN_1,10,NULL,NULL,&s_ofcchase1}; +statetype s_ofcpain1 = {2,SPR_OFC_PAIN_2,10,NULL,NULL,&s_ofcchase1}; + +statetype s_ofcshoot1 = {false,SPR_OFC_SHOOT1,6,NULL,NULL,&s_ofcshoot2}; +statetype s_ofcshoot2 = {false,SPR_OFC_SHOOT2,20,NULL,T_Shoot,&s_ofcshoot3}; +statetype s_ofcshoot3 = {false,SPR_OFC_SHOOT3,10,NULL,NULL,&s_ofcchase1}; + +statetype s_ofcchase1 = {true,SPR_OFC_W1_1,10,T_Chase,NULL,&s_ofcchase1s}; +statetype s_ofcchase1s = {true,SPR_OFC_W1_1,3,NULL,NULL,&s_ofcchase2}; +statetype s_ofcchase2 = {true,SPR_OFC_W2_1,8,T_Chase,NULL,&s_ofcchase3}; +statetype s_ofcchase3 = {true,SPR_OFC_W3_1,10,T_Chase,NULL,&s_ofcchase3s}; +statetype s_ofcchase3s = {true,SPR_OFC_W3_1,3,NULL,NULL,&s_ofcchase4}; +statetype s_ofcchase4 = {true,SPR_OFC_W4_1,8,T_Chase,NULL,&s_ofcchase1}; + +statetype s_ofcdie1 = {false,SPR_OFC_DIE_1,11,NULL,A_DeathScream,&s_ofcdie2}; +statetype s_ofcdie2 = {false,SPR_OFC_DIE_2,11,NULL,NULL,&s_ofcdie3}; +statetype s_ofcdie3 = {false,SPR_OFC_DIE_3,11,NULL,NULL,&s_ofcdie4}; +statetype s_ofcdie4 = {false,SPR_OFC_DIE_4,11,NULL,NULL,&s_ofcdie5}; +statetype s_ofcdie5 = {false,SPR_OFC_DEAD,0,NULL,NULL,&s_ofcdie5}; + + +// +// mutant +// + +extern statetype s_mutstand; + +extern statetype s_mutpath1; +extern statetype s_mutpath1s; +extern statetype s_mutpath2; +extern statetype s_mutpath3; +extern statetype s_mutpath3s; +extern statetype s_mutpath4; + +extern statetype s_mutpain; +extern statetype s_mutpain1; + +extern statetype s_mutgiveup; + +extern statetype s_mutshoot1; +extern statetype s_mutshoot2; +extern statetype s_mutshoot3; +extern statetype s_mutshoot4; + +extern statetype s_mutchase1; +extern statetype s_mutchase1s; +extern statetype s_mutchase2; +extern statetype s_mutchase3; +extern statetype s_mutchase3s; +extern statetype s_mutchase4; + +extern statetype s_mutdie1; +extern statetype s_mutdie2; +extern statetype s_mutdie3; +extern statetype s_mutdie4; +extern statetype s_mutdie5; + +statetype s_mutstand = {true,SPR_MUT_S_1,0,T_Stand,NULL,&s_mutstand}; + +statetype s_mutpath1 = {true,SPR_MUT_W1_1,20,T_Path,NULL,&s_mutpath1s}; +statetype s_mutpath1s = {true,SPR_MUT_W1_1,5,NULL,NULL,&s_mutpath2}; +statetype s_mutpath2 = {true,SPR_MUT_W2_1,15,T_Path,NULL,&s_mutpath3}; +statetype s_mutpath3 = {true,SPR_MUT_W3_1,20,T_Path,NULL,&s_mutpath3s}; +statetype s_mutpath3s = {true,SPR_MUT_W3_1,5,NULL,NULL,&s_mutpath4}; +statetype s_mutpath4 = {true,SPR_MUT_W4_1,15,T_Path,NULL,&s_mutpath1}; + +statetype s_mutpain = {2,SPR_MUT_PAIN_1,10,NULL,NULL,&s_mutchase1}; +statetype s_mutpain1 = {2,SPR_MUT_PAIN_2,10,NULL,NULL,&s_mutchase1}; + +statetype s_mutshoot1 = {false,SPR_MUT_SHOOT1,6,NULL,T_Shoot,&s_mutshoot2}; +statetype s_mutshoot2 = {false,SPR_MUT_SHOOT2,20,NULL,NULL,&s_mutshoot3}; +statetype s_mutshoot3 = {false,SPR_MUT_SHOOT3,10,NULL,T_Shoot,&s_mutshoot4}; +statetype s_mutshoot4 = {false,SPR_MUT_SHOOT4,20,NULL,NULL,&s_mutchase1}; + +statetype s_mutchase1 = {true,SPR_MUT_W1_1,10,T_Chase,NULL,&s_mutchase1s}; +statetype s_mutchase1s = {true,SPR_MUT_W1_1,3,NULL,NULL,&s_mutchase2}; +statetype s_mutchase2 = {true,SPR_MUT_W2_1,8,T_Chase,NULL,&s_mutchase3}; +statetype s_mutchase3 = {true,SPR_MUT_W3_1,10,T_Chase,NULL,&s_mutchase3s}; +statetype s_mutchase3s = {true,SPR_MUT_W3_1,3,NULL,NULL,&s_mutchase4}; +statetype s_mutchase4 = {true,SPR_MUT_W4_1,8,T_Chase,NULL,&s_mutchase1}; + +statetype s_mutdie1 = {false,SPR_MUT_DIE_1,7,NULL,A_DeathScream,&s_mutdie2}; +statetype s_mutdie2 = {false,SPR_MUT_DIE_2,7,NULL,NULL,&s_mutdie3}; +statetype s_mutdie3 = {false,SPR_MUT_DIE_3,7,NULL,NULL,&s_mutdie4}; +statetype s_mutdie4 = {false,SPR_MUT_DIE_4,7,NULL,NULL,&s_mutdie5}; +statetype s_mutdie5 = {false,SPR_MUT_DEAD,0,NULL,NULL,&s_mutdie5}; + + +// +// SS +// + +extern statetype s_ssstand; + +extern statetype s_sspath1; +extern statetype s_sspath1s; +extern statetype s_sspath2; +extern statetype s_sspath3; +extern statetype s_sspath3s; +extern statetype s_sspath4; + +extern statetype s_sspain; +extern statetype s_sspain1; + +extern statetype s_ssshoot1; +extern statetype s_ssshoot2; +extern statetype s_ssshoot3; +extern statetype s_ssshoot4; +extern statetype s_ssshoot5; +extern statetype s_ssshoot6; +extern statetype s_ssshoot7; +extern statetype s_ssshoot8; +extern statetype s_ssshoot9; + +extern statetype s_sschase1; +extern statetype s_sschase1s; +extern statetype s_sschase2; +extern statetype s_sschase3; +extern statetype s_sschase3s; +extern statetype s_sschase4; + +extern statetype s_ssdie1; +extern statetype s_ssdie2; +extern statetype s_ssdie3; +extern statetype s_ssdie4; + +statetype s_ssstand = {true,SPR_SS_S_1,0,T_Stand,NULL,&s_ssstand}; + +statetype s_sspath1 = {true,SPR_SS_W1_1,20,T_Path,NULL,&s_sspath1s}; +statetype s_sspath1s = {true,SPR_SS_W1_1,5,NULL,NULL,&s_sspath2}; +statetype s_sspath2 = {true,SPR_SS_W2_1,15,T_Path,NULL,&s_sspath3}; +statetype s_sspath3 = {true,SPR_SS_W3_1,20,T_Path,NULL,&s_sspath3s}; +statetype s_sspath3s = {true,SPR_SS_W3_1,5,NULL,NULL,&s_sspath4}; +statetype s_sspath4 = {true,SPR_SS_W4_1,15,T_Path,NULL,&s_sspath1}; + +statetype s_sspain = {2,SPR_SS_PAIN_1,10,NULL,NULL,&s_sschase1}; +statetype s_sspain1 = {2,SPR_SS_PAIN_2,10,NULL,NULL,&s_sschase1}; + +statetype s_ssshoot1 = {false,SPR_SS_SHOOT1,20,NULL,NULL,&s_ssshoot2}; +statetype s_ssshoot2 = {false,SPR_SS_SHOOT2,20,NULL,T_Shoot,&s_ssshoot3}; +statetype s_ssshoot3 = {false,SPR_SS_SHOOT3,10,NULL,NULL,&s_ssshoot4}; +statetype s_ssshoot4 = {false,SPR_SS_SHOOT2,10,NULL,T_Shoot,&s_ssshoot5}; +statetype s_ssshoot5 = {false,SPR_SS_SHOOT3,10,NULL,NULL,&s_ssshoot6}; +statetype s_ssshoot6 = {false,SPR_SS_SHOOT2,10,NULL,T_Shoot,&s_ssshoot7}; +statetype s_ssshoot7 = {false,SPR_SS_SHOOT3,10,NULL,NULL,&s_ssshoot8}; +statetype s_ssshoot8 = {false,SPR_SS_SHOOT2,10,NULL,T_Shoot,&s_ssshoot9}; +statetype s_ssshoot9 = {false,SPR_SS_SHOOT3,10,NULL,NULL,&s_sschase1}; + +statetype s_sschase1 = {true,SPR_SS_W1_1,10,T_Chase,NULL,&s_sschase1s}; +statetype s_sschase1s = {true,SPR_SS_W1_1,3,NULL,NULL,&s_sschase2}; +statetype s_sschase2 = {true,SPR_SS_W2_1,8,T_Chase,NULL,&s_sschase3}; +statetype s_sschase3 = {true,SPR_SS_W3_1,10,T_Chase,NULL,&s_sschase3s}; +statetype s_sschase3s = {true,SPR_SS_W3_1,3,NULL,NULL,&s_sschase4}; +statetype s_sschase4 = {true,SPR_SS_W4_1,8,T_Chase,NULL,&s_sschase1}; + +statetype s_ssdie1 = {false,SPR_SS_DIE_1,15,NULL,A_DeathScream,&s_ssdie2}; +statetype s_ssdie2 = {false,SPR_SS_DIE_2,15,NULL,NULL,&s_ssdie3}; +statetype s_ssdie3 = {false,SPR_SS_DIE_3,15,NULL,NULL,&s_ssdie4}; +statetype s_ssdie4 = {false,SPR_SS_DEAD,0,NULL,NULL,&s_ssdie4}; + + +#ifndef SPEAR +// +// hans +// +extern statetype s_bossstand; + +extern statetype s_bosschase1; +extern statetype s_bosschase1s; +extern statetype s_bosschase2; +extern statetype s_bosschase3; +extern statetype s_bosschase3s; +extern statetype s_bosschase4; + +extern statetype s_bossdie1; +extern statetype s_bossdie2; +extern statetype s_bossdie3; +extern statetype s_bossdie4; + +extern statetype s_bossshoot1; +extern statetype s_bossshoot2; +extern statetype s_bossshoot3; +extern statetype s_bossshoot4; +extern statetype s_bossshoot5; +extern statetype s_bossshoot6; +extern statetype s_bossshoot7; +extern statetype s_bossshoot8; + + +statetype s_bossstand = {false,SPR_BOSS_W1,0,T_Stand,NULL,&s_bossstand}; + +statetype s_bosschase1 = {false,SPR_BOSS_W1,10,T_Chase,NULL,&s_bosschase1s}; +statetype s_bosschase1s = {false,SPR_BOSS_W1,3,NULL,NULL,&s_bosschase2}; +statetype s_bosschase2 = {false,SPR_BOSS_W2,8,T_Chase,NULL,&s_bosschase3}; +statetype s_bosschase3 = {false,SPR_BOSS_W3,10,T_Chase,NULL,&s_bosschase3s}; +statetype s_bosschase3s = {false,SPR_BOSS_W3,3,NULL,NULL,&s_bosschase4}; +statetype s_bosschase4 = {false,SPR_BOSS_W4,8,T_Chase,NULL,&s_bosschase1}; + +statetype s_bossdie1 = {false,SPR_BOSS_DIE1,15,NULL,A_DeathScream,&s_bossdie2}; +statetype s_bossdie2 = {false,SPR_BOSS_DIE2,15,NULL,NULL,&s_bossdie3}; +statetype s_bossdie3 = {false,SPR_BOSS_DIE3,15,NULL,NULL,&s_bossdie4}; +statetype s_bossdie4 = {false,SPR_BOSS_DEAD,0,NULL,NULL,&s_bossdie4}; + +statetype s_bossshoot1 = {false,SPR_BOSS_SHOOT1,30,NULL,NULL,&s_bossshoot2}; +statetype s_bossshoot2 = {false,SPR_BOSS_SHOOT2,10,NULL,T_Shoot,&s_bossshoot3}; +statetype s_bossshoot3 = {false,SPR_BOSS_SHOOT3,10,NULL,T_Shoot,&s_bossshoot4}; +statetype s_bossshoot4 = {false,SPR_BOSS_SHOOT2,10,NULL,T_Shoot,&s_bossshoot5}; +statetype s_bossshoot5 = {false,SPR_BOSS_SHOOT3,10,NULL,T_Shoot,&s_bossshoot6}; +statetype s_bossshoot6 = {false,SPR_BOSS_SHOOT2,10,NULL,T_Shoot,&s_bossshoot7}; +statetype s_bossshoot7 = {false,SPR_BOSS_SHOOT3,10,NULL,T_Shoot,&s_bossshoot8}; +statetype s_bossshoot8 = {false,SPR_BOSS_SHOOT1,10,NULL,NULL,&s_bosschase1}; + + +// +// gretel +// +extern statetype s_gretelstand; + +extern statetype s_gretelchase1; +extern statetype s_gretelchase1s; +extern statetype s_gretelchase2; +extern statetype s_gretelchase3; +extern statetype s_gretelchase3s; +extern statetype s_gretelchase4; + +extern statetype s_greteldie1; +extern statetype s_greteldie2; +extern statetype s_greteldie3; +extern statetype s_greteldie4; + +extern statetype s_gretelshoot1; +extern statetype s_gretelshoot2; +extern statetype s_gretelshoot3; +extern statetype s_gretelshoot4; +extern statetype s_gretelshoot5; +extern statetype s_gretelshoot6; +extern statetype s_gretelshoot7; +extern statetype s_gretelshoot8; + + +statetype s_gretelstand = {false,SPR_GRETEL_W1,0,T_Stand,NULL,&s_gretelstand}; + +statetype s_gretelchase1 = {false,SPR_GRETEL_W1,10,T_Chase,NULL,&s_gretelchase1s}; +statetype s_gretelchase1s = {false,SPR_GRETEL_W1,3,NULL,NULL,&s_gretelchase2}; +statetype s_gretelchase2 = {false,SPR_GRETEL_W2,8,T_Chase,NULL,&s_gretelchase3}; +statetype s_gretelchase3 = {false,SPR_GRETEL_W3,10,T_Chase,NULL,&s_gretelchase3s}; +statetype s_gretelchase3s = {false,SPR_GRETEL_W3,3,NULL,NULL,&s_gretelchase4}; +statetype s_gretelchase4 = {false,SPR_GRETEL_W4,8,T_Chase,NULL,&s_gretelchase1}; + +statetype s_greteldie1 = {false,SPR_GRETEL_DIE1,15,NULL,A_DeathScream,&s_greteldie2}; +statetype s_greteldie2 = {false,SPR_GRETEL_DIE2,15,NULL,NULL,&s_greteldie3}; +statetype s_greteldie3 = {false,SPR_GRETEL_DIE3,15,NULL,NULL,&s_greteldie4}; +statetype s_greteldie4 = {false,SPR_GRETEL_DEAD,0,NULL,NULL,&s_greteldie4}; + +statetype s_gretelshoot1 = {false,SPR_GRETEL_SHOOT1,30,NULL,NULL,&s_gretelshoot2}; +statetype s_gretelshoot2 = {false,SPR_GRETEL_SHOOT2,10,NULL,T_Shoot,&s_gretelshoot3}; +statetype s_gretelshoot3 = {false,SPR_GRETEL_SHOOT3,10,NULL,T_Shoot,&s_gretelshoot4}; +statetype s_gretelshoot4 = {false,SPR_GRETEL_SHOOT2,10,NULL,T_Shoot,&s_gretelshoot5}; +statetype s_gretelshoot5 = {false,SPR_GRETEL_SHOOT3,10,NULL,T_Shoot,&s_gretelshoot6}; +statetype s_gretelshoot6 = {false,SPR_GRETEL_SHOOT2,10,NULL,T_Shoot,&s_gretelshoot7}; +statetype s_gretelshoot7 = {false,SPR_GRETEL_SHOOT3,10,NULL,T_Shoot,&s_gretelshoot8}; +statetype s_gretelshoot8 = {false,SPR_GRETEL_SHOOT1,10,NULL,NULL,&s_gretelchase1}; +#endif + + +/* +=============== += += SpawnStand += +=============== +*/ + +void SpawnStand (enemy_t which, int tilex, int tiley, int dir) +{ + unsigned far *map,tile; + + switch (which) + { + case en_guard: + SpawnNewObj (tilex,tiley,&s_grdstand); + new->speed = SPDPATROL; + if (!loadedgame) + gamestate.killtotal++; + break; + + case en_officer: + SpawnNewObj (tilex,tiley,&s_ofcstand); + new->speed = SPDPATROL; + if (!loadedgame) + gamestate.killtotal++; + break; + + case en_mutant: + SpawnNewObj (tilex,tiley,&s_mutstand); + new->speed = SPDPATROL; + if (!loadedgame) + gamestate.killtotal++; + break; + + case en_ss: + SpawnNewObj (tilex,tiley,&s_ssstand); + new->speed = SPDPATROL; + if (!loadedgame) + gamestate.killtotal++; + break; + } + + + map = mapsegs[0]+farmapylookup[tiley]+tilex; + if (*map == AMBUSHTILE) + { + tilemap[tilex][tiley] = 0; + + if (*(map+1) >= AREATILE) + tile = *(map+1); + if (*(map-mapwidth) >= AREATILE) + tile = *(map-mapwidth); + if (*(map+mapwidth) >= AREATILE) + tile = *(map+mapwidth); + if ( *(map-1) >= AREATILE) + tile = *(map-1); + + *map = tile; + new->areanumber = tile-AREATILE; + + new->flags |= FL_AMBUSH; + } + + new->obclass = guardobj+which; + new->hitpoints = starthitpoints[gamestate.difficulty][which]; + new->dir = dir*2; + new->flags |= FL_SHOOTABLE; +} + + + +/* +=============== += += SpawnDeadGuard += +=============== +*/ + +void SpawnDeadGuard (int tilex, int tiley) +{ + SpawnNewObj (tilex,tiley,&s_grddie4); + new->obclass = inertobj; +} + + + +#ifndef SPEAR +/* +=============== += += SpawnBoss += +=============== +*/ + +void SpawnBoss (int tilex, int tiley) +{ + unsigned far *map,tile; + + SpawnNewObj (tilex,tiley,&s_bossstand); + new->speed = SPDPATROL; + + new->obclass = bossobj; + new->hitpoints = starthitpoints[gamestate.difficulty][en_boss]; + new->dir = south; + new->flags |= FL_SHOOTABLE|FL_AMBUSH; + if (!loadedgame) + gamestate.killtotal++; +} + +/* +=============== += += SpawnGretel += +=============== +*/ + +void SpawnGretel (int tilex, int tiley) +{ + unsigned far *map,tile; + + SpawnNewObj (tilex,tiley,&s_gretelstand); + new->speed = SPDPATROL; + + new->obclass = gretelobj; + new->hitpoints = starthitpoints[gamestate.difficulty][en_gretel]; + new->dir = north; + new->flags |= FL_SHOOTABLE|FL_AMBUSH; + if (!loadedgame) + gamestate.killtotal++; +} +#endif + +/* +=============== += += SpawnPatrol += +=============== +*/ + +void SpawnPatrol (enemy_t which, int tilex, int tiley, int dir) +{ + switch (which) + { + case en_guard: + SpawnNewObj (tilex,tiley,&s_grdpath1); + new->speed = SPDPATROL; + if (!loadedgame) + gamestate.killtotal++; + break; + + case en_officer: + SpawnNewObj (tilex,tiley,&s_ofcpath1); + new->speed = SPDPATROL; + if (!loadedgame) + gamestate.killtotal++; + break; + + case en_ss: + SpawnNewObj (tilex,tiley,&s_sspath1); + new->speed = SPDPATROL; + if (!loadedgame) + gamestate.killtotal++; + break; + + case en_mutant: + SpawnNewObj (tilex,tiley,&s_mutpath1); + new->speed = SPDPATROL; + if (!loadedgame) + gamestate.killtotal++; + break; + + case en_dog: + SpawnNewObj (tilex,tiley,&s_dogpath1); + new->speed = SPDDOG; + if (!loadedgame) + gamestate.killtotal++; + break; + } + + new->obclass = guardobj+which; + new->dir = dir*2; + new->hitpoints = starthitpoints[gamestate.difficulty][which]; + new->distance = tileglobal; + new->flags |= FL_SHOOTABLE; + new->active = true; + + actorat[new->tilex][new->tiley] = NULL; // don't use original spot + + switch (dir) + { + case 0: + new->tilex++; + break; + case 1: + new->tiley--; + break; + case 2: + new->tilex--; + break; + case 3: + new->tiley++; + break; + } + + actorat[new->tilex][new->tiley] = new; +} + + + +/* +================== += += A_DeathScream += +================== +*/ + +void A_DeathScream (objtype *ob) +{ +#ifndef UPLOAD +#ifndef SPEAR + if (mapon==9 && !US_RndT()) +#else + if ((mapon==18 || mapon==19) && !US_RndT()) +#endif + { + switch(ob->obclass) + { + case mutantobj: + case guardobj: + case officerobj: + case ssobj: + case dogobj: + PlaySoundLocActor(DEATHSCREAM6SND,ob); + return; + } + } +#endif + + switch (ob->obclass) + { + case mutantobj: + PlaySoundLocActor(AHHHGSND,ob); + break; + + case guardobj: + { + int sounds[9]={ DEATHSCREAM1SND, + DEATHSCREAM2SND, + DEATHSCREAM3SND, + DEATHSCREAM4SND, + DEATHSCREAM5SND, + DEATHSCREAM7SND, + DEATHSCREAM8SND, + DEATHSCREAM9SND + }; + + #ifndef UPLOAD + PlaySoundLocActor(sounds[US_RndT()%8],ob); + #else + PlaySoundLocActor(sounds[US_RndT()%2],ob); + #endif + } + break; + case officerobj: + PlaySoundLocActor(NEINSOVASSND,ob); + break; + case ssobj: + PlaySoundLocActor(LEBENSND,ob); // JAB + break; + case dogobj: + PlaySoundLocActor(DOGDEATHSND,ob); // JAB + break; +#ifndef SPEAR + case bossobj: + SD_PlaySound(MUTTISND); // JAB + break; + case schabbobj: + SD_PlaySound(MEINGOTTSND); + break; + case fakeobj: + SD_PlaySound(HITLERHASND); + break; + case mechahitlerobj: + SD_PlaySound(SCHEISTSND); + break; + case realhitlerobj: + SD_PlaySound(EVASND); + break; + case gretelobj: + SD_PlaySound(MEINSND); + break; + case giftobj: + SD_PlaySound(DONNERSND); + break; + case fatobj: + SD_PlaySound(ROSESND); + break; +#else + case spectreobj: + SD_PlaySound(GHOSTFADESND); + break; + case angelobj: + SD_PlaySound(ANGELDEATHSND); + break; + case transobj: + SD_PlaySound(TRANSDEATHSND); + break; + case uberobj: + SD_PlaySound(UBERDEATHSND); + break; + case willobj: + SD_PlaySound(WILHELMDEATHSND); + break; + case deathobj: + SD_PlaySound(KNIGHTDEATHSND); + break; +#endif + } +} + + +/* +============================================================================= + + SPEAR ACTORS + +============================================================================= +*/ + +#ifdef SPEAR + +void T_Launch (objtype *ob); +void T_Will (objtype *ob); + +extern statetype s_angelshoot1; +extern statetype s_deathshoot1; +extern statetype s_spark1; + +// +// trans +// +extern statetype s_transstand; + +extern statetype s_transchase1; +extern statetype s_transchase1s; +extern statetype s_transchase2; +extern statetype s_transchase3; +extern statetype s_transchase3s; +extern statetype s_transchase4; + +extern statetype s_transdie0; +extern statetype s_transdie01; +extern statetype s_transdie1; +extern statetype s_transdie2; +extern statetype s_transdie3; +extern statetype s_transdie4; + +extern statetype s_transshoot1; +extern statetype s_transshoot2; +extern statetype s_transshoot3; +extern statetype s_transshoot4; +extern statetype s_transshoot5; +extern statetype s_transshoot6; +extern statetype s_transshoot7; +extern statetype s_transshoot8; + + +statetype s_transstand = {false,SPR_TRANS_W1,0,T_Stand,NULL,&s_transstand}; + +statetype s_transchase1 = {false,SPR_TRANS_W1,10,T_Chase,NULL,&s_transchase1s}; +statetype s_transchase1s = {false,SPR_TRANS_W1,3,NULL,NULL,&s_transchase2}; +statetype s_transchase2 = {false,SPR_TRANS_W2,8,T_Chase,NULL,&s_transchase3}; +statetype s_transchase3 = {false,SPR_TRANS_W3,10,T_Chase,NULL,&s_transchase3s}; +statetype s_transchase3s = {false,SPR_TRANS_W3,3,NULL,NULL,&s_transchase4}; +statetype s_transchase4 = {false,SPR_TRANS_W4,8,T_Chase,NULL,&s_transchase1}; + +statetype s_transdie0 = {false,SPR_TRANS_W1,1,NULL,A_DeathScream,&s_transdie01}; +statetype s_transdie01 = {false,SPR_TRANS_W1,1,NULL,NULL,&s_transdie1}; +statetype s_transdie1 = {false,SPR_TRANS_DIE1,15,NULL,NULL,&s_transdie2}; +statetype s_transdie2 = {false,SPR_TRANS_DIE2,15,NULL,NULL,&s_transdie3}; +statetype s_transdie3 = {false,SPR_TRANS_DIE3,15,NULL,NULL,&s_transdie4}; +statetype s_transdie4 = {false,SPR_TRANS_DEAD,0,NULL,NULL,&s_transdie4}; + +statetype s_transshoot1 = {false,SPR_TRANS_SHOOT1,30,NULL,NULL,&s_transshoot2}; +statetype s_transshoot2 = {false,SPR_TRANS_SHOOT2,10,NULL,T_Shoot,&s_transshoot3}; +statetype s_transshoot3 = {false,SPR_TRANS_SHOOT3,10,NULL,T_Shoot,&s_transshoot4}; +statetype s_transshoot4 = {false,SPR_TRANS_SHOOT2,10,NULL,T_Shoot,&s_transshoot5}; +statetype s_transshoot5 = {false,SPR_TRANS_SHOOT3,10,NULL,T_Shoot,&s_transshoot6}; +statetype s_transshoot6 = {false,SPR_TRANS_SHOOT2,10,NULL,T_Shoot,&s_transshoot7}; +statetype s_transshoot7 = {false,SPR_TRANS_SHOOT3,10,NULL,T_Shoot,&s_transshoot8}; +statetype s_transshoot8 = {false,SPR_TRANS_SHOOT1,10,NULL,NULL,&s_transchase1}; + + +/* +=============== += += SpawnTrans += +=============== +*/ + +void SpawnTrans (int tilex, int tiley) +{ + unsigned far *map,tile; + + if (SoundBlasterPresent && DigiMode != sds_Off) + s_transdie01.tictime = 105; + + SpawnNewObj (tilex,tiley,&s_transstand); + new->obclass = transobj; + new->hitpoints = starthitpoints[gamestate.difficulty][en_trans]; + new->flags |= FL_SHOOTABLE|FL_AMBUSH; + if (!loadedgame) + gamestate.killtotal++; +} + + +// +// uber +// +void T_UShoot (objtype *ob); + +extern statetype s_uberstand; + +extern statetype s_uberchase1; +extern statetype s_uberchase1s; +extern statetype s_uberchase2; +extern statetype s_uberchase3; +extern statetype s_uberchase3s; +extern statetype s_uberchase4; + +extern statetype s_uberdie0; +extern statetype s_uberdie01; +extern statetype s_uberdie1; +extern statetype s_uberdie2; +extern statetype s_uberdie3; +extern statetype s_uberdie4; +extern statetype s_uberdie5; + +extern statetype s_ubershoot1; +extern statetype s_ubershoot2; +extern statetype s_ubershoot3; +extern statetype s_ubershoot4; +extern statetype s_ubershoot5; +extern statetype s_ubershoot6; +extern statetype s_ubershoot7; + + +statetype s_uberstand = {false,SPR_UBER_W1,0,T_Stand,NULL,&s_uberstand}; + +statetype s_uberchase1 = {false,SPR_UBER_W1,10,T_Chase,NULL,&s_uberchase1s}; +statetype s_uberchase1s = {false,SPR_UBER_W1,3,NULL,NULL,&s_uberchase2}; +statetype s_uberchase2 = {false,SPR_UBER_W2,8,T_Chase,NULL,&s_uberchase3}; +statetype s_uberchase3 = {false,SPR_UBER_W3,10,T_Chase,NULL,&s_uberchase3s}; +statetype s_uberchase3s = {false,SPR_UBER_W3,3,NULL,NULL,&s_uberchase4}; +statetype s_uberchase4 = {false,SPR_UBER_W4,8,T_Chase,NULL,&s_uberchase1}; + +statetype s_uberdie0 = {false,SPR_UBER_W1,1,NULL,A_DeathScream,&s_uberdie01}; +statetype s_uberdie01 = {false,SPR_UBER_W1,1,NULL,NULL,&s_uberdie1}; +statetype s_uberdie1 = {false,SPR_UBER_DIE1,15,NULL,NULL,&s_uberdie2}; +statetype s_uberdie2 = {false,SPR_UBER_DIE2,15,NULL,NULL,&s_uberdie3}; +statetype s_uberdie3 = {false,SPR_UBER_DIE3,15,NULL,NULL,&s_uberdie4}; +statetype s_uberdie4 = {false,SPR_UBER_DIE4,15,NULL,NULL,&s_uberdie5}; +statetype s_uberdie5 = {false,SPR_UBER_DEAD,0,NULL,NULL,&s_uberdie5}; + +statetype s_ubershoot1 = {false,SPR_UBER_SHOOT1,30,NULL,NULL,&s_ubershoot2}; +statetype s_ubershoot2 = {false,SPR_UBER_SHOOT2,12,NULL,T_UShoot,&s_ubershoot3}; +statetype s_ubershoot3 = {false,SPR_UBER_SHOOT3,12,NULL,T_UShoot,&s_ubershoot4}; +statetype s_ubershoot4 = {false,SPR_UBER_SHOOT4,12,NULL,T_UShoot,&s_ubershoot5}; +statetype s_ubershoot5 = {false,SPR_UBER_SHOOT3,12,NULL,T_UShoot,&s_ubershoot6}; +statetype s_ubershoot6 = {false,SPR_UBER_SHOOT2,12,NULL,T_UShoot,&s_ubershoot7}; +statetype s_ubershoot7 = {false,SPR_UBER_SHOOT1,12,NULL,NULL,&s_uberchase1}; + + +/* +=============== += += SpawnUber += +=============== +*/ + +void SpawnUber (int tilex, int tiley) +{ + unsigned far *map,tile; + + if (SoundBlasterPresent && DigiMode != sds_Off) + s_uberdie01.tictime = 70; + + SpawnNewObj (tilex,tiley,&s_uberstand); + new->obclass = uberobj; + new->hitpoints = starthitpoints[gamestate.difficulty][en_uber]; + new->flags |= FL_SHOOTABLE|FL_AMBUSH; + if (!loadedgame) + gamestate.killtotal++; +} + + +/* +=============== += += T_UShoot += +=============== +*/ + +void T_UShoot (objtype *ob) +{ + int dx,dy,dist; + + T_Shoot (ob); + + dx = abs(ob->tilex - player->tilex); + dy = abs(ob->tiley - player->tiley); + dist = dx>dy ? dx : dy; + if (dist <= 1) + TakeDamage (10,ob); +} + + +// +// will +// +extern statetype s_willstand; + +extern statetype s_willchase1; +extern statetype s_willchase1s; +extern statetype s_willchase2; +extern statetype s_willchase3; +extern statetype s_willchase3s; +extern statetype s_willchase4; + +extern statetype s_willdie1; +extern statetype s_willdie2; +extern statetype s_willdie3; +extern statetype s_willdie4; +extern statetype s_willdie5; +extern statetype s_willdie6; + +extern statetype s_willshoot1; +extern statetype s_willshoot2; +extern statetype s_willshoot3; +extern statetype s_willshoot4; +extern statetype s_willshoot5; +extern statetype s_willshoot6; + + +statetype s_willstand = {false,SPR_WILL_W1,0,T_Stand,NULL,&s_willstand}; + +statetype s_willchase1 = {false,SPR_WILL_W1,10,T_Will,NULL,&s_willchase1s}; +statetype s_willchase1s = {false,SPR_WILL_W1,3,NULL,NULL,&s_willchase2}; +statetype s_willchase2 = {false,SPR_WILL_W2,8,T_Will,NULL,&s_willchase3}; +statetype s_willchase3 = {false,SPR_WILL_W3,10,T_Will,NULL,&s_willchase3s}; +statetype s_willchase3s = {false,SPR_WILL_W3,3,NULL,NULL,&s_willchase4}; +statetype s_willchase4 = {false,SPR_WILL_W4,8,T_Will,NULL,&s_willchase1}; + +statetype s_willdeathcam = {false,SPR_WILL_W1,1,NULL,NULL,&s_willdie1}; + +statetype s_willdie1 = {false,SPR_WILL_W1,1,NULL,A_DeathScream,&s_willdie2}; +statetype s_willdie2 = {false,SPR_WILL_W1,10,NULL,NULL,&s_willdie3}; +statetype s_willdie3 = {false,SPR_WILL_DIE1,10,NULL,NULL,&s_willdie4}; +statetype s_willdie4 = {false,SPR_WILL_DIE2,10,NULL,NULL,&s_willdie5}; +statetype s_willdie5 = {false,SPR_WILL_DIE3,10,NULL,NULL,&s_willdie6}; +statetype s_willdie6 = {false,SPR_WILL_DEAD,20,NULL,NULL,&s_willdie6}; + +statetype s_willshoot1 = {false,SPR_WILL_SHOOT1,30,NULL,NULL,&s_willshoot2}; +statetype s_willshoot2 = {false,SPR_WILL_SHOOT2,10,NULL,T_Launch,&s_willshoot3}; +statetype s_willshoot3 = {false,SPR_WILL_SHOOT3,10,NULL,T_Shoot,&s_willshoot4}; +statetype s_willshoot4 = {false,SPR_WILL_SHOOT4,10,NULL,T_Shoot,&s_willshoot5}; +statetype s_willshoot5 = {false,SPR_WILL_SHOOT3,10,NULL,T_Shoot,&s_willshoot6}; +statetype s_willshoot6 = {false,SPR_WILL_SHOOT4,10,NULL,T_Shoot,&s_willchase1}; + + +/* +=============== += += SpawnWill += +=============== +*/ + +void SpawnWill (int tilex, int tiley) +{ + unsigned far *map,tile; + + if (SoundBlasterPresent && DigiMode != sds_Off) + s_willdie2.tictime = 70; + + SpawnNewObj (tilex,tiley,&s_willstand); + new->obclass = willobj; + new->hitpoints = starthitpoints[gamestate.difficulty][en_will]; + new->flags |= FL_SHOOTABLE|FL_AMBUSH; + if (!loadedgame) + gamestate.killtotal++; +} + + +/* +================ += += T_Will += +================ +*/ + +void T_Will (objtype *ob) +{ + long move; + int dx,dy,dist; + boolean dodge; + + dodge = false; + dx = abs(ob->tilex - player->tilex); + dy = abs(ob->tiley - player->tiley); + dist = dx>dy ? dx : dy; + + if (CheckLine(ob)) // got a shot at player? + { + if ( US_RndT() < (tics<<3) ) + { + // + // go into attack frame + // + if (ob->obclass == willobj) + NewState (ob,&s_willshoot1); + else if (ob->obclass == angelobj) + NewState (ob,&s_angelshoot1); + else + NewState (ob,&s_deathshoot1); + return; + } + dodge = true; + } + + if (ob->dir == nodir) + { + if (dodge) + SelectDodgeDir (ob); + else + SelectChaseDir (ob); + if (ob->dir == nodir) + return; // object is blocked in + } + + move = ob->speed*tics; + + while (move) + { + if (ob->distance < 0) + { + // + // waiting for a door to open + // + OpenDoor (-ob->distance-1); + if (doorobjlist[-ob->distance-1].action != dr_open) + return; + ob->distance = TILEGLOBAL; // go ahead, the door is now opoen + } + + if (move < ob->distance) + { + MoveObj (ob,move); + break; + } + + // + // reached goal tile, so select another one + // + + // + // fix position to account for round off during moving + // + ob->x = ((long)ob->tilex<y = ((long)ob->tiley<distance; + + if (dist <4) + SelectRunDir (ob); + else if (dodge) + SelectDodgeDir (ob); + else + SelectChaseDir (ob); + + if (ob->dir == nodir) + return; // object is blocked in + } + +} + + +// +// death +// +extern statetype s_deathstand; + +extern statetype s_deathchase1; +extern statetype s_deathchase1s; +extern statetype s_deathchase2; +extern statetype s_deathchase3; +extern statetype s_deathchase3s; +extern statetype s_deathchase4; + +extern statetype s_deathdie1; +extern statetype s_deathdie2; +extern statetype s_deathdie3; +extern statetype s_deathdie4; +extern statetype s_deathdie5; +extern statetype s_deathdie6; +extern statetype s_deathdie7; +extern statetype s_deathdie8; +extern statetype s_deathdie9; + +extern statetype s_deathshoot1; +extern statetype s_deathshoot2; +extern statetype s_deathshoot3; +extern statetype s_deathshoot4; +extern statetype s_deathshoot5; + + +statetype s_deathstand = {false,SPR_DEATH_W1,0,T_Stand,NULL,&s_deathstand}; + +statetype s_deathchase1 = {false,SPR_DEATH_W1,10,T_Will,NULL,&s_deathchase1s}; +statetype s_deathchase1s = {false,SPR_DEATH_W1,3,NULL,NULL,&s_deathchase2}; +statetype s_deathchase2 = {false,SPR_DEATH_W2,8,T_Will,NULL,&s_deathchase3}; +statetype s_deathchase3 = {false,SPR_DEATH_W3,10,T_Will,NULL,&s_deathchase3s}; +statetype s_deathchase3s = {false,SPR_DEATH_W3,3,NULL,NULL,&s_deathchase4}; +statetype s_deathchase4 = {false,SPR_DEATH_W4,8,T_Will,NULL,&s_deathchase1}; + +statetype s_deathdeathcam = {false,SPR_DEATH_W1,1,NULL,NULL,&s_deathdie1}; + +statetype s_deathdie1 = {false,SPR_DEATH_W1,1,NULL,A_DeathScream,&s_deathdie2}; +statetype s_deathdie2 = {false,SPR_DEATH_W1,10,NULL,NULL,&s_deathdie3}; +statetype s_deathdie3 = {false,SPR_DEATH_DIE1,10,NULL,NULL,&s_deathdie4}; +statetype s_deathdie4 = {false,SPR_DEATH_DIE2,10,NULL,NULL,&s_deathdie5}; +statetype s_deathdie5 = {false,SPR_DEATH_DIE3,10,NULL,NULL,&s_deathdie6}; +statetype s_deathdie6 = {false,SPR_DEATH_DIE4,10,NULL,NULL,&s_deathdie7}; +statetype s_deathdie7 = {false,SPR_DEATH_DIE5,10,NULL,NULL,&s_deathdie8}; +statetype s_deathdie8 = {false,SPR_DEATH_DIE6,10,NULL,NULL,&s_deathdie9}; +statetype s_deathdie9 = {false,SPR_DEATH_DEAD,0,NULL,NULL,&s_deathdie9}; + +statetype s_deathshoot1 = {false,SPR_DEATH_SHOOT1,30,NULL,NULL,&s_deathshoot2}; +statetype s_deathshoot2 = {false,SPR_DEATH_SHOOT2,10,NULL,T_Launch,&s_deathshoot3}; +statetype s_deathshoot3 = {false,SPR_DEATH_SHOOT4,10,NULL,T_Shoot,&s_deathshoot4}; +statetype s_deathshoot4 = {false,SPR_DEATH_SHOOT3,10,NULL,T_Launch,&s_deathshoot5}; +statetype s_deathshoot5 = {false,SPR_DEATH_SHOOT4,10,NULL,T_Shoot,&s_deathchase1}; + + +/* +=============== += += SpawnDeath += +=============== +*/ + +void SpawnDeath (int tilex, int tiley) +{ + unsigned far *map,tile; + + if (SoundBlasterPresent && DigiMode != sds_Off) + s_deathdie2.tictime = 105; + + SpawnNewObj (tilex,tiley,&s_deathstand); + new->obclass = deathobj; + new->hitpoints = starthitpoints[gamestate.difficulty][en_death]; + new->flags |= FL_SHOOTABLE|FL_AMBUSH; + if (!loadedgame) + gamestate.killtotal++; +} + +/* +=============== += += T_Launch += +=============== +*/ + +void T_Launch (objtype *ob) +{ + long deltax,deltay; + float angle; + int iangle; + + deltax = player->x - ob->x; + deltay = ob->y - player->y; + angle = atan2 (deltay,deltax); + if (angle<0) + angle = M_PI*2+angle; + iangle = angle/(M_PI*2)*ANGLES; + if (ob->obclass == deathobj) + { + T_Shoot (ob); + if (ob->state == &s_deathshoot2) + { + iangle-=4; + if (iangle<0) + iangle+=ANGLES; + } + else + { + iangle+=4; + if (iangle>=ANGLES) + iangle-=ANGLES; + } + } + + GetNewActor (); + new->state = &s_rocket; + new->ticcount = 1; + + new->tilex = ob->tilex; + new->tiley = ob->tiley; + new->x = ob->x; + new->y = ob->y; + new->obclass = rocketobj; + switch(ob->obclass) + { + case deathobj: + new->state = &s_hrocket; + new->obclass = hrocketobj; + PlaySoundLocActor (KNIGHTMISSILESND,new); + break; + case angelobj: + new->state = &s_spark1; + new->obclass = sparkobj; + PlaySoundLocActor (ANGELFIRESND,new); + break; + default: + PlaySoundLocActor (MISSILEFIRESND,new); + } + + new->dir = nodir; + new->angle = iangle; + new->speed = 0x2000l; + new->flags = FL_NONMARK; + new->active = true; +} + + + +// +// angel +// +void A_Relaunch (objtype *ob); +void A_Victory (objtype *ob); +void A_StartAttack (objtype *ob); +void A_Breathing (objtype *ob); + +extern statetype s_angelstand; + +extern statetype s_angelchase1; +extern statetype s_angelchase1s; +extern statetype s_angelchase2; +extern statetype s_angelchase3; +extern statetype s_angelchase3s; +extern statetype s_angelchase4; + +extern statetype s_angeldie1; +extern statetype s_angeldie11; +extern statetype s_angeldie2; +extern statetype s_angeldie3; +extern statetype s_angeldie4; +extern statetype s_angeldie5; +extern statetype s_angeldie6; +extern statetype s_angeldie7; +extern statetype s_angeldie8; +extern statetype s_angeldie9; + +extern statetype s_angelshoot1; +extern statetype s_angelshoot2; +extern statetype s_angelshoot3; +extern statetype s_angelshoot4; +extern statetype s_angelshoot5; +extern statetype s_angelshoot6; + +extern statetype s_angeltired; +extern statetype s_angeltired2; +extern statetype s_angeltired3; +extern statetype s_angeltired4; +extern statetype s_angeltired5; +extern statetype s_angeltired6; +extern statetype s_angeltired7; + +extern statetype s_spark1; +extern statetype s_spark2; +extern statetype s_spark3; +extern statetype s_spark4; + + +statetype s_angelstand = {false,SPR_ANGEL_W1,0,T_Stand,NULL,&s_angelstand}; + +statetype s_angelchase1 = {false,SPR_ANGEL_W1,10,T_Will,NULL,&s_angelchase1s}; +statetype s_angelchase1s = {false,SPR_ANGEL_W1,3,NULL,NULL,&s_angelchase2}; +statetype s_angelchase2 = {false,SPR_ANGEL_W2,8,T_Will,NULL,&s_angelchase3}; +statetype s_angelchase3 = {false,SPR_ANGEL_W3,10,T_Will,NULL,&s_angelchase3s}; +statetype s_angelchase3s = {false,SPR_ANGEL_W3,3,NULL,NULL,&s_angelchase4}; +statetype s_angelchase4 = {false,SPR_ANGEL_W4,8,T_Will,NULL,&s_angelchase1}; + +statetype s_angeldie1 = {false,SPR_ANGEL_W1,1,NULL,A_DeathScream,&s_angeldie11}; +statetype s_angeldie11 = {false,SPR_ANGEL_W1,1,NULL,NULL,&s_angeldie2}; +statetype s_angeldie2 = {false,SPR_ANGEL_DIE1,10,NULL,A_Slurpie,&s_angeldie3}; +statetype s_angeldie3 = {false,SPR_ANGEL_DIE2,10,NULL,NULL,&s_angeldie4}; +statetype s_angeldie4 = {false,SPR_ANGEL_DIE3,10,NULL,NULL,&s_angeldie5}; +statetype s_angeldie5 = {false,SPR_ANGEL_DIE4,10,NULL,NULL,&s_angeldie6}; +statetype s_angeldie6 = {false,SPR_ANGEL_DIE5,10,NULL,NULL,&s_angeldie7}; +statetype s_angeldie7 = {false,SPR_ANGEL_DIE6,10,NULL,NULL,&s_angeldie8}; +statetype s_angeldie8 = {false,SPR_ANGEL_DIE7,10,NULL,NULL,&s_angeldie9}; +statetype s_angeldie9 = {false,SPR_ANGEL_DEAD,130,NULL,A_Victory,&s_angeldie9}; + +statetype s_angelshoot1 = {false,SPR_ANGEL_SHOOT1,10,NULL,A_StartAttack,&s_angelshoot2}; +statetype s_angelshoot2 = {false,SPR_ANGEL_SHOOT2,20,NULL,T_Launch,&s_angelshoot3}; +statetype s_angelshoot3 = {false,SPR_ANGEL_SHOOT1,10,NULL,A_Relaunch,&s_angelshoot2}; + +statetype s_angeltired = {false,SPR_ANGEL_TIRED1,40,NULL,A_Breathing,&s_angeltired2}; +statetype s_angeltired2 = {false,SPR_ANGEL_TIRED2,40,NULL,NULL,&s_angeltired3}; +statetype s_angeltired3 = {false,SPR_ANGEL_TIRED1,40,NULL,A_Breathing,&s_angeltired4}; +statetype s_angeltired4 = {false,SPR_ANGEL_TIRED2,40,NULL,NULL,&s_angeltired5}; +statetype s_angeltired5 = {false,SPR_ANGEL_TIRED1,40,NULL,A_Breathing,&s_angeltired6}; +statetype s_angeltired6 = {false,SPR_ANGEL_TIRED2,40,NULL,NULL,&s_angeltired7}; +statetype s_angeltired7 = {false,SPR_ANGEL_TIRED1,40,NULL,A_Breathing,&s_angelchase1}; + +statetype s_spark1 = {false,SPR_SPARK1,6,T_Projectile,NULL,&s_spark2}; +statetype s_spark2 = {false,SPR_SPARK2,6,T_Projectile,NULL,&s_spark3}; +statetype s_spark3 = {false,SPR_SPARK3,6,T_Projectile,NULL,&s_spark4}; +statetype s_spark4 = {false,SPR_SPARK4,6,T_Projectile,NULL,&s_spark1}; + + +#pragma argsused +void A_Slurpie (objtype *ob) +{ + SD_PlaySound(SLURPIESND); +} + +#pragma argsused +void A_Breathing (objtype *ob) +{ + SD_PlaySound(ANGELTIREDSND); +} + +/* +=============== += += SpawnAngel += +=============== +*/ + +void SpawnAngel (int tilex, int tiley) +{ + unsigned far *map,tile; + + + if (SoundBlasterPresent && DigiMode != sds_Off) + s_angeldie11.tictime = 105; + + SpawnNewObj (tilex,tiley,&s_angelstand); + new->obclass = angelobj; + new->hitpoints = starthitpoints[gamestate.difficulty][en_angel]; + new->flags |= FL_SHOOTABLE|FL_AMBUSH; + if (!loadedgame) + gamestate.killtotal++; +} + + +/* +================= += += A_Victory += +================= +*/ + +#pragma argsused +void A_Victory (objtype *ob) +{ + playstate = ex_victorious; +} + + +/* +================= += += A_StartAttack += +================= +*/ + +void A_StartAttack (objtype *ob) +{ + ob->temp1 = 0; +} + + +/* +================= += += A_Relaunch += +================= +*/ + +void A_Relaunch (objtype *ob) +{ + if (++ob->temp1 == 3) + { + NewState (ob,&s_angeltired); + return; + } + + if (US_RndT()&1) + { + NewState (ob,&s_angelchase1); + return; + } +} + + + + +// +// spectre +// +void T_SpectreWait (objtype *ob); +void A_Dormant (objtype *ob); + +extern statetype s_spectrewait1; +extern statetype s_spectrewait2; +extern statetype s_spectrewait3; +extern statetype s_spectrewait4; + +extern statetype s_spectrechase1; +extern statetype s_spectrechase2; +extern statetype s_spectrechase3; +extern statetype s_spectrechase4; + +extern statetype s_spectredie1; +extern statetype s_spectredie2; +extern statetype s_spectredie3; +extern statetype s_spectredie4; + +extern statetype s_spectrewake; + +statetype s_spectrewait1 = {false,SPR_SPECTRE_W1,10,T_Stand,NULL,&s_spectrewait2}; +statetype s_spectrewait2 = {false,SPR_SPECTRE_W2,10,T_Stand,NULL,&s_spectrewait3}; +statetype s_spectrewait3 = {false,SPR_SPECTRE_W3,10,T_Stand,NULL,&s_spectrewait4}; +statetype s_spectrewait4 = {false,SPR_SPECTRE_W4,10,T_Stand,NULL,&s_spectrewait1}; + +statetype s_spectrechase1 = {false,SPR_SPECTRE_W1,10,T_Ghosts,NULL,&s_spectrechase2}; +statetype s_spectrechase2 = {false,SPR_SPECTRE_W2,10,T_Ghosts,NULL,&s_spectrechase3}; +statetype s_spectrechase3 = {false,SPR_SPECTRE_W3,10,T_Ghosts,NULL,&s_spectrechase4}; +statetype s_spectrechase4 = {false,SPR_SPECTRE_W4,10,T_Ghosts,NULL,&s_spectrechase1}; + +statetype s_spectredie1 = {false,SPR_SPECTRE_F1,10,NULL,NULL,&s_spectredie2}; +statetype s_spectredie2 = {false,SPR_SPECTRE_F2,10,NULL,NULL,&s_spectredie3}; +statetype s_spectredie3 = {false,SPR_SPECTRE_F3,10,NULL,NULL,&s_spectredie4}; +statetype s_spectredie4 = {false,SPR_SPECTRE_F4,300,NULL,NULL,&s_spectrewake}; +statetype s_spectrewake = {false,SPR_SPECTRE_F4,10,NULL,A_Dormant,&s_spectrewake}; + +/* +=============== += += SpawnSpectre += +=============== +*/ + +void SpawnSpectre (int tilex, int tiley) +{ + unsigned far *map,tile; + + SpawnNewObj (tilex,tiley,&s_spectrewait1); + new->obclass = spectreobj; + new->hitpoints = starthitpoints[gamestate.difficulty][en_spectre]; + new->flags |= FL_SHOOTABLE|FL_AMBUSH; // |FL_NEVERMARK|FL_NONMARK; + if (!loadedgame) + gamestate.killtotal++; +} + + +/* +=============== += += A_Dormant += +=============== +*/ + +void A_Dormant (objtype *ob) +{ + long deltax,deltay; + int xl,xh,yl,yh; + int x,y; + objtype *tile; + + deltax = ob->x - player->x; + if (deltax < -MINACTORDIST || deltax > MINACTORDIST) + goto moveok; + deltay = ob->y - player->y; + if (deltay < -MINACTORDIST || deltay > MINACTORDIST) + goto moveok; + + return; +moveok: + + xl = (ob->x-MINDIST) >> TILESHIFT; + xh = (ob->x+MINDIST) >> TILESHIFT; + yl = (ob->y-MINDIST) >> TILESHIFT; + yh = (ob->y+MINDIST) >> TILESHIFT; + + for (y=yl ; y<=yh ; y++) + for (x=xl ; x<=xh ; x++) + { + tile = actorat[x][y]; + if (!tile) + continue; + if (tile && tileflags&FL_SHOOTABLE) + return; + } + + ob->flags |= FL_AMBUSH | FL_SHOOTABLE; + ob->flags &= ~FL_ATTACKMODE; + ob->dir = nodir; + NewState (ob,&s_spectrewait1); +} + + +#endif + +/* +============================================================================= + + SCHABBS / GIFT / FAT + +============================================================================= +*/ + +#ifndef SPEAR +/* +=============== += += SpawnGhosts += +=============== +*/ + +void SpawnGhosts (int which, int tilex, int tiley) +{ + unsigned far *map,tile; + + switch(which) + { + case en_blinky: + SpawnNewObj (tilex,tiley,&s_blinkychase1); + break; + case en_clyde: + SpawnNewObj (tilex,tiley,&s_clydechase1); + break; + case en_pinky: + SpawnNewObj (tilex,tiley,&s_pinkychase1); + break; + case en_inky: + SpawnNewObj (tilex,tiley,&s_inkychase1); + break; + } + + new->obclass = ghostobj; + new->speed = SPDDOG; + + new->dir = east; + new->flags |= FL_AMBUSH; + if (!loadedgame) + gamestate.killtotal++; +} + + + +void T_Gift (objtype *ob); +void T_GiftThrow (objtype *ob); + +void T_Fat (objtype *ob); +void T_FatThrow (objtype *ob); + +// +// schabb +// +extern statetype s_schabbstand; + +extern statetype s_schabbchase1; +extern statetype s_schabbchase1s; +extern statetype s_schabbchase2; +extern statetype s_schabbchase3; +extern statetype s_schabbchase3s; +extern statetype s_schabbchase4; + +extern statetype s_schabbdie1; +extern statetype s_schabbdie2; +extern statetype s_schabbdie3; +extern statetype s_schabbdie4; +extern statetype s_schabbdie5; +extern statetype s_schabbdie6; + +extern statetype s_schabbshoot1; +extern statetype s_schabbshoot2; + +extern statetype s_needle1; +extern statetype s_needle2; +extern statetype s_needle3; +extern statetype s_needle4; + +extern statetype s_schabbdeathcam; + + +statetype s_schabbstand = {false,SPR_SCHABB_W1,0,T_Stand,NULL,&s_schabbstand}; + +statetype s_schabbchase1 = {false,SPR_SCHABB_W1,10,T_Schabb,NULL,&s_schabbchase1s}; +statetype s_schabbchase1s = {false,SPR_SCHABB_W1,3,NULL,NULL,&s_schabbchase2}; +statetype s_schabbchase2 = {false,SPR_SCHABB_W2,8,T_Schabb,NULL,&s_schabbchase3}; +statetype s_schabbchase3 = {false,SPR_SCHABB_W3,10,T_Schabb,NULL,&s_schabbchase3s}; +statetype s_schabbchase3s = {false,SPR_SCHABB_W3,3,NULL,NULL,&s_schabbchase4}; +statetype s_schabbchase4 = {false,SPR_SCHABB_W4,8,T_Schabb,NULL,&s_schabbchase1}; + +statetype s_schabbdeathcam = {false,SPR_SCHABB_W1,1,NULL,NULL,&s_schabbdie1}; + +statetype s_schabbdie1 = {false,SPR_SCHABB_W1,10,NULL,A_DeathScream,&s_schabbdie2}; +statetype s_schabbdie2 = {false,SPR_SCHABB_W1,10,NULL,NULL,&s_schabbdie3}; +statetype s_schabbdie3 = {false,SPR_SCHABB_DIE1,10,NULL,NULL,&s_schabbdie4}; +statetype s_schabbdie4 = {false,SPR_SCHABB_DIE2,10,NULL,NULL,&s_schabbdie5}; +statetype s_schabbdie5 = {false,SPR_SCHABB_DIE3,10,NULL,NULL,&s_schabbdie6}; +statetype s_schabbdie6 = {false,SPR_SCHABB_DEAD,20,NULL,A_StartDeathCam,&s_schabbdie6}; + +statetype s_schabbshoot1 = {false,SPR_SCHABB_SHOOT1,30,NULL,NULL,&s_schabbshoot2}; +statetype s_schabbshoot2 = {false,SPR_SCHABB_SHOOT2,10,NULL,T_SchabbThrow,&s_schabbchase1}; + +statetype s_needle1 = {false,SPR_HYPO1,6,T_Projectile,NULL,&s_needle2}; +statetype s_needle2 = {false,SPR_HYPO2,6,T_Projectile,NULL,&s_needle3}; +statetype s_needle3 = {false,SPR_HYPO3,6,T_Projectile,NULL,&s_needle4}; +statetype s_needle4 = {false,SPR_HYPO4,6,T_Projectile,NULL,&s_needle1}; + + +// +// gift +// +extern statetype s_giftstand; + +extern statetype s_giftchase1; +extern statetype s_giftchase1s; +extern statetype s_giftchase2; +extern statetype s_giftchase3; +extern statetype s_giftchase3s; +extern statetype s_giftchase4; + +extern statetype s_giftdie1; +extern statetype s_giftdie2; +extern statetype s_giftdie3; +extern statetype s_giftdie4; +extern statetype s_giftdie5; +extern statetype s_giftdie6; + +extern statetype s_giftshoot1; +extern statetype s_giftshoot2; + +extern statetype s_needle1; +extern statetype s_needle2; +extern statetype s_needle3; +extern statetype s_needle4; + +extern statetype s_giftdeathcam; + +extern statetype s_boom1; +extern statetype s_boom2; +extern statetype s_boom3; + + +statetype s_giftstand = {false,SPR_GIFT_W1,0,T_Stand,NULL,&s_giftstand}; + +statetype s_giftchase1 = {false,SPR_GIFT_W1,10,T_Gift,NULL,&s_giftchase1s}; +statetype s_giftchase1s = {false,SPR_GIFT_W1,3,NULL,NULL,&s_giftchase2}; +statetype s_giftchase2 = {false,SPR_GIFT_W2,8,T_Gift,NULL,&s_giftchase3}; +statetype s_giftchase3 = {false,SPR_GIFT_W3,10,T_Gift,NULL,&s_giftchase3s}; +statetype s_giftchase3s = {false,SPR_GIFT_W3,3,NULL,NULL,&s_giftchase4}; +statetype s_giftchase4 = {false,SPR_GIFT_W4,8,T_Gift,NULL,&s_giftchase1}; + +statetype s_giftdeathcam = {false,SPR_GIFT_W1,1,NULL,NULL,&s_giftdie1}; + +statetype s_giftdie1 = {false,SPR_GIFT_W1,1,NULL,A_DeathScream,&s_giftdie2}; +statetype s_giftdie2 = {false,SPR_GIFT_W1,10,NULL,NULL,&s_giftdie3}; +statetype s_giftdie3 = {false,SPR_GIFT_DIE1,10,NULL,NULL,&s_giftdie4}; +statetype s_giftdie4 = {false,SPR_GIFT_DIE2,10,NULL,NULL,&s_giftdie5}; +statetype s_giftdie5 = {false,SPR_GIFT_DIE3,10,NULL,NULL,&s_giftdie6}; +statetype s_giftdie6 = {false,SPR_GIFT_DEAD,20,NULL,A_StartDeathCam,&s_giftdie6}; + +statetype s_giftshoot1 = {false,SPR_GIFT_SHOOT1,30,NULL,NULL,&s_giftshoot2}; +statetype s_giftshoot2 = {false,SPR_GIFT_SHOOT2,10,NULL,T_GiftThrow,&s_giftchase1}; + + +// +// fat +// +extern statetype s_fatstand; + +extern statetype s_fatchase1; +extern statetype s_fatchase1s; +extern statetype s_fatchase2; +extern statetype s_fatchase3; +extern statetype s_fatchase3s; +extern statetype s_fatchase4; + +extern statetype s_fatdie1; +extern statetype s_fatdie2; +extern statetype s_fatdie3; +extern statetype s_fatdie4; +extern statetype s_fatdie5; +extern statetype s_fatdie6; + +extern statetype s_fatshoot1; +extern statetype s_fatshoot2; +extern statetype s_fatshoot3; +extern statetype s_fatshoot4; +extern statetype s_fatshoot5; +extern statetype s_fatshoot6; + +extern statetype s_needle1; +extern statetype s_needle2; +extern statetype s_needle3; +extern statetype s_needle4; + +extern statetype s_fatdeathcam; + + +statetype s_fatstand = {false,SPR_FAT_W1,0,T_Stand,NULL,&s_fatstand}; + +statetype s_fatchase1 = {false,SPR_FAT_W1,10,T_Fat,NULL,&s_fatchase1s}; +statetype s_fatchase1s = {false,SPR_FAT_W1,3,NULL,NULL,&s_fatchase2}; +statetype s_fatchase2 = {false,SPR_FAT_W2,8,T_Fat,NULL,&s_fatchase3}; +statetype s_fatchase3 = {false,SPR_FAT_W3,10,T_Fat,NULL,&s_fatchase3s}; +statetype s_fatchase3s = {false,SPR_FAT_W3,3,NULL,NULL,&s_fatchase4}; +statetype s_fatchase4 = {false,SPR_FAT_W4,8,T_Fat,NULL,&s_fatchase1}; + +statetype s_fatdeathcam = {false,SPR_FAT_W1,1,NULL,NULL,&s_fatdie1}; + +statetype s_fatdie1 = {false,SPR_FAT_W1,1,NULL,A_DeathScream,&s_fatdie2}; +statetype s_fatdie2 = {false,SPR_FAT_W1,10,NULL,NULL,&s_fatdie3}; +statetype s_fatdie3 = {false,SPR_FAT_DIE1,10,NULL,NULL,&s_fatdie4}; +statetype s_fatdie4 = {false,SPR_FAT_DIE2,10,NULL,NULL,&s_fatdie5}; +statetype s_fatdie5 = {false,SPR_FAT_DIE3,10,NULL,NULL,&s_fatdie6}; +statetype s_fatdie6 = {false,SPR_FAT_DEAD,20,NULL,A_StartDeathCam,&s_fatdie6}; + +statetype s_fatshoot1 = {false,SPR_FAT_SHOOT1,30,NULL,NULL,&s_fatshoot2}; +statetype s_fatshoot2 = {false,SPR_FAT_SHOOT2,10,NULL,T_GiftThrow,&s_fatshoot3}; +statetype s_fatshoot3 = {false,SPR_FAT_SHOOT3,10,NULL,T_Shoot,&s_fatshoot4}; +statetype s_fatshoot4 = {false,SPR_FAT_SHOOT4,10,NULL,T_Shoot,&s_fatshoot5}; +statetype s_fatshoot5 = {false,SPR_FAT_SHOOT3,10,NULL,T_Shoot,&s_fatshoot6}; +statetype s_fatshoot6 = {false,SPR_FAT_SHOOT4,10,NULL,T_Shoot,&s_fatchase1}; + + +/* +=============== += += SpawnSchabbs += +=============== +*/ + +void SpawnSchabbs (int tilex, int tiley) +{ + unsigned far *map,tile; + + if (DigiMode != sds_Off) + s_schabbdie2.tictime = 140; + else + s_schabbdie2.tictime = 5; + + SpawnNewObj (tilex,tiley,&s_schabbstand); + new->speed = SPDPATROL; + + new->obclass = schabbobj; + new->hitpoints = starthitpoints[gamestate.difficulty][en_schabbs]; + new->dir = south; + new->flags |= FL_SHOOTABLE|FL_AMBUSH; + if (!loadedgame) + gamestate.killtotal++; +} + + +/* +=============== += += SpawnGift += +=============== +*/ + +void SpawnGift (int tilex, int tiley) +{ + unsigned far *map,tile; + + if (DigiMode != sds_Off) + s_giftdie2.tictime = 140; + else + s_giftdie2.tictime = 5; + + SpawnNewObj (tilex,tiley,&s_giftstand); + new->speed = SPDPATROL; + + new->obclass = giftobj; + new->hitpoints = starthitpoints[gamestate.difficulty][en_gift]; + new->dir = north; + new->flags |= FL_SHOOTABLE|FL_AMBUSH; + if (!loadedgame) + gamestate.killtotal++; +} + + +/* +=============== += += SpawnFat += +=============== +*/ + +void SpawnFat (int tilex, int tiley) +{ + unsigned far *map,tile; + + if (DigiMode != sds_Off) + s_fatdie2.tictime = 140; + else + s_fatdie2.tictime = 5; + + SpawnNewObj (tilex,tiley,&s_fatstand); + new->speed = SPDPATROL; + + new->obclass = fatobj; + new->hitpoints = starthitpoints[gamestate.difficulty][en_fat]; + new->dir = south; + new->flags |= FL_SHOOTABLE|FL_AMBUSH; + if (!loadedgame) + gamestate.killtotal++; +} + + +/* +================= += += T_SchabbThrow += +================= +*/ + +void T_SchabbThrow (objtype *ob) +{ + long deltax,deltay; + float angle; + int iangle; + + deltax = player->x - ob->x; + deltay = ob->y - player->y; + angle = atan2 (deltay,deltax); + if (angle<0) + angle = M_PI*2+angle; + iangle = angle/(M_PI*2)*ANGLES; + + GetNewActor (); + new->state = &s_needle1; + new->ticcount = 1; + + new->tilex = ob->tilex; + new->tiley = ob->tiley; + new->x = ob->x; + new->y = ob->y; + new->obclass = needleobj; + new->dir = nodir; + new->angle = iangle; + new->speed = 0x2000l; + + new->flags = FL_NONMARK; + new->active = true; + + PlaySoundLocActor (SCHABBSTHROWSND,new); +} + +/* +================= += += T_GiftThrow += +================= +*/ + +void T_GiftThrow (objtype *ob) +{ + long deltax,deltay; + float angle; + int iangle; + + deltax = player->x - ob->x; + deltay = ob->y - player->y; + angle = atan2 (deltay,deltax); + if (angle<0) + angle = M_PI*2+angle; + iangle = angle/(M_PI*2)*ANGLES; + + GetNewActor (); + new->state = &s_rocket; + new->ticcount = 1; + + new->tilex = ob->tilex; + new->tiley = ob->tiley; + new->x = ob->x; + new->y = ob->y; + new->obclass = rocketobj; + new->dir = nodir; + new->angle = iangle; + new->speed = 0x2000l; + new->flags = FL_NONMARK; + new->active = true; + + PlaySoundLocActor (MISSILEFIRESND,new); +} + + + +/* +================= += += T_Schabb += +================= +*/ + +void T_Schabb (objtype *ob) +{ + long move; + int dx,dy,dist; + boolean dodge; + + dodge = false; + dx = abs(ob->tilex - player->tilex); + dy = abs(ob->tiley - player->tiley); + dist = dx>dy ? dx : dy; + + if (CheckLine(ob)) // got a shot at player? + { + + if ( US_RndT() < (tics<<3) ) + { + // + // go into attack frame + // + NewState (ob,&s_schabbshoot1); + return; + } + dodge = true; + } + + if (ob->dir == nodir) + { + if (dodge) + SelectDodgeDir (ob); + else + SelectChaseDir (ob); + if (ob->dir == nodir) + return; // object is blocked in + } + + move = ob->speed*tics; + + while (move) + { + if (ob->distance < 0) + { + // + // waiting for a door to open + // + OpenDoor (-ob->distance-1); + if (doorobjlist[-ob->distance-1].action != dr_open) + return; + ob->distance = TILEGLOBAL; // go ahead, the door is now opoen + } + + if (move < ob->distance) + { + MoveObj (ob,move); + break; + } + + // + // reached goal tile, so select another one + // + + // + // fix position to account for round off during moving + // + ob->x = ((long)ob->tilex<y = ((long)ob->tiley<distance; + + if (dist <4) + SelectRunDir (ob); + else if (dodge) + SelectDodgeDir (ob); + else + SelectChaseDir (ob); + + if (ob->dir == nodir) + return; // object is blocked in + } + +} + + + + +/* +================= += += T_Gift += +================= +*/ + +void T_Gift (objtype *ob) +{ + long move; + int dx,dy,dist; + boolean dodge; + + dodge = false; + dx = abs(ob->tilex - player->tilex); + dy = abs(ob->tiley - player->tiley); + dist = dx>dy ? dx : dy; + + if (CheckLine(ob)) // got a shot at player? + { + + if ( US_RndT() < (tics<<3) ) + { + // + // go into attack frame + // + NewState (ob,&s_giftshoot1); + return; + } + dodge = true; + } + + if (ob->dir == nodir) + { + if (dodge) + SelectDodgeDir (ob); + else + SelectChaseDir (ob); + if (ob->dir == nodir) + return; // object is blocked in + } + + move = ob->speed*tics; + + while (move) + { + if (ob->distance < 0) + { + // + // waiting for a door to open + // + OpenDoor (-ob->distance-1); + if (doorobjlist[-ob->distance-1].action != dr_open) + return; + ob->distance = TILEGLOBAL; // go ahead, the door is now opoen + } + + if (move < ob->distance) + { + MoveObj (ob,move); + break; + } + + // + // reached goal tile, so select another one + // + + // + // fix position to account for round off during moving + // + ob->x = ((long)ob->tilex<y = ((long)ob->tiley<distance; + + if (dist <4) + SelectRunDir (ob); + else if (dodge) + SelectDodgeDir (ob); + else + SelectChaseDir (ob); + + if (ob->dir == nodir) + return; // object is blocked in + } + +} + + + + +/* +================= += += T_Fat += +================= +*/ + +void T_Fat (objtype *ob) +{ + long move; + int dx,dy,dist; + boolean dodge; + + dodge = false; + dx = abs(ob->tilex - player->tilex); + dy = abs(ob->tiley - player->tiley); + dist = dx>dy ? dx : dy; + + if (CheckLine(ob)) // got a shot at player? + { + + if ( US_RndT() < (tics<<3) ) + { + // + // go into attack frame + // + NewState (ob,&s_fatshoot1); + return; + } + dodge = true; + } + + if (ob->dir == nodir) + { + if (dodge) + SelectDodgeDir (ob); + else + SelectChaseDir (ob); + if (ob->dir == nodir) + return; // object is blocked in + } + + move = ob->speed*tics; + + while (move) + { + if (ob->distance < 0) + { + // + // waiting for a door to open + // + OpenDoor (-ob->distance-1); + if (doorobjlist[-ob->distance-1].action != dr_open) + return; + ob->distance = TILEGLOBAL; // go ahead, the door is now opoen + } + + if (move < ob->distance) + { + MoveObj (ob,move); + break; + } + + // + // reached goal tile, so select another one + // + + // + // fix position to account for round off during moving + // + ob->x = ((long)ob->tilex<y = ((long)ob->tiley<distance; + + if (dist <4) + SelectRunDir (ob); + else if (dodge) + SelectDodgeDir (ob); + else + SelectChaseDir (ob); + + if (ob->dir == nodir) + return; // object is blocked in + } + +} + + + +/* +============================================================================= + + HITLERS + +============================================================================= +*/ + + +// +// fake +// +extern statetype s_fakestand; + +extern statetype s_fakechase1; +extern statetype s_fakechase1s; +extern statetype s_fakechase2; +extern statetype s_fakechase3; +extern statetype s_fakechase3s; +extern statetype s_fakechase4; + +extern statetype s_fakedie1; +extern statetype s_fakedie2; +extern statetype s_fakedie3; +extern statetype s_fakedie4; +extern statetype s_fakedie5; +extern statetype s_fakedie6; + +extern statetype s_fakeshoot1; +extern statetype s_fakeshoot2; +extern statetype s_fakeshoot3; +extern statetype s_fakeshoot4; +extern statetype s_fakeshoot5; +extern statetype s_fakeshoot6; +extern statetype s_fakeshoot7; +extern statetype s_fakeshoot8; +extern statetype s_fakeshoot9; + +extern statetype s_fire1; +extern statetype s_fire2; + +statetype s_fakestand = {false,SPR_FAKE_W1,0,T_Stand,NULL,&s_fakestand}; + +statetype s_fakechase1 = {false,SPR_FAKE_W1,10,T_Fake,NULL,&s_fakechase1s}; +statetype s_fakechase1s = {false,SPR_FAKE_W1,3,NULL,NULL,&s_fakechase2}; +statetype s_fakechase2 = {false,SPR_FAKE_W2,8,T_Fake,NULL,&s_fakechase3}; +statetype s_fakechase3 = {false,SPR_FAKE_W3,10,T_Fake,NULL,&s_fakechase3s}; +statetype s_fakechase3s = {false,SPR_FAKE_W3,3,NULL,NULL,&s_fakechase4}; +statetype s_fakechase4 = {false,SPR_FAKE_W4,8,T_Fake,NULL,&s_fakechase1}; + +statetype s_fakedie1 = {false,SPR_FAKE_DIE1,10,NULL,A_DeathScream,&s_fakedie2}; +statetype s_fakedie2 = {false,SPR_FAKE_DIE2,10,NULL,NULL,&s_fakedie3}; +statetype s_fakedie3 = {false,SPR_FAKE_DIE3,10,NULL,NULL,&s_fakedie4}; +statetype s_fakedie4 = {false,SPR_FAKE_DIE4,10,NULL,NULL,&s_fakedie5}; +statetype s_fakedie5 = {false,SPR_FAKE_DIE5,10,NULL,NULL,&s_fakedie6}; +statetype s_fakedie6 = {false,SPR_FAKE_DEAD,0,NULL,NULL,&s_fakedie6}; + +statetype s_fakeshoot1 = {false,SPR_FAKE_SHOOT,8,NULL,T_FakeFire,&s_fakeshoot2}; +statetype s_fakeshoot2 = {false,SPR_FAKE_SHOOT,8,NULL,T_FakeFire,&s_fakeshoot3}; +statetype s_fakeshoot3 = {false,SPR_FAKE_SHOOT,8,NULL,T_FakeFire,&s_fakeshoot4}; +statetype s_fakeshoot4 = {false,SPR_FAKE_SHOOT,8,NULL,T_FakeFire,&s_fakeshoot5}; +statetype s_fakeshoot5 = {false,SPR_FAKE_SHOOT,8,NULL,T_FakeFire,&s_fakeshoot6}; +statetype s_fakeshoot6 = {false,SPR_FAKE_SHOOT,8,NULL,T_FakeFire,&s_fakeshoot7}; +statetype s_fakeshoot7 = {false,SPR_FAKE_SHOOT,8,NULL,T_FakeFire,&s_fakeshoot8}; +statetype s_fakeshoot8 = {false,SPR_FAKE_SHOOT,8,NULL,T_FakeFire,&s_fakeshoot9}; +statetype s_fakeshoot9 = {false,SPR_FAKE_SHOOT,8,NULL,NULL,&s_fakechase1}; + +statetype s_fire1 = {false,SPR_FIRE1,6,NULL,T_Projectile,&s_fire2}; +statetype s_fire2 = {false,SPR_FIRE2,6,NULL,T_Projectile,&s_fire1}; + +// +// hitler +// +extern statetype s_mechachase1; +extern statetype s_mechachase1s; +extern statetype s_mechachase2; +extern statetype s_mechachase3; +extern statetype s_mechachase3s; +extern statetype s_mechachase4; + +extern statetype s_mechadie1; +extern statetype s_mechadie2; +extern statetype s_mechadie3; +extern statetype s_mechadie4; + +extern statetype s_mechashoot1; +extern statetype s_mechashoot2; +extern statetype s_mechashoot3; +extern statetype s_mechashoot4; +extern statetype s_mechashoot5; +extern statetype s_mechashoot6; + + +extern statetype s_hitlerchase1; +extern statetype s_hitlerchase1s; +extern statetype s_hitlerchase2; +extern statetype s_hitlerchase3; +extern statetype s_hitlerchase3s; +extern statetype s_hitlerchase4; + +extern statetype s_hitlerdie1; +extern statetype s_hitlerdie2; +extern statetype s_hitlerdie3; +extern statetype s_hitlerdie4; +extern statetype s_hitlerdie5; +extern statetype s_hitlerdie6; +extern statetype s_hitlerdie7; +extern statetype s_hitlerdie8; +extern statetype s_hitlerdie9; +extern statetype s_hitlerdie10; + +extern statetype s_hitlershoot1; +extern statetype s_hitlershoot2; +extern statetype s_hitlershoot3; +extern statetype s_hitlershoot4; +extern statetype s_hitlershoot5; +extern statetype s_hitlershoot6; + +extern statetype s_hitlerdeathcam; + +statetype s_mechastand = {false,SPR_MECHA_W1,0,T_Stand,NULL,&s_mechastand}; + +statetype s_mechachase1 = {false,SPR_MECHA_W1,10,T_Chase,A_MechaSound,&s_mechachase1s}; +statetype s_mechachase1s = {false,SPR_MECHA_W1,6,NULL,NULL,&s_mechachase2}; +statetype s_mechachase2 = {false,SPR_MECHA_W2,8,T_Chase,NULL,&s_mechachase3}; +statetype s_mechachase3 = {false,SPR_MECHA_W3,10,T_Chase,A_MechaSound,&s_mechachase3s}; +statetype s_mechachase3s = {false,SPR_MECHA_W3,6,NULL,NULL,&s_mechachase4}; +statetype s_mechachase4 = {false,SPR_MECHA_W4,8,T_Chase,NULL,&s_mechachase1}; + +statetype s_mechadie1 = {false,SPR_MECHA_DIE1,10,NULL,A_DeathScream,&s_mechadie2}; +statetype s_mechadie2 = {false,SPR_MECHA_DIE2,10,NULL,NULL,&s_mechadie3}; +statetype s_mechadie3 = {false,SPR_MECHA_DIE3,10,NULL,A_HitlerMorph,&s_mechadie4}; +statetype s_mechadie4 = {false,SPR_MECHA_DEAD,0,NULL,NULL,&s_mechadie4}; + +statetype s_mechashoot1 = {false,SPR_MECHA_SHOOT1,30,NULL,NULL,&s_mechashoot2}; +statetype s_mechashoot2 = {false,SPR_MECHA_SHOOT2,10,NULL,T_Shoot,&s_mechashoot3}; +statetype s_mechashoot3 = {false,SPR_MECHA_SHOOT3,10,NULL,T_Shoot,&s_mechashoot4}; +statetype s_mechashoot4 = {false,SPR_MECHA_SHOOT2,10,NULL,T_Shoot,&s_mechashoot5}; +statetype s_mechashoot5 = {false,SPR_MECHA_SHOOT3,10,NULL,T_Shoot,&s_mechashoot6}; +statetype s_mechashoot6 = {false,SPR_MECHA_SHOOT2,10,NULL,T_Shoot,&s_mechachase1}; + + +statetype s_hitlerchase1 = {false,SPR_HITLER_W1,6,T_Chase,NULL,&s_hitlerchase1s}; +statetype s_hitlerchase1s = {false,SPR_HITLER_W1,4,NULL,NULL,&s_hitlerchase2}; +statetype s_hitlerchase2 = {false,SPR_HITLER_W2,2,T_Chase,NULL,&s_hitlerchase3}; +statetype s_hitlerchase3 = {false,SPR_HITLER_W3,6,T_Chase,NULL,&s_hitlerchase3s}; +statetype s_hitlerchase3s = {false,SPR_HITLER_W3,4,NULL,NULL,&s_hitlerchase4}; +statetype s_hitlerchase4 = {false,SPR_HITLER_W4,2,T_Chase,NULL,&s_hitlerchase1}; + +statetype s_hitlerdeathcam = {false,SPR_HITLER_W1,10,NULL,NULL,&s_hitlerdie1}; + +statetype s_hitlerdie1 = {false,SPR_HITLER_W1,1,NULL,A_DeathScream,&s_hitlerdie2}; +statetype s_hitlerdie2 = {false,SPR_HITLER_W1,10,NULL,NULL,&s_hitlerdie3}; +statetype s_hitlerdie3 = {false,SPR_HITLER_DIE1,10,NULL,A_Slurpie,&s_hitlerdie4}; +statetype s_hitlerdie4 = {false,SPR_HITLER_DIE2,10,NULL,NULL,&s_hitlerdie5}; +statetype s_hitlerdie5 = {false,SPR_HITLER_DIE3,10,NULL,NULL,&s_hitlerdie6}; +statetype s_hitlerdie6 = {false,SPR_HITLER_DIE4,10,NULL,NULL,&s_hitlerdie7}; +statetype s_hitlerdie7 = {false,SPR_HITLER_DIE5,10,NULL,NULL,&s_hitlerdie8}; +statetype s_hitlerdie8 = {false,SPR_HITLER_DIE6,10,NULL,NULL,&s_hitlerdie9}; +statetype s_hitlerdie9 = {false,SPR_HITLER_DIE7,10,NULL,NULL,&s_hitlerdie10}; +statetype s_hitlerdie10 = {false,SPR_HITLER_DEAD,20,NULL,A_StartDeathCam,&s_hitlerdie10}; + +statetype s_hitlershoot1 = {false,SPR_HITLER_SHOOT1,30,NULL,NULL,&s_hitlershoot2}; +statetype s_hitlershoot2 = {false,SPR_HITLER_SHOOT2,10,NULL,T_Shoot,&s_hitlershoot3}; +statetype s_hitlershoot3 = {false,SPR_HITLER_SHOOT3,10,NULL,T_Shoot,&s_hitlershoot4}; +statetype s_hitlershoot4 = {false,SPR_HITLER_SHOOT2,10,NULL,T_Shoot,&s_hitlershoot5}; +statetype s_hitlershoot5 = {false,SPR_HITLER_SHOOT3,10,NULL,T_Shoot,&s_hitlershoot6}; +statetype s_hitlershoot6 = {false,SPR_HITLER_SHOOT2,10,NULL,T_Shoot,&s_hitlerchase1}; + + + +/* +=============== += += SpawnFakeHitler += +=============== +*/ + +void SpawnFakeHitler (int tilex, int tiley) +{ + unsigned far *map,tile; + + + if (DigiMode != sds_Off) + s_hitlerdie2.tictime = 140; + else + s_hitlerdie2.tictime = 5; + + SpawnNewObj (tilex,tiley,&s_fakestand); + new->speed = SPDPATROL; + + new->obclass = fakeobj; + new->hitpoints = starthitpoints[gamestate.difficulty][en_fake]; + new->dir = north; + new->flags |= FL_SHOOTABLE|FL_AMBUSH; + if (!loadedgame) + gamestate.killtotal++; +} + + +/* +=============== += += SpawnHitler += +=============== +*/ + +void SpawnHitler (int tilex, int tiley) +{ + unsigned far *map,tile; + + if (DigiMode != sds_Off) + s_hitlerdie2.tictime = 140; + else + s_hitlerdie2.tictime = 5; + + + SpawnNewObj (tilex,tiley,&s_mechastand); + new->speed = SPDPATROL; + + new->obclass = mechahitlerobj; + new->hitpoints = starthitpoints[gamestate.difficulty][en_hitler]; + new->dir = south; + new->flags |= FL_SHOOTABLE|FL_AMBUSH; + if (!loadedgame) + gamestate.killtotal++; +} + + +/* +=============== += += A_HitlerMorph += +=============== +*/ + +void A_HitlerMorph (objtype *ob) +{ + unsigned far *map,tile,hitpoints[4]={500,700,800,900}; + + + SpawnNewObj (ob->tilex,ob->tiley,&s_hitlerchase1); + new->speed = SPDPATROL*5; + + new->x = ob->x; + new->y = ob->y; + + new->distance = ob->distance; + new->dir = ob->dir; + new->flags = ob->flags | FL_SHOOTABLE; + + new->obclass = realhitlerobj; + new->hitpoints = hitpoints[gamestate.difficulty]; +} + + +//////////////////////////////////////////////////////// +// +// A_MechaSound +// A_Slurpie +// +//////////////////////////////////////////////////////// +void A_MechaSound (objtype *ob) +{ + if (areabyplayer[ob->areanumber]) + PlaySoundLocActor (MECHSTEPSND,ob); +} + + +#pragma argsused +void A_Slurpie (objtype *ob) +{ + SD_PlaySound(SLURPIESND); +} + +/* +================= += += T_FakeFire += +================= +*/ + +void T_FakeFire (objtype *ob) +{ + long deltax,deltay; + float angle; + int iangle; + + deltax = player->x - ob->x; + deltay = ob->y - player->y; + angle = atan2 (deltay,deltax); + if (angle<0) + angle = M_PI*2+angle; + iangle = angle/(M_PI*2)*ANGLES; + + GetNewActor (); + new->state = &s_fire1; + new->ticcount = 1; + + new->tilex = ob->tilex; + new->tiley = ob->tiley; + new->x = ob->x; + new->y = ob->y; + new->dir = nodir; + new->angle = iangle; + new->obclass = fireobj; + new->speed = 0x1200l; + new->flags = FL_NEVERMARK; + new->active = true; + + PlaySoundLocActor (FLAMETHROWERSND,new); +} + + + +/* +================= += += T_Fake += +================= +*/ + +void T_Fake (objtype *ob) +{ + long move; + int dx,dy,dist; + boolean dodge; + + if (CheckLine(ob)) // got a shot at player? + { + if ( US_RndT() < (tics<<1) ) + { + // + // go into attack frame + // + NewState (ob,&s_fakeshoot1); + return; + } + } + + if (ob->dir == nodir) + { + SelectDodgeDir (ob); + if (ob->dir == nodir) + return; // object is blocked in + } + + move = ob->speed*tics; + + while (move) + { + if (move < ob->distance) + { + MoveObj (ob,move); + break; + } + + // + // reached goal tile, so select another one + // + + // + // fix position to account for round off during moving + // + ob->x = ((long)ob->tilex<y = ((long)ob->tiley<distance; + + SelectDodgeDir (ob); + + if (ob->dir == nodir) + return; // object is blocked in + } + +} + +#endif +/* +============================================================================ + + STAND + +============================================================================ +*/ + + +/* +=============== += += T_Stand += +=============== +*/ + +void T_Stand (objtype *ob) +{ + SightPlayer (ob); +} + + +/* +============================================================================ + + CHASE + +============================================================================ +*/ + +/* +================= += += T_Chase += +================= +*/ + +void T_Chase (objtype *ob) +{ + long move; + int dx,dy,dist,chance; + boolean dodge; + + if (gamestate.victoryflag) + return; + + dodge = false; + if (CheckLine(ob)) // got a shot at player? + { + dx = abs(ob->tilex - player->tilex); + dy = abs(ob->tiley - player->tiley); + dist = dx>dy ? dx : dy; + if (!dist || (dist==1 && ob->distance<0x4000) ) + chance = 300; + else + chance = (tics<<4)/dist; + + if ( US_RndT()obclass) + { + case guardobj: + NewState (ob,&s_grdshoot1); + break; + case officerobj: + NewState (ob,&s_ofcshoot1); + break; + case mutantobj: + NewState (ob,&s_mutshoot1); + break; + case ssobj: + NewState (ob,&s_ssshoot1); + break; +#ifndef SPEAR + case bossobj: + NewState (ob,&s_bossshoot1); + break; + case gretelobj: + NewState (ob,&s_gretelshoot1); + break; + case mechahitlerobj: + NewState (ob,&s_mechashoot1); + break; + case realhitlerobj: + NewState (ob,&s_hitlershoot1); + break; +#else + case angelobj: + NewState (ob,&s_angelshoot1); + break; + case transobj: + NewState (ob,&s_transshoot1); + break; + case uberobj: + NewState (ob,&s_ubershoot1); + break; + case willobj: + NewState (ob,&s_willshoot1); + break; + case deathobj: + NewState (ob,&s_deathshoot1); + break; +#endif + } + return; + } + dodge = true; + } + + if (ob->dir == nodir) + { + if (dodge) + SelectDodgeDir (ob); + else + SelectChaseDir (ob); + if (ob->dir == nodir) + return; // object is blocked in + } + + move = ob->speed*tics; + + while (move) + { + if (ob->distance < 0) + { + // + // waiting for a door to open + // + OpenDoor (-ob->distance-1); + if (doorobjlist[-ob->distance-1].action != dr_open) + return; + ob->distance = TILEGLOBAL; // go ahead, the door is now opoen + } + + if (move < ob->distance) + { + MoveObj (ob,move); + break; + } + + // + // reached goal tile, so select another one + // + + // + // fix position to account for round off during moving + // + ob->x = ((long)ob->tilex<y = ((long)ob->tiley<distance; + + if (dodge) + SelectDodgeDir (ob); + else + SelectChaseDir (ob); + + if (ob->dir == nodir) + return; // object is blocked in + } + +} + + +/* +================= += += T_Ghosts += +================= +*/ + +void T_Ghosts (objtype *ob) +{ + long move; + + + if (ob->dir == nodir) + { + SelectChaseDir (ob); + if (ob->dir == nodir) + return; // object is blocked in + } + + move = ob->speed*tics; + + while (move) + { + if (move < ob->distance) + { + MoveObj (ob,move); + break; + } + + // + // reached goal tile, so select another one + // + + // + // fix position to account for round off during moving + // + ob->x = ((long)ob->tilex<y = ((long)ob->tiley<distance; + + SelectChaseDir (ob); + + if (ob->dir == nodir) + return; // object is blocked in + } + +} + +/* +================= += += T_DogChase += +================= +*/ + +void T_DogChase (objtype *ob) +{ + long move; + int dist,chance; + long dx,dy; + + + if (ob->dir == nodir) + { + SelectDodgeDir (ob); + if (ob->dir == nodir) + return; // object is blocked in + } + + move = ob->speed*tics; + + while (move) + { + // + // check for byte range + // + dx = player->x - ob->x; + if (dx<0) + dx = -dx; + dx -= move; + if (dx <= MINACTORDIST) + { + dy = player->y - ob->y; + if (dy<0) + dy = -dy; + dy -= move; + if (dy <= MINACTORDIST) + { + NewState (ob,&s_dogjump1); + return; + } + } + + if (move < ob->distance) + { + MoveObj (ob,move); + break; + } + + // + // reached goal tile, so select another one + // + + // + // fix position to account for round off during moving + // + ob->x = ((long)ob->tilex<y = ((long)ob->tiley<distance; + + SelectDodgeDir (ob); + + if (ob->dir == nodir) + return; // object is blocked in + } + +} + + + +/* +============================================================================ + + PATH + +============================================================================ +*/ + + +/* +=============== += += SelectPathDir += +=============== +*/ + +void SelectPathDir (objtype *ob) +{ + unsigned spot; + + spot = MAPSPOT(ob->tilex,ob->tiley,1)-ICONARROWS; + + if (spot<8) + { + // new direction + ob->dir = spot; + } + + ob->distance = TILEGLOBAL; + + if (!TryWalk (ob)) + ob->dir = nodir; +} + + +/* +=============== += += T_Path += +=============== +*/ + +void T_Path (objtype *ob) +{ + long move; + long deltax,deltay,size; + + if (SightPlayer (ob)) + return; + + if (ob->dir == nodir) + { + SelectPathDir (ob); + if (ob->dir == nodir) + return; // all movement is blocked + } + + + move = ob->speed*tics; + + while (move) + { + if (ob->distance < 0) + { + // + // waiting for a door to open + // + OpenDoor (-ob->distance-1); + if (doorobjlist[-ob->distance-1].action != dr_open) + return; + ob->distance = TILEGLOBAL; // go ahead, the door is now opoen + } + + if (move < ob->distance) + { + MoveObj (ob,move); + break; + } + + if (ob->tilex>MAPSIZE || ob->tiley>MAPSIZE) + { + sprintf (str,"T_Path hit a wall at %u,%u, dir %u" + ,ob->tilex,ob->tiley,ob->dir); + Quit (str); + } + + + + ob->x = ((long)ob->tilex<y = ((long)ob->tiley<distance; + + SelectPathDir (ob); + + if (ob->dir == nodir) + return; // all movement is blocked + } +} + + +/* +============================================================================= + + FIGHT + +============================================================================= +*/ + + +/* +=============== += += T_Shoot += += Try to damage the player, based on skill level and player's speed += +=============== +*/ + +void T_Shoot (objtype *ob) +{ + int dx,dy,dist; + int hitchance,damage; + + hitchance = 128; + + if (!areabyplayer[ob->areanumber]) + return; + + if (!CheckLine (ob)) // player is behind a wall + return; + + dx = abs(ob->tilex - player->tilex); + dy = abs(ob->tiley - player->tiley); + dist = dx>dy ? dx:dy; + + if (ob->obclass == ssobj || ob->obclass == bossobj) + dist = dist*2/3; // ss are better shots + + if (thrustspeed >= RUNSPEED) + { + if (ob->flags&FL_VISABLE) + hitchance = 160-dist*16; // player can see to dodge + else + hitchance = 160-dist*8; + } + else + { + if (ob->flags&FL_VISABLE) + hitchance = 256-dist*16; // player can see to dodge + else + hitchance = 256-dist*8; + } + +// see if the shot was a hit + + if (US_RndT()>2; + else if (dist<4) + damage = US_RndT()>>3; + else + damage = US_RndT()>>4; + + TakeDamage (damage,ob); + } + + switch(ob->obclass) + { + case ssobj: + PlaySoundLocActor(SSFIRESND,ob); + break; +#ifndef SPEAR + case giftobj: + case fatobj: + PlaySoundLocActor(MISSILEFIRESND,ob); + break; + case mechahitlerobj: + case realhitlerobj: + case bossobj: + PlaySoundLocActor(BOSSFIRESND,ob); + break; + case schabbobj: + PlaySoundLocActor(SCHABBSTHROWSND,ob); + break; + case fakeobj: + PlaySoundLocActor(FLAMETHROWERSND,ob); + break; +#endif + default: + PlaySoundLocActor(NAZIFIRESND,ob); + } + +} + + +/* +=============== += += T_Bite += +=============== +*/ + +void T_Bite (objtype *ob) +{ + long dx,dy; + int hitchance,damage; + + + PlaySoundLocActor(DOGATTACKSND,ob); // JAB + + dx = player->x - ob->x; + if (dx<0) + dx = -dx; + dx -= TILEGLOBAL; + if (dx <= MINACTORDIST) + { + dy = player->y - ob->y; + if (dy<0) + dy = -dy; + dy -= TILEGLOBAL; + if (dy <= MINACTORDIST) + { + if (US_RndT()<180) + { + TakeDamage (US_RndT()>>4,ob); + return; + } + } + } + + return; +} + + +#ifndef SPEAR +/* +============================================================================ + + BJ VICTORY + +============================================================================ +*/ + + +// +// BJ victory +// + +void T_BJRun (objtype *ob); +void T_BJJump (objtype *ob); +void T_BJDone (objtype *ob); +void T_BJYell (objtype *ob); + +void T_DeathCam (objtype *ob); + +extern statetype s_bjrun1; +extern statetype s_bjrun1s; +extern statetype s_bjrun2; +extern statetype s_bjrun3; +extern statetype s_bjrun3s; +extern statetype s_bjrun4; + +extern statetype s_bjjump1; +extern statetype s_bjjump2; +extern statetype s_bjjump3; +extern statetype s_bjjump4; + + +statetype s_bjrun1 = {false,SPR_BJ_W1,12,T_BJRun,NULL,&s_bjrun1s}; +statetype s_bjrun1s = {false,SPR_BJ_W1,3, NULL,NULL,&s_bjrun2}; +statetype s_bjrun2 = {false,SPR_BJ_W2,8,T_BJRun,NULL,&s_bjrun3}; +statetype s_bjrun3 = {false,SPR_BJ_W3,12,T_BJRun,NULL,&s_bjrun3s}; +statetype s_bjrun3s = {false,SPR_BJ_W3,3, NULL,NULL,&s_bjrun4}; +statetype s_bjrun4 = {false,SPR_BJ_W4,8,T_BJRun,NULL,&s_bjrun1}; + + +statetype s_bjjump1 = {false,SPR_BJ_JUMP1,14,T_BJJump,NULL,&s_bjjump2}; +statetype s_bjjump2 = {false,SPR_BJ_JUMP2,14,T_BJJump,T_BJYell,&s_bjjump3}; +statetype s_bjjump3 = {false,SPR_BJ_JUMP3,14,T_BJJump,NULL,&s_bjjump4}; +statetype s_bjjump4 = {false,SPR_BJ_JUMP4,300,NULL,T_BJDone,&s_bjjump4}; + + +statetype s_deathcam = {false,0,0,NULL,NULL,NULL}; + + +/* +=============== += += SpawnBJVictory += +=============== +*/ + +void SpawnBJVictory (void) +{ + unsigned far *map,tile; + + SpawnNewObj (player->tilex,player->tiley+1,&s_bjrun1); + new->x = player->x; + new->y = player->y; + new->obclass = bjobj; + new->dir = north; + new->temp1 = 6; // tiles to run forward +} + + + +/* +=============== += += T_BJRun += +=============== +*/ + +void T_BJRun (objtype *ob) +{ + long move; + + move = BJRUNSPEED*tics; + + while (move) + { + if (move < ob->distance) + { + MoveObj (ob,move); + break; + } + + + ob->x = ((long)ob->tilex<y = ((long)ob->tiley<distance; + + SelectPathDir (ob); + + if ( !(--ob->temp1) ) + { + NewState (ob,&s_bjjump1); + return; + } + } +} + + +/* +=============== += += T_BJJump += +=============== +*/ + +void T_BJJump (objtype *ob) +{ + long move; + + move = BJJUMPSPEED*tics; + MoveObj (ob,move); +} + + +/* +=============== += += T_BJYell += +=============== +*/ + +void T_BJYell (objtype *ob) +{ + PlaySoundLocActor(YEAHSND,ob); // JAB +} + + +/* +=============== += += T_BJDone += +=============== +*/ + +#pragma argsused +void T_BJDone (objtype *ob) +{ + playstate = ex_victorious; // exit castle tile +} + + + +//=========================================================================== + + +/* +=============== += += CheckPosition += +=============== +*/ + +boolean CheckPosition (objtype *ob) +{ + int x,y,xl,yl,xh,yh; + objtype *check; + + xl = (ob->x-PLAYERSIZE) >>TILESHIFT; + yl = (ob->y-PLAYERSIZE) >>TILESHIFT; + + xh = (ob->x+PLAYERSIZE) >>TILESHIFT; + yh = (ob->y+PLAYERSIZE) >>TILESHIFT; + + // + // check for solid walls + // + for (y=yl;y<=yh;y++) + for (x=xl;x<=xh;x++) + { + check = actorat[x][y]; + if (check && checkx = gamestate.killx; + player->y = gamestate.killy; + + dx = ob->x - player->x; + dy = player->y - ob->y; + + fangle = atan2(dy,dx); // returns -pi to pi + if (fangle<0) + fangle = M_PI*2+fangle; + + player->angle = fangle/(M_PI*2)*ANGLES; + +// +// try to position as close as possible without being in a wall +// + dist = 0x14000l; + do + { + xmove = FixedByFrac(dist,costable[player->angle]); + ymove = -FixedByFrac(dist,sintable[player->angle]); + + player->x = ob->x - xmove; + player->y = ob->y - ymove; + dist += 0x1000; + + } while (!CheckPosition (player)); + plux = player->x >> UNSIGNEDSHIFT; // scale to fit in unsigned + pluy = player->y >> UNSIGNEDSHIFT; + player->tilex = player->x >> TILESHIFT; // scale to tile values + player->tiley = player->y >> TILESHIFT; + +// +// go back to the game +// + temp = bufferofs; + for (i=0;i<3;i++) + { + bufferofs = screenloc[i]; + DrawPlayBorder (); + } + bufferofs = temp; + + fizzlein = true; + switch (ob->obclass) + { +#ifndef SPEAR + case schabbobj: + NewState (ob,&s_schabbdeathcam); + break; + case realhitlerobj: + NewState (ob,&s_hitlerdeathcam); + break; + case giftobj: + NewState (ob,&s_giftdeathcam); + break; + case fatobj: + NewState (ob,&s_fatdeathcam); + break; +#endif + } + +} + +#endif diff --git a/16/sod8086/wl_agent.c b/16/sod8086/wl_agent.c new file mode 100755 index 00000000..631478d0 --- /dev/null +++ b/16/sod8086/wl_agent.c @@ -0,0 +1,1421 @@ +// WL_AGENT.C + +#include "WL_DEF.H" +#pragma hdrstop + + +/* +============================================================================= + + LOCAL CONSTANTS + +============================================================================= +*/ + +#define MAXMOUSETURN 10 + + +#define MOVESCALE 150l +#define BACKMOVESCALE 100l +#define ANGLESCALE 20 + +/* +============================================================================= + + GLOBAL VARIABLES + +============================================================================= +*/ + + + +// +// player state info +// +boolean running; +long thrustspeed; + +unsigned plux,pluy; // player coordinates scaled to unsigned + +int anglefrac; +int gotgatgun; // JR + +objtype *LastAttacker; + +/* +============================================================================= + + LOCAL VARIABLES + +============================================================================= +*/ + + +void T_Player (objtype *ob); +void T_Attack (objtype *ob); + +statetype s_player = {false,0,0,T_Player,NULL,NULL}; +statetype s_attack = {false,0,0,T_Attack,NULL,NULL}; + + +long playerxmove,playerymove; + +struct atkinf +{ + char tics,attack,frame; // attack is 1 for gun, 2 for knife +} attackinfo[4][14] = + +{ +{ {6,0,1},{6,2,2},{6,0,3},{6,-1,4} }, +{ {6,0,1},{6,1,2},{6,0,3},{6,-1,4} }, +{ {6,0,1},{6,1,2},{6,3,3},{6,-1,4} }, +{ {6,0,1},{6,1,2},{6,4,3},{6,-1,4} }, +}; + + +int strafeangle[9] = {0,90,180,270,45,135,225,315,0}; + +void DrawWeapon (void); +void GiveWeapon (int weapon); +void GiveAmmo (int ammo); + +//=========================================================================== + +//---------- + +void Attack (void); +void Use (void); +void Search (objtype *ob); +void SelectWeapon (void); +void SelectItem (void); + +//---------- + +boolean TryMove (objtype *ob); +void T_Player (objtype *ob); + +void ClipMove (objtype *ob, long xmove, long ymove); + +/* +============================================================================= + + CONTROL STUFF + +============================================================================= +*/ + +/* +====================== += += CheckWeaponChange += += Keys 1-4 change weapons += +====================== +*/ + +void CheckWeaponChange (void) +{ + int i,buttons; + + if (!gamestate.ammo) // must use knife with no ammo + return; + + for (i=wp_knife ; i<=gamestate.bestweapon ; i++) + if (buttonstate[bt_readyknife+i-wp_knife]) + { + gamestate.weapon = gamestate.chosenweapon = i; + DrawWeapon (); + return; + } +} + + +/* +======================= += += ControlMovement += += Takes controlx,controly, and buttonstate[bt_strafe] += += Changes the player's angle and position += += There is an angle hack because when going 70 fps, the roundoff becomes += significant += +======================= +*/ + +void ControlMovement (objtype *ob) +{ + long oldx,oldy; + int angle,maxxmove; + int angleunits; + long speed; + + thrustspeed = 0; + + oldx = player->x; + oldy = player->y; + +// +// side to side move +// + if (buttonstate[bt_strafe]) + { + // + // strafing + // + // + if (controlx > 0) + { + angle = ob->angle - ANGLES/4; + if (angle < 0) + angle += ANGLES; + Thrust (angle,controlx*MOVESCALE); // move to left + } + else if (controlx < 0) + { + angle = ob->angle + ANGLES/4; + if (angle >= ANGLES) + angle -= ANGLES; + Thrust (angle,-controlx*MOVESCALE); // move to right + } + } + else + { + // + // not strafing + // + anglefrac += controlx; + angleunits = anglefrac/ANGLESCALE; + anglefrac -= angleunits*ANGLESCALE; + ob->angle -= angleunits; + + if (ob->angle >= ANGLES) + ob->angle -= ANGLES; + if (ob->angle < 0) + ob->angle += ANGLES; + + } + +// +// forward/backwards move +// + if (controly < 0) + { + Thrust (ob->angle,-controly*MOVESCALE); // move forwards + } + else if (controly > 0) + { + angle = ob->angle + ANGLES/2; + if (angle >= ANGLES) + angle -= ANGLES; + Thrust (angle,controly*BACKMOVESCALE); // move backwards + } + + if (gamestate.victoryflag) // watching the BJ actor + return; + +// +// calculate total move +// + playerxmove = player->x - oldx; + playerymove = player->y - oldy; +} + +/* +============================================================================= + + STATUS WINDOW STUFF + +============================================================================= +*/ + + +/* +================== += += StatusDrawPic += +================== +*/ + +void StatusDrawPic (unsigned x, unsigned y, unsigned picnum) +{ + unsigned temp; + + temp = bufferofs; + bufferofs = 0; + + bufferofs = PAGE1START+(200-STATUSLINES)*SCREENWIDTH; + LatchDrawPic (x,y,picnum); + bufferofs = PAGE2START+(200-STATUSLINES)*SCREENWIDTH; + LatchDrawPic (x,y,picnum); + bufferofs = PAGE3START+(200-STATUSLINES)*SCREENWIDTH; + LatchDrawPic (x,y,picnum); + + bufferofs = temp; +} + + +/* +================== += += DrawFace += +================== +*/ + +void DrawFace (void) +{ + if (gamestate.health) + { + #ifdef SPEAR + if (godmode) + StatusDrawPic (17,4,GODMODEFACE1PIC+gamestate.faceframe); + else + #endif + StatusDrawPic (17,4,FACE1APIC+3*((100-gamestate.health)/16)+gamestate.faceframe); + } + else + { +#ifndef SPEAR + if (LastAttacker->obclass == needleobj) + StatusDrawPic (17,4,MUTANTBJPIC); + else +#endif + StatusDrawPic (17,4,FACE8APIC); + } +} + + +/* +=============== += += UpdateFace += += Calls draw face if time to change += +=============== +*/ + +#define FACETICS 70 + +int facecount; + +void UpdateFace (void) +{ + + if (SD_SoundPlaying() == GETGATLINGSND) + return; + + facecount += tics; + if (facecount > US_RndT()) + { + gamestate.faceframe = (US_RndT()>>6); + if (gamestate.faceframe==3) + gamestate.faceframe = 1; + + facecount = 0; + DrawFace (); + } +} + + + +/* +=============== += += LatchNumber += += right justifies and pads with blanks += +=============== +*/ + +void LatchNumber (int x, int y, int width, long number) +{ + unsigned length,c; + char str[20]; + + ltoa (number,str,10); + + length = strlen (str); + + while (length>=2; + + if (!godmode) + gamestate.health -= points; + + if (gamestate.health<=0) + { + gamestate.health = 0; + playstate = ex_died; + killerobj = attacker; + } + + StartDamageFlash (points); + + gotgatgun=0; + + DrawHealth (); + DrawFace (); + + // + // MAKE BJ'S EYES BUG IF MAJOR DAMAGE! + // + #ifdef SPEAR + if (points > 30 && gamestate.health!=0 && !godmode) + { + StatusDrawPic (17,4,BJOUCHPIC); + facecount = 0; + } + #endif + +} + + +/* +=============== += += HealSelf += +=============== +*/ + +void HealSelf (int points) +{ + gamestate.health += points; + if (gamestate.health>100) + gamestate.health = 100; + + DrawHealth (); + gotgatgun = 0; // JR + DrawFace (); +} + + +//=========================================================================== + + +/* +=============== += += DrawLevel += +=============== +*/ + +void DrawLevel (void) +{ +#ifdef SPEAR + if (gamestate.mapon == 20) + LatchNumber (2,16,2,18); + else +#endif + LatchNumber (2,16,2,gamestate.mapon+1); +} + +//=========================================================================== + + +/* +=============== += += DrawLives += +=============== +*/ + +void DrawLives (void) +{ + LatchNumber (14,16,1,gamestate.lives); +} + + +/* +=============== += += GiveExtraMan += +=============== +*/ + +void GiveExtraMan (void) +{ + if (gamestate.lives<9) + gamestate.lives++; + DrawLives (); + SD_PlaySound (BONUS1UPSND); +} + +//=========================================================================== + +/* +=============== += += DrawScore += +=============== +*/ + +void DrawScore (void) +{ + LatchNumber (6,16,6,gamestate.score); +} + +/* +=============== += += GivePoints += +=============== +*/ + +void GivePoints (long points) +{ + gamestate.score += points; + while (gamestate.score >= gamestate.nextextra) + { + gamestate.nextextra += EXTRAPOINTS; + GiveExtraMan (); + } + DrawScore (); +} + +//=========================================================================== + +/* +================== += += DrawWeapon += +================== +*/ + +void DrawWeapon (void) +{ + StatusDrawPic (32,8,KNIFEPIC+gamestate.weapon); +} + + +/* +================== += += DrawKeys += +================== +*/ + +void DrawKeys (void) +{ + if (gamestate.keys & 1) + StatusDrawPic (30,4,GOLDKEYPIC); + else + StatusDrawPic (30,4,NOKEYPIC); + + if (gamestate.keys & 2) + StatusDrawPic (30,20,SILVERKEYPIC); + else + StatusDrawPic (30,20,NOKEYPIC); +} + + + +/* +================== += += GiveWeapon += +================== +*/ + +void GiveWeapon (int weapon) +{ + GiveAmmo (6); + + if (gamestate.bestweapon 99) + gamestate.ammo = 99; + DrawAmmo (); +} + +//=========================================================================== + +/* +================== += += GiveKey += +================== +*/ + +void GiveKey (int key) +{ + gamestate.keys |= (1<itemnumber) + { + case bo_firstaid: + if (gamestate.health == 100) + return; + + SD_PlaySound (HEALTH2SND); + HealSelf (25); + break; + + case bo_key1: + case bo_key2: + case bo_key3: + case bo_key4: + GiveKey (check->itemnumber - bo_key1); + SD_PlaySound (GETKEYSND); + break; + + case bo_cross: + SD_PlaySound (BONUS1SND); + GivePoints (100); + gamestate.treasurecount++; + break; + case bo_chalice: + SD_PlaySound (BONUS2SND); + GivePoints (500); + gamestate.treasurecount++; + break; + case bo_bible: + SD_PlaySound (BONUS3SND); + GivePoints (1000); + gamestate.treasurecount++; + break; + case bo_crown: + SD_PlaySound (BONUS4SND); + GivePoints (5000); + gamestate.treasurecount++; + break; + + case bo_clip: + if (gamestate.ammo == 99) + return; + + SD_PlaySound (GETAMMOSND); + GiveAmmo (8); + break; + case bo_clip2: + if (gamestate.ammo == 99) + return; + + SD_PlaySound (GETAMMOSND); + GiveAmmo (4); + break; + +#ifdef SPEAR + case bo_25clip: + if (gamestate.ammo == 99) + return; + + SD_PlaySound (GETAMMOBOXSND); + GiveAmmo (25); + break; +#endif + + case bo_machinegun: + SD_PlaySound (GETMACHINESND); + GiveWeapon (wp_machinegun); + break; + case bo_chaingun: + SD_PlaySound (GETGATLINGSND); + GiveWeapon (wp_chaingun); + + StatusDrawPic (17,4,GOTGATLINGPIC); + facecount = 0; + gotgatgun = 1; + break; + + case bo_fullheal: + SD_PlaySound (BONUS1UPSND); + HealSelf (99); + GiveAmmo (25); + GiveExtraMan (); + gamestate.treasurecount++; + break; + + case bo_food: + if (gamestate.health == 100) + return; + + SD_PlaySound (HEALTH1SND); + HealSelf (10); + break; + + case bo_alpo: + if (gamestate.health == 100) + return; + + SD_PlaySound (HEALTH1SND); + HealSelf (4); + break; + + case bo_gibs: + if (gamestate.health >10) + return; + + SD_PlaySound (SLURPIESND); + HealSelf (1); + break; + + case bo_spear: + spearflag = true; + spearx = player->x; + speary = player->y; + spearangle = player->angle; + playstate = ex_completed; + } + + StartBonusFlash (); + check->shapenum = -1; // remove from list +} + + +/* +=================== += += TryMove += += returns true if move ok += debug: use pointers to optimize +=================== +*/ + +boolean TryMove (objtype *ob) +{ + int xl,yl,xh,yh,x,y; + objtype *check; + long deltax,deltay; + + xl = (ob->x-PLAYERSIZE) >>TILESHIFT; + yl = (ob->y-PLAYERSIZE) >>TILESHIFT; + + xh = (ob->x+PLAYERSIZE) >>TILESHIFT; + yh = (ob->y+PLAYERSIZE) >>TILESHIFT; + +// +// check for solid walls +// + for (y=yl;y<=yh;y++) + for (x=xl;x<=xh;x++) + { + check = actorat[x][y]; + if (check && check0) + yl--; + if (yh0) + xl--; + if (xh objlist + && (check->flags & FL_SHOOTABLE) ) + { + deltax = ob->x - check->x; + if (deltax < -MINACTORDIST || deltax > MINACTORDIST) + continue; + deltay = ob->y - check->y; + if (deltay < -MINACTORDIST || deltay > MINACTORDIST) + continue; + + return false; + } + } + + return true; +} + + +/* +=================== += += ClipMove += +=================== +*/ + +void ClipMove (objtype *ob, long xmove, long ymove) +{ + long basex,basey; + + basex = ob->x; + basey = ob->y; + + ob->x = basex+xmove; + ob->y = basey+ymove; + if (TryMove (ob)) + return; + + if (noclip && ob->x > 2*TILEGLOBAL && ob->y > 2*TILEGLOBAL && + ob->x < (((long)(mapwidth-1))<y < (((long)(mapheight-1))<x = basex+xmove; + ob->y = basey; + if (TryMove (ob)) + return; + + ob->x = basex; + ob->y = basey+ymove; + if (TryMove (ob)) + return; + + ob->x = basex; + ob->y = basey; +} + +//========================================================================== + +/* +=================== += += VictoryTile += +=================== +*/ + +void VictoryTile (void) +{ +#ifndef SPEAR + SpawnBJVictory (); +#endif + + gamestate.victoryflag = true; +} + + +/* +=================== += += Thrust += +=================== +*/ + +void Thrust (int angle, long speed) +{ + long xmove,ymove; + long slowmax; + unsigned offset; + + + // + // ZERO FUNNY COUNTER IF MOVED! + // + #ifdef SPEAR + if (speed) + funnyticount = 0; + #endif + + thrustspeed += speed; +// +// moving bounds speed +// + if (speed >= MINDIST*2) + speed = MINDIST*2-1; + + xmove = FixedByFrac(speed,costable[angle]); + ymove = -FixedByFrac(speed,sintable[angle]); + + ClipMove(player,xmove,ymove); + + player->tilex = player->x >> TILESHIFT; // scale to tile values + player->tiley = player->y >> TILESHIFT; + + offset = farmapylookup[player->tiley]+player->tilex; + player->areanumber = *(mapsegs[0] + offset) -AREATILE; + + if (*(mapsegs[1] + offset) == EXITTILE) + VictoryTile (); +} + + +/* +============================================================================= + + ACTIONS + +============================================================================= +*/ + + +/* +=============== += += Cmd_Fire += +=============== +*/ + +void Cmd_Fire (void) +{ + buttonheld[bt_attack] = true; + + gamestate.weaponframe = 0; + + player->state = &s_attack; + + gamestate.attackframe = 0; + gamestate.attackcount = + attackinfo[gamestate.weapon][gamestate.attackframe].tics; + gamestate.weaponframe = + attackinfo[gamestate.weapon][gamestate.attackframe].frame; +} + +//=========================================================================== + +/* +=============== += += Cmd_Use += +=============== +*/ + +void Cmd_Use (void) +{ + objtype *check; + int checkx,checky,doornum,dir; + boolean elevatorok; + + +// +// find which cardinal direction the player is facing +// + if (player->angle < ANGLES/8 || player->angle > 7*ANGLES/8) + { + checkx = player->tilex + 1; + checky = player->tiley; + dir = di_east; + elevatorok = true; + } + else if (player->angle < 3*ANGLES/8) + { + checkx = player->tilex; + checky = player->tiley-1; + dir = di_north; + elevatorok = false; + } + else if (player->angle < 5*ANGLES/8) + { + checkx = player->tilex - 1; + checky = player->tiley; + dir = di_west; + elevatorok = true; + } + else + { + checkx = player->tilex; + checky = player->tiley + 1; + dir = di_south; + elevatorok = false; + } + + doornum = tilemap[checkx][checky]; + if (*(mapsegs[1]+farmapylookup[checky]+checkx) == PUSHABLETILE) + { + // + // pushable wall + // + + PushWall (checkx,checky,dir); + return; + } + if (!buttonheld[bt_use] && doornum == ELEVATORTILE && elevatorok) + { + // + // use elevator + // + buttonheld[bt_use] = true; + + tilemap[checkx][checky]++; // flip switch + if (*(mapsegs[0]+farmapylookup[player->tiley]+player->tilex) == ALTELEVATORTILE) + playstate = ex_secretlevel; + else + playstate = ex_completed; + SD_PlaySound (LEVELDONESND); + SD_WaitSoundDone(); + } + else if (!buttonheld[bt_use] && doornum & 0x80) + { + buttonheld[bt_use] = true; + OperateDoor (doornum & ~0x80); + } + else + SD_PlaySound (DONOTHINGSND); + +} + +/* +============================================================================= + + PLAYER CONTROL + +============================================================================= +*/ + + + +/* +=============== += += SpawnPlayer += +=============== +*/ + +void SpawnPlayer (int tilex, int tiley, int dir) +{ + player->obclass = playerobj; + player->active = true; + player->tilex = tilex; + player->tiley = tiley; + player->areanumber = + *(mapsegs[0] + farmapylookup[player->tiley]+player->tilex); + player->x = ((long)tilex<y = ((long)tiley<state = &s_player; + player->angle = (1-dir)*90; + if (player->angle<0) + player->angle += ANGLES; + player->flags = FL_NEVERMARK; + Thrust (0,0); // set some variables + + InitAreas (); +} + + +//=========================================================================== + +/* +=============== += += T_KnifeAttack += += Update player hands, and try to do damage when the proper frame is reached += +=============== +*/ + +void KnifeAttack (objtype *ob) +{ + objtype *check,*closest; + long dist; + + SD_PlaySound (ATKKNIFESND); +// actually fire + dist = 0x7fffffff; + closest = NULL; + for (check=ob->next ; check ; check=check->next) + if ( (check->flags & FL_SHOOTABLE) + && (check->flags & FL_VISABLE) + && abs (check->viewx-centerx) < shootdelta + ) + { + if (check->transx < dist) + { + dist = check->transx; + closest = check; + } + } + + if (!closest || dist> 0x18000l) + { + // missed + + return; + } + +// hit something + DamageActor (closest,US_RndT() >> 4); +} + + + +void GunAttack (objtype *ob) +{ + objtype *check,*closest,*oldclosest; + int damage; + int dx,dy,dist; + long viewdist; + + switch (gamestate.weapon) + { + case wp_pistol: + SD_PlaySound (ATKPISTOLSND); + break; + case wp_machinegun: + SD_PlaySound (ATKMACHINEGUNSND); + break; + case wp_chaingun: + SD_PlaySound (ATKGATLINGSND); + break; + } + + madenoise = true; + +// +// find potential targets +// + viewdist = 0x7fffffffl; + closest = NULL; + + while (1) + { + oldclosest = closest; + + for (check=ob->next ; check ; check=check->next) + if ( (check->flags & FL_SHOOTABLE) + && (check->flags & FL_VISABLE) + && abs (check->viewx-centerx) < shootdelta + ) + { + if (check->transx < viewdist) + { + viewdist = check->transx; + closest = check; + } + } + + if (closest == oldclosest) + return; // no more targets, all missed + + // + // trace a line from player to enemey + // + if (CheckLine(closest)) + break; + + } + +// +// hit something +// + dx = abs(closest->tilex - player->tilex); + dy = abs(closest->tiley - player->tiley); + dist = dx>dy ? dx:dy; + + if (dist<2) + damage = US_RndT() / 4; + else if (dist<4) + damage = US_RndT() / 6; + else + { + if ( (US_RndT() / 12) < dist) // missed + return; + damage = US_RndT() / 6; + } + + DamageActor (closest,damage); +} + +//=========================================================================== + +/* +=============== += += VictorySpin += +=============== +*/ + +void VictorySpin (void) +{ + long desty; + + if (player->angle > 270) + { + player->angle -= tics * 3; + if (player->angle < 270) + player->angle = 270; + } + else if (player->angle < 270) + { + player->angle += tics * 3; + if (player->angle > 270) + player->angle = 270; + } + + desty = (((long)player->tiley-5)<y > desty) + { + player->y -= tics*4096; + if (player->y < desty) + player->y = desty; + } +} + + +//=========================================================================== + +/* +=============== += += T_Attack += +=============== +*/ + +void T_Attack (objtype *ob) +{ + struct atkinf *cur; + + UpdateFace (); + + if (gamestate.victoryflag) // watching the BJ actor + { + VictorySpin (); + return; + } + + if ( buttonstate[bt_use] && !buttonheld[bt_use] ) + buttonstate[bt_use] = false; + + if ( buttonstate[bt_attack] && !buttonheld[bt_attack]) + buttonstate[bt_attack] = false; + + ControlMovement (ob); + if (gamestate.victoryflag) // watching the BJ actor + return; + + plux = player->x >> UNSIGNEDSHIFT; // scale to fit in unsigned + pluy = player->y >> UNSIGNEDSHIFT; + player->tilex = player->x >> TILESHIFT; // scale to tile values + player->tiley = player->y >> TILESHIFT; + +// +// change frame and fire +// + gamestate.attackcount -= tics; + while (gamestate.attackcount <= 0) + { + cur = &attackinfo[gamestate.weapon][gamestate.attackframe]; + switch (cur->attack) + { + case -1: + ob->state = &s_player; + if (!gamestate.ammo) + { + gamestate.weapon = wp_knife; + DrawWeapon (); + } + else + { + if (gamestate.weapon != gamestate.chosenweapon) + { + gamestate.weapon = gamestate.chosenweapon; + DrawWeapon (); + } + }; + gamestate.attackframe = gamestate.weaponframe = 0; + return; + + case 4: + if (!gamestate.ammo) + break; + if (buttonstate[bt_attack]) + gamestate.attackframe -= 2; + case 1: + if (!gamestate.ammo) + { // can only happen with chain gun + gamestate.attackframe++; + break; + } + GunAttack (ob); + gamestate.ammo--; + DrawAmmo (); + break; + + case 2: + KnifeAttack (ob); + break; + + case 3: + if (gamestate.ammo && buttonstate[bt_attack]) + gamestate.attackframe -= 2; + break; + } + + gamestate.attackcount += cur->tics; + gamestate.attackframe++; + gamestate.weaponframe = + attackinfo[gamestate.weapon][gamestate.attackframe].frame; + } + +} + + + +//=========================================================================== + +/* +=============== += += T_Player += +=============== +*/ + +void T_Player (objtype *ob) +{ + if (gamestate.victoryflag) // watching the BJ actor + { + VictorySpin (); + return; + } + + UpdateFace (); + CheckWeaponChange (); + + if ( buttonstate[bt_use] ) + Cmd_Use (); + + if ( buttonstate[bt_attack] && !buttonheld[bt_attack]) + Cmd_Fire (); + + ControlMovement (ob); + if (gamestate.victoryflag) // watching the BJ actor + return; + + + plux = player->x >> UNSIGNEDSHIFT; // scale to fit in unsigned + pluy = player->y >> UNSIGNEDSHIFT; + player->tilex = player->x >> TILESHIFT; // scale to tile values + player->tiley = player->y >> TILESHIFT; +} + + diff --git a/16/sod8086/wl_asm.asm b/16/sod8086/wl_asm.asm new file mode 100755 index 00000000..cca5d690 --- /dev/null +++ b/16/sod8086/wl_asm.asm @@ -0,0 +1,69 @@ +; JABHACK.ASM + +.386C +IDEAL +MODEL MEDIUM + +EXTRN LDIV@:far + +;============================================================================ + +DATASEG + +;============================================================================ + +CODESEG + +; Hacked up Juan Jimenez's code a bit to just return 386/not 386 +PROC _CheckIs386 +PUBLIC _CheckIs386 + +;hack to never look for a 386, for benchmark comparisons of same code on all CPUs +; pushf ; Save flag registers, we use them here +; xor ax,ax ; Clear AX and... +; push ax ; ...push it onto the stack +; popf ; Pop 0 into flag registers (all bits to 0), +; pushf ; attempting to set bits 12-15 of flags to 0's +; pop ax ; Recover the save flags +; and ax,08000h ; If bits 12-15 of flags are set to +; cmp ax,08000h ; zero then it's 8088/86 or 80188/186 +; jz not386 +; +; mov ax,07000h ; Try to set flag bits 12-14 to 1's +; push ax ; Push the test value onto the stack +; popf ; Pop it into the flag register +; pushf ; Push it back onto the stack +; pop ax ; Pop it into AX for check +; and ax,07000h ; if bits 12-14 are cleared then +; jz not386 ; the chip is an 80286 +; +; mov ax,1 ; We now assume it's a 80386 or better +; popf +; retf +;end benchmark hack + +not386: + xor ax,ax + popf + retf + + ENDP + + +PROC _jabhack2 +PUBLIC _jabhack2 + + push es + + mov ax,seg LDIV@ + mov es,ax + mov ax,9090h ;Two NOP's + mov [WORD FAR es:LDIV@],ax ;Patch over XOR AX,AX + mov [WORD FAR es:LDIV@+2],ax ;and over JMP SHORT COMMON + + pop es + retf + + ENDP + + END diff --git a/16/sod8086/wl_debug.c b/16/sod8086/wl_debug.c new file mode 100755 index 00000000..dd4674b1 --- /dev/null +++ b/16/sod8086/wl_debug.c @@ -0,0 +1,722 @@ +// WL_DEBUG.C + +#include "WL_DEF.H" +#pragma hdrstop +#include + +/* +============================================================================= + + LOCAL CONSTANTS + +============================================================================= +*/ + +#define VIEWTILEX (viewwidth/16) +#define VIEWTILEY (viewheight/16) + +/* +============================================================================= + + GLOBAL VARIABLES + +============================================================================= +*/ + + +int DebugKeys (void); + +/* +============================================================================= + + LOCAL VARIABLES + +============================================================================= +*/ + + +int maporgx; +int maporgy; +enum {mapview,tilemapview,actoratview,visview} viewtype; + +void ViewMap (void); + +//=========================================================================== + +/* +================== += += DebugMemory += +================== +*/ + +void DebugMemory (void) +{ + int i; + char scratch[80],str[10]; + long mem; + spritetype _seg *block; + + CenterWindow (16,7); + + US_CPrint ("Memory Usage"); + US_CPrint ("------------"); + US_Print ("Total :"); + US_PrintUnsigned (mminfo.mainmem/1024); + US_Print ("k\nFree :"); + US_PrintUnsigned (MM_UnusedMemory()/1024); + US_Print ("k\nWith purge:"); + US_PrintUnsigned (MM_TotalFree()/1024); + US_Print ("k\n"); + VW_UpdateScreen(); + IN_Ack (); +} + +//=========================================================================== + +/* +================== += += CountObjects += +================== +*/ + +void CountObjects (void) +{ + int i,total,count,active,inactive,doors; + objtype *obj; + + CenterWindow (16,7); + active = inactive = count = doors = 0; + + US_Print ("Total statics :"); + total = laststatobj-&statobjlist[0]; + US_PrintUnsigned (total); + + US_Print ("\nIn use statics:"); + for (i=0;inext;obj;obj=obj->next) + { + if (obj->active) + active++; + else + inactive++; + } + + US_Print ("\nTotal actors :"); + US_PrintUnsigned (active+inactive); + + US_Print ("\nActive actors :"); + US_PrintUnsigned (active); + + VW_UpdateScreen(); + IN_Ack (); +} + +//=========================================================================== + +/* +================ += += PicturePause += +================ +*/ + +void PicturePause (void) +{ + int i; + byte p; + unsigned x; + byte far *dest,far *src; + memptr buffer; + + VW_ColorBorder (15); + FinishPaletteShifts (); + + LastScan = 0; + while (!LastScan) + ; + if (LastScan != sc_Enter) + { + VW_ColorBorder (0); + return; + } + + VW_ColorBorder (1); + VW_SetScreen (0,0); +// +// vga stuff... +// + + ClearMemory (); + CA_SetAllPurge(); + MM_GetPtr (&buffer,64000); + for (p=0;p<4;p++) + { + src = MK_FP(0xa000,displayofs); + dest = (byte far *)buffer+p; + VGAREADMAP(p); + for (x=0;x<16000;x++,dest+=4) + *dest = *src++; + } + + +#if 0 + for (p=0;p<4;p++) + { + src = MK_FP(0xa000,0); + dest = (byte far *)buffer+51200+p; + VGAREADMAP(p); + for (x=0;x<3200;x++,dest+=4) + *dest = *src++; + } +#endif + + asm mov ax,0x13 + asm int 0x10 + + dest = MK_FP(0xa000,0); + _fmemcpy (dest,buffer,64000); + + VL_SetPalette (&gamepal); + + + IN_Shutdown (); + + VW_WaitVBL(70); + bioskey(0); + VW_WaitVBL(70); + Quit (NULL); +} + + +//=========================================================================== + + +/* +================ += += ShapeTest += +================ +*/ + +#pragma warn -pia +void ShapeTest (void) +{ +extern word NumDigi; +extern word _seg *DigiList; +static char buf[10]; + + boolean done; + ScanCode scan; + int i,j,k,x; + longword l; + memptr addr; + PageListStruct far *page; + + CenterWindow(20,16); + VW_UpdateScreen(); + for (i = 0,done = false;!done;) + { + US_ClearWindow(); +// sound = -1; + + page = &PMPages[i]; + US_Print(" Page #"); + US_PrintUnsigned(i); + if (i < PMSpriteStart) + US_Print(" (Wall)"); + else if (i < PMSoundStart) + US_Print(" (Sprite)"); + else if (i == ChunksInFile - 1) + US_Print(" (Sound Info)"); + else + US_Print(" (Sound)"); + + US_Print("\n XMS: "); + if (page->xmsPage != -1) + US_PrintUnsigned(page->xmsPage); + else + US_Print("No"); + + US_Print("\n Main: "); + if (page->mainPage != -1) + US_PrintUnsigned(page->mainPage); + else if (page->emsPage != -1) + { + US_Print("EMS "); + US_PrintUnsigned(page->emsPage); + } + else + US_Print("No"); + + US_Print("\n Last hit: "); + US_PrintUnsigned(page->lastHit); + + US_Print("\n Address: "); + addr = PM_GetPageAddress(i); + sprintf(buf,"0x%04x",(word)addr); + US_Print(buf); + + if (addr) + { + if (i < PMSpriteStart) + { + // + // draw the wall + // + bufferofs += 32*SCREENWIDTH; + postx = 128; + postwidth = 1; + postsource = ((long)((unsigned)addr))<<16; + for (x=0;x<64;x++,postx++,postsource+=64) + { + wallheight[postx] = 256; + FarScalePost (); + } + bufferofs -= 32*SCREENWIDTH; + } + else if (i < PMSoundStart) + { + // + // draw the sprite + // + bufferofs += 32*SCREENWIDTH; + SimpleScaleShape (160, i-PMSpriteStart, 64); + bufferofs -= 32*SCREENWIDTH; + } + else if (i == ChunksInFile - 1) + { + US_Print("\n\n Number of sounds: "); + US_PrintUnsigned(NumDigi); + for (l = j = k = 0;j < NumDigi;j++) + { + l += DigiList[(j * 2) + 1]; + k += (DigiList[(j * 2) + 1] + (PMPageSize - 1)) / PMPageSize; + } + US_Print("\n Total bytes: "); + US_PrintUnsigned(l); + US_Print("\n Total pages: "); + US_PrintUnsigned(k); + } + else + { + byte far *dp = (byte far *)MK_FP(addr,0); + for (j = 0;j < NumDigi;j++) + { + k = (DigiList[(j * 2) + 1] + (PMPageSize - 1)) / PMPageSize; + if + ( + (i >= PMSoundStart + DigiList[j * 2]) + && (i < PMSoundStart + DigiList[j * 2] + k) + ) + break; + } + if (j < NumDigi) + { +// sound = j; + US_Print("\n Sound #"); + US_PrintUnsigned(j); + US_Print("\n Segment #"); + US_PrintUnsigned(i - PMSoundStart - DigiList[j * 2]); + } + for (j = 0;j < page->length;j += 32) + { + byte v = dp[j]; + int v2 = (unsigned)v; + v2 -= 128; + v2 /= 4; + if (v2 < 0) + VWB_Vlin(WindowY + WindowH - 32 + v2, + WindowY + WindowH - 32, + WindowX + 8 + (j / 32),BLACK); + else + VWB_Vlin(WindowY + WindowH - 32, + WindowY + WindowH - 32 + v2, + WindowX + 8 + (j / 32),BLACK); + } + } + } + + VW_UpdateScreen(); + + while (!(scan = LastScan)) + SD_Poll(); + + IN_ClearKey(scan); + switch (scan) + { + case sc_LeftArrow: + if (i) + i--; + break; + case sc_RightArrow: + if (++i >= ChunksInFile) + i--; + break; + case sc_W: // Walls + i = 0; + break; + case sc_S: // Sprites + i = PMSpriteStart; + break; + case sc_D: // Digitized + i = PMSoundStart; + break; + case sc_I: // Digitized info + i = ChunksInFile - 1; + break; + case sc_L: // Load all pages + for (j = 0;j < ChunksInFile;j++) + PM_GetPage(j); + break; + case sc_P: +// if (sound != -1) +// SD_PlayDigitized(sound); + break; + case sc_Escape: + done = true; + break; + case sc_Enter: + PM_GetPage(i); + break; + } + } + SD_StopDigitized(); +} +#pragma warn +pia + + + +//=========================================================================== + + +/* +================ += += DebugKeys += +================ +*/ + +int DebugKeys (void) +{ + boolean esc; + int level,i; + + if (Keyboard[sc_B]) // B = border color + { + CenterWindow(24,3); + PrintY+=6; + US_Print(" Border color (0-15):"); + VW_UpdateScreen(); + esc = !US_LineInput (px,py,str,NULL,true,2,0); + if (!esc) + { + level = atoi (str); + if (level>=0 && level<=15) + VW_ColorBorder (level); + } + return 1; + } + + if (Keyboard[sc_C]) // C = count objects + { + CountObjects(); + return 1; + } + + if (Keyboard[sc_E]) // E = quit level + { + if (tedlevel) + Quit (NULL); + playstate = ex_completed; +// gamestate.mapon++; + } + + if (Keyboard[sc_F]) // F = facing spot + { + CenterWindow (14,4); + US_Print ("X:"); + US_PrintUnsigned (player->x); + US_Print ("\nY:"); + US_PrintUnsigned (player->y); + US_Print ("\nA:"); + US_PrintUnsigned (player->angle); + VW_UpdateScreen(); + IN_Ack(); + return 1; + } + + if (Keyboard[sc_G]) // G = god mode + { + CenterWindow (12,2); + if (godmode) + US_PrintCentered ("God mode OFF"); + else + US_PrintCentered ("God mode ON"); + VW_UpdateScreen(); + IN_Ack(); + godmode ^= 1; + return 1; + } + if (Keyboard[sc_H]) // H = hurt self + { + IN_ClearKeysDown (); + TakeDamage (16,NULL); + } + else if (Keyboard[sc_I]) // I = item cheat + { + CenterWindow (12,3); + US_PrintCentered ("Free items!"); + VW_UpdateScreen(); + GivePoints (100000); + HealSelf (99); + if (gamestate.bestweapon 99) + gamestate.ammo = 99; + DrawAmmo (); + IN_Ack (); + return 1; + } + else if (Keyboard[sc_M]) // M = memory info + { + DebugMemory(); + return 1; + } +#ifdef SPEAR + else if (Keyboard[sc_N]) // N = no clip + { + noclip^=1; + CenterWindow (18,3); + if (noclip) + US_PrintCentered ("No clipping ON"); + else + US_PrintCentered ("No clipping OFF"); + VW_UpdateScreen(); + IN_Ack (); + return 1; + } +#endif +#if 0 + else if (Keyboard[sc_O]) // O = overhead + { + ViewMap(); + return 1; + } +#endif + else if (Keyboard[sc_P]) // P = pause with no screen disruptioon + { + PicturePause (); + return 1; + } + else if (Keyboard[sc_Q]) // Q = fast quit + Quit (NULL); + else if (Keyboard[sc_S]) // S = slow motion + { + singlestep^=1; + CenterWindow (18,3); + if (singlestep) + US_PrintCentered ("Slow motion ON"); + else + US_PrintCentered ("Slow motion OFF"); + VW_UpdateScreen(); + IN_Ack (); + return 1; + } + else if (Keyboard[sc_T]) // T = shape test + { + ShapeTest (); + return 1; + } + else if (Keyboard[sc_V]) // V = extra VBLs + { + CenterWindow(30,3); + PrintY+=6; + US_Print(" Add how many extra VBLs(0-8):"); + VW_UpdateScreen(); + esc = !US_LineInput (px,py,str,NULL,true,2,0); + if (!esc) + { + level = atoi (str); + if (level>=0 && level<=8) + extravbls = level; + } + return 1; + } + else if (Keyboard[sc_W]) // W = warp to level + { + CenterWindow(26,3); + PrintY+=6; +#ifndef SPEAR + US_Print(" Warp to which level(1-10):"); +#else + US_Print(" Warp to which level(1-21):"); +#endif + VW_UpdateScreen(); + esc = !US_LineInput (px,py,str,NULL,true,2,0); + if (!esc) + { + level = atoi (str); +#ifndef SPEAR + if (level>0 && level<11) +#else + if (level>0 && level<22) +#endif + { + gamestate.mapon = level-1; + playstate = ex_warped; + } + } + return 1; + } + else if (Keyboard[sc_X]) // X = item cheat + { + CenterWindow (12,3); + US_PrintCentered ("Extra stuff!"); + VW_UpdateScreen(); + // DEBUG: put stuff here + IN_Ack (); + return 1; + } + + return 0; +} + + +#if 0 +/* +=================== += += OverheadRefresh += +=================== +*/ + +void OverheadRefresh (void) +{ + unsigned x,y,endx,endy,sx,sy; + unsigned tile; + + + endx = maporgx+VIEWTILEX; + endy = maporgy+VIEWTILEY; + + for (y=maporgy;y>12)); + LatchDrawChar(sx+8,sy,NUMBERCHARS+((tile&0x0f00)>>8)); + LatchDrawChar(sx,sy+8,NUMBERCHARS+((tile&0x00f0)>>4)); + LatchDrawChar(sx+8,sy+8,NUMBERCHARS+(tile&0x000f)); + } + } + +} +#endif + +#if 0 +/* +=================== += += ViewMap += +=================== +*/ + +void ViewMap (void) +{ + boolean button0held; + + viewtype = actoratview; +// button0held = false; + + + maporgx = player->tilex - VIEWTILEX/2; + if (maporgx<0) + maporgx = 0; + if (maporgx>MAPSIZE-VIEWTILEX) + maporgx=MAPSIZE-VIEWTILEX; + maporgy = player->tiley - VIEWTILEY/2; + if (maporgy<0) + maporgy = 0; + if (maporgy>MAPSIZE-VIEWTILEY) + maporgy=MAPSIZE-VIEWTILEY; + + do + { +// +// let user pan around +// + PollControls (); + if (controlx < 0 && maporgx>0) + maporgx--; + if (controlx > 0 && maporgx0) + maporgy--; + if (controly > 0 && maporgyvisview) + viewtype = mapview; + } + if (!c.button0) + button0held = false; +#endif + + OverheadRefresh (); + + } while (!Keyboard[sc_Escape]); + + IN_ClearKeysDown (); +} +#endif + diff --git a/16/sod8086/wl_def.h b/16/sod8086/wl_def.h new file mode 100755 index 00000000..d1bc0802 --- /dev/null +++ b/16/sod8086/wl_def.h @@ -0,0 +1,1276 @@ +//#define BETA +#define YEAR 1992 +#define MONTH 9 +#define DAY 30 + +#include "ID_HEADS.H" +#include +#include + +#include "WL_MENU.H" + +#ifdef SPANISH +#include "SPANISH.H" +#else +#include "FOREIGN.H" +#endif + +#ifdef SPEAR +#include "F_SPEAR.H" +#endif + +/* +============================================================================= + + MACROS + +============================================================================= +*/ + + +#define COLORBORDER(color) asm{mov dx,STATUS_REGISTER_1;in al,dx;\ + mov dx,ATR_INDEX;mov al,ATR_OVERSCAN;out dx,al;mov al,color;out dx,al;\ + mov al,32;out dx,al}; + +#define MAPSPOT(x,y,plane) (*(mapsegs[plane]+farmapylookup[y]+x)) + +#define SIGN(x) ((x)>0?1:-1) +#define ABS(x) ((int)(x)>0?(x):-(x)) +#define LABS(x) ((long)(x)>0?(x):-(x)) + +/* +============================================================================= + + GLOBAL CONSTANTS + +============================================================================= +*/ + +#define MAXACTORS 150 // max number of nazis, etc / map +#define MAXSTATS 400 // max number of lamps, bonus, etc +#define MAXDOORS 64 // max number of sliding doors +#define MAXWALLTILES 64 // max number of wall tiles + +// +// tile constants +// + +#define ICONARROWS 90 +#define PUSHABLETILE 98 +#define EXITTILE 99 // at end of castle +#define AREATILE 107 // first of NUMAREAS floor tiles +#define NUMAREAS 37 +#define ELEVATORTILE 21 +#define AMBUSHTILE 106 +#define ALTELEVATORTILE 107 + +#define NUMBERCHARS 9 + + +//---------------- + +#define EXTRAPOINTS 40000 + +#define PLAYERSPEED 3000 +#define RUNSPEED 6000 + +#define SCREENSEG 0xa000 + +#define SCREENBWIDE 80 + +#define HEIGHTRATIO 0.50 // also defined in id_mm.c + +#define BORDERCOLOR 3 +#define FLASHCOLOR 5 +#define FLASHTICS 4 + + +#define PLAYERSIZE MINDIST // player radius +#define MINACTORDIST 0x10000l // minimum dist from player center + // to any actor center + +#define NUMLATCHPICS 100 + + +#define PI 3.141592657 + +#define GLOBAL1 (1l<<16) +#define TILEGLOBAL GLOBAL1 +#define PIXGLOBAL (GLOBAL1/64) +#define TILESHIFT 16l +#define UNSIGNEDSHIFT 8 + +#define ANGLES 360 // must be divisable by 4 +#define ANGLEQUAD (ANGLES/4) +#define FINEANGLES 3600 +#define ANG90 (FINEANGLES/4) +#define ANG180 (ANG90*2) +#define ANG270 (ANG90*3) +#define ANG360 (ANG90*4) +#define VANG90 (ANGLES/4) +#define VANG180 (VANG90*2) +#define VANG270 (VANG90*3) +#define VANG360 (VANG90*4) + +#define MINDIST (0x5800l) + + +#define MAXSCALEHEIGHT 256 // largest scale on largest view + +#define MAXVIEWWIDTH 320 + +#define MAPSIZE 64 // maps are 64*64 max +#define NORTH 0 +#define EAST 1 +#define SOUTH 2 +#define WEST 3 + + +#define STATUSLINES 40 + +#define SCREENSIZE (SCREENBWIDE*208) +#define PAGE1START 0 +#define PAGE2START (SCREENSIZE) +#define PAGE3START (SCREENSIZE*2u) +#define FREESTART (SCREENSIZE*3u) + + +#define PIXRADIUS 512 + +#define STARTAMMO 8 + + +// object flag values + +#define FL_SHOOTABLE 1 +#define FL_BONUS 2 +#define FL_NEVERMARK 4 +#define FL_VISABLE 8 +#define FL_ATTACKMODE 16 +#define FL_FIRSTATTACK 32 +#define FL_AMBUSH 64 +#define FL_NONMARK 128 + + +// +// sprite constants +// + +enum { + SPR_DEMO, + SPR_DEATHCAM, +// +// static sprites +// + SPR_STAT_0,SPR_STAT_1,SPR_STAT_2,SPR_STAT_3, + SPR_STAT_4,SPR_STAT_5,SPR_STAT_6,SPR_STAT_7, + + SPR_STAT_8,SPR_STAT_9,SPR_STAT_10,SPR_STAT_11, + SPR_STAT_12,SPR_STAT_13,SPR_STAT_14,SPR_STAT_15, + + SPR_STAT_16,SPR_STAT_17,SPR_STAT_18,SPR_STAT_19, + SPR_STAT_20,SPR_STAT_21,SPR_STAT_22,SPR_STAT_23, + + SPR_STAT_24,SPR_STAT_25,SPR_STAT_26,SPR_STAT_27, + SPR_STAT_28,SPR_STAT_29,SPR_STAT_30,SPR_STAT_31, + + SPR_STAT_32,SPR_STAT_33,SPR_STAT_34,SPR_STAT_35, + SPR_STAT_36,SPR_STAT_37,SPR_STAT_38,SPR_STAT_39, + + SPR_STAT_40,SPR_STAT_41,SPR_STAT_42,SPR_STAT_43, + SPR_STAT_44,SPR_STAT_45,SPR_STAT_46,SPR_STAT_47, + +#ifdef SPEAR + SPR_STAT_48,SPR_STAT_49,SPR_STAT_50,SPR_STAT_51, +#endif + +// +// guard +// + SPR_GRD_S_1,SPR_GRD_S_2,SPR_GRD_S_3,SPR_GRD_S_4, + SPR_GRD_S_5,SPR_GRD_S_6,SPR_GRD_S_7,SPR_GRD_S_8, + + SPR_GRD_W1_1,SPR_GRD_W1_2,SPR_GRD_W1_3,SPR_GRD_W1_4, + SPR_GRD_W1_5,SPR_GRD_W1_6,SPR_GRD_W1_7,SPR_GRD_W1_8, + + SPR_GRD_W2_1,SPR_GRD_W2_2,SPR_GRD_W2_3,SPR_GRD_W2_4, + SPR_GRD_W2_5,SPR_GRD_W2_6,SPR_GRD_W2_7,SPR_GRD_W2_8, + + SPR_GRD_W3_1,SPR_GRD_W3_2,SPR_GRD_W3_3,SPR_GRD_W3_4, + SPR_GRD_W3_5,SPR_GRD_W3_6,SPR_GRD_W3_7,SPR_GRD_W3_8, + + SPR_GRD_W4_1,SPR_GRD_W4_2,SPR_GRD_W4_3,SPR_GRD_W4_4, + SPR_GRD_W4_5,SPR_GRD_W4_6,SPR_GRD_W4_7,SPR_GRD_W4_8, + + SPR_GRD_PAIN_1,SPR_GRD_DIE_1,SPR_GRD_DIE_2,SPR_GRD_DIE_3, + SPR_GRD_PAIN_2,SPR_GRD_DEAD, + + SPR_GRD_SHOOT1,SPR_GRD_SHOOT2,SPR_GRD_SHOOT3, + +// +// dogs +// + SPR_DOG_W1_1,SPR_DOG_W1_2,SPR_DOG_W1_3,SPR_DOG_W1_4, + SPR_DOG_W1_5,SPR_DOG_W1_6,SPR_DOG_W1_7,SPR_DOG_W1_8, + + SPR_DOG_W2_1,SPR_DOG_W2_2,SPR_DOG_W2_3,SPR_DOG_W2_4, + SPR_DOG_W2_5,SPR_DOG_W2_6,SPR_DOG_W2_7,SPR_DOG_W2_8, + + SPR_DOG_W3_1,SPR_DOG_W3_2,SPR_DOG_W3_3,SPR_DOG_W3_4, + SPR_DOG_W3_5,SPR_DOG_W3_6,SPR_DOG_W3_7,SPR_DOG_W3_8, + + SPR_DOG_W4_1,SPR_DOG_W4_2,SPR_DOG_W4_3,SPR_DOG_W4_4, + SPR_DOG_W4_5,SPR_DOG_W4_6,SPR_DOG_W4_7,SPR_DOG_W4_8, + + SPR_DOG_DIE_1,SPR_DOG_DIE_2,SPR_DOG_DIE_3,SPR_DOG_DEAD, + SPR_DOG_JUMP1,SPR_DOG_JUMP2,SPR_DOG_JUMP3, + + + +// +// ss +// + SPR_SS_S_1,SPR_SS_S_2,SPR_SS_S_3,SPR_SS_S_4, + SPR_SS_S_5,SPR_SS_S_6,SPR_SS_S_7,SPR_SS_S_8, + + SPR_SS_W1_1,SPR_SS_W1_2,SPR_SS_W1_3,SPR_SS_W1_4, + SPR_SS_W1_5,SPR_SS_W1_6,SPR_SS_W1_7,SPR_SS_W1_8, + + SPR_SS_W2_1,SPR_SS_W2_2,SPR_SS_W2_3,SPR_SS_W2_4, + SPR_SS_W2_5,SPR_SS_W2_6,SPR_SS_W2_7,SPR_SS_W2_8, + + SPR_SS_W3_1,SPR_SS_W3_2,SPR_SS_W3_3,SPR_SS_W3_4, + SPR_SS_W3_5,SPR_SS_W3_6,SPR_SS_W3_7,SPR_SS_W3_8, + + SPR_SS_W4_1,SPR_SS_W4_2,SPR_SS_W4_3,SPR_SS_W4_4, + SPR_SS_W4_5,SPR_SS_W4_6,SPR_SS_W4_7,SPR_SS_W4_8, + + SPR_SS_PAIN_1,SPR_SS_DIE_1,SPR_SS_DIE_2,SPR_SS_DIE_3, + SPR_SS_PAIN_2,SPR_SS_DEAD, + + SPR_SS_SHOOT1,SPR_SS_SHOOT2,SPR_SS_SHOOT3, + +// +// mutant +// + SPR_MUT_S_1,SPR_MUT_S_2,SPR_MUT_S_3,SPR_MUT_S_4, + SPR_MUT_S_5,SPR_MUT_S_6,SPR_MUT_S_7,SPR_MUT_S_8, + + SPR_MUT_W1_1,SPR_MUT_W1_2,SPR_MUT_W1_3,SPR_MUT_W1_4, + SPR_MUT_W1_5,SPR_MUT_W1_6,SPR_MUT_W1_7,SPR_MUT_W1_8, + + SPR_MUT_W2_1,SPR_MUT_W2_2,SPR_MUT_W2_3,SPR_MUT_W2_4, + SPR_MUT_W2_5,SPR_MUT_W2_6,SPR_MUT_W2_7,SPR_MUT_W2_8, + + SPR_MUT_W3_1,SPR_MUT_W3_2,SPR_MUT_W3_3,SPR_MUT_W3_4, + SPR_MUT_W3_5,SPR_MUT_W3_6,SPR_MUT_W3_7,SPR_MUT_W3_8, + + SPR_MUT_W4_1,SPR_MUT_W4_2,SPR_MUT_W4_3,SPR_MUT_W4_4, + SPR_MUT_W4_5,SPR_MUT_W4_6,SPR_MUT_W4_7,SPR_MUT_W4_8, + + SPR_MUT_PAIN_1,SPR_MUT_DIE_1,SPR_MUT_DIE_2,SPR_MUT_DIE_3, + SPR_MUT_PAIN_2,SPR_MUT_DIE_4,SPR_MUT_DEAD, + + SPR_MUT_SHOOT1,SPR_MUT_SHOOT2,SPR_MUT_SHOOT3,SPR_MUT_SHOOT4, + +// +// officer +// + SPR_OFC_S_1,SPR_OFC_S_2,SPR_OFC_S_3,SPR_OFC_S_4, + SPR_OFC_S_5,SPR_OFC_S_6,SPR_OFC_S_7,SPR_OFC_S_8, + + SPR_OFC_W1_1,SPR_OFC_W1_2,SPR_OFC_W1_3,SPR_OFC_W1_4, + SPR_OFC_W1_5,SPR_OFC_W1_6,SPR_OFC_W1_7,SPR_OFC_W1_8, + + SPR_OFC_W2_1,SPR_OFC_W2_2,SPR_OFC_W2_3,SPR_OFC_W2_4, + SPR_OFC_W2_5,SPR_OFC_W2_6,SPR_OFC_W2_7,SPR_OFC_W2_8, + + SPR_OFC_W3_1,SPR_OFC_W3_2,SPR_OFC_W3_3,SPR_OFC_W3_4, + SPR_OFC_W3_5,SPR_OFC_W3_6,SPR_OFC_W3_7,SPR_OFC_W3_8, + + SPR_OFC_W4_1,SPR_OFC_W4_2,SPR_OFC_W4_3,SPR_OFC_W4_4, + SPR_OFC_W4_5,SPR_OFC_W4_6,SPR_OFC_W4_7,SPR_OFC_W4_8, + + SPR_OFC_PAIN_1,SPR_OFC_DIE_1,SPR_OFC_DIE_2,SPR_OFC_DIE_3, + SPR_OFC_PAIN_2,SPR_OFC_DIE_4,SPR_OFC_DEAD, + + SPR_OFC_SHOOT1,SPR_OFC_SHOOT2,SPR_OFC_SHOOT3, + +#ifndef SPEAR +// +// ghosts +// + SPR_BLINKY_W1,SPR_BLINKY_W2,SPR_PINKY_W1,SPR_PINKY_W2, + SPR_CLYDE_W1,SPR_CLYDE_W2,SPR_INKY_W1,SPR_INKY_W2, + +// +// hans +// + SPR_BOSS_W1,SPR_BOSS_W2,SPR_BOSS_W3,SPR_BOSS_W4, + SPR_BOSS_SHOOT1,SPR_BOSS_SHOOT2,SPR_BOSS_SHOOT3,SPR_BOSS_DEAD, + + SPR_BOSS_DIE1,SPR_BOSS_DIE2,SPR_BOSS_DIE3, + +// +// schabbs +// + SPR_SCHABB_W1,SPR_SCHABB_W2,SPR_SCHABB_W3,SPR_SCHABB_W4, + SPR_SCHABB_SHOOT1,SPR_SCHABB_SHOOT2, + + SPR_SCHABB_DIE1,SPR_SCHABB_DIE2,SPR_SCHABB_DIE3,SPR_SCHABB_DEAD, + SPR_HYPO1,SPR_HYPO2,SPR_HYPO3,SPR_HYPO4, + +// +// fake +// + SPR_FAKE_W1,SPR_FAKE_W2,SPR_FAKE_W3,SPR_FAKE_W4, + SPR_FAKE_SHOOT,SPR_FIRE1,SPR_FIRE2, + + SPR_FAKE_DIE1,SPR_FAKE_DIE2,SPR_FAKE_DIE3,SPR_FAKE_DIE4, + SPR_FAKE_DIE5,SPR_FAKE_DEAD, + +// +// hitler +// + SPR_MECHA_W1,SPR_MECHA_W2,SPR_MECHA_W3,SPR_MECHA_W4, + SPR_MECHA_SHOOT1,SPR_MECHA_SHOOT2,SPR_MECHA_SHOOT3,SPR_MECHA_DEAD, + + SPR_MECHA_DIE1,SPR_MECHA_DIE2,SPR_MECHA_DIE3, + + SPR_HITLER_W1,SPR_HITLER_W2,SPR_HITLER_W3,SPR_HITLER_W4, + SPR_HITLER_SHOOT1,SPR_HITLER_SHOOT2,SPR_HITLER_SHOOT3,SPR_HITLER_DEAD, + + SPR_HITLER_DIE1,SPR_HITLER_DIE2,SPR_HITLER_DIE3,SPR_HITLER_DIE4, + SPR_HITLER_DIE5,SPR_HITLER_DIE6,SPR_HITLER_DIE7, + +// +// giftmacher +// + SPR_GIFT_W1,SPR_GIFT_W2,SPR_GIFT_W3,SPR_GIFT_W4, + SPR_GIFT_SHOOT1,SPR_GIFT_SHOOT2, + + SPR_GIFT_DIE1,SPR_GIFT_DIE2,SPR_GIFT_DIE3,SPR_GIFT_DEAD, +#endif +// +// Rocket, smoke and small explosion +// + SPR_ROCKET_1,SPR_ROCKET_2,SPR_ROCKET_3,SPR_ROCKET_4, + SPR_ROCKET_5,SPR_ROCKET_6,SPR_ROCKET_7,SPR_ROCKET_8, + + SPR_SMOKE_1,SPR_SMOKE_2,SPR_SMOKE_3,SPR_SMOKE_4, + SPR_BOOM_1,SPR_BOOM_2,SPR_BOOM_3, + +// +// Angel of Death's DeathSparks(tm) +// +#ifdef SPEAR + SPR_HROCKET_1,SPR_HROCKET_2,SPR_HROCKET_3,SPR_HROCKET_4, + SPR_HROCKET_5,SPR_HROCKET_6,SPR_HROCKET_7,SPR_HROCKET_8, + + SPR_HSMOKE_1,SPR_HSMOKE_2,SPR_HSMOKE_3,SPR_HSMOKE_4, + SPR_HBOOM_1,SPR_HBOOM_2,SPR_HBOOM_3, + + SPR_SPARK1,SPR_SPARK2,SPR_SPARK3,SPR_SPARK4, +#endif + +#ifndef SPEAR +// +// gretel +// + SPR_GRETEL_W1,SPR_GRETEL_W2,SPR_GRETEL_W3,SPR_GRETEL_W4, + SPR_GRETEL_SHOOT1,SPR_GRETEL_SHOOT2,SPR_GRETEL_SHOOT3,SPR_GRETEL_DEAD, + + SPR_GRETEL_DIE1,SPR_GRETEL_DIE2,SPR_GRETEL_DIE3, + +// +// fat face +// + SPR_FAT_W1,SPR_FAT_W2,SPR_FAT_W3,SPR_FAT_W4, + SPR_FAT_SHOOT1,SPR_FAT_SHOOT2,SPR_FAT_SHOOT3,SPR_FAT_SHOOT4, + + SPR_FAT_DIE1,SPR_FAT_DIE2,SPR_FAT_DIE3,SPR_FAT_DEAD, + +// +// bj +// + SPR_BJ_W1,SPR_BJ_W2,SPR_BJ_W3,SPR_BJ_W4, + SPR_BJ_JUMP1,SPR_BJ_JUMP2,SPR_BJ_JUMP3,SPR_BJ_JUMP4, +#else +// +// THESE ARE FOR 'SPEAR OF DESTINY' +// + +// +// Trans Grosse +// + SPR_TRANS_W1,SPR_TRANS_W2,SPR_TRANS_W3,SPR_TRANS_W4, + SPR_TRANS_SHOOT1,SPR_TRANS_SHOOT2,SPR_TRANS_SHOOT3,SPR_TRANS_DEAD, + + SPR_TRANS_DIE1,SPR_TRANS_DIE2,SPR_TRANS_DIE3, + +// +// Wilhelm +// + SPR_WILL_W1,SPR_WILL_W2,SPR_WILL_W3,SPR_WILL_W4, + SPR_WILL_SHOOT1,SPR_WILL_SHOOT2,SPR_WILL_SHOOT3,SPR_WILL_SHOOT4, + + SPR_WILL_DIE1,SPR_WILL_DIE2,SPR_WILL_DIE3,SPR_WILL_DEAD, + +// +// UberMutant +// + SPR_UBER_W1,SPR_UBER_W2,SPR_UBER_W3,SPR_UBER_W4, + SPR_UBER_SHOOT1,SPR_UBER_SHOOT2,SPR_UBER_SHOOT3,SPR_UBER_SHOOT4, + + SPR_UBER_DIE1,SPR_UBER_DIE2,SPR_UBER_DIE3,SPR_UBER_DIE4, + SPR_UBER_DEAD, + +// +// Death Knight +// + SPR_DEATH_W1,SPR_DEATH_W2,SPR_DEATH_W3,SPR_DEATH_W4, + SPR_DEATH_SHOOT1,SPR_DEATH_SHOOT2,SPR_DEATH_SHOOT3,SPR_DEATH_SHOOT4, + + SPR_DEATH_DIE1,SPR_DEATH_DIE2,SPR_DEATH_DIE3,SPR_DEATH_DIE4, + SPR_DEATH_DIE5,SPR_DEATH_DIE6,SPR_DEATH_DEAD, + +// +// Ghost +// + SPR_SPECTRE_W1,SPR_SPECTRE_W2,SPR_SPECTRE_W3,SPR_SPECTRE_W4, + SPR_SPECTRE_F1,SPR_SPECTRE_F2,SPR_SPECTRE_F3,SPR_SPECTRE_F4, + +// +// Angel of Death +// + SPR_ANGEL_W1,SPR_ANGEL_W2,SPR_ANGEL_W3,SPR_ANGEL_W4, + SPR_ANGEL_SHOOT1,SPR_ANGEL_SHOOT2,SPR_ANGEL_TIRED1,SPR_ANGEL_TIRED2, + + SPR_ANGEL_DIE1,SPR_ANGEL_DIE2,SPR_ANGEL_DIE3,SPR_ANGEL_DIE4, + SPR_ANGEL_DIE5,SPR_ANGEL_DIE6,SPR_ANGEL_DIE7,SPR_ANGEL_DEAD, + +#endif + +// +// player attack frames +// + SPR_KNIFEREADY,SPR_KNIFEATK1,SPR_KNIFEATK2,SPR_KNIFEATK3, + SPR_KNIFEATK4, + + SPR_PISTOLREADY,SPR_PISTOLATK1,SPR_PISTOLATK2,SPR_PISTOLATK3, + SPR_PISTOLATK4, + + SPR_MACHINEGUNREADY,SPR_MACHINEGUNATK1,SPR_MACHINEGUNATK2,MACHINEGUNATK3, + SPR_MACHINEGUNATK4, + + SPR_CHAINREADY,SPR_CHAINATK1,SPR_CHAINATK2,SPR_CHAINATK3, + SPR_CHAINATK4, + + }; + + +/* +============================================================================= + + GLOBAL TYPES + +============================================================================= +*/ + +typedef long fixed; + +typedef enum { + di_north, + di_east, + di_south, + di_west +} controldir_t; + +typedef enum { + dr_normal, + dr_lock1, + dr_lock2, + dr_lock3, + dr_lock4, + dr_elevator +} door_t; + +typedef enum { + ac_badobject = -1, + ac_no, + ac_yes, + ac_allways +} activetype; + +typedef enum { + nothing, + playerobj, + inertobj, + guardobj, + officerobj, + ssobj, + dogobj, + bossobj, + schabbobj, + fakeobj, + mechahitlerobj, + mutantobj, + needleobj, + fireobj, + bjobj, + ghostobj, + realhitlerobj, + gretelobj, + giftobj, + fatobj, + rocketobj, + + spectreobj, + angelobj, + transobj, + uberobj, + willobj, + deathobj, + hrocketobj, + sparkobj +} classtype; + +typedef enum { + dressing, + block, + bo_gibs, + bo_alpo, + bo_firstaid, + bo_key1, + bo_key2, + bo_key3, + bo_key4, + bo_cross, + bo_chalice, + bo_bible, + bo_crown, + bo_clip, + bo_clip2, + bo_machinegun, + bo_chaingun, + bo_food, + bo_fullheal, + bo_25clip, + bo_spear +} stat_t; + +typedef enum { + east, + northeast, + north, + northwest, + west, + southwest, + south, + southeast, + nodir +} dirtype; + + +#define NUMENEMIES 22 +typedef enum { + en_guard, + en_officer, + en_ss, + en_dog, + en_boss, + en_schabbs, + en_fake, + en_hitler, + en_mutant, + en_blinky, + en_clyde, + en_pinky, + en_inky, + en_gretel, + en_gift, + en_fat, + en_spectre, + en_angel, + en_trans, + en_uber, + en_will, + en_death +} enemy_t; + + +typedef struct statestruct +{ + boolean rotate; + int shapenum; // a shapenum of -1 means get from ob->temp1 + int tictime; + void (*think) (),(*action) (); + struct statestruct *next; +} statetype; + + +//--------------------- +// +// trivial actor structure +// +//--------------------- + +typedef struct statstruct +{ + byte tilex,tiley; + byte *visspot; + int shapenum; // if shapenum == -1 the obj has been removed + byte flags; + byte itemnumber; +} statobj_t; + + +//--------------------- +// +// door actor structure +// +//--------------------- + +typedef struct doorstruct +{ + byte tilex,tiley; + boolean vertical; + byte lock; + enum {dr_open,dr_closed,dr_opening,dr_closing} action; + int ticcount; +} doorobj_t; + + +//-------------------- +// +// thinking actor structure +// +//-------------------- + +typedef struct objstruct +{ + activetype active; + int ticcount; + classtype obclass; + statetype *state; + + byte flags; // FL_SHOOTABLE, etc + + long distance; // if negative, wait for that door to open + dirtype dir; + + fixed x,y; + unsigned tilex,tiley; + byte areanumber; + + int viewx; + unsigned viewheight; + fixed transx,transy; // in global coord + + int angle; + int hitpoints; + long speed; + + int temp1,temp2,temp3; + struct objstruct *next,*prev; +} objtype; + + +#define NUMBUTTONS 8 +enum { + bt_nobutton=-1, + bt_attack=0, + bt_strafe, + bt_run, + bt_use, + bt_readyknife, + bt_readypistol, + bt_readymachinegun, + bt_readychaingun +}; + + +#define NUMWEAPONS 5 +typedef enum { + wp_knife, + wp_pistol, + wp_machinegun, + wp_chaingun +} weapontype; + + +typedef enum { + gd_baby, + gd_easy, + gd_medium, + gd_hard +}; + +//--------------- +// +// gamestate structure +// +//--------------- + +typedef struct +{ + int difficulty; + int mapon; + long oldscore,score,nextextra; + int lives; + int health; + int ammo; + int keys; + weapontype bestweapon,weapon,chosenweapon; + + int faceframe; + int attackframe,attackcount,weaponframe; + + int episode,secretcount,treasurecount,killcount, + secrettotal,treasuretotal,killtotal; + long TimeCount; + long killx,killy; + boolean victoryflag; // set during victory animations +} gametype; + + +typedef enum { + ex_stillplaying, + ex_completed, + ex_died, + ex_warped, + ex_resetgame, + ex_loadedgame, + ex_victorious, + ex_abort, + ex_demodone, + ex_secretlevel +} exit_t; + + +/* +============================================================================= + + WL_MAIN DEFINITIONS + +============================================================================= +*/ + +extern boolean MS_CheckParm (char far *string); + +extern char str[80],str2[20]; +extern int tedlevelnum; +extern boolean tedlevel; +extern boolean nospr; +extern boolean IsA386; + +extern byte far *scalermemory; + +extern fixed focallength; +extern unsigned viewangles; +extern unsigned screenofs; +extern int viewwidth; +extern int viewheight; +extern int centerx; +extern int shootdelta; + +extern int dirangle[9]; + +extern boolean startgame,loadedgame,virtualreality; +extern int mouseadjustment; +// +// math tables +// +extern int pixelangle[MAXVIEWWIDTH]; +extern long far finetangent[FINEANGLES/4]; +extern fixed far sintable[],far *costable; + +// +// derived constants +// +extern fixed scale,maxslope; +extern long heightnumerator; +extern int minheightdiv; + +extern char configname[13]; + + + +void HelpScreens (void); +void OrderingInfo (void); +void TEDDeath(void); +void Quit (char *error); +void CalcProjection (long focal); +boolean SetViewSize (unsigned width, unsigned height); +void NewGame (int difficulty,int episode); +void NewViewSize (int width); +boolean LoadTheGame(int file,int x,int y); +boolean SaveTheGame(int file,int x,int y); +void ShowViewSize (int width); +void ShutdownId (void); + + +/* +============================================================================= + + WL_GAME DEFINITIONS + +============================================================================= +*/ + + +extern boolean ingame,fizzlein; +extern unsigned latchpics[NUMLATCHPICS]; +extern gametype gamestate; +extern int doornum; + +extern char demoname[13]; + +extern long spearx,speary; +extern unsigned spearangle; +extern boolean spearflag; + + +void DrawPlayBorder (void); +void ScanInfoPlane (void); +void SetupGameLevel (void); +void NormalScreen (void); +void DrawPlayScreen (void); +void FizzleOut (void); +void GameLoop (void); +void ClearMemory (void); +void PlayDemo (int demonumber); +void RecordDemo (void); +void DrawAllPlayBorder (void); +void DrawHighScores(void); +void DrawAllPlayBorderSides (void); + + +// JAB +#define PlaySoundLocTile(s,tx,ty) PlaySoundLocGlobal(s,(((long)(tx) << TILESHIFT) + (1L << (TILESHIFT - 1))),(((long)ty << TILESHIFT) + (1L << (TILESHIFT - 1)))) +#define PlaySoundLocActor(s,ob) PlaySoundLocGlobal(s,(ob)->x,(ob)->y) +void PlaySoundLocGlobal(word s,fixed gx,fixed gy); +void UpdateSoundLoc(void); + + +/* +============================================================================= + + WL_PLAY DEFINITIONS + +============================================================================= +*/ + +#ifdef SPEAR +extern long funnyticount; // FOR FUNNY BJ FACE +#endif + +extern exit_t playstate; + +extern boolean madenoise; + +extern objtype objlist[MAXACTORS],*new,*obj,*player,*lastobj, + *objfreelist,*killerobj; +extern statobj_t statobjlist[MAXSTATS],*laststatobj; +extern doorobj_t doorobjlist[MAXDOORS],*lastdoorobj; + +extern unsigned farmapylookup[MAPSIZE]; +extern byte *nearmapylookup[MAPSIZE]; + +extern byte tilemap[MAPSIZE][MAPSIZE]; // wall values only +extern byte spotvis[MAPSIZE][MAPSIZE]; +extern objtype *actorat[MAPSIZE][MAPSIZE]; + +#define UPDATESIZE (UPDATEWIDE*UPDATEHIGH) +extern byte update[UPDATESIZE]; + +extern boolean singlestep,godmode,noclip; +extern int extravbls; + +// +// control info +// +extern boolean mouseenabled,joystickenabled,joypadenabled,joystickprogressive; +extern int joystickport; +extern int dirscan[4]; +extern int buttonscan[NUMBUTTONS]; +extern int buttonmouse[4]; +extern int buttonjoy[4]; + +extern boolean buttonheld[NUMBUTTONS]; + +extern int viewsize; + +// +// curent user input +// +extern int controlx,controly; // range from -100 to 100 +extern boolean buttonstate[NUMBUTTONS]; + +extern boolean demorecord,demoplayback; +extern char far *demoptr, far *lastdemoptr; +extern memptr demobuffer; + + + +void InitRedShifts (void); +void FinishPaletteShifts (void); + +void CenterWindow(word w,word h); +void InitActorList (void); +void GetNewActor (void); +void RemoveObj (objtype *gone); +void PollControls (void); +void StopMusic(void); +void StartMusic(void); +void PlayLoop (void); +void StartDamageFlash (int damage); +void StartBonusFlash (void); + +/* +============================================================================= + + WL_INTER + +============================================================================= +*/ + +void IntroScreen (void); +void PreloadGraphics(void); +void LevelCompleted (void); +void CheckHighScore (long score,word other); +void Victory (void); +void ClearSplitVWB (void); + + +/* +============================================================================= + + WL_DEBUG + +============================================================================= +*/ + +int DebugKeys (void); +void PicturePause (void); + + +/* +============================================================================= + + WL_DRAW DEFINITIONS + +============================================================================= +*/ + +extern unsigned screenloc[3]; +extern unsigned freelatch; + +extern long lasttimecount; +extern long frameon; +extern boolean fizzlein; + +extern unsigned wallheight[MAXVIEWWIDTH]; + +extern fixed tileglobal; +extern fixed focallength; +extern fixed mindist; + +// +// math tables +// +extern int pixelangle[MAXVIEWWIDTH]; +extern long far finetangent[FINEANGLES/4]; +extern fixed far sintable[],far *costable; + +// +// derived constants +// +extern fixed scale; +extern long heightnumerator,mindist; + +// +// refresh variables +// +extern fixed viewx,viewy; // the focal point +extern int viewangle; +extern fixed viewsin,viewcos; + +extern long postsource; +extern unsigned postx; +extern unsigned postwidth; + + +extern int horizwall[],vertwall[]; + +extern unsigned pwallpos; + + +fixed FixedByFrac (fixed a, fixed b); +void TransformActor (objtype *ob); +void BuildTables (void); +void ClearScreen (void); +int CalcRotate (objtype *ob); +void DrawScaleds (void); +void CalcTics (void); +void FixOfs (void); +void ThreeDRefresh (void); +void FarScalePost (void); + +/* +============================================================================= + + WL_STATE DEFINITIONS + +============================================================================= +*/ +#define TURNTICS 10 +#define SPDPATROL 512 +#define SPDDOG 1500 + + +extern dirtype opposite[9]; +extern dirtype diagonal[9][9]; + + +void InitHitRect (objtype *ob, unsigned radius); +void SpawnNewObj (unsigned tilex, unsigned tiley, statetype *state); +void NewState (objtype *ob, statetype *state); + +boolean TryWalk (objtype *ob); +void SelectChaseDir (objtype *ob); +void SelectDodgeDir (objtype *ob); +void SelectRunDir (objtype *ob); +void MoveObj (objtype *ob, long move); +boolean SightPlayer (objtype *ob); + +void KillActor (objtype *ob); +void DamageActor (objtype *ob, unsigned damage); + +boolean CheckLine (objtype *ob); +boolean CheckSight (objtype *ob); + + +/* +============================================================================= + + WL_SCALE DEFINITIONS + +============================================================================= +*/ + + +#define COMPSCALECODESTART (65*4) // offset to start of code in comp scaler + +typedef struct +{ + unsigned codeofs[65]; + unsigned width[65]; + byte code[]; +} t_compscale; + +typedef struct +{ + unsigned leftpix,rightpix; + unsigned dataofs[64]; +// table data after dataofs[rightpix-leftpix+1] +} t_compshape; + + +extern t_compscale _seg *scaledirectory[MAXSCALEHEIGHT+1]; +extern long fullscalefarcall[MAXSCALEHEIGHT+1]; + +extern byte bitmasks1[8][8]; +extern byte bitmasks2[8][8]; +extern unsigned wordmasks[8][8]; + +extern byte mapmasks1[4][8]; +extern byte mapmasks2[4][8]; +extern byte mapmasks3[4][8]; + +extern int maxscale,maxscaleshl2; + +extern boolean insetupscaling; + +void SetupScaling (int maxscaleheight); +void ScaleShape (int xcenter, int shapenum, unsigned height); +void SimpleScaleShape (int xcenter, int shapenum, unsigned height); + +/* +============================================================================= + + WL_AGENT DEFINITIONS + +============================================================================= +*/ + +// +// player state info +// +extern boolean running; +extern long thrustspeed; +extern unsigned plux,pluy; // player coordinates scaled to unsigned + +extern int anglefrac; +extern int facecount; + +void SpawnPlayer (int tilex, int tiley, int dir); +void DrawFace (void); +void DrawHealth (void); +void TakeDamage (int points,objtype *attacker); +void HealSelf (int points); +void DrawLevel (void); +void DrawLives (void); +void GiveExtraMan (void); +void DrawScore (void); +void GivePoints (long points); +void DrawWeapon (void); +void DrawKeys (void); +void GiveWeapon (int weapon); +void DrawAmmo (void); +void GiveAmmo (int ammo); +void GiveKey (int key); +void GetBonus (statobj_t *check); + +void Thrust (int angle, long speed); + +/* +============================================================================= + + WL_ACT1 DEFINITIONS + +============================================================================= +*/ + +extern doorobj_t doorobjlist[MAXDOORS],*lastdoorobj; +extern int doornum; + +extern unsigned doorposition[MAXDOORS],pwallstate; + +extern byte far areaconnect[NUMAREAS][NUMAREAS]; + +extern boolean areabyplayer[NUMAREAS]; + +extern unsigned pwallstate; +extern unsigned pwallpos; // amount a pushable wall has been moved (0-63) +extern unsigned pwallx,pwally; +extern int pwalldir; + + +void InitDoorList (void); +void InitStaticList (void); +void SpawnStatic (int tilex, int tiley, int type); +void SpawnDoor (int tilex, int tiley, boolean vertical, int lock); +void MoveDoors (void); +void MovePWalls (void); +void OpenDoor (int door); +void PlaceItemType (int itemtype, int tilex, int tiley); +void PushWall (int checkx, int checky, int dir); +void OperateDoor (int door); +void InitAreas (void); + +/* +============================================================================= + + WL_ACT2 DEFINITIONS + +============================================================================= +*/ + +#define s_nakedbody s_static10 + +extern statetype s_grddie1; +extern statetype s_dogdie1; +extern statetype s_ofcdie1; +extern statetype s_mutdie1; +extern statetype s_ssdie1; +extern statetype s_bossdie1; +extern statetype s_schabbdie1; +extern statetype s_fakedie1; +extern statetype s_mechadie1; +extern statetype s_hitlerdie1; +extern statetype s_greteldie1; +extern statetype s_giftdie1; +extern statetype s_fatdie1; + +extern statetype s_spectredie1; +extern statetype s_angeldie1; +extern statetype s_transdie0; +extern statetype s_uberdie0; +extern statetype s_willdie1; +extern statetype s_deathdie1; + + +extern statetype s_grdchase1; +extern statetype s_dogchase1; +extern statetype s_ofcchase1; +extern statetype s_sschase1; +extern statetype s_mutchase1; +extern statetype s_bosschase1; +extern statetype s_schabbchase1; +extern statetype s_fakechase1; +extern statetype s_mechachase1; +extern statetype s_gretelchase1; +extern statetype s_giftchase1; +extern statetype s_fatchase1; + +extern statetype s_spectrechase1; +extern statetype s_angelchase1; +extern statetype s_transchase1; +extern statetype s_uberchase1; +extern statetype s_willchase1; +extern statetype s_deathchase1; + +extern statetype s_blinkychase1; +extern statetype s_hitlerchase1; + +extern statetype s_grdpain; +extern statetype s_grdpain1; +extern statetype s_ofcpain; +extern statetype s_ofcpain1; +extern statetype s_sspain; +extern statetype s_sspain1; +extern statetype s_mutpain; +extern statetype s_mutpain1; + +extern statetype s_deathcam; + +extern statetype s_schabbdeathcam2; +extern statetype s_hitlerdeathcam2; +extern statetype s_giftdeathcam2; +extern statetype s_fatdeathcam2; + +void SpawnStand (enemy_t which, int tilex, int tiley, int dir); +void SpawnPatrol (enemy_t which, int tilex, int tiley, int dir); +void KillActor (objtype *ob); + +void US_ControlPanel(byte); + +void SpawnDeadGuard (int tilex, int tiley); +void SpawnBoss (int tilex, int tiley); +void SpawnGretel (int tilex, int tiley); +void SpawnTrans (int tilex, int tiley); +void SpawnUber (int tilex, int tiley); +void SpawnWill (int tilex, int tiley); +void SpawnDeath (int tilex, int tiley); +void SpawnAngel (int tilex, int tiley); +void SpawnSpectre (int tilex, int tiley); +void SpawnGhosts (int which, int tilex, int tiley); +void SpawnSchabbs (int tilex, int tiley); +void SpawnGift (int tilex, int tiley); +void SpawnFat (int tilex, int tiley); +void SpawnFakeHitler (int tilex, int tiley); +void SpawnHitler (int tilex, int tiley); + +/* +============================================================================= + + WL_TEXT DEFINITIONS + +============================================================================= +*/ + +extern char helpfilename[],endfilename[]; + +extern void HelpScreens(void); +extern void EndText(void); diff --git a/16/sod8086/wl_dr_a.asm b/16/sod8086/wl_dr_a.asm new file mode 100755 index 00000000..aec139a1 --- /dev/null +++ b/16/sod8086/wl_dr_a.asm @@ -0,0 +1,795 @@ + IDEAL + MODEL MEDIUM,C + P286 + +SCREENSEG = 0a000h + +FINEANGLES = 3600 +DEG90 = 900 +DEG180 = 1800 +DEG270 = 2700 +DEG360 = 3600 + +OP_JLE = 07eh +OP_JGE = 07dh + +EXTRN finetangent:DWORD ; far array, starts at offset 0 + +EXTRN HitHorizWall:FAR +EXTRN HitVertWall:FAR +EXTRN HitHorizDoor:FAR +EXTRN HitVertDoor:FAR +EXTRN HitHorizPWall:FAR +EXTRN HitVertPWall:FAR + + +DATASEG + +EXTRN viewwidth:WORD + +EXTRN tilemap:BYTE +EXTRN spotvis:BYTE +EXTRN pixelangle:WORD + + +EXTRN midangle:WORD +EXTRN angle:WORD + +EXTRN focaltx:WORD +EXTRN focalty:WORD +EXTRN viewtx:WORD +EXTRN viewty:WORD +EXTRN viewx:DWORD +EXTRN viewy:DWORD + +EXTRN xpartialup:WORD +EXTRN ypartialup:WORD +EXTRN xpartialdown:WORD +EXTRN ypartialdown:WORD + +EXTRN tilehit:WORD +EXTRN pixx:WORD +EXTRN wallheight:WORD ; array of VIEWWIDTH entries + +EXTRN xtile:WORD +EXTRN ytile:WORD +EXTRN xtilestep:WORD +EXTRN ytilestep:WORD +EXTRN xintercept:DWORD +EXTRN yintercept:DWORD +EXTRN xstep:DWORD +EXTRN ystep:DWORD + +EXTRN doorposition:WORD ; table of door position values + + +EXTRN pwallpos:WORD ; amound a pushable wall has been moved + +CODESEG + +;------------------- +; +; xpartialbyystep +; +; multiplies long [ystep] (possibly negative), by word [xpartial] (in BX) +; +; returns dx:ax +; trashes bx,cx,di +; +;------------------- + +PROC xpartialbyystep NEAR +; +; setup +; + mov ax,[WORD ystep] + mov cx,[WORD ystep+2] + or cx,cx ; is ystep negatice? + jns @@multpos +; +; multiply negative cx:ax by bx +; + neg cx + neg ax + sbb cx,0 + + mul bx ; fraction*fraction + mov di,dx ; di is low word of result + mov ax,cx ; + mul bx ; units*fraction + add ax,di + adc dx,0 + + neg dx + neg ax + sbb dx,0 + ret +; +; multiply positive cx:ax by bx +; +EVEN +@@multpos: + mul bx ; fraction*fraction + mov di,dx ; di is low word of result + mov ax,cx ; + mul bx ; units*fraction + add ax,di + adc dx,0 + + ret + +ENDP + + + +;------------------- +; +; ypartialbyxstep +; +; multiplies long [xstep] (possibly negative), by word [ypartial] (in BP) +; +; returns dx:ax +; trashes cx,di,bp +; +;------------------- + +PROC ypartialbyxstep NEAR +; +; setup +; + mov ax,[WORD xstep] + mov cx,[WORD xstep+2] + or cx,cx ; is ystep negatice? + jns @@multpos +; +; multiply negative cx:ax by bx +; + neg cx + neg ax + sbb cx,0 + + mul bp ; fraction*fraction + mov di,dx ; di is low word of result + mov ax,cx ; + mul bp ; units*fraction + add ax,di + adc dx,0 + + neg dx + neg ax + sbb dx,0 + ret +; +; multiply positive cx:ax by bx +; +EVEN +@@multpos: + mul bp ; fraction*fraction + mov di,dx ; di is low word of result + mov ax,cx ; + mul bp ; units*fraction + add ax,di + adc dx,0 + ret + +ENDP + + +;============================ +; +; AsmRefresh +; +; +;============================ + +PROC AsmRefresh +PUBLIC AsmRefresh + + push si + push di + push bp + + mov [pixx],0 +;--------------------------------------------------------------------------- +; +; Setup to trace a ray through pixx view pixel +; +; CX : angle of the ray through pixx +; ES : points to segment of finetangent array for this block of code +; +; Upon entrance to initialize block +; +; BX : xpartial +; BP : ypartial +; +;--------------------------------------------------------------------------- + EVEN +pixxloop: + mov ax,SEG finetangent + mov es,ax + mov cx,[midangle] ; center of view area + mov bx,[pixx] + shl bx,1 + add cx,[pixelangle+bx] ; delta for this pixel + cmp cx,0 + jge not0 +;---------- +; +; -90 - -1 degree arc +; +;---------- + add cx,FINEANGLES ; -90 is the same as 270 + jmp entry360 + +not0: + cmp cx,DEG90 + jge not90 +;---------- +; +; 0-89 degree arc +; +;---------- +entry90: + mov [xtilestep],1 ; xtilestep = 1 + mov [ytilestep],-1 ; ytilestep = -1 + mov [BYTE cs:horizop],OP_JGE ; patch a jge in + mov [BYTE cs:vertop],OP_JLE ; patch a jle in + mov bx,DEG90-1 + sub bx,cx + ;begin 8086 hack + ;shl bx,2 + shl bx,1 + shl bx,1 + ;end 8086 hack + mov ax,[es:bx] + mov dx,[es:bx+2] + mov [WORD xstep],ax + mov [WORD xstep+2],dx ; xstep = finetangent[DEG90-1-angle] + mov bx,cx + ;begin 8086 hack + ;shl bx,2 + shl bx,1 + shl bx,1 + ;end 8086 hack + mov ax,[es:bx] + mov dx,[es:bx+2] + neg dx + neg ax + sbb dx,0 + mov [WORD ystep],ax + mov [WORD ystep+2],dx ; ystep = -finetangent[angle] + + mov bx,[xpartialup] ; xpartial = xpartialup + mov bp,[ypartialdown] ; ypartial = ypartialdown + jmp initvars + +not90: + cmp cx,DEG180 + jge not180 +;---------- +; +; 90-179 degree arc +; +;---------- + mov ax,-1 + mov [xtilestep],ax ; xtilestep = -1 + mov [ytilestep],ax ; ytilestep = -1 + mov [BYTE cs:horizop],OP_JLE ; patch a jle in + mov [BYTE cs:vertop],OP_JLE ; patch a jle in + + mov bx,cx + ;begin 8086 hack + ;shl bx,2 + shl bx,1 + shl bx,1 + ;end 8086 hack + mov ax,[es:bx-DEG90*4] + mov dx,[es:bx+2-DEG90*4] + neg dx + neg ax + sbb dx,0 + mov [WORD xstep],ax + mov [WORD xstep+2],dx ; xstep = -finetangent[angle-DEG90] + mov bx,DEG180-1 + sub bx,cx + ;begin 8086 hack + ;shl bx,2 + shl bx,1 + shl bx,1 + ;end 8086 hack + mov ax,[es:bx] + mov dx,[es:bx+2] + neg dx + neg ax + sbb dx,0 + mov [WORD ystep],ax + mov [WORD ystep+2],dx ; ystep = -finetangent[DEG180-1-angle] + + mov bx,[xpartialdown] ; xpartial = xpartialdown + mov bp,[ypartialdown] ; ypartial = ypartialdown + jmp initvars + +not180: + cmp cx,DEG270 + jge not270 +;---------- +; +; 180-269 degree arc +; +;---------- + mov [xtilestep],-1 ; xtilestep = -1 + mov [ytilestep],1 ; ytilestep = 1 + mov [BYTE cs:horizop],OP_JLE ; patch a jle in + mov [BYTE cs:vertop],OP_JGE ; patch a jge in + + mov bx,DEG270-1 + sub bx,cx + ;begin 8086 hack + ;shl bx,2 + shl bx,1 + shl bx,1 + ;end 8086 hack + mov ax,[es:bx] + mov dx,[es:bx+2] + neg dx + neg ax + sbb dx,0 + mov [WORD xstep],ax + mov [WORD xstep+2],dx ; xstep = -finetangent[DEG270-1-angle] + mov bx,cx + ;begin 8086 hack + ;shl bx,2 + shl bx,1 + shl bx,1 + ;end 8086 hack + mov ax,[es:bx-DEG180*4] + mov dx,[es:bx+2-DEG180*4] + mov [WORD ystep],ax + mov [WORD ystep+2],dx ; ystep = finetangent[angle-DEG180] + + mov bx,[xpartialdown] ; xpartial = xpartialdown + mov bp,[ypartialup] ; ypartial = ypartialup + jmp initvars + + +not270: + cmp cx,DEG360 + jge not360 +;---------- +; +; 270-359 degree arc +; +;---------- +entry360: + mov ax,1 + mov [xtilestep],ax ; xtilestep = 1 + mov [ytilestep],ax ; ytilestep = 1 + mov [BYTE cs:horizop],OP_JGE ; patch a jge in + mov [BYTE cs:vertop],OP_JGE ; patch a jge in + + mov bx,cx + ;begin 8086 hack + ;shl bx,2 + shl bx,1 + shl bx,1 + ;end 8086 hack + mov ax,[es:bx-DEG270*4] + mov dx,[es:bx+2-DEG270*4] + mov [WORD xstep],ax + mov [WORD xstep+2],dx ; xstep = finetangent[angle-DEG270] + mov bx,DEG360-1 + sub bx,cx + ;begin 8086 hack + ;shl bx,2 + shl bx,1 + shl bx,1 + ;end 8086 hack + mov ax,[es:bx] + mov dx,[es:bx+2] + mov [WORD ystep],ax + mov [WORD ystep+2],dx ; ystep = finetangent[DEG360-1-angle] + + mov bx,[xpartialup] ; xpartial = xpartialup + mov bp,[ypartialup] ; ypartial = ypartialup + jmp initvars + + +not360: +;---------- +; +; 360-449 degree arc +; +;---------- + sub cx,FINEANGLES ; -449 is the same as 89 + jmp entry90 + +;--------------------------------------------------------------------------- +; +; initialise variables for intersection testing +; +;--------------------------------------------------------------------------- +initvars: + call NEAR xpartialbyystep ; xpartial is in BX + add ax,[WORD viewy] + adc dx,[WORD viewy+2] + mov [WORD yintercept],ax + mov [WORD yintercept+2],dx + + mov si,[focaltx] + add si,[xtilestep] + mov [xtile],si ; xtile = focaltx+xtilestep + ;begin 8086 hack + ;shl si,6 + push cx + mov cl,6 + shl si,cl + pop cx + ;end 8086 hack + add si,dx ; xspot = (xtile<<6) + yinttile + + + call NEAR ypartialbyxstep ; ypartial is in BP + add ax,[WORD viewx] + adc dx,[WORD viewx+2] + mov [WORD xintercept],ax + mov cx,dx + + mov bx,[focalty] + add bx,[ytilestep] + mov bp,bx ; ytile = focalty+ytilestep + mov di,dx + ;begin 8086 hack + ;shl di,6 + push cx + mov cl,6 + shl di,cl + pop cx + ;end 8086 hack + add di,bx ; yspot = (xinttile<<6) + ytile + + mov bx,[xtile] + mov dx,[WORD yintercept+2] + mov ax,SCREENSEG + mov es,ax ; faster than mov es,[screenseg] + + +;--------------------------------------------------------------------------- +; +; trace along this angle until we hit a wall +; +; CORE LOOP! +; +; All variables are killed when a wall is hit +; +; AX : scratch +; BX : xtile +; CX : high word of xintercept +; DX : high word of yintercept +; SI : xspot (yinttile<<6)+xtile (index into tilemap and spotvis) +; DI : yspot (xinttile<<6)+ytile (index into tilemap and spotvis) +; BP : ytile +; ES : screenseg +; +;--------------------------------------------------------------------------- + +;----------- +; +; check intersections with vertical walls +; +;----------- + + EVEN +vertcheck: + cmp dx,bp +vertop: ; 0x7e = jle (ytilestep==-1) + jle horizentry ; 0x7d = jge (ytilestep==1) +vertentry: + test [BYTE tilemap+si],0ffh ; tilehit = *((byte *)tilemap+xspot); + jnz hitvert +passvert: + mov [BYTE spotvis+si],1 ; *((byte *)spotvis+xspot) = true; + add bx,[xtilestep] ; xtile+=xtilestep + mov ax,[WORD ystep] + add [WORD yintercept],ax ; yintercept += ystep + adc dx,[WORD ystep+2] + mov si,bx + ;begin 8086 hack + ;shl si,6 + push cx + mov cl,6 + shl si,cl + pop cx + ;end 8086 hack + add si,dx ; xspot = (xtile<<6)+yinttile + jmp vertcheck + + EVEN +hitvert: + mov al,[BYTE tilemap+si] ; tilehit = *((byte *)tilemap+xspot); + mov [BYTE tilehit],al + or al,al ; set flags + jns notvertdoor + jmp vertdoor +notvertdoor: + mov [WORD xintercept],0 + mov [WORD xintercept+2],bx + mov [xtile],bx + mov [WORD yintercept+2],dx + mov [ytile],dx + call FAR HitVertWall + jmp nextpix + + +;----------- +; +; check intersections with horizontal walls +; +;----------- + EVEN +horizcheck: + cmp cx,bx +horizop: ; 0x7e = jle (xtilestep==-1) + jle vertentry ; 0x7d = jge (xtilestep==1) +horizentry: + test [BYTE tilemap+di],0ffh ; tilehit = *((byte *)tilemap+yspot); + jnz hithoriz +passhoriz: + mov [BYTE spotvis+di],1 ; *((byte *)spotvis+yspot) = true; + add bp,[ytilestep] ; ytile+=ytilestep + mov ax,[WORD xstep] + add [WORD xintercept],ax ; xintercept += xstep + adc cx,[WORD xstep+2] + mov di,cx + ;begin 8086 hack + ;shl di,6 + push cx + mov cl,6 + shl di,cl + pop cx + ;end 8086 hack + add di,bp ; yspot = (xinttile<<6)+ytile + jmp horizcheck + + EVEN +hithoriz: + mov al,[BYTE tilemap+di] ; tilehit = *((byte *)tilemap+yspot); + mov [BYTE tilehit],al + or al,al ; set flags + js horizdoor + mov [WORD xintercept+2],cx + mov [xtile],cx + mov [WORD yintercept],0 + mov [WORD yintercept+2],bp + mov [ytile],bp + call FAR HitHorizWall + jmp nextpix + +;--------------------------------------------------------------------------- +; +; next pixel over +; +;--------------------------------------------------------------------------- + +nextpix: + mov ax,[pixx] + inc ax + mov [pixx],ax + cmp ax,[viewwidth] + jge done + jmp pixxloop +done: + pop bp + pop di + pop si + retf + +;=========================================================================== + +;============= +; +; hit a special horizontal wall, so find which coordinate a door would be +; intersected at, and check to see if the door is open past that point +; +;============= +horizdoor: + mov [xtile],bx ; save off live register variables + mov [WORD yintercept+2],dx + + test al,040h ; both high bits set == pushable wall + jnz horizpushwall + + mov bx,ax + and bx,7fh ; strip high bit + shl bx,1 ; index into word width door table + + mov ax,[WORD xstep] + mov dx,[WORD xstep+2] + sar dx,1 + rcr ax,1 ; half a step gets to door position + + add ax,[WORD xintercept] ; add half step to current intercept pos + adc dx,cx ; CX hold high word of xintercept + + cmp cx,dx ; is it still in the same tile? + je hithmid +; +; midpoint is outside tile, so it hit the side of the wall before a door +; +continuehoriz: + mov bx,[xtile] ; reload register variables + mov dx,[WORD yintercept+2] + jmp passhoriz ; continue tracing +; +; the trace hit the door plane at pixel position AX, see if the door is +; closed that much +; +hithmid: + cmp ax,[doorposition+bx] ; position of leading edge of door + jb continuehoriz +; +; draw the door +; + mov [WORD xintercept],ax ; save pixel intercept position + mov [WORD xintercept+2],cx + + mov [WORD yintercept],8000h ; intercept in middle of tile + mov [WORD yintercept+2],bp + + call FAR HitHorizDoor + jmp nextpix + +;============ +; +; hit a sliding horizontal wall +; +;============ + +horizpushwall: + mov ax,[WORD xstep+2] ; multiply xstep by pwallmove (0-63) + mul [pwallpos] + mov bx,ax + mov ax,[WORD xstep] + mul [pwallpos] + add dx,bx + + sar dx,1 ; then divide by 64 to accomplish a + rcr ax,1 ; fixed point multiplication + sar dx,1 + rcr ax,1 + sar dx,1 + rcr ax,1 + sar dx,1 + rcr ax,1 + sar dx,1 + rcr ax,1 + sar dx,1 + rcr ax,1 + + add ax,[WORD xintercept] ; add partial step to current intercept + adc dx,cx ; CX hold high word of xintercept + + cmp cx,dx ; is it still in the same tile? + jne continuehoriz ; no, it hit the side + +; +; draw the pushable wall at the new height +; + mov [WORD xintercept],ax ; save pixel intercept position + mov [WORD xintercept+2],dx + + mov [WORD yintercept+2],bp + mov [WORD yintercept],0 + + call FAR HitHorizPWall + jmp nextpix + + + +;=========================================================================== + +;============= +; +; hit a special vertical wall, so find which coordinate a door would be +; intersected at, and check to see if the door is open past that point +; +;============= +vertdoor: + mov [xtile],bx ; save off live register variables + mov [WORD yintercept+2],dx + + test al,040h ; both high bits set == pushable wall + jnz vertpushwall + + mov bx,ax + and bx,7fh ; strip high bit + shl bx,1 ; index into word width doorposition + + mov ax,[WORD ystep] + mov dx,[WORD ystep+2] + sar dx,1 + rcr ax,1 ; half a step gets to door position + + add ax,[WORD yintercept] ; add half step to current intercept pos + adc dx,[WORD yintercept+2] + + cmp [WORD yintercept+2],dx ; is it still in the same tile? + je hitvmid +; +; midpoint is outside tile, so it hit the side of the wall before a door +; +continuevert: + mov bx,[xtile] ; reload register variables + mov dx,[WORD yintercept+2] + jmp passvert ; continue tracing +; +; the trace hit the door plane at pixel position AX, see if the door is +; closed that much +; +hitvmid: + cmp ax,[doorposition+bx] ; position of leading edge of door + jb continuevert +; +; draw the door +; + mov [WORD yintercept],ax ; save pixel intercept position + mov [WORD xintercept],8000h ; intercept in middle of tile + mov ax,[xtile] + mov [WORD xintercept+2],ax + + call FAR HitVertDoor + jmp nextpix + +;============ +; +; hit a sliding vertical wall +; +;============ + +vertpushwall: + mov ax,[WORD ystep+2] ; multiply ystep by pwallmove (0-63) + mul [pwallpos] + mov bx,ax + mov ax,[WORD ystep] + mul [pwallpos] + add dx,bx + + sar dx,1 ; then divide by 64 to accomplish a + rcr ax,1 ; fixed point multiplication + sar dx,1 + rcr ax,1 + sar dx,1 + rcr ax,1 + sar dx,1 + rcr ax,1 + sar dx,1 + rcr ax,1 + sar dx,1 + rcr ax,1 + + add ax,[WORD yintercept] ; add partial step to current intercept + adc dx,[WORD yintercept+2] + + cmp [WORD yintercept+2],dx ; is it still in the same tile? + jne continuevert ; no, it hit the side + +; +; draw the pushable wall at the new height +; + mov [WORD yintercept],ax ; save pixel intercept position + mov [WORD yintercept+2],dx + + mov bx,[xtile] + mov [WORD xintercept+2],bx + mov [WORD xintercept],0 + + call FAR HitVertPWall + jmp nextpix + + + +ENDP + + +END + + diff --git a/16/sod8086/wl_draw.c b/16/sod8086/wl_draw.c new file mode 100755 index 00000000..3c32e39e --- /dev/null +++ b/16/sod8086/wl_draw.c @@ -0,0 +1,1419 @@ +// WL_DRAW.C + +#include "WL_DEF.H" +#include +#pragma hdrstop + +//#define DEBUGWALLS +//#define DEBUGTICS + +/* +============================================================================= + + LOCAL CONSTANTS + +============================================================================= +*/ + +// the door is the last picture before the sprites +#define DOORWALL (PMSpriteStart-8) + +#define ACTORSIZE 0x4000 + +/* +============================================================================= + + GLOBAL VARIABLES + +============================================================================= +*/ + + +#ifdef DEBUGWALLS +unsigned screenloc[3]= {0,0,0}; +#else +unsigned screenloc[3]= {PAGE1START,PAGE2START,PAGE3START}; +#endif +unsigned freelatch = FREESTART; + +long lasttimecount; +long frameon; + +unsigned wallheight[MAXVIEWWIDTH]; + +fixed tileglobal = TILEGLOBAL; +fixed mindist = MINDIST; + + +// +// math tables +// +int pixelangle[MAXVIEWWIDTH]; +long far finetangent[FINEANGLES/4]; +fixed far sintable[ANGLES+ANGLES/4],far *costable = sintable+(ANGLES/4); + +// +// refresh variables +// +fixed viewx,viewy; // the focal point +int viewangle; +fixed viewsin,viewcos; + + + +fixed FixedByFrac (fixed a, fixed b); +void TransformActor (objtype *ob); +void BuildTables (void); +void ClearScreen (void); +int CalcRotate (objtype *ob); +void DrawScaleds (void); +void CalcTics (void); +void FixOfs (void); +void ThreeDRefresh (void); + + + +// +// wall optimization variables +// +int lastside; // true for vertical +long lastintercept; +int lasttilehit; + + +// +// ray tracing variables +// +int focaltx,focalty,viewtx,viewty; + +int midangle,angle; +unsigned xpartial,ypartial; +unsigned xpartialup,xpartialdown,ypartialup,ypartialdown; +unsigned xinttile,yinttile; + +unsigned tilehit; +unsigned pixx; + +int xtile,ytile; +int xtilestep,ytilestep; +long xintercept,yintercept; +long xstep,ystep; + +int horizwall[MAXWALLTILES],vertwall[MAXWALLTILES]; + + +/* +============================================================================= + + LOCAL VARIABLES + +============================================================================= +*/ + + +void AsmRefresh (void); // in WL_DR_A.ASM + +/* +============================================================================ + + 3 - D DEFINITIONS + +============================================================================ +*/ + + +//========================================================================== + + +/* +======================== += += FixedByFrac += += multiply a 16/16 bit, 2's complement fixed point number by a 16 bit += fraction, passed as a signed magnitude 32 bit number += +======================== +*/ + +#pragma warn -rvl // I stick the return value in with ASMs + +fixed FixedByFrac (fixed a, fixed b) +{ +// +// setup +// +asm mov si,[WORD PTR b+2] // sign of result = sign of fraction + +asm mov ax,[WORD PTR a] +asm mov cx,[WORD PTR a+2] + +asm or cx,cx +asm jns aok: // negative? +asm neg cx +asm neg ax +asm sbb cx,0 +asm xor si,0x8000 // toggle sign of result +aok: + +// +// multiply cx:ax by bx +// +asm mov bx,[WORD PTR b] +asm mul bx // fraction*fraction +asm mov di,dx // di is low word of result +asm mov ax,cx // +asm mul bx // units*fraction +asm add ax,di +asm adc dx,0 + +// +// put result dx:ax in 2's complement +// +asm test si,0x8000 // is the result negative? +asm jz ansok: +asm neg dx +asm neg ax +asm sbb dx,0 + +ansok:; + +} + +#pragma warn +rvl + +//========================================================================== + +/* +======================== += += TransformActor += += Takes paramaters: += gx,gy : globalx/globaly of point += += globals: += viewx,viewy : point of view += viewcos,viewsin : sin/cos of viewangle += scale : conversion from global value to screen value += += sets: += screenx,transx,transy,screenheight: projected edge location and size += +======================== +*/ + + +// +// transform actor +// +void TransformActor (objtype *ob) +{ + int ratio; + fixed gx,gy,gxt,gyt,nx,ny; + long temp; + +// +// translate point to view centered coordinates +// + gx = ob->x-viewx; + gy = ob->y-viewy; + +// +// calculate newx +// + gxt = FixedByFrac(gx,viewcos); + gyt = FixedByFrac(gy,viewsin); + nx = gxt-gyt-ACTORSIZE; // fudge the shape forward a bit, because + // the midpoint could put parts of the shape + // into an adjacent wall + +// +// calculate newy +// + gxt = FixedByFrac(gx,viewsin); + gyt = FixedByFrac(gy,viewcos); + ny = gyt+gxt; + +// +// calculate perspective ratio +// + ob->transx = nx; + ob->transy = ny; + + if (nxviewheight = 0; + return; + } + + ob->viewx = centerx + ny*scale/nx; // DEBUG: use assembly divide + +// +// calculate height (heightnumerator/(nx>>8)) +// + asm mov ax,[WORD PTR heightnumerator] + asm mov dx,[WORD PTR heightnumerator+2] + asm idiv [WORD PTR nx+1] // nx>>8 + asm mov [WORD PTR temp],ax + asm mov [WORD PTR temp+2],dx + + ob->viewheight = temp; +} + +//========================================================================== + +/* +======================== += += TransformTile += += Takes paramaters: += tx,ty : tile the object is centered in += += globals: += viewx,viewy : point of view += viewcos,viewsin : sin/cos of viewangle += scale : conversion from global value to screen value += += sets: += screenx,transx,transy,screenheight: projected edge location and size += += Returns true if the tile is withing getting distance += +======================== +*/ + +boolean TransformTile (int tx, int ty, int *dispx, int *dispheight) +{ + int ratio; + fixed gx,gy,gxt,gyt,nx,ny; + long temp; + +// +// translate point to view centered coordinates +// + gx = ((long)tx<>8)) +// + asm mov ax,[WORD PTR heightnumerator] + asm mov dx,[WORD PTR heightnumerator+2] + asm idiv [WORD PTR nx+1] // nx>>8 + asm mov [WORD PTR temp],ax + asm mov [WORD PTR temp+2],dx + + *dispheight = temp; + +// +// see if it should be grabbed +// + if (nx-TILEGLOBAL/2 && ny>8)) + // + if (nx>8 +} + + +//========================================================================== + +/* +=================== += += ScalePost += +=================== +*/ + +long postsource; +unsigned postx; +unsigned postwidth; + +void near ScalePost (void) // VGA version +{ + asm mov ax,SCREENSEG + asm mov es,ax + + asm mov bx,[postx] + asm shl bx,1 + asm mov bp,WORD PTR [wallheight+bx] // fractional height (low 3 bits frac) + asm and bp,0xfff8 // bp = heightscaler*4 + asm shr bp,1 + asm cmp bp,[maxscaleshl2] + asm jle heightok + asm mov bp,[maxscaleshl2] +heightok: + asm add bp,OFFSET fullscalefarcall + // + // scale a byte wide strip of wall + // + asm mov bx,[postx] + asm mov di,bx + asm shr di,1 // X in bytes + asm shr di,1 + asm add di,[bufferofs] + + asm and bx,3 + /* begin 8086 hack + asm shl bx,3 + */ + asm push cx + asm mov cl,3 + asm shl bx,cl + asm pop cx + /* end 8086 hack */ + asm add bx,[postwidth] + + asm mov al,BYTE PTR [mapmasks1-1+bx] // -1 because no widths of 0 + asm mov dx,SC_INDEX+1 + asm out dx,al // set bit mask register + asm lds si,DWORD PTR [postsource] + asm call DWORD PTR [bp] // scale the line of pixels + + asm mov al,BYTE PTR [ss:mapmasks2-1+bx] // -1 because no widths of 0 + asm or al,al + asm jz nomore + + // + // draw a second byte for vertical strips that cross two bytes + // + asm inc di + asm out dx,al // set bit mask register + asm call DWORD PTR [bp] // scale the line of pixels + + asm mov al,BYTE PTR [ss:mapmasks3-1+bx] // -1 because no widths of 0 + asm or al,al + asm jz nomore + // + // draw a third byte for vertical strips that cross three bytes + // + asm inc di + asm out dx,al // set bit mask register + asm call DWORD PTR [bp] // scale the line of pixels + + +nomore: + asm mov ax,ss + asm mov ds,ax +} + +void FarScalePost (void) // just so other files can call +{ + ScalePost (); +} + + +/* +==================== += += HitVertWall += += tilehit bit 7 is 0, because it's not a door tile += if bit 6 is 1 and the adjacent tile is a door tile, use door side pic += +==================== +*/ + +void HitVertWall (void) +{ + int wallpic; + unsigned texture; + + texture = (yintercept>>4)&0xfc0; + if (xtilestep == -1) + { + texture = 0xfc0-texture; + xintercept += TILEGLOBAL; + } + wallheight[pixx] = CalcHeight(); + + if (lastside==1 && lastintercept == xtile && lasttilehit == tilehit) + { + // in the same wall type as last time, so check for optimized draw + if (texture == (unsigned)postsource) + { + // wide scale + postwidth++; + wallheight[pixx] = wallheight[pixx-1]; + return; + } + else + { + ScalePost (); + (unsigned)postsource = texture; + postwidth = 1; + postx = pixx; + } + } + else + { + // new wall + if (lastside != -1) // if not the first scaled post + ScalePost (); + + lastside = true; + lastintercept = xtile; + + lasttilehit = tilehit; + postx = pixx; + postwidth = 1; + + if (tilehit & 0x40) + { // check for adjacent doors + ytile = yintercept>>TILESHIFT; + if ( tilemap[xtile-xtilestep][ytile]&0x80 ) + wallpic = DOORWALL+3; + else + wallpic = vertwall[tilehit & ~0x40]; + } + else + wallpic = vertwall[tilehit]; + + *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(wallpic); + (unsigned)postsource = texture; + + } +} + + +/* +==================== += += HitHorizWall += += tilehit bit 7 is 0, because it's not a door tile += if bit 6 is 1 and the adjacent tile is a door tile, use door side pic += +==================== +*/ + +void HitHorizWall (void) +{ + int wallpic; + unsigned texture; + + texture = (xintercept>>4)&0xfc0; + if (ytilestep == -1) + yintercept += TILEGLOBAL; + else + texture = 0xfc0-texture; + wallheight[pixx] = CalcHeight(); + + if (lastside==0 && lastintercept == ytile && lasttilehit == tilehit) + { + // in the same wall type as last time, so check for optimized draw + if (texture == (unsigned)postsource) + { + // wide scale + postwidth++; + wallheight[pixx] = wallheight[pixx-1]; + return; + } + else + { + ScalePost (); + (unsigned)postsource = texture; + postwidth = 1; + postx = pixx; + } + } + else + { + // new wall + if (lastside != -1) // if not the first scaled post + ScalePost (); + + lastside = 0; + lastintercept = ytile; + + lasttilehit = tilehit; + postx = pixx; + postwidth = 1; + + if (tilehit & 0x40) + { // check for adjacent doors + xtile = xintercept>>TILESHIFT; + if ( tilemap[xtile][ytile-ytilestep]&0x80 ) + wallpic = DOORWALL+2; + else + wallpic = horizwall[tilehit & ~0x40]; + } + else + wallpic = horizwall[tilehit]; + + *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(wallpic); + (unsigned)postsource = texture; + } + +} + +//========================================================================== + +/* +==================== += += HitHorizDoor += +==================== +*/ + +void HitHorizDoor (void) +{ + unsigned texture,doorpage,doornum; + + doornum = tilehit&0x7f; + texture = ( (xintercept-doorposition[doornum]) >> 4) &0xfc0; + + wallheight[pixx] = CalcHeight(); + + if (lasttilehit == tilehit) + { + // in the same door as last time, so check for optimized draw + if (texture == (unsigned)postsource) + { + // wide scale + postwidth++; + wallheight[pixx] = wallheight[pixx-1]; + return; + } + else + { + ScalePost (); + (unsigned)postsource = texture; + postwidth = 1; + postx = pixx; + } + } + else + { + if (lastside != -1) // if not the first scaled post + ScalePost (); // draw last post + // first pixel in this door + lastside = 2; + lasttilehit = tilehit; + postx = pixx; + postwidth = 1; + + switch (doorobjlist[doornum].lock) + { + case dr_normal: + doorpage = DOORWALL; + break; + case dr_lock1: + case dr_lock2: + case dr_lock3: + case dr_lock4: + doorpage = DOORWALL+6; + break; + case dr_elevator: + doorpage = DOORWALL+4; + break; + } + + *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(doorpage); + (unsigned)postsource = texture; + } +} + +//========================================================================== + +/* +==================== += += HitVertDoor += +==================== +*/ + +void HitVertDoor (void) +{ + unsigned texture,doorpage,doornum; + + doornum = tilehit&0x7f; + texture = ( (yintercept-doorposition[doornum]) >> 4) &0xfc0; + + wallheight[pixx] = CalcHeight(); + + if (lasttilehit == tilehit) + { + // in the same door as last time, so check for optimized draw + if (texture == (unsigned)postsource) + { + // wide scale + postwidth++; + wallheight[pixx] = wallheight[pixx-1]; + return; + } + else + { + ScalePost (); + (unsigned)postsource = texture; + postwidth = 1; + postx = pixx; + } + } + else + { + if (lastside != -1) // if not the first scaled post + ScalePost (); // draw last post + // first pixel in this door + lastside = 2; + lasttilehit = tilehit; + postx = pixx; + postwidth = 1; + + switch (doorobjlist[doornum].lock) + { + case dr_normal: + doorpage = DOORWALL; + break; + case dr_lock1: + case dr_lock2: + case dr_lock3: + case dr_lock4: + doorpage = DOORWALL+6; + break; + case dr_elevator: + doorpage = DOORWALL+4; + break; + } + + *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(doorpage+1); + (unsigned)postsource = texture; + } +} + +//========================================================================== + + +/* +==================== += += HitHorizPWall += += A pushable wall in action has been hit += +==================== +*/ + +void HitHorizPWall (void) +{ + int wallpic; + unsigned texture,offset; + + texture = (xintercept>>4)&0xfc0; + offset = pwallpos<<10; + if (ytilestep == -1) + yintercept += TILEGLOBAL-offset; + else + { + texture = 0xfc0-texture; + yintercept += offset; + } + + wallheight[pixx] = CalcHeight(); + + if (lasttilehit == tilehit) + { + // in the same wall type as last time, so check for optimized draw + if (texture == (unsigned)postsource) + { + // wide scale + postwidth++; + wallheight[pixx] = wallheight[pixx-1]; + return; + } + else + { + ScalePost (); + (unsigned)postsource = texture; + postwidth = 1; + postx = pixx; + } + } + else + { + // new wall + if (lastside != -1) // if not the first scaled post + ScalePost (); + + lasttilehit = tilehit; + postx = pixx; + postwidth = 1; + + wallpic = horizwall[tilehit&63]; + + *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(wallpic); + (unsigned)postsource = texture; + } + +} + + +/* +==================== += += HitVertPWall += += A pushable wall in action has been hit += +==================== +*/ + +void HitVertPWall (void) +{ + int wallpic; + unsigned texture,offset; + + texture = (yintercept>>4)&0xfc0; + offset = pwallpos<<10; + if (xtilestep == -1) + { + xintercept += TILEGLOBAL-offset; + texture = 0xfc0-texture; + } + else + xintercept += offset; + + wallheight[pixx] = CalcHeight(); + + if (lasttilehit == tilehit) + { + // in the same wall type as last time, so check for optimized draw + if (texture == (unsigned)postsource) + { + // wide scale + postwidth++; + wallheight[pixx] = wallheight[pixx-1]; + return; + } + else + { + ScalePost (); + (unsigned)postsource = texture; + postwidth = 1; + postx = pixx; + } + } + else + { + // new wall + if (lastside != -1) // if not the first scaled post + ScalePost (); + + lasttilehit = tilehit; + postx = pixx; + postwidth = 1; + + wallpic = vertwall[tilehit&63]; + + *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(wallpic); + (unsigned)postsource = texture; + } + +} + +//========================================================================== + +//========================================================================== + +#if 0 +/* +===================== += += ClearScreen += +===================== +*/ + +void ClearScreen (void) +{ + unsigned floor=egaFloor[gamestate.episode*10+mapon], + ceiling=egaCeiling[gamestate.episode*10+mapon]; + + // + // clear the screen + // +asm mov dx,GC_INDEX +asm mov ax,GC_MODE + 256*2 // read mode 0, write mode 2 +asm out dx,ax +asm mov ax,GC_BITMASK + 255*256 +asm out dx,ax + +asm mov dx,40 +asm mov ax,[viewwidth] +asm shr ax,1 +asm shr ax,1 +asm shr ax,1 +asm sub dx,ax // dx = 40-viewwidth/8 + +asm mov bx,[viewwidth] +asm shr bx,1 // bl = viewwidth/16 +asm shr bx,1 +asm shr bx,1 +asm shr bx,1 +asm mov bh,BYTE PTR [viewheight] +asm shr bh,1 // half height + +asm mov ax,[ceiling] +asm mov es,[screenseg] +asm mov di,[bufferofs] + +toploop: +asm mov cl,bl +asm rep stosw +asm add di,dx +asm dec bh +asm jnz toploop + +asm mov bh,BYTE PTR [viewheight] +asm shr bh,1 // half height +asm mov ax,[floor] + +bottomloop: +asm mov cl,bl +asm rep stosw +asm add di,dx +asm dec bh +asm jnz bottomloop + + +asm mov dx,GC_INDEX +asm mov ax,GC_MODE + 256*10 // read mode 1, write mode 2 +asm out dx,ax +asm mov al,GC_BITMASK +asm out dx,al + +} +#endif +//========================================================================== + +unsigned vgaCeiling[]= +{ +#ifndef SPEAR + 0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0xbfbf, + 0x4e4e,0x4e4e,0x4e4e,0x1d1d,0x8d8d,0x4e4e,0x1d1d,0x2d2d,0x1d1d,0x8d8d, + 0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x2d2d,0xdddd,0x1d1d,0x1d1d,0x9898, + + 0x1d1d,0x9d9d,0x2d2d,0xdddd,0xdddd,0x9d9d,0x2d2d,0x4d4d,0x1d1d,0xdddd, + 0x7d7d,0x1d1d,0x2d2d,0x2d2d,0xdddd,0xd7d7,0x1d1d,0x1d1d,0x1d1d,0x2d2d, + 0x1d1d,0x1d1d,0x1d1d,0x1d1d,0xdddd,0xdddd,0x7d7d,0xdddd,0xdddd,0xdddd +#else + 0x6f6f,0x4f4f,0x1d1d,0xdede,0xdfdf,0x2e2e,0x7f7f,0x9e9e,0xaeae,0x7f7f, + 0x1d1d,0xdede,0xdfdf,0xdede,0xdfdf,0xdede,0xe1e1,0xdcdc,0x2e2e,0x1d1d,0xdcdc +#endif +}; + +/* +===================== += += VGAClearScreen += +===================== +*/ + +void VGAClearScreen (void) +{ + unsigned ceiling=vgaCeiling[gamestate.episode*10+mapon]; + + // + // clear the screen + // +asm mov dx,SC_INDEX +asm mov ax,SC_MAPMASK+15*256 // write through all planes +asm out dx,ax + +asm mov dx,80 +asm mov ax,[viewwidth] +asm shr ax,1 +asm shr ax,1 +asm sub dx,ax // dx = 40-viewwidth/2 + +asm mov bx,[viewwidth] +asm shr bx,1 // bl = viewwidth/8 +asm shr bx,1 +asm shr bx,1 +asm mov bh,BYTE PTR [viewheight] +asm shr bh,1 // half height + +asm mov es,[screenseg] +asm mov di,[bufferofs] +asm mov ax,[ceiling] + +toploop: +asm mov cl,bl +asm rep stosw +asm add di,dx +asm dec bh +asm jnz toploop + +asm mov bh,BYTE PTR [viewheight] +asm shr bh,1 // half height +asm mov ax,0x1919 + +bottomloop: +asm mov cl,bl +asm rep stosw +asm add di,dx +asm dec bh +asm jnz bottomloop +} + +//========================================================================== + +/* +===================== += += CalcRotate += +===================== +*/ + +int CalcRotate (objtype *ob) +{ + int angle,viewangle; + + // this isn't exactly correct, as it should vary by a trig value, + // but it is close enough with only eight rotations + + viewangle = player->angle + (centerx - ob->viewx)/8; + + if (ob->obclass == rocketobj || ob->obclass == hrocketobj) + angle = (viewangle-180)- ob->angle; + else + angle = (viewangle-180)- dirangle[ob->dir]; + + angle+=ANGLES/16; + while (angle>=ANGLES) + angle-=ANGLES; + while (angle<0) + angle+=ANGLES; + + if (ob->state->rotate == 2) // 2 rotation pain frame + return 4*(angle/(ANGLES/2)); // seperated by 3 (art layout...) + + return angle/(ANGLES/8); +} + + +/* +===================== += += DrawScaleds += += Draws all objects that are visable += +===================== +*/ + +#define MAXVISABLE 50 + +typedef struct +{ + int viewx, + viewheight, + shapenum; +} visobj_t; + +visobj_t vislist[MAXVISABLE],*visptr,*visstep,*farthest; + +void DrawScaleds (void) +{ + int i,j,least,numvisable,height; + memptr shape; + byte *tilespot,*visspot; + int shapenum; + unsigned spotloc; + + statobj_t *statptr; + objtype *obj; + + visptr = &vislist[0]; + +// +// place static objects +// + for (statptr = &statobjlist[0] ; statptr !=laststatobj ; statptr++) + { + if ((visptr->shapenum = statptr->shapenum) == -1) + continue; // object has been deleted + + if (!*statptr->visspot) + continue; // not visable + + if (TransformTile (statptr->tilex,statptr->tiley + ,&visptr->viewx,&visptr->viewheight) && statptr->flags & FL_BONUS) + { + GetBonus (statptr); + continue; + } + + if (!visptr->viewheight) + continue; // to close to the object + + if (visptr < &vislist[MAXVISABLE-1]) // don't let it overflow + visptr++; + } + +// +// place active objects +// + for (obj = player->next;obj;obj=obj->next) + { + if (!(visptr->shapenum = obj->state->shapenum)) + continue; // no shape + + spotloc = (obj->tilex<<6)+obj->tiley; // optimize: keep in struct? + visspot = &spotvis[0][0]+spotloc; + tilespot = &tilemap[0][0]+spotloc; + + // + // could be in any of the nine surrounding tiles + // + if (*visspot + || ( *(visspot-1) && !*(tilespot-1) ) + || ( *(visspot+1) && !*(tilespot+1) ) + || ( *(visspot-65) && !*(tilespot-65) ) + || ( *(visspot-64) && !*(tilespot-64) ) + || ( *(visspot-63) && !*(tilespot-63) ) + || ( *(visspot+65) && !*(tilespot+65) ) + || ( *(visspot+64) && !*(tilespot+64) ) + || ( *(visspot+63) && !*(tilespot+63) ) ) + { + obj->active = true; + TransformActor (obj); + if (!obj->viewheight) + continue; // too close or far away + + visptr->viewx = obj->viewx; + visptr->viewheight = obj->viewheight; + if (visptr->shapenum == -1) + visptr->shapenum = obj->temp1; // special shape + + if (obj->state->rotate) + visptr->shapenum += CalcRotate (obj); + + if (visptr < &vislist[MAXVISABLE-1]) // don't let it overflow + visptr++; + obj->flags |= FL_VISABLE; + } + else + obj->flags &= ~FL_VISABLE; + } + +// +// draw from back to front +// + numvisable = visptr-&vislist[0]; + + if (!numvisable) + return; // no visable objects + + for (i = 0; iviewheight; + if (height < least) + { + least = height; + farthest = visstep; + } + } + // + // draw farthest + // + ScaleShape(farthest->viewx,farthest->shapenum,farthest->viewheight); + + farthest->viewheight = 32000; + } + +} + +//========================================================================== + +/* +============== += += DrawPlayerWeapon += += Draw the player's hands += +============== +*/ + +int weaponscale[NUMWEAPONS] = {SPR_KNIFEREADY,SPR_PISTOLREADY + ,SPR_MACHINEGUNREADY,SPR_CHAINREADY}; + +void DrawPlayerWeapon (void) +{ + int shapenum; + +#ifndef SPEAR + if (gamestate.victoryflag) + { + if (player->state == &s_deathcam && (TimeCount&32) ) + SimpleScaleShape(viewwidth/2,SPR_DEATHCAM,viewheight+1); + return; + } +#endif + + if (gamestate.weapon != -1) + { + shapenum = weaponscale[gamestate.weapon]+gamestate.weaponframe; + SimpleScaleShape(viewwidth/2,shapenum,viewheight+1); + } + + if (demorecord || demoplayback) + SimpleScaleShape(viewwidth/2,SPR_DEMO,viewheight+1); +} + + +//========================================================================== + + +/* +===================== += += CalcTics += +===================== +*/ + +void CalcTics (void) +{ + long newtime,oldtimecount; + +// +// calculate tics since last refresh for adaptive timing +// + if (lasttimecount > TimeCount) + TimeCount = lasttimecount; // if the game was paused a LONG time + + do + { + newtime = TimeCount; + tics = newtime-lasttimecount; + } while (!tics); // make sure at least one tic passes + + lasttimecount = newtime; + +#ifdef FILEPROFILE + strcpy (scratch,"\tTics:"); + itoa (tics,str,10); + strcat (scratch,str); + strcat (scratch,"\n"); + write (profilehandle,scratch,strlen(scratch)); +#endif + + if (tics>MAXTICS) + { + TimeCount -= (tics-MAXTICS); + tics = MAXTICS; + } +} + + +//========================================================================== + + +/* +======================== += += FixOfs += +======================== +*/ + +void FixOfs (void) +{ + VW_ScreenToScreen (displayofs,bufferofs,viewwidth/8,viewheight); +} + + +//========================================================================== + + +/* +==================== += += WallRefresh += +==================== +*/ + +void WallRefresh (void) +{ +// +// set up variables for this view +// + viewangle = player->angle; + midangle = viewangle*(FINEANGLES/ANGLES); + viewsin = sintable[viewangle]; + viewcos = costable[viewangle]; + viewx = player->x - FixedByFrac(focallength,viewcos); + viewy = player->y + FixedByFrac(focallength,viewsin); + + focaltx = viewx>>TILESHIFT; + focalty = viewy>>TILESHIFT; + + viewtx = player->x >> TILESHIFT; + viewty = player->y >> TILESHIFT; + + xpartialdown = viewx&(TILEGLOBAL-1); + xpartialup = TILEGLOBAL-xpartialdown; + ypartialdown = viewy&(TILEGLOBAL-1); + ypartialup = TILEGLOBAL-ypartialdown; + + lastside = -1; // the first pixel is on a new wall + AsmRefresh (); + ScalePost (); // no more optimization on last post +} + +//========================================================================== + +/* +======================== += += ThreeDRefresh += +======================== +*/ + +void ThreeDRefresh (void) +{ + int tracedir; + +// this wouldn't need to be done except for my debugger/video wierdness + outportb (SC_INDEX,SC_MAPMASK); + +// +// clear out the traced array +// +asm mov ax,ds +asm mov es,ax +asm mov di,OFFSET spotvis +asm xor ax,ax +asm mov cx,2048 // 64*64 / 2 +asm rep stosw + + bufferofs += screenofs; + +// +// follow the walls from there to the right, drawwing as we go +// + VGAClearScreen (); + + WallRefresh (); + +// +// draw all the scaled images +// + DrawScaleds(); // draw scaled stuff + DrawPlayerWeapon (); // draw player's hands + +// +// show screen and time last cycle +// + if (fizzlein) + { + FizzleFade(bufferofs,displayofs+screenofs,viewwidth,viewheight,20,false); + fizzlein = false; + + lasttimecount = TimeCount = 0; // don't make a big tic count + + } + + bufferofs -= screenofs; + displayofs = bufferofs; + + asm cli + asm mov cx,[displayofs] + asm mov dx,3d4h // CRTC address register + asm mov al,0ch // start address high register + asm out dx,al + asm inc dx + asm mov al,ch + asm out dx,al // set the high byte + asm sti + + bufferofs += SCREENSIZE; + if (bufferofs > PAGE3START) + bufferofs = PAGE1START; + + frameon++; + PM_NextFrame(); +} + + +//=========================================================================== + diff --git a/16/sod8086/wl_game.c b/16/sod8086/wl_game.c new file mode 100755 index 00000000..9f63d9fe --- /dev/null +++ b/16/sod8086/wl_game.c @@ -0,0 +1,1484 @@ +// WL_GAME.C + +#include "WL_DEF.H" +#pragma hdrstop + +#ifdef MYPROFILE +#include +#endif + + +/* +============================================================================= + + LOCAL CONSTANTS + +============================================================================= +*/ + + +/* +============================================================================= + + GLOBAL VARIABLES + +============================================================================= +*/ + +boolean ingame,fizzlein; +unsigned latchpics[NUMLATCHPICS]; +gametype gamestate; + +long spearx,speary; +unsigned spearangle; +boolean spearflag; + +// +// ELEVATOR BACK MAPS - REMEMBER (-1)!! +// +int ElevatorBackTo[]={1,1,7,3,5,3}; + +void ScanInfoPlane (void); +void SetupGameLevel (void); +void DrawPlayScreen (void); +void LoadLatchMem (void); +void GameLoop (void); + +/* +============================================================================= + + LOCAL VARIABLES + +============================================================================= +*/ + + + +//=========================================================================== +//=========================================================================== + + +/* +========================== += += SetSoundLoc - Given the location of an object (in terms of global += coordinates, held in globalsoundx and globalsoundy), munges the values += for an approximate distance from the left and right ear, and puts += those values into leftchannel and rightchannel. += += JAB += +========================== +*/ + + fixed globalsoundx,globalsoundy; + int leftchannel,rightchannel; +#define ATABLEMAX 15 +byte righttable[ATABLEMAX][ATABLEMAX * 2] = { +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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} +}; +byte lefttable[ATABLEMAX][ATABLEMAX * 2] = { +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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}, +{ 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} +}; + +void +SetSoundLoc(fixed gx,fixed gy) +{ + fixed xt,yt; + int x,y; + +// +// translate point to view centered coordinates +// + gx -= viewx; + gy -= viewy; + +// +// calculate newx +// + xt = FixedByFrac(gx,viewcos); + yt = FixedByFrac(gy,viewsin); + x = (xt - yt) >> TILESHIFT; + +// +// calculate newy +// + xt = FixedByFrac(gx,viewsin); + yt = FixedByFrac(gy,viewcos); + y = (yt + xt) >> TILESHIFT; + + if (y >= ATABLEMAX) + y = ATABLEMAX - 1; + else if (y <= -ATABLEMAX) + y = -ATABLEMAX; + if (x < 0) + x = -x; + if (x >= ATABLEMAX) + x = ATABLEMAX - 1; + leftchannel = lefttable[x][y + ATABLEMAX]; + rightchannel = righttable[x][y + ATABLEMAX]; + +#if 0 + CenterWindow(8,1); + US_PrintSigned(leftchannel); + US_Print(","); + US_PrintSigned(rightchannel); + VW_UpdateScreen(); +#endif +} + +/* +========================== += += SetSoundLocGlobal - Sets up globalsoundx & globalsoundy and then calls += UpdateSoundLoc() to transform that into relative channel volumes. Those += values are then passed to the Sound Manager so that they'll be used for += the next sound played (if possible). += += JAB += +========================== +*/ +void PlaySoundLocGlobal(word s,fixed gx,fixed gy) +{ + SetSoundLoc(gx,gy); + SD_PositionSound(leftchannel,rightchannel); + if (SD_PlaySound(s)) + { + globalsoundx = gx; + globalsoundy = gy; + } +} + +void UpdateSoundLoc(void) +{ + if (SoundPositioned) + { + SetSoundLoc(globalsoundx,globalsoundy); + SD_SetPosition(leftchannel,rightchannel); + } +} + +/* +** JAB End +*/ + + +/* +========================== += += ClearMemory += +========================== +*/ + +void ClearMemory (void) +{ + PM_UnlockMainMem(); + SD_StopDigitized(); + MM_SortMem (); +} + + +/* +========================== += += ScanInfoPlane += += Spawn all actors and mark down special places += +========================== +*/ + +void ScanInfoPlane (void) +{ + unsigned x,y,i,j; + int tile; + unsigned far *start; + + start = mapsegs[1]; + for (y=0;ywidth; + mapheight = mapheaderseg[mapon]->height; + + if (mapwidth != 64 || mapheight != 64) + Quit ("Map not 64*64!"); + + +// +// copy the wall data to a data segment array +// + memset (tilemap,0,sizeof(tilemap)); + memset (actorat,0,sizeof(actorat)); + map = mapsegs[0]; + for (y=0;y= 90 && tile <= 101) + { + // door + switch (tile) + { + case 90: + case 92: + case 94: + case 96: + case 98: + case 100: + SpawnDoor (x,y,1,(tile-90)/2); + break; + case 91: + case 93: + case 95: + case 97: + case 99: + case 101: + SpawnDoor (x,y,0,(tile-91)/2); + break; + } + } + } + +// +// spawn actors +// + ScanInfoPlane (); + +// +// take out the ambush markers +// + map = mapsegs[0]; + for (y=0;y= AREATILE) + tile = *map; + if (*(map-1-mapwidth) >= AREATILE) + tile = *(map-1-mapwidth); + if (*(map-1+mapwidth) >= AREATILE) + tile = *(map-1+mapwidth); + if ( *(map-2) >= AREATILE) + tile = *(map-2); + + *(map-1) = tile; + } + } + + + +// +// have the caching manager load and purge stuff to make sure all marks +// are in memory +// + CA_LoadAllSounds (); + +} + + +//========================================================================== + + +/* +=================== += += DrawPlayBorderSides += += To fix window overwrites += +=================== +*/ + +void DrawPlayBorderSides (void) +{ + int xl,yl; + + xl = 160-viewwidth/2; + yl = (200-STATUSLINES-viewheight)/2; + + VWB_Bar (0,0,xl-1,200-STATUSLINES,127); + VWB_Bar (xl+viewwidth+1,0,xl-2,200-STATUSLINES,127); + + VWB_Vlin (yl-1,yl+viewheight,xl-1,0); + VWB_Vlin (yl-1,yl+viewheight,xl+viewwidth,125); +} + + +/* +=================== += += DrawAllPlayBorderSides += +=================== +*/ + +void DrawAllPlayBorderSides (void) +{ + unsigned i,temp; + + temp = bufferofs; + for (i=0;i<3;i++) + { + bufferofs = screenloc[i]; + DrawPlayBorderSides (); + } + bufferofs = temp; +} + +/* +=================== += += DrawPlayBorder += +=================== +*/ +void DrawAllPlayBorder (void) +{ + unsigned i,temp; + + temp = bufferofs; + for (i=0;i<3;i++) + { + bufferofs = screenloc[i]; + DrawPlayBorder (); + } + bufferofs = temp; +} + +/* +=================== += += DrawPlayBorder += +=================== +*/ + +void DrawPlayBorder (void) +{ + int xl,yl; + + VWB_Bar (0,0,320,200-STATUSLINES,127); + + xl = 160-viewwidth/2; + yl = (200-STATUSLINES-viewheight)/2; + VWB_Bar (xl,yl,viewwidth,viewheight,0); + + VWB_Hlin (xl-1,xl+viewwidth,yl-1,0); + VWB_Hlin (xl-1,xl+viewwidth,yl+viewheight,125); + VWB_Vlin (yl-1,yl+viewheight,xl-1,0); + VWB_Vlin (yl-1,yl+viewheight,xl+viewwidth,125); + VWB_Plot (xl-1,yl+viewheight,124); +} + + + +/* +=================== += += DrawPlayScreen += +=================== +*/ + +void DrawPlayScreen (void) +{ + int i,j,p,m; + unsigned temp; + + VW_FadeOut (); + + temp = bufferofs; + + CA_CacheGrChunk (STATUSBARPIC); + + for (i=0;i<3;i++) + { + bufferofs = screenloc[i]; + DrawPlayBorder (); + VWB_DrawPic (0,200-STATUSLINES,STATUSBARPIC); + } + + bufferofs = temp; + + UNCACHEGRCHUNK (STATUSBARPIC); + + DrawFace (); + DrawHealth (); + DrawLives (); + DrawLevel (); + DrawAmmo (); + DrawKeys (); + DrawWeapon (); + DrawScore (); +} + + + +//========================================================================== + +/* +================== += += StartDemoRecord += +================== +*/ + +#define MAXDEMOSIZE 8192 + +void StartDemoRecord (int levelnumber) +{ + MM_GetPtr (&demobuffer,MAXDEMOSIZE); + MM_SetLock (&demobuffer,true); + demoptr = (char far *)demobuffer; + lastdemoptr = demoptr+MAXDEMOSIZE; + + *demoptr = levelnumber; + demoptr += 4; // leave space for length + demorecord = true; +} + + +/* +================== += += FinishDemoRecord += +================== +*/ + +char demoname[13] = "DEMO?."; + +void FinishDemoRecord (void) +{ + long length,level; + + demorecord = false; + + length = demoptr - (char far *)demobuffer; + + demoptr = ((char far *)demobuffer)+1; + *(unsigned far *)demoptr = length; + + CenterWindow(24,3); + PrintY+=6; + US_Print(" Demo number (0-9):"); + VW_UpdateScreen(); + + if (US_LineInput (px,py,str,NULL,true,2,0)) + { + level = atoi (str); + if (level>=0 && level<=9) + { + demoname[4] = '0'+level; + CA_WriteFile (demoname,(void far *)demobuffer,length); + } + } + + + MM_FreePtr (&demobuffer); +} + +//========================================================================== + +/* +================== += += RecordDemo += += Fades the screen out, then starts a demo. Exits with the screen faded += +================== +*/ + +void RecordDemo (void) +{ + int level,esc; + + CenterWindow(26,3); + PrintY+=6; + CA_CacheGrChunk(STARTFONT); + fontnumber=0; + US_Print(" Demo which level(1-10):"); + VW_UpdateScreen(); + VW_FadeIn (); + esc = !US_LineInput (px,py,str,NULL,true,2,0); + if (esc) + return; + + level = atoi (str); + level--; + + SETFONTCOLOR(0,15); + VW_FadeOut (); + +#ifndef SPEAR + NewGame (gd_hard,level/10); + gamestate.mapon = level%10; +#else + NewGame (gd_hard,0); + gamestate.mapon = level; +#endif + + StartDemoRecord (level); + + DrawPlayScreen (); + VW_FadeIn (); + + startgame = false; + demorecord = true; + + SetupGameLevel (); + StartMusic (); + PM_CheckMainMem (); + fizzlein = true; + + PlayLoop (); + + demoplayback = false; + + StopMusic (); + VW_FadeOut (); + ClearMemory (); + + FinishDemoRecord (); +} + +//========================================================================== + +/* +================== += += PlayDemo += += Fades the screen out, then starts a demo. Exits with the screen faded += +================== +*/ + +void PlayDemo (int demonumber) +{ + int length; + +#ifdef DEMOSEXTERN +// debug: load chunk +#ifndef SPEARDEMO + int dems[4]={T_DEMO0,T_DEMO1,T_DEMO2,T_DEMO3}; +#else + int dems[1]={T_DEMO0}; +#endif + + CA_CacheGrChunk(dems[demonumber]); + demoptr = grsegs[dems[demonumber]]; + MM_SetLock (&grsegs[dems[demonumber]],true); +#else + demoname[4] = '0'+demonumber; + CA_LoadFile (demoname,&demobuffer); + MM_SetLock (&demobuffer,true); + demoptr = (char far *)demobuffer; +#endif + + NewGame (1,0); + gamestate.mapon = *demoptr++; + gamestate.difficulty = gd_hard; + length = *((unsigned far *)demoptr)++; + demoptr++; + lastdemoptr = demoptr-4+length; + + VW_FadeOut (); + + SETFONTCOLOR(0,15); + DrawPlayScreen (); + VW_FadeIn (); + + startgame = false; + demoplayback = true; + + SetupGameLevel (); + StartMusic (); + PM_CheckMainMem (); + fizzlein = true; + + PlayLoop (); + +#ifdef DEMOSEXTERN + UNCACHEGRCHUNK(dems[demonumber]); +#else + MM_FreePtr (&demobuffer); +#endif + + demoplayback = false; + + StopMusic (); + VW_FadeOut (); + ClearMemory (); +} + +//========================================================================== + +/* +================== += += Died += +================== +*/ + +#define DEATHROTATE 2 + +void Died (void) +{ + float fangle; + long dx,dy; + int iangle,curangle,clockwise,counter,change; + + gamestate.weapon = -1; // take away weapon + SD_PlaySound (PLAYERDEATHSND); +// +// swing around to face attacker +// + dx = killerobj->x - player->x; + dy = player->y - killerobj->y; + + fangle = atan2(dy,dx); // returns -pi to pi + if (fangle<0) + fangle = M_PI*2+fangle; + + iangle = fangle/(M_PI*2)*ANGLES; + + if (player->angle > iangle) + { + counter = player->angle - iangle; + clockwise = ANGLES-player->angle + iangle; + } + else + { + clockwise = iangle - player->angle; + counter = player->angle + ANGLES-iangle; + } + + curangle = player->angle; + + if (clockwiseiangle) + curangle -= ANGLES; + do + { + change = tics*DEATHROTATE; + if (curangle + change > iangle) + change = iangle-curangle; + + curangle += change; + player->angle += change; + if (player->angle >= ANGLES) + player->angle -= ANGLES; + + ThreeDRefresh (); + CalcTics (); + } while (curangle != iangle); + } + else + { + // + // rotate counterclockwise + // + if (curangleangle += change; + if (player->angle < 0) + player->angle += ANGLES; + + ThreeDRefresh (); + CalcTics (); + } while (curangle != iangle); + } + +// +// fade to red +// + FinishPaletteShifts (); + + bufferofs += screenofs; + VW_Bar (0,0,viewwidth,viewheight,4); + IN_ClearKeysDown (); + FizzleFade(bufferofs,displayofs+screenofs,viewwidth,viewheight,70,false); + bufferofs -= screenofs; + IN_UserInput(100); + SD_WaitSoundDone (); + + if (tedlevel == false) // SO'S YA DON'T GET KILLED WHILE LAUNCHING! + gamestate.lives--; + + if (gamestate.lives > -1) + { + gamestate.health = 100; + gamestate.weapon = gamestate.bestweapon + = gamestate.chosenweapon = wp_pistol; + gamestate.ammo = STARTAMMO; + gamestate.keys = 0; + gamestate.attackframe = gamestate.attackcount = + gamestate.weaponframe = 0; + + DrawKeys (); + DrawWeapon (); + DrawAmmo (); + DrawHealth (); + DrawFace (); + DrawLives (); + } + +} + +//========================================================================== + +/* +=================== += += GameLoop += +=================== +*/ + +void GameLoop (void) +{ + int i,xl,yl,xh,yh; + char num[20]; + boolean died; +#ifdef MYPROFILE + clock_t start,end; +#endif + +restartgame: + ClearMemory (); + SETFONTCOLOR(0,15); + DrawPlayScreen (); + died = false; +restart: + do + { + if (!loadedgame) + gamestate.score = gamestate.oldscore; + DrawScore(); + + startgame = false; + if (loadedgame) + loadedgame = false; + else + SetupGameLevel (); + +#ifdef SPEAR + if (gamestate.mapon == 20) // give them the key allways + { + gamestate.keys |= 1; + DrawKeys (); + } +#endif + + ingame = true; + StartMusic (); + PM_CheckMainMem (); + if (!died) + PreloadGraphics (); + else + died = false; + + fizzlein = true; + DrawLevel (); + +startplayloop: + PlayLoop (); + +#ifdef SPEAR + if (spearflag) + { + SD_StopSound(); + SD_PlaySound(GETSPEARSND); + if (DigiMode != sds_Off) + { + long lasttimecount = TimeCount; + + while(TimeCount < lasttimecount+150) + //while(DigiPlaying!=false) + SD_Poll(); + } + else + SD_WaitSoundDone(); + + ClearMemory (); + gamestate.oldscore = gamestate.score; + gamestate.mapon = 20; + SetupGameLevel (); + StartMusic (); + PM_CheckMainMem (); + player->x = spearx; + player->y = speary; + player->angle = spearangle; + spearflag = false; + Thrust (0,0); + goto startplayloop; + } +#endif + + StopMusic (); + ingame = false; + + if (demorecord && playstate != ex_warped) + FinishDemoRecord (); + + if (startgame || loadedgame) + goto restartgame; + + switch (playstate) + { + case ex_completed: + case ex_secretlevel: + gamestate.keys = 0; + DrawKeys (); + VW_FadeOut (); + + ClearMemory (); + + LevelCompleted (); // do the intermission +#ifdef SPEARDEMO + if (gamestate.mapon == 1) + { + died = true; // don't "get psyched!" + + VW_FadeOut (); + + ClearMemory (); + + CheckHighScore (gamestate.score,gamestate.mapon+1); + + #pragma warn -sus + #ifndef JAPAN + _fstrcpy(MainMenu[viewscores].string,STR_VS); + #endif + MainMenu[viewscores].routine = CP_ViewScores; + #pragma warn +sus + + return; + } +#endif + +#ifdef JAPDEMO + if (gamestate.mapon == 3) + { + died = true; // don't "get psyched!" + + VW_FadeOut (); + + ClearMemory (); + + CheckHighScore (gamestate.score,gamestate.mapon+1); + + #pragma warn -sus + #ifndef JAPAN + _fstrcpy(MainMenu[viewscores].string,STR_VS); + #endif + MainMenu[viewscores].routine = CP_ViewScores; + #pragma warn +sus + + return; + } +#endif + + gamestate.oldscore = gamestate.score; + +#ifndef SPEAR + // + // COMING BACK FROM SECRET LEVEL + // + if (gamestate.mapon == 9) + gamestate.mapon = ElevatorBackTo[gamestate.episode]; // back from secret + else + // + // GOING TO SECRET LEVEL + // + if (playstate == ex_secretlevel) + gamestate.mapon = 9; +#else + +#define FROMSECRET1 3 +#define FROMSECRET2 11 + + // + // GOING TO SECRET LEVEL + // + if (playstate == ex_secretlevel) + switch(gamestate.mapon) + { + case FROMSECRET1: gamestate.mapon = 18; break; + case FROMSECRET2: gamestate.mapon = 19; break; + } + else + // + // COMING BACK FROM SECRET LEVEL + // + if (gamestate.mapon == 18 || gamestate.mapon == 19) + switch(gamestate.mapon) + { + case 18: gamestate.mapon = FROMSECRET1+1; break; + case 19: gamestate.mapon = FROMSECRET2+1; break; + } +#endif + else + // + // GOING TO NEXT LEVEL + // + gamestate.mapon++; + + + break; + + case ex_died: + Died (); + died = true; // don't "get psyched!" + + if (gamestate.lives > -1) + break; // more lives left + + VW_FadeOut (); + + ClearMemory (); + + CheckHighScore (gamestate.score,gamestate.mapon+1); + + #pragma warn -sus + #ifndef JAPAN + _fstrcpy(MainMenu[viewscores].string,STR_VS); + #endif + MainMenu[viewscores].routine = CP_ViewScores; + #pragma warn +sus + + return; + + case ex_victorious: + +#ifndef SPEAR + VW_FadeOut (); +#else + VL_FadeOut (0,255,0,17,17,300); +#endif + ClearMemory (); + + Victory (); + + ClearMemory (); + + CheckHighScore (gamestate.score,gamestate.mapon+1); + + #pragma warn -sus + #ifndef JAPAN + _fstrcpy(MainMenu[viewscores].string,STR_VS); + #endif + MainMenu[viewscores].routine = CP_ViewScores; + #pragma warn +sus + + return; + + default: + ClearMemory (); + break; + } + + } while (1); + +} + diff --git a/16/sod8086/wl_inter.c b/16/sod8086/wl_inter.c new file mode 100755 index 00000000..93e363cc --- /dev/null +++ b/16/sod8086/wl_inter.c @@ -0,0 +1,1720 @@ +// WL_INTER.C + +#include "WL_DEF.H" +#pragma hdrstop + + +//========================================================================== + +/* +================== += += CLearSplitVWB += +================== +*/ + +void ClearSplitVWB (void) +{ + memset (update,0,sizeof(update)); + WindowX = 0; + WindowY = 0; + WindowW = 320; + WindowH = 160; +} + + +//========================================================================== + +#ifdef SPEAR +#ifndef SPEARDEMO +//////////////////////////////////////////////////////// +// +// End of Spear of Destiny +// +//////////////////////////////////////////////////////// + +void EndScreen (int palette, int screen) +{ + CA_CacheScreen (screen); + VW_UpdateScreen (); + CA_CacheGrChunk (palette); + VL_FadeIn(0,255,grsegs[palette],30); + UNCACHEGRCHUNK (palette); + IN_ClearKeysDown (); + IN_Ack (); + VW_FadeOut (); +} + + +void EndSpear(void) +{ + EndScreen (END1PALETTE, ENDSCREEN11PIC); + + CA_CacheScreen (ENDSCREEN3PIC); + VW_UpdateScreen (); + CA_CacheGrChunk (END3PALETTE); + VL_FadeIn(0,255,grsegs[END3PALETTE],30); + UNCACHEGRCHUNK (END3PALETTE); + fontnumber = 0; + fontcolor = 0xd0; + WindowX = 0; + WindowW = 320; + PrintX = 0; + PrintY = 180; + US_CPrint (STR_ENDGAME1"\n"); + US_CPrint (STR_ENDGAME2); + VW_UpdateScreen (); + IN_StartAck (); + TimeCount = 0; + while (!IN_CheckAck () && TimeCount < 700); + + PrintX = 0; + PrintY = 180; + VWB_Bar(0,180,320,20,0); + US_CPrint (STR_ENDGAME3"\n"); + US_CPrint (STR_ENDGAME4); + VW_UpdateScreen (); + IN_StartAck (); + TimeCount = 0; + while (!IN_CheckAck () && TimeCount < 700); + + VW_FadeOut (); + + EndScreen (END4PALETTE, ENDSCREEN4PIC); + EndScreen (END5PALETTE, ENDSCREEN5PIC); + EndScreen (END6PALETTE, ENDSCREEN6PIC); + EndScreen (END7PALETTE, ENDSCREEN7PIC); + EndScreen (END8PALETTE, ENDSCREEN8PIC); + EndScreen (END9PALETTE, ENDSCREEN9PIC); + + EndScreen (END2PALETTE, ENDSCREEN12PIC); + + MainMenu[savegame].active = 0; +} +#endif +#endif + +//========================================================================== + +/* +================== += += Victory += +================== +*/ + +void Victory (void) +{ +#ifndef SPEARDEMO + long sec; + int i,min,kr,sr,tr,x; + char tempstr[8]; + +#define RATIOX 6 +#define RATIOY 14 +#define TIMEX 14 +#define TIMEY 8 + + +#ifdef SPEAR + StartCPMusic (XTHEEND_MUS); + + CA_CacheGrChunk(BJCOLLAPSE1PIC); + CA_CacheGrChunk(BJCOLLAPSE2PIC); + CA_CacheGrChunk(BJCOLLAPSE3PIC); + CA_CacheGrChunk(BJCOLLAPSE4PIC); + + VWB_Bar(0,0,320,200,VIEWCOLOR); + VWB_DrawPic (124,44,BJCOLLAPSE1PIC); + VW_UpdateScreen (); + VW_FadeIn (); + VW_WaitVBL(2*70); + VWB_DrawPic (124,44,BJCOLLAPSE2PIC); + VW_UpdateScreen (); + VW_WaitVBL(105); + VWB_DrawPic (124,44,BJCOLLAPSE3PIC); + VW_UpdateScreen (); + VW_WaitVBL(105); + VWB_DrawPic (124,44,BJCOLLAPSE4PIC); + VW_UpdateScreen (); + VW_WaitVBL(3*70); + + UNCACHEGRCHUNK(BJCOLLAPSE1PIC); + UNCACHEGRCHUNK(BJCOLLAPSE2PIC); + UNCACHEGRCHUNK(BJCOLLAPSE3PIC); + UNCACHEGRCHUNK(BJCOLLAPSE4PIC); + VL_FadeOut (0,255,0,17,17,5); +#endif + + StartCPMusic (URAHERO_MUS); + ClearSplitVWB (); + CacheLump(LEVELEND_LUMP_START,LEVELEND_LUMP_END); + CA_CacheGrChunk(STARTFONT); + +#ifndef SPEAR + CA_CacheGrChunk(C_TIMECODEPIC); +#endif + + + VWB_Bar (0,0,320,200-STATUSLINES,127); +#ifdef JAPAN +#ifndef JAPDEMO + CA_CacheGrChunk(C_ENDRATIOSPIC); + VWB_DrawPic(0,0,C_ENDRATIOSPIC); + UNCACHEGRCHUNK(C_ENDRATIOSPIC); +#endif +#else + Write(18,2,STR_YOUWIN); + + Write(TIMEX,TIMEY-2,STR_TOTALTIME); + + Write(12,RATIOY-2,"averages"); + + #ifdef SPANISH + Write(RATIOX+2, RATIOY, STR_RATKILL); + Write(RATIOX+2, RATIOY+2, STR_RATSECRET); + Write(RATIOX+2, RATIOY+4,STR_RATTREASURE); + #else + Write(RATIOX+8,RATIOY, STR_RATKILL); + Write(RATIOX+4,RATIOY+2, STR_RATSECRET); + Write(RATIOX, RATIOY+4,STR_RATTREASURE); + #endif + +#endif + +#ifndef JAPDEMO + VWB_DrawPic (8,4,L_BJWINSPIC); +#endif + + +#ifndef SPEAR + for (kr = sr = tr = sec = i = 0;i < 8;i++) +#else + for (kr = sr = tr = sec = i = 0;i < 20;i++) +#endif + { + sec += LevelRatios[i].time; + kr += LevelRatios[i].kill; + sr += LevelRatios[i].secret; + tr += LevelRatios[i].treasure; + } + +#ifndef SPEAR + kr /= 8; + sr /= 8; + tr /= 8; +#else + kr /= 14; + sr /= 14; + tr /= 14; +#endif + + min = sec/60; + sec %= 60; + + if (min > 99) + min = sec = 99; + + i = TIMEX*8+1; + VWB_DrawPic(i,TIMEY*8,L_NUM0PIC+(min/10)); + i += 2*8; + VWB_DrawPic(i,TIMEY*8,L_NUM0PIC+(min%10)); + i += 2*8; + Write(i/8,TIMEY,":"); + i += 1*8; + VWB_DrawPic(i,TIMEY*8,L_NUM0PIC+(sec/10)); + i += 2*8; + VWB_DrawPic(i,TIMEY*8,L_NUM0PIC+(sec%10)); + VW_UpdateScreen (); + + itoa(kr,tempstr,10); + x=RATIOX+24-strlen(tempstr)*2; + Write(x,RATIOY,tempstr); + + itoa(sr,tempstr,10); + x=RATIOX+24-strlen(tempstr)*2; + Write(x,RATIOY+2,tempstr); + + itoa(tr,tempstr,10); + x=RATIOX+24-strlen(tempstr)*2; + Write(x,RATIOY+4,tempstr); + + +#ifndef SPANISH +#ifndef UPLOAD +#ifndef SPEAR + // + // TOTAL TIME VERIFICATION CODE + // + if (gamestate.difficulty>=gd_medium) + { + VWB_DrawPic (30*8,TIMEY*8,C_TIMECODEPIC); + fontnumber = 0; + fontcolor = READHCOLOR; + PrintX = 30*8-3; + PrintY = TIMEY*8+8; + PrintX+=4; + tempstr[0] = (((min/10)^(min%10))^0xa)+'A'; + tempstr[1] = (((sec/10)^(sec%10))^0xa)+'A'; + tempstr[2] = (tempstr[0]^tempstr[1])+'A'; + tempstr[3] = 0; + US_Print(tempstr); + } +#endif +#endif +#endif + + + fontnumber = 1; + + VW_UpdateScreen (); + VW_FadeIn (); + + IN_Ack(); + + #ifndef SPEAR + if (Keyboard[sc_P] && MS_CheckParm("goobers")) + PicturePause(); + #endif + + VW_FadeOut (); + +#ifndef SPEAR + UNCACHEGRCHUNK(C_TIMECODEPIC); +#endif + UnCacheLump(LEVELEND_LUMP_START,LEVELEND_LUMP_END); + +#ifndef SPEAR + EndText(); +#else + EndSpear(); +#endif + +#endif // SPEARDEMO +} + + +//========================================================================== + +#ifndef JAPAN +/* +================== += += PG13 += +================== +*/ + +void PG13 (void) +{ + VW_FadeOut(); + VWB_Bar(0,0,320,200,0x82); // background + + CA_CacheGrChunk (PG13PIC); + VWB_DrawPic (216,110,PG13PIC); + VW_UpdateScreen (); + + UNCACHEGRCHUNK (PG13PIC); + + VW_FadeIn(); + IN_UserInput(TickBase*7); + + VW_FadeOut (); +} +#endif + + +//========================================================================== + +void Write(int x,int y,char *string) +{ + int alpha[]={L_NUM0PIC,L_NUM1PIC,L_NUM2PIC,L_NUM3PIC,L_NUM4PIC,L_NUM5PIC, + L_NUM6PIC,L_NUM7PIC,L_NUM8PIC,L_NUM9PIC,L_COLONPIC,0,0,0,0,0,0,L_APIC,L_BPIC, + L_CPIC,L_DPIC,L_EPIC,L_FPIC,L_GPIC,L_HPIC,L_IPIC,L_JPIC,L_KPIC, + L_LPIC,L_MPIC,L_NPIC,L_OPIC,L_PPIC,L_QPIC,L_RPIC,L_SPIC,L_TPIC, + L_UPIC,L_VPIC,L_WPIC,L_XPIC,L_YPIC,L_ZPIC}; + + int i,ox,nx,ny; + char ch; + + + ox=nx=x*8; + ny=y*8; + for (i=0;i='a') + ch-=('a'-'A'); + ch-='0'; + + switch(string[i]) + { + case '!': + VWB_DrawPic(nx,ny,L_EXPOINTPIC); + nx+=8; + continue; + + case '\'': + VWB_DrawPic(nx,ny,L_APOSTROPHEPIC); + nx+=8; + continue; + + case ' ': break; + case 0x3a: // ':' + + VWB_DrawPic(nx,ny,L_COLONPIC); + nx+=8; + continue; + + case '%': + VWB_DrawPic(nx,ny,L_PERCENTPIC); + break; + + default: + VWB_DrawPic(nx,ny,alpha[ch]); + } + nx+=16; + } +} + + +// +// Breathe Mr. BJ!!! +// +void BJ_Breathe(void) +{ + static int which=0,max=10; + int pics[2]={L_GUYPIC,L_GUY2PIC}; + + + if (TimeCount>max) + { + which^=1; + VWB_DrawPic(0,16,pics[which]); + VW_UpdateScreen(); + TimeCount=0; + max=35; + } +} + + + +/* +================== += += LevelCompleted += += Entered with the screen faded out += Still in split screen mode with the status bar += += Exit with the screen faded out += +================== +*/ + +#ifndef SPEAR +LRstruct LevelRatios[8]; +#else +LRstruct LevelRatios[20]; +#endif + +void LevelCompleted (void) +{ + #define VBLWAIT 30 + #define PAR_AMOUNT 500 + #define PERCENT100AMT 10000 + typedef struct { + float time; + char timestr[6]; + } times; + + int x,i,min,sec,ratio,kr,sr,tr; + unsigned temp; + char tempstr[10]; + long bonus,timeleft=0; + times parTimes[]= + { +#ifndef SPEAR + // + // Episode One Par Times + // + {1.5, "01:30"}, + {2, "02:00"}, + {2, "02:00"}, + {3.5, "03:30"}, + {3, "03:00"}, + {3, "03:00"}, + {2.5, "02:30"}, + {2.5, "02:30"}, + {0, "??:??"}, // Boss level + {0, "??:??"}, // Secret level + + // + // Episode Two Par Times + // + {1.5, "01:30"}, + {3.5, "03:30"}, + {3, "03:00"}, + {2, "02:00"}, + {4, "04:00"}, + {6, "06:00"}, + {1, "01:00"}, + {3, "03:00"}, + {0, "??:??"}, + {0, "??:??"}, + + // + // Episode Three Par Times + // + {1.5, "01:30"}, + {1.5, "01:30"}, + {2.5, "02:30"}, + {2.5, "02:30"}, + {3.5, "03:30"}, + {2.5, "02:30"}, + {2, "02:00"}, + {6, "06:00"}, + {0, "??:??"}, + {0, "??:??"}, + + // + // Episode Four Par Times + // + {2, "02:00"}, + {2, "02:00"}, + {1.5, "01:30"}, + {1, "01:00"}, + {4.5, "04:30"}, + {3.5, "03:30"}, + {2, "02:00"}, + {4.5, "04:30"}, + {0, "??:??"}, + {0, "??:??"}, + + // + // Episode Five Par Times + // + {2.5, "02:30"}, + {1.5, "01:30"}, + {2.5, "02:30"}, + {2.5, "02:30"}, + {4, "04:00"}, + {3, "03:00"}, + {4.5, "04:30"}, + {3.5, "03:30"}, + {0, "??:??"}, + {0, "??:??"}, + + // + // Episode Six Par Times + // + {6.5, "06:30"}, + {4, "04:00"}, + {4.5, "04:30"}, + {6, "06:00"}, + {5, "05:00"}, + {5.5, "05:30"}, + {5.5, "05:30"}, + {8.5, "08:30"}, + {0, "??:??"}, + {0, "??:??"} +#else + // + // SPEAR OF DESTINY TIMES + // + {1.5, "01:30"}, + {3.5, "03:30"}, + {2.75, "02:45"}, + {3.5, "03:30"}, + {0, "??:??"}, // Boss 1 + {4.5, "04:30"}, + {3.25, "03:15"}, + {2.75, "02:45"}, + {4.75, "04:45"}, + {0, "??:??"}, // Boss 2 + {6.5, "06:30"}, + {4.5, "04:30"}, + {2.75, "02:45"}, + {4.5, "04:30"}, + {6, "06:00"}, + {0, "??:??"}, // Boss 3 + {6, "06:00"}, + {0, "??:??"}, // Boss 4 + {0, "??:??"}, // Secret level 1 + {0, "??:??"}, // Secret level 2 +#endif + }; + + + + CacheLump(LEVELEND_LUMP_START,LEVELEND_LUMP_END); + ClearSplitVWB (); // set up for double buffering in split screen + VWB_Bar (0,0,320,200-STATUSLINES,127); + StartCPMusic(ENDLEVEL_MUS); + +// +// do the intermission +// + IN_ClearKeysDown(); + IN_StartAck(); + +#ifdef JAPAN + CA_CacheGrChunk(C_INTERMISSIONPIC); + VWB_DrawPic(0,0,C_INTERMISSIONPIC); + UNCACHEGRCHUNK(C_INTERMISSIONPIC); +#endif + VWB_DrawPic(0,16,L_GUYPIC); + +#ifndef SPEAR + if (mapon<8) +#else + if (mapon != 4 && + mapon != 9 && + mapon != 15 && + mapon < 17) +#endif + { +#ifndef JAPAN + #ifdef SPANISH + Write(14,2,"piso\ncompletado"); + #else + Write(14,2,"floor\ncompleted"); + #endif + + Write(14,7,STR_BONUS" 0"); + Write(16,10,STR_TIME); + Write(16,12,STR_PAR); + + #ifdef SPANISH + Write(11,14, STR_RAT2KILL); + Write(11,16, STR_RAT2SECRET); + Write(11,18,STR_RAT2TREASURE); + #else + Write(9,14, STR_RAT2KILL); + Write(5,16, STR_RAT2SECRET); + Write(1,18,STR_RAT2TREASURE); + #endif + + Write(26,2,itoa(gamestate.mapon+1,tempstr,10)); +#endif + + #ifdef SPANISH + Write(30,12,parTimes[gamestate.episode*10+mapon].timestr); + #else + Write(26,12,parTimes[gamestate.episode*10+mapon].timestr); + #endif + + // + // PRINT TIME + // + sec=gamestate.TimeCount/70; + + if (sec > 99*60) // 99 minutes max + sec = 99*60; + + if (gamestate.TimeCountname); + + // + // level + // + ultoa(s->completed,buffer,10); +#ifndef SPEAR + for (str = buffer;*str;str++) + *str = *str + (129 - '0'); // Used fixed-width numbers (129...) + USL_MeasureString(buffer,&w,&h); + PrintX = (22 * 8)-w; +#else + USL_MeasureString(buffer,&w,&h); + PrintX = 194 - w; +#endif + +#ifndef UPLOAD +#ifndef SPEAR + PrintX -= 6; + itoa(s->episode+1,buffer1,10); + US_Print("E"); + US_Print(buffer1); + US_Print("/L"); +#endif +#endif + +#ifdef SPEAR + if (s->completed == 21) + VWB_DrawPic (PrintX+8,PrintY-1,C_WONSPEARPIC); + else +#endif + US_Print(buffer); + + // + // score + // + ultoa(s->score,buffer,10); +#ifndef SPEAR + for (str = buffer;*str;str++) + *str = *str + (129 - '0'); // Used fixed-width numbers (129...) + USL_MeasureString(buffer,&w,&h); + PrintX = (34 * 8) - 8 - w; +#else + USL_MeasureString(buffer,&w,&h); + PrintX = 292 - w; +#endif + US_Print(buffer); + + #if 0 +#ifndef UPLOAD +#ifndef SPEAR + // + // verification # + // + if (!i) + { + temp=(((s->score >> 28)& 0xf)^ + ((s->score >> 24)& 0xf))+'A'; + temp1=(((s->score >> 20)& 0xf)^ + ((s->score >> 16)& 0xf))+'A'; + temp2=(((s->score >> 12)& 0xf)^ + ((s->score >> 8)& 0xf))+'A'; + temp3=(((s->score >> 4)& 0xf)^ + ((s->score >> 0)& 0xf))+'A'; + + SETFONTCOLOR(0x49,0x29); + PrintX = 35*8; + buffer[0]=temp; + buffer[1]=temp1; + buffer[2]=temp2; + buffer[3]=temp3; + buffer[4]=0; + US_Print(buffer); + SETFONTCOLOR(15,0x29); + } +#endif +#endif + #endif + } + + VW_UpdateScreen (); + +#ifdef SPEAR + UnCacheLump (HIGHSCORES_LUMP_START,HIGHSCORES_LUMP_END); + fontnumber = 0; +#endif +} + +//=========================================================================== + + +/* +======================= += += CheckHighScore += +======================= +*/ + +void CheckHighScore (long score,word other) +{ + word i,j; + int n; + HighScore myscore; + + strcpy(myscore.name,""); + myscore.score = score; + myscore.episode = gamestate.episode; + myscore.completed = other; + + for (i = 0,n = -1;i < MaxScores;i++) + { + if + ( + (myscore.score > Scores[i].score) + || ( + (myscore.score == Scores[i].score) + && (myscore.completed > Scores[i].completed) + ) + ) + { + for (j = MaxScores;--j > i;) + Scores[j] = Scores[j - 1]; + Scores[i] = myscore; + n = i; + break; + } + } + +#ifdef SPEAR + StartCPMusic (XAWARD_MUS); +#else + StartCPMusic (ROSTER_MUS); +#endif + DrawHighScores (); + + VW_FadeIn (); + + if (n != -1) + { + // + // got a high score + // + PrintY = 76 + (16 * n); +#ifndef SPEAR + PrintX = 4*8; + backcolor = BORDCOLOR; + fontcolor = 15; + US_LineInput(PrintX,PrintY,Scores[n].name,nil,true,MaxHighName,100); +#else + PrintX = 16; + fontnumber = 1; + VWB_Bar (PrintX-2,PrintY-2,145,15,0x9c); + VW_UpdateScreen (); + backcolor = 0x9c; + fontcolor = 15; + US_LineInput(PrintX,PrintY,Scores[n].name,nil,true,MaxHighName,130); +#endif + } + else + { + IN_ClearKeysDown (); + IN_UserInput(500); + } + +} + + +#ifndef UPLOAD +#ifndef SPEAR +#ifndef JAPAN +//////////////////////////////////////////////////////// +// +// NON-SHAREWARE NOTICE +// +//////////////////////////////////////////////////////// +void NonShareware(void) +{ + VW_FadeOut(); + + ClearMScreen(); + DrawStripes(10); + + CA_CacheGrChunk(STARTFONT+1); + fontnumber = 1; + + SETFONTCOLOR(READHCOLOR,BKGDCOLOR); + PrintX=110; + PrintY=15; + + #ifdef SPANISH + US_Print("Atencion"); + #else + US_Print("Attention"); + #endif + + SETFONTCOLOR(HIGHLIGHT,BKGDCOLOR); + WindowX=PrintX=40; + PrintY=60; + #ifdef SPANISH + US_Print("Este juego NO es gratis y\n"); + US_Print("NO es Shareware; favor de\n"); + US_Print("no distribuirlo.\n\n"); + #else + US_Print("This game is NOT shareware.\n"); + US_Print("Please do not distribute it.\n"); + US_Print("Thanks.\n\n"); + #endif + US_Print(" Id Software\n"); + + VW_UpdateScreen (); + VW_FadeIn(); + IN_Ack(); +} +#endif +#endif +#endif + +#if 0 +#ifdef SPEAR +#ifndef SPEARDEMO +//////////////////////////////////////////////////////// +// +// COPY PROTECTION FOR FormGen +// +//////////////////////////////////////////////////////// +char far CopyProFailedStrs[][100] = { + STR_COPY1, + STR_COPY2, + + STR_COPY3, + STR_COPY4, + + STR_COPY5, + STR_COPY6, + + STR_COPY7, + STR_COPY8, + + STR_COPY9, + "", + + STR_COPY10, + STR_COPY11, + + STR_COPY12, + "", + + STR_COPY13, + "", + + STR_COPY14, + "" + }, + + far BackDoorStrs[5][16] = { + "a spoon?", + "bite me!", + "joshua", + "pelt", +#ifdef BETA + "beta" +#else + "snoops" +#endif + }, + + far GoodBoyStrs[10][40] = { + "...is the CORRECT ANSWER!", + "", + + "Consider yourself bitten, sir.", + "", + + "Greetings Professor Falken, would you", + "like to play Spear of Destiny?", + + "Do you have any gold spray paint?", + "", + +#ifdef BETA + "Beta testing approved.", +#else + "I wish I had a 21\" monitor...", +#endif + "" + }, + + far bossstrs[4][24] = { + "DEATH KNIGHT", + "BARNACLE WILHELM", + "UBERMUTANTUBER MUTANT", + "TRANS GROSSE" + }, + + far WordStr[5][20] = { + "New Game", + "Sound...F4", + "Control...F6", + "Change View...F5", + "Quit...F10"}, + + far WordCorrect[5][2] = {"3","4","4","5","5"}, + + far MemberStr[10][40] = { + STR_COPY15, + "", + + STR_COPY16, + "", + + STR_COPY17, + STR_COPY18, + + STR_COPY19, + STR_COPY20, + + STR_COPY21, + STR_COPY22}, + + far MemberCorrect[5][24] = { + "adrian carmack", + "john carmackjohn romero", + "tom hall", + "jay wilbur", + "kevin cloud"}, + + far DosMessages[9][80] = { + STR_NOPE1, + STR_NOPE2, + STR_NOPE3, + STR_NOPE4, + STR_NOPE5, + STR_NOPE6, + STR_NOPE7, + STR_NOPE8, + STR_NOPE9}, + + far MiscTitle[4][20] = { + "BLOOD TEST", + "STRAIGHT-LACED", + "QUITE SHAPELY", + "I AM WHAT I AMMO" + }, + + far MiscStr[12][40] = { + STR_MISC1, + STR_MISC2, + "", + + STR_MISC3, + STR_MISC4, + "", + + STR_MISC5, + STR_MISC6, + "", + + STR_MISC7, + STR_MISC8, + STR_MISC9 + }, + + far MiscCorrect[4][5] = {"ss","8",STR_STAR,"45"}; + + +int BackDoor(char *s) +{ + int i; + + + strlwr(s); + + for (i=0;i<5;i++) + if (!_fstrcmp(s,BackDoorStrs[i])) + { + SETFONTCOLOR(14,15); + fontnumber = 0; + PrintY = 175; + VWB_DrawPic (0,20*8,COPYPROTBOXPIC); + US_CPrint(GoodBoyStrs[i*2]); + US_CPrint(GoodBoyStrs[i*2+1]); + VW_UpdateScreen(); + return 1; + } + + return 0; +} + + +void CopyProtection(void) +{ +#define TYPEBOX_Y 177 +#define TYPEBOX_BKGD 0x9c +#define PRINTCOLOR HIGHLIGHT + + int i,match,whichboss,bossnum,try,whichline,enemypicked[4]={0,0,0,0}, + bosses[4] = { BOSSPIC1PIC,BOSSPIC2PIC,BOSSPIC3PIC,BOSSPIC4PIC }, + whichone,whichpicked[4]={0,0,0,0},quiztype,whichmem, + memberpicked[5]={0,0,0,0,0},wordpicked[5]={0,0,0,0,0},whichword; + + char inputbuffer[20], + message[80]; + + enum + { + debriefing, + checkmanual, + staffquiz, + miscquiz, + + totaltypes + }; + + + + try = 0; + VW_FadeOut(); + CA_CacheGrChunk(C_BACKDROPPIC); + CacheLump(COPYPROT_LUMP_START,COPYPROT_LUMP_END); + CA_CacheGrChunk(STARTFONT+1); + CA_LoadAllSounds(); + StartCPMusic(COPYPRO_MUS); + US_InitRndT(true); + + while (try<3) + { + fontnumber = 1; + SETFONTCOLOR(PRINTCOLOR-2,15); + VWB_DrawPic (0,0,C_BACKDROPPIC); + VWB_DrawPic (0,0,COPYPROTTOPPIC); + VWB_DrawPic (0,20*8,COPYPROTBOXPIC); + WindowX = WindowY = 0; + WindowW = 320; + WindowH = 200; + PrintY = 65; + + quiztype = US_RndT()%totaltypes; + switch(quiztype) + { + // + // BOSSES QUIZ + // + case debriefing: + PrintX = 0; + US_Print(STR_DEBRIEF); + SETFONTCOLOR(PRINTCOLOR,15); + + while (enemypicked[whichboss = US_RndT()&3]); + enemypicked[whichboss] = 1; + bossnum = bosses[whichboss]; + VWB_DrawPic(128,60,bossnum); + fontnumber = 0; + PrintY = 130; + US_CPrint(STR_ENEMY1"\n"); + US_CPrint(STR_ENEMY2"\n\n"); + + VW_UpdateScreen(); + VW_FadeIn(); + + PrintX = 100; + fontcolor = 15; + backcolor = TYPEBOX_BKGD; + inputbuffer[0] = 0; + PrintY = TYPEBOX_Y; + fontnumber = 1; + US_LineInput(PrintX,PrintY,inputbuffer,nil,true,20,100); + + match = 0; + for (i=0;i<_fstrlen(bossstrs[whichboss]);i++) + if (!_fstrnicmp(inputbuffer,bossstrs[whichboss]+i,strlen(inputbuffer)) && + strlen(inputbuffer)>3) + match = 1; + + match += BackDoor(inputbuffer); + break; + + // + // MANUAL CHECK + // + case checkmanual: + while (wordpicked[whichword = US_RndT()%5]); + wordpicked[whichword] = 1; + US_CPrint(STR_CHECKMAN); + SETFONTCOLOR(PRINTCOLOR,15); + PrintY += 25; + US_CPrint(STR_MAN1); + US_CPrint(STR_MAN2); + _fstrcpy(message,STR_MAN3" \""); + _fstrcat(message,WordStr[whichword]); + _fstrcat(message,"\" "STR_MAN4); + US_CPrint(message); + VW_UpdateScreen(); + VW_FadeIn(); + + PrintX = 146; + fontcolor = 15; + backcolor = TYPEBOX_BKGD; + inputbuffer[0] = 0; + PrintY = TYPEBOX_Y; + US_LineInput(PrintX,PrintY,inputbuffer,nil,true,6,100); + + strlwr(inputbuffer); + match = 1-(_fstrcmp(inputbuffer,WordCorrect[whichword])!=0); + match += BackDoor(inputbuffer); + break; + + // + // STAFF QUIZ + // + case staffquiz: + while (memberpicked[whichmem = US_RndT()%5]); + memberpicked[whichmem] = 1; + US_CPrint(STR_ID1); + SETFONTCOLOR(PRINTCOLOR,15); + PrintY += 25; + US_CPrint(MemberStr[whichmem*2]); + US_CPrint(MemberStr[whichmem*2+1]); + VW_UpdateScreen(); + VW_FadeIn(); + + PrintX = 100; + fontcolor = 15; + backcolor = TYPEBOX_BKGD; + inputbuffer[0] = 0; + PrintY = TYPEBOX_Y; + US_LineInput(PrintX,PrintY,inputbuffer,nil,true,20,120); + + strlwr(inputbuffer); + match = 0; + for (i=0;i<_fstrlen(MemberCorrect[whichmem]);i++) + if (!_fstrnicmp(inputbuffer,MemberCorrect[whichmem]+i,strlen(inputbuffer)) && + strlen(inputbuffer)>2) + match = 1; + match += BackDoor(inputbuffer); + break; + + // + // MISCELLANEOUS QUESTIONS + // + case miscquiz: + while (whichpicked[whichone = US_RndT()&3]); + whichpicked[whichone] = 1; + US_CPrint(MiscTitle[whichone]); + SETFONTCOLOR(PRINTCOLOR,15); + PrintY += 25; + US_CPrint(MiscStr[whichone*3]); + US_CPrint(MiscStr[whichone*3+1]); + US_CPrint(MiscStr[whichone*3+2]); + VW_UpdateScreen(); + VW_FadeIn(); + + PrintX = 146; + fontcolor = 15; + backcolor = TYPEBOX_BKGD; + inputbuffer[0] = 0; + PrintY = TYPEBOX_Y; + US_LineInput(PrintX,PrintY,inputbuffer,nil,true,6,100); + + strlwr(inputbuffer); + match = 1-(_fstrcmp(inputbuffer,MiscCorrect[whichone])!=0); + match += BackDoor(inputbuffer); + break; + } + + // + // IF NO MATCH, WE'VE GOT A (MINOR) PROBLEM! + // + + if (!match) + { + whichline = 2*(US_RndT()%9); + SETFONTCOLOR(14,15); + fontnumber = 0; + PrintY = 175; + VWB_DrawPic (0,20*8,COPYPROTBOXPIC); + US_CPrint(CopyProFailedStrs[whichline]); + US_CPrint(CopyProFailedStrs[whichline+1]); + + VW_UpdateScreen(); + SD_PlaySound(NOWAYSND); + IN_UserInput(TickBase*3); + VW_FadeOut(); + try++; + } + else + { + int start; + + + SD_PlaySound(BONUS1UPSND); + SD_WaitSoundDone(); + UNCACHEGRCHUNK (STARTFONT+1); + UNCACHEGRCHUNK (C_BACKDROPPIC); + UnCacheLump (COPYPROT_LUMP_START,COPYPROT_LUMP_END); + + switch(SoundMode) + { + case sdm_Off: return; + case sdm_PC: start = STARTPCSOUNDS; break; + case sdm_AdLib: start = STARTADLIBSOUNDS; + } + + for (i=0;i +#include "WL_DEF.H" +#pragma hdrstop + + +/* +============================================================================= + + WOLFENSTEIN 3-D + + An Id Software production + + by John Carmack + +============================================================================= +*/ + +/* +============================================================================= + + LOCAL CONSTANTS + +============================================================================= +*/ + + +#define FOCALLENGTH (0x5700l) // in global coordinates +#define VIEWGLOBAL 0x10000 // globals visable flush to wall + +#define VIEWWIDTH 256 // size of view window +#define VIEWHEIGHT 144 + +/* +============================================================================= + + GLOBAL VARIABLES + +============================================================================= +*/ + +char str[80],str2[20]; +int tedlevelnum; +boolean tedlevel; +boolean nospr; +boolean IsA386; +int dirangle[9] = {0,ANGLES/8,2*ANGLES/8,3*ANGLES/8,4*ANGLES/8, + 5*ANGLES/8,6*ANGLES/8,7*ANGLES/8,ANGLES}; + +// +// proejection variables +// +fixed focallength; +unsigned screenofs; +int viewwidth; +int viewheight; +int centerx; +int shootdelta; // pixels away from centerx a target can be +fixed scale,maxslope; +long heightnumerator; +int minheightdiv; + + +void Quit (char *error); + +boolean startgame,loadedgame,virtualreality; +int mouseadjustment; + +char configname[13]="CONFIG."; + + +/* +============================================================================= + + LOCAL VARIABLES + +============================================================================= +*/ + + +/* +==================== += += ReadConfig += +==================== +*/ + +void ReadConfig(void) +{ + int file; + SDMode sd; + SMMode sm; + SDSMode sds; + + + if ( (file = open(configname,O_BINARY | O_RDONLY)) != -1) + { + // + // valid config file + // + read(file,Scores,sizeof(HighScore) * MaxScores); + + read(file,&sd,sizeof(sd)); + read(file,&sm,sizeof(sm)); + read(file,&sds,sizeof(sds)); + + read(file,&mouseenabled,sizeof(mouseenabled)); + read(file,&joystickenabled,sizeof(joystickenabled)); + read(file,&joypadenabled,sizeof(joypadenabled)); + read(file,&joystickprogressive,sizeof(joystickprogressive)); + read(file,&joystickport,sizeof(joystickport)); + + read(file,&dirscan,sizeof(dirscan)); + read(file,&buttonscan,sizeof(buttonscan)); + read(file,&buttonmouse,sizeof(buttonmouse)); + read(file,&buttonjoy,sizeof(buttonjoy)); + + read(file,&viewsize,sizeof(viewsize)); + read(file,&mouseadjustment,sizeof(mouseadjustment)); + + close(file); + + if (sd == sdm_AdLib && !AdLibPresent && !SoundBlasterPresent) + { + sd = sdm_PC; + sd = smm_Off; + } + + if ((sds == sds_SoundBlaster && !SoundBlasterPresent) || + (sds == sds_SoundSource && !SoundSourcePresent)) + sds = sds_Off; + + if (!MousePresent) + mouseenabled = false; + if (!JoysPresent[joystickport]) + joystickenabled = false; + + MainMenu[6].active=1; + MainItems.curpos=0; + } + else + { + // + // no config file, so select by hardware + // + if (SoundBlasterPresent || AdLibPresent) + { + sd = sdm_AdLib; + sm = smm_AdLib; + } + else + { + sd = sdm_PC; + sm = smm_Off; + } + + if (SoundBlasterPresent) + sds = sds_SoundBlaster; + else if (SoundSourcePresent) + sds = sds_SoundSource; + else + sds = sds_Off; + + if (MousePresent) + mouseenabled = true; + + joystickenabled = false; + joypadenabled = false; + joystickport = 0; + joystickprogressive = false; + + viewsize = 15; + mouseadjustment=5; + } + + SD_SetMusicMode (sm); + SD_SetSoundMode (sd); + SD_SetDigiDevice (sds); + +} + + +/* +==================== += += WriteConfig += +==================== +*/ + +void WriteConfig(void) +{ + int file; + + file = open(configname,O_CREAT | O_BINARY | O_WRONLY, + S_IREAD | S_IWRITE | S_IFREG); + + if (file != -1) + { + write(file,Scores,sizeof(HighScore) * MaxScores); + + write(file,&SoundMode,sizeof(SoundMode)); + write(file,&MusicMode,sizeof(MusicMode)); + write(file,&DigiMode,sizeof(DigiMode)); + + write(file,&mouseenabled,sizeof(mouseenabled)); + write(file,&joystickenabled,sizeof(joystickenabled)); + write(file,&joypadenabled,sizeof(joypadenabled)); + write(file,&joystickprogressive,sizeof(joystickprogressive)); + write(file,&joystickport,sizeof(joystickport)); + + write(file,&dirscan,sizeof(dirscan)); + write(file,&buttonscan,sizeof(buttonscan)); + write(file,&buttonmouse,sizeof(buttonmouse)); + write(file,&buttonjoy,sizeof(buttonjoy)); + + write(file,&viewsize,sizeof(viewsize)); + write(file,&mouseadjustment,sizeof(mouseadjustment)); + + close(file); + } +} + + +//=========================================================================== + + +/* +======================== += += Patch386 += += Patch ldiv to use 32 bit instructions += +======================== +*/ + +char *JHParmStrings[] = {"no386",nil}; +void Patch386 (void) +{ +extern void far jabhack2(void); +extern int far CheckIs386(void); + + int i; + + for (i = 1;i < _argc;i++) + if (US_CheckParm(_argv[i],JHParmStrings) == 0) + { + IsA386 = false; + return; + } + + if (CheckIs386()) + { + IsA386 = true; + jabhack2(); + } + else + IsA386 = false; +} + +//=========================================================================== + +/* +===================== += += NewGame += += Set up new game to start from the beginning += +===================== +*/ + +void NewGame (int difficulty,int episode) +{ + memset (&gamestate,0,sizeof(gamestate)); + gamestate.difficulty = difficulty; + gamestate.weapon = gamestate.bestweapon + = gamestate.chosenweapon = wp_pistol; + gamestate.health = 100; + gamestate.ammo = STARTAMMO; + gamestate.lives = 3; + gamestate.nextextra = EXTRAPOINTS; + gamestate.episode=episode; + + startgame = true; +} + +//=========================================================================== + +void DiskFlopAnim(int x,int y) +{ + static char which=0; + if (!x && !y) + return; + VWB_DrawPic(x,y,C_DISKLOADING1PIC+which); + VW_UpdateScreen(); + which^=1; +} + + +long DoChecksum(byte far *source,unsigned size,long checksum) +{ + unsigned i; + + for (i=0;inext) + size += sizeof(*ob); + size += sizeof(nullobj); + + size += sizeof(gamestate) + + sizeof(LRstruct)*8 + + sizeof(tilemap) + + sizeof(actorat) + + sizeof(laststatobj) + + sizeof(statobjlist) + + sizeof(doorposition) + + sizeof(pwallstate) + + sizeof(pwallx) + + sizeof(pwally) + + sizeof(pwalldir) + + sizeof(pwallpos); + + if (avail < size) + { + Message(STR_NOSPACE1"\n" + STR_NOSPACE2); + return false; + } + + checksum = 0; + + + DiskFlopAnim(x,y); + CA_FarWrite (file,(void far *)&gamestate,sizeof(gamestate)); + checksum = DoChecksum((byte far *)&gamestate,sizeof(gamestate),checksum); + + DiskFlopAnim(x,y); +#ifdef SPEAR + CA_FarWrite (file,(void far *)&LevelRatios[0],sizeof(LRstruct)*20); + checksum = DoChecksum((byte far *)&LevelRatios[0],sizeof(LRstruct)*20,checksum); +#else + CA_FarWrite (file,(void far *)&LevelRatios[0],sizeof(LRstruct)*8); + checksum = DoChecksum((byte far *)&LevelRatios[0],sizeof(LRstruct)*8,checksum); +#endif + + DiskFlopAnim(x,y); + CA_FarWrite (file,(void far *)tilemap,sizeof(tilemap)); + checksum = DoChecksum((byte far *)tilemap,sizeof(tilemap),checksum); + DiskFlopAnim(x,y); + CA_FarWrite (file,(void far *)actorat,sizeof(actorat)); + checksum = DoChecksum((byte far *)actorat,sizeof(actorat),checksum); + + CA_FarWrite (file,(void far *)areaconnect,sizeof(areaconnect)); + CA_FarWrite (file,(void far *)areabyplayer,sizeof(areabyplayer)); + + for (ob = player ; ob ; ob=ob->next) + { + DiskFlopAnim(x,y); + CA_FarWrite (file,(void far *)ob,sizeof(*ob)); + } + nullobj.active = ac_badobject; // end of file marker + DiskFlopAnim(x,y); + CA_FarWrite (file,(void far *)&nullobj,sizeof(nullobj)); + + + + DiskFlopAnim(x,y); + CA_FarWrite (file,(void far *)&laststatobj,sizeof(laststatobj)); + checksum = DoChecksum((byte far *)&laststatobj,sizeof(laststatobj),checksum); + DiskFlopAnim(x,y); + CA_FarWrite (file,(void far *)statobjlist,sizeof(statobjlist)); + checksum = DoChecksum((byte far *)statobjlist,sizeof(statobjlist),checksum); + + DiskFlopAnim(x,y); + CA_FarWrite (file,(void far *)doorposition,sizeof(doorposition)); + checksum = DoChecksum((byte far *)doorposition,sizeof(doorposition),checksum); + DiskFlopAnim(x,y); + CA_FarWrite (file,(void far *)doorobjlist,sizeof(doorobjlist)); + checksum = DoChecksum((byte far *)doorobjlist,sizeof(doorobjlist),checksum); + + DiskFlopAnim(x,y); + CA_FarWrite (file,(void far *)&pwallstate,sizeof(pwallstate)); + checksum = DoChecksum((byte far *)&pwallstate,sizeof(pwallstate),checksum); + CA_FarWrite (file,(void far *)&pwallx,sizeof(pwallx)); + checksum = DoChecksum((byte far *)&pwallx,sizeof(pwallx),checksum); + CA_FarWrite (file,(void far *)&pwally,sizeof(pwally)); + checksum = DoChecksum((byte far *)&pwally,sizeof(pwally),checksum); + CA_FarWrite (file,(void far *)&pwalldir,sizeof(pwalldir)); + checksum = DoChecksum((byte far *)&pwalldir,sizeof(pwalldir),checksum); + CA_FarWrite (file,(void far *)&pwallpos,sizeof(pwallpos)); + checksum = DoChecksum((byte far *)&pwallpos,sizeof(pwallpos),checksum); + + // + // WRITE OUT CHECKSUM + // + CA_FarWrite (file,(void far *)&checksum,sizeof(checksum)); + + return(true); +} + +//=========================================================================== + +/* +================== += += LoadTheGame += +================== +*/ + +boolean LoadTheGame(int file,int x,int y) +{ + long checksum,oldchecksum; + objtype *ob,nullobj; + + + checksum = 0; + + DiskFlopAnim(x,y); + CA_FarRead (file,(void far *)&gamestate,sizeof(gamestate)); + checksum = DoChecksum((byte far *)&gamestate,sizeof(gamestate),checksum); + + DiskFlopAnim(x,y); +#ifdef SPEAR + CA_FarRead (file,(void far *)&LevelRatios[0],sizeof(LRstruct)*20); + checksum = DoChecksum((byte far *)&LevelRatios[0],sizeof(LRstruct)*20,checksum); +#else + CA_FarRead (file,(void far *)&LevelRatios[0],sizeof(LRstruct)*8); + checksum = DoChecksum((byte far *)&LevelRatios[0],sizeof(LRstruct)*8,checksum); +#endif + + DiskFlopAnim(x,y); + SetupGameLevel (); + + DiskFlopAnim(x,y); + CA_FarRead (file,(void far *)tilemap,sizeof(tilemap)); + checksum = DoChecksum((byte far *)tilemap,sizeof(tilemap),checksum); + DiskFlopAnim(x,y); + CA_FarRead (file,(void far *)actorat,sizeof(actorat)); + checksum = DoChecksum((byte far *)actorat,sizeof(actorat),checksum); + + CA_FarRead (file,(void far *)areaconnect,sizeof(areaconnect)); + CA_FarRead (file,(void far *)areabyplayer,sizeof(areabyplayer)); + + + + InitActorList (); + DiskFlopAnim(x,y); + CA_FarRead (file,(void far *)player,sizeof(*player)); + + while (1) + { + DiskFlopAnim(x,y); + CA_FarRead (file,(void far *)&nullobj,sizeof(nullobj)); + if (nullobj.active == ac_badobject) + break; + GetNewActor (); + // don't copy over the links + memcpy (new,&nullobj,sizeof(nullobj)-4); + } + + + + DiskFlopAnim(x,y); + CA_FarRead (file,(void far *)&laststatobj,sizeof(laststatobj)); + checksum = DoChecksum((byte far *)&laststatobj,sizeof(laststatobj),checksum); + DiskFlopAnim(x,y); + CA_FarRead (file,(void far *)statobjlist,sizeof(statobjlist)); + checksum = DoChecksum((byte far *)statobjlist,sizeof(statobjlist),checksum); + + DiskFlopAnim(x,y); + CA_FarRead (file,(void far *)doorposition,sizeof(doorposition)); + checksum = DoChecksum((byte far *)doorposition,sizeof(doorposition),checksum); + DiskFlopAnim(x,y); + CA_FarRead (file,(void far *)doorobjlist,sizeof(doorobjlist)); + checksum = DoChecksum((byte far *)doorobjlist,sizeof(doorobjlist),checksum); + + DiskFlopAnim(x,y); + CA_FarRead (file,(void far *)&pwallstate,sizeof(pwallstate)); + checksum = DoChecksum((byte far *)&pwallstate,sizeof(pwallstate),checksum); + CA_FarRead (file,(void far *)&pwallx,sizeof(pwallx)); + checksum = DoChecksum((byte far *)&pwallx,sizeof(pwallx),checksum); + CA_FarRead (file,(void far *)&pwally,sizeof(pwally)); + checksum = DoChecksum((byte far *)&pwally,sizeof(pwally),checksum); + CA_FarRead (file,(void far *)&pwalldir,sizeof(pwalldir)); + checksum = DoChecksum((byte far *)&pwalldir,sizeof(pwalldir),checksum); + CA_FarRead (file,(void far *)&pwallpos,sizeof(pwallpos)); + checksum = DoChecksum((byte far *)&pwallpos,sizeof(pwallpos),checksum); + + CA_FarRead (file,(void far *)&oldchecksum,sizeof(oldchecksum)); + + if (oldchecksum != checksum) + { + Message(STR_SAVECHT1"\n" + STR_SAVECHT2"\n" + STR_SAVECHT3"\n" + STR_SAVECHT4); + + IN_ClearKeysDown(); + IN_Ack(); + + gamestate.score = 0; + gamestate.lives = 1; + gamestate.weapon = + gamestate.chosenweapon = + gamestate.bestweapon = wp_pistol; + gamestate.ammo = 8; + } + + return true; +} + +//=========================================================================== + +/* +========================== += += ShutdownId += += Shuts down all ID_?? managers += +========================== +*/ + +void ShutdownId (void) +{ + US_Shutdown (); + SD_Shutdown (); + PM_Shutdown (); + IN_Shutdown (); + VW_Shutdown (); + CA_Shutdown (); + MM_Shutdown (); +} + + +//=========================================================================== + +/* +================== += += BuildTables += += Calculates: += += scale projection constant += sintable/costable overlapping fractional tables += +================== +*/ + +const float radtoint = (float)FINEANGLES/2/PI; + +void BuildTables (void) +{ + int i; + float angle,anglestep; + double tang; + fixed value; + + +// +// calculate fine tangents +// + + for (i=0;i>2 +// + heightnumerator = (TILEGLOBAL*scale)>>6; + minheightdiv = heightnumerator/0x7fff +1; + +// +// calculate the angle offset from view angle of each pixel's ray +// + + for (i=0;i>= 8; +} + + + +//=========================================================================== + +/* +=================== += += SetupWalls += += Map tile values to scaled pics += +=================== +*/ + +void SetupWalls (void) +{ + int i; + + for (i=1;i=0) + { + if (lastsong >= 0) + MusicMenu[start+lastsong].active = 1; + + StartCPMusic(songs[start + which]); + MusicMenu[start+which].active = 2; + DrawMenu (&MusicItems,&MusicMenu[start]); + VW_UpdateScreen(); + lastsong = which; + } + } while(which>=0); + + MenuFadeOut(); + IN_ClearKeysDown(); +#ifdef SPEAR + UnCacheLump (BACKDROP_LUMP_START,BACKDROP_LUMP_END); +#else + UnCacheLump (CONTROLS_LUMP_START,CONTROLS_LUMP_END); +#endif +} +#endif + + +/* +========================== += += InitGame += += Load a few things right away += +========================== +*/ + +void InitGame (void) +{ + int i,x,y; + unsigned *blockstart; + + if (MS_CheckParm ("virtual")) + virtualreality = true; + else + virtualreality = false; + + MM_Startup (); // so the signon screen can be freed + + SignonScreen (); + + VW_Startup (); + IN_Startup (); + PM_Startup (); + PM_UnlockMainMem (); + SD_Startup (); + CA_Startup (); + US_Startup (); + + +#ifndef SPEAR + if (mminfo.mainmem < 235000L) +#else + if (mminfo.mainmem < 257000L && !MS_CheckParm("debugmode")) +#endif + { + memptr screen; + + CA_CacheGrChunk (ERRORSCREEN); + screen = grsegs[ERRORSCREEN]; + ShutdownId(); + movedata ((unsigned)screen,7+7*160,0xb800,0,17*160); + gotoxy (1,23); + exit(1); + } + + +// +// build some tables +// + InitDigiMap (); + + for (i=0;i YEAR || + (d.month >= MONTH && d.day >= DAY)) + { + printf("Sorry, BETA-TESTING is over. Thanks for you help.\n"); + exit(1); + } +#endif + + CheckForEpisodes(); + + //00-- Patch386 (); + + InitGame (); + + DemoLoop(); + + Quit("Demo loop exited???"); +} + diff --git a/16/sod8086/wl_menu.c b/16/sod8086/wl_menu.c new file mode 100755 index 00000000..2003f6e8 --- /dev/null +++ b/16/sod8086/wl_menu.c @@ -0,0 +1,3987 @@ +//////////////////////////////////////////////////////////////////// +// +// WL_MENU.C +// by John Romero (C) 1992 Id Software, Inc. +// +//////////////////////////////////////////////////////////////////// +#include "wl_def.h" +#pragma hdrstop + +// +// PRIVATE PROTOTYPES +// +void CP_ReadThis(void); + +#ifdef SPEAR +#define STARTITEM newgame + +#else +#ifdef GOODTIMES +#define STARTITEM newgame + +#else +#define STARTITEM readthis +#endif +#endif + +char far endStrings[9][80]= +{ +#ifndef SPEAR + {"Dost thou wish to\nleave with such hasty\nabandon?"}, + {"Chickening out...\nalready?"}, + {"Press N for more carnage.\nPress Y to be a weenie."}, + {"So, you think you can\nquit this easily, huh?"}, + {"Press N to save the world.\nPress Y to abandon it in\nits hour of need."}, + {"Press N if you are brave.\nPress Y to cower in shame."}, + {"Heroes, press N.\nWimps, press Y."}, + {"You are at an intersection.\nA sign says, 'Press Y to quit.'\n>"}, + {"For guns and glory, press N.\nFor work and worry, press Y."} +#else + ENDSTR1, + ENDSTR2, + ENDSTR3, + ENDSTR4, + ENDSTR5, + ENDSTR6, + ENDSTR7, + ENDSTR8, + ENDSTR9 +#endif +}; + +CP_iteminfo + MainItems={MENU_X,MENU_Y,10,STARTITEM,24}, + SndItems={SM_X,SM_Y1,12,0,52}, + LSItems={LSM_X,LSM_Y,10,0,24}, + CtlItems={CTL_X,CTL_Y,6,-1,56}, + CusItems={8,CST_Y+13*2,9,-1,0}, + NewEitems={NE_X,NE_Y,11,0,88}, + NewItems={NM_X,NM_Y,4,2,24}; + +#pragma warn -sus +CP_itemtype far +MainMenu[]= +{ +#ifdef JAPAN + {1,"",CP_NewGame}, + {1,"",CP_Sound}, + {1,"",CP_Control}, + {1,"",CP_LoadGame}, + {0,"",CP_SaveGame}, + {1,"",CP_ChangeView}, + {2,"",CP_ReadThis}, + {1,"",CP_ViewScores}, + {1,"",0}, + {1,"",0} +#else + + {1,STR_NG,CP_NewGame}, + {1,STR_SD,CP_Sound}, + {1,STR_CL,CP_Control}, + {1,STR_LG,CP_LoadGame}, + {0,STR_SG,CP_SaveGame}, + {1,STR_CV,CP_ChangeView}, + +#ifndef GOODTIMES +#ifndef SPEAR + + #ifdef SPANISH + {2,"Ve esto!",CP_ReadThis}, + #else + {2,"Read This!",CP_ReadThis}, + #endif + +#endif +#endif + + {1,STR_VS,CP_ViewScores}, + {1,STR_BD,0}, + {1,STR_QT,0} +#endif +}, + +far SndMenu[]= +{ +#ifdef JAPAN + {1,"",0}, + {1,"",0}, + {1,"",0}, + {0,"",0}, + {0,"",0}, + {1,"",0}, + {1,"",0}, + {1,"",0}, + {0,"",0}, + {0,"",0}, + {1,"",0}, + {1,"",0}, +#else + {1,STR_NONE,0}, + {1,STR_PC,0}, + {1,STR_ALSB,0}, + {0,"",0}, + {0,"",0}, + {1,STR_NONE,0}, + {1,STR_DISNEY,0}, + {1,STR_SB,0}, + {0,"",0}, + {0,"",0}, + {1,STR_NONE,0}, + {1,STR_ALSB,0} +#endif +}, + +far CtlMenu[]= +{ +#ifdef JAPAN + {0,"",0}, + {0,"",0}, + {0,"",0}, + {0,"",0}, + {0,"",MouseSensitivity}, + {1,"",CustomControls} +#else + {0,STR_MOUSEEN,0}, + {0,STR_JOYEN,0}, + {0,STR_PORT2,0}, + {0,STR_GAMEPAD,0}, + {0,STR_SENS,MouseSensitivity}, + {1,STR_CUSTOM,CustomControls} +#endif +}, + +#pragma warn +sus + +#ifndef SPEAR +far NewEmenu[]= +{ +#ifdef JAPAN +#ifdef JAPDEMO + {1,"",0}, + {0,"",0}, + {0,"",0}, + {0,"",0}, + {0,"",0}, + {0,"",0}, + {0,"",0}, + {0,"",0}, + {0,"",0}, + {0,"",0}, + {0,"",0}, + {0,"",0}, +#else + {1,"",0}, + {0,"",0}, + {1,"",0}, + {0,"",0}, + {1,"",0}, + {0,"",0}, + {1,"",0}, + {0,"",0}, + {1,"",0}, + {0,"",0}, + {1,"",0}, + {0,"",0} +#endif +#else + #ifdef SPANISH + {1,"Episodio 1\n" + "Fuga desde Wolfenstein",0}, + {0,"",0}, + {3,"Episodio 2\n" + "Operacion Eisenfaust",0}, + {0,"",0}, + {3,"Episodio 3\n" + "Muere, Fuhrer, Muere!",0}, + {0,"",0}, + {3,"Episodio 4\n" + "Un Negro Secreto",0}, + {0,"",0}, + {3,"Episodio 5\n" + "Huellas del Loco",0}, + {0,"",0}, + {3,"Episodio 6\n" + "Confrontacion",0} + #else + {1,"Episode 1\n" + "Escape from Wolfenstein",0}, + {0,"",0}, + {3,"Episode 2\n" + "Operation: Eisenfaust",0}, + {0,"",0}, + {3,"Episode 3\n" + "Die, Fuhrer, Die!",0}, + {0,"",0}, + {3,"Episode 4\n" + "A Dark Secret",0}, + {0,"",0}, + {3,"Episode 5\n" + "Trail of the Madman",0}, + {0,"",0}, + {3,"Episode 6\n" + "Confrontation",0} + #endif +#endif +}, +#endif + + +far NewMenu[]= +{ +#ifdef JAPAN + {1,"",0}, + {1,"",0}, + {1,"",0}, + {1,"",0} +#else + {1,STR_DADDY,0}, + {1,STR_HURTME,0}, + {1,STR_BRINGEM,0}, + {1,STR_DEATH,0} +#endif +}, + +far LSMenu[]= +{ + {1,"",0}, + {1,"",0}, + {1,"",0}, + {1,"",0}, + {1,"",0}, + {1,"",0}, + {1,"",0}, + {1,"",0}, + {1,"",0}, + {1,"",0} +}, + +far CusMenu[]= +{ + {1,"",0}, + {0,"",0}, + {0,"",0}, + {1,"",0}, + {0,"",0}, + {0,"",0}, + {1,"",0}, + {0,"",0}, + {1,"",0} +} +; + + +int color_hlite[]={ + DEACTIVE, + HIGHLIGHT, + READHCOLOR, + 0x67 + }, + + color_norml[]={ + DEACTIVE, + TEXTCOLOR, + READCOLOR, + 0x6b + }; + +int EpisodeSelect[6]={1}; + + +int SaveGamesAvail[10],StartGame,SoundStatus=1,pickquick; +char SaveGameNames[10][32],SaveName[13]="SAVEGAM?."; + + +//////////////////////////////////////////////////////////////////// +// +// INPUT MANAGER SCANCODE TABLES +// +//////////////////////////////////////////////////////////////////// +static byte + *ScanNames[] = // Scan code names with single chars + { + "?","?","1","2","3","4","5","6","7","8","9","0","-","+","?","?", + "Q","W","E","R","T","Y","U","I","O","P","[","]","|","?","A","S", + "D","F","G","H","J","K","L",";","\"","?","?","?","Z","X","C","V", + "B","N","M",",",".","/","?","?","?","?","?","?","?","?","?","?", + "?","?","?","?","?","?","?","?","\xf","?","-","\x15","5","\x11","+","?", + "\x13","?","?","?","?","?","?","?","?","?","?","?","?","?","?","?", + "?","?","?","?","?","?","?","?","?","?","?","?","?","?","?","?", + "?","?","?","?","?","?","?","?","?","?","?","?","?","?","?","?" + }, // DEBUG - consolidate these + far ExtScanCodes[] = // Scan codes with >1 char names + { + 1,0xe,0xf,0x1d,0x2a,0x39,0x3a,0x3b,0x3c,0x3d,0x3e, + 0x3f,0x40,0x41,0x42,0x43,0x44,0x57,0x59,0x46,0x1c,0x36, + 0x37,0x38,0x47,0x49,0x4f,0x51,0x52,0x53,0x45,0x48, + 0x50,0x4b,0x4d,0x00 + }, + *ExtScanNames[] = // Names corresponding to ExtScanCodes + { + "Esc","BkSp","Tab","Ctrl","LShft","Space","CapsLk","F1","F2","F3","F4", + "F5","F6","F7","F8","F9","F10","F11","F12","ScrlLk","Enter","RShft", + "PrtSc","Alt","Home","PgUp","End","PgDn","Ins","Del","NumLk","Up", + "Down","Left","Right","" + }; + + +//////////////////////////////////////////////////////////////////// +// +// Wolfenstein Control Panel! Ta Da! +// +//////////////////////////////////////////////////////////////////// +void US_ControlPanel(byte scancode) +{ + int which,i,start; + + + if (ingame) + if (CP_CheckQuick(scancode)) + return; + + StartCPMusic(MENUSONG); + SetupControlPanel(); + + // + // F-KEYS FROM WITHIN GAME + // + switch(scancode) + { +#ifndef SPEAR + case sc_F1: + #ifdef SPEAR + BossKey(); + #else + #ifdef GOODTIMES + BossKey(); + #else + HelpScreens(); + #endif + #endif + goto finishup; +#endif + case sc_F2: + CP_SaveGame(0); + goto finishup; + + case sc_F3: + CP_LoadGame(0); + goto finishup; + + case sc_F4: + CP_Sound(); + goto finishup; + + case sc_F5: + CP_ChangeView(); + goto finishup; + + case sc_F6: + CP_Control(); + goto finishup; + + finishup: + CleanupControlPanel(); + #ifdef SPEAR + UnCacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); + #endif + return; + } + +#ifdef SPEAR + CacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); +#endif + + DrawMainMenu(); + MenuFadeIn(); + StartGame=0; + + // + // MAIN MENU LOOP + // + do + { + which=HandleMenu(&MainItems,&MainMenu[0],NULL); + + #ifdef SPEAR + #ifndef SPEARDEMO + // + // EASTER EGG FOR SPEAR OF DESTINY! + // + if (Keyboard[sc_I] && Keyboard[sc_D]) + { + VW_FadeOut(); + StartCPMusic (XJAZNAZI_MUS); + UnCacheLump(OPTIONS_LUMP_START,OPTIONS_LUMP_END); + UnCacheLump(BACKDROP_LUMP_START,BACKDROP_LUMP_END); + MM_SortMem (); + ClearMemory (); + + + CA_CacheGrChunk (IDGUYS1PIC); + VWB_DrawPic(0,0,IDGUYS1PIC); + UNCACHEGRCHUNK(IDGUYS1PIC); + + CA_CacheGrChunk (IDGUYS2PIC); + VWB_DrawPic(0,80,IDGUYS2PIC); + UNCACHEGRCHUNK(IDGUYS2PIC); + + VW_UpdateScreen(); + + CA_CacheGrChunk (IDGUYSPALETTE); + VL_FadeIn(0,255,grsegs[IDGUYSPALETTE],30); + UNCACHEGRCHUNK(IDGUYSPALETTE); + + while (Keyboard[sc_I] || Keyboard[sc_D]); + IN_ClearKeysDown(); + IN_Ack(); + + VW_FadeOut(); + + CacheLump(BACKDROP_LUMP_START,BACKDROP_LUMP_END); + CacheLump(OPTIONS_LUMP_START,OPTIONS_LUMP_END); + DrawMainMenu(); + StartCPMusic (MENUSONG); + MenuFadeIn(); + } + #endif + #endif + + switch(which) + { + case viewscores: + if (MainMenu[viewscores].routine == NULL) + if (CP_EndGame()) + StartGame=1; + + DrawMainMenu(); + MenuFadeIn(); + break; + + case backtodemo: + #ifdef SPEAR + if (!ingame) + { + // + // DEALLOCATE ALL SOUNDS! + // + switch (SoundMode) + { + case sdm_PC: + start = STARTPCSOUNDS; + break; + case sdm_AdLib: + start = STARTADLIBSOUNDS; + break; + } + + if (SoundMode != sdm_Off) + for (i=0;i"); + while (!Keyboard[sc_Escape]) + IN_ClearKeysDown(); + + SD_MusicOn(); + VL_SetVGAPlaneMode (); + VL_TestPaletteSet (); + VL_SetPalette (&gamepal); + LoadLatchMem(); +} +#endif +#endif + +//////////////////////////////////////////////////////////////////// +// +// CHECK QUICK-KEYS & QUIT (WHILE IN A GAME) +// +//////////////////////////////////////////////////////////////////// +int CP_CheckQuick(unsigned scancode) +{ + switch(scancode) + { + // + // END GAME + // + case sc_F7: + CA_CacheGrChunk(STARTFONT+1); + + WindowH=160; + #ifdef JAPAN + if (GetYorN(7,8,C_JAPQUITPIC)) + #else + if (Confirm(ENDGAMESTR)) + #endif + { + playstate = ex_died; + pickquick = gamestate.lives = 0; + } + + DrawAllPlayBorder(); + WindowH=200; + fontnumber=0; + MainMenu[savegame].active = 0; + return 1; + + // + // QUICKSAVE + // + case sc_F8: + if (SaveGamesAvail[LSItems.curpos] && pickquick) + { + CA_CacheGrChunk(STARTFONT+1); + fontnumber = 1; + Message(STR_SAVING"..."); + CP_SaveGame(1); + fontnumber=0; + } + else + { + #ifndef SPEAR + CA_CacheGrChunk(STARTFONT+1); + CA_CacheGrChunk(C_CURSOR1PIC); + CA_CacheGrChunk(C_CURSOR2PIC); + CA_CacheGrChunk(C_DISKLOADING1PIC); + CA_CacheGrChunk(C_DISKLOADING2PIC); + CA_CacheGrChunk(C_SAVEGAMEPIC); + CA_CacheGrChunk(C_MOUSELBACKPIC); + #else + CacheLump (BACKDROP_LUMP_START,BACKDROP_LUMP_END); + CA_CacheGrChunk(C_CURSOR1PIC); + #endif + + VW_FadeOut (); + + StartCPMusic(MENUSONG); + pickquick=CP_SaveGame(0); + + SETFONTCOLOR(0,15); + IN_ClearKeysDown(); + DrawPlayScreen (); + + if (!startgame && !loadedgame) + { + VW_FadeIn (); + StartMusic (); + } + + if (loadedgame) + playstate = ex_abort; + lasttimecount = TimeCount; + + if (MousePresent) + Mouse(MDelta); // Clear accumulated mouse movement + + PM_CheckMainMem (); + + #ifndef SPEAR + UNCACHEGRCHUNK(C_CURSOR1PIC); + UNCACHEGRCHUNK(C_CURSOR2PIC); + UNCACHEGRCHUNK(C_DISKLOADING1PIC); + UNCACHEGRCHUNK(C_DISKLOADING2PIC); + UNCACHEGRCHUNK(C_SAVEGAMEPIC); + UNCACHEGRCHUNK(C_MOUSELBACKPIC); + #else + UnCacheLump (BACKDROP_LUMP_START,BACKDROP_LUMP_END); + #endif + } + return 1; + + // + // QUICKLOAD + // + case sc_F9: + if (SaveGamesAvail[LSItems.curpos] && pickquick) + { + char string[100]=STR_LGC; + + + CA_CacheGrChunk(STARTFONT+1); + fontnumber = 1; + + strcat(string,SaveGameNames[LSItems.curpos]); + strcat(string,"\"?"); + + if (Confirm(string)) + CP_LoadGame(1); + + DrawAllPlayBorder(); + fontnumber=0; + } + else + { + #ifndef SPEAR + CA_CacheGrChunk(STARTFONT+1); + CA_CacheGrChunk(C_CURSOR1PIC); + CA_CacheGrChunk(C_CURSOR2PIC); + CA_CacheGrChunk(C_DISKLOADING1PIC); + CA_CacheGrChunk(C_DISKLOADING2PIC); + CA_CacheGrChunk(C_LOADGAMEPIC); + CA_CacheGrChunk(C_MOUSELBACKPIC); + #else + CA_CacheGrChunk(C_CURSOR1PIC); + CacheLump (BACKDROP_LUMP_START,BACKDROP_LUMP_END); + #endif + + VW_FadeOut (); + + StartCPMusic(MENUSONG); + pickquick=CP_LoadGame(0); + + SETFONTCOLOR(0,15); + IN_ClearKeysDown(); + DrawPlayScreen (); + + if (!startgame && !loadedgame) + { + VW_FadeIn (); + StartMusic (); + } + + if (loadedgame) + playstate = ex_abort; + + lasttimecount = TimeCount; + + if (MousePresent) + Mouse(MDelta); // Clear accumulated mouse movement + PM_CheckMainMem (); + + #ifndef SPEAR + UNCACHEGRCHUNK(C_CURSOR1PIC); + UNCACHEGRCHUNK(C_CURSOR2PIC); + UNCACHEGRCHUNK(C_DISKLOADING1PIC); + UNCACHEGRCHUNK(C_DISKLOADING2PIC); + UNCACHEGRCHUNK(C_LOADGAMEPIC); + UNCACHEGRCHUNK(C_MOUSELBACKPIC); + #else + UnCacheLump (BACKDROP_LUMP_START,BACKDROP_LUMP_END); + #endif + } + return 1; + + // + // QUIT + // + case sc_F10: + CA_CacheGrChunk(STARTFONT+1); + + WindowX=WindowY=0; + WindowW=320; + WindowH=160; + #ifdef JAPAN + if (GetYorN(7,8,C_QUITMSGPIC)) + #else + #ifdef SPANISH + if (Confirm(ENDGAMESTR)) + #else + if (Confirm(endStrings[US_RndT()&0x7+(US_RndT()&1)])) + #endif + #endif + { + int i; + + + VW_UpdateScreen(); + SD_MusicOff(); + SD_StopSound(); + MenuFadeOut(); + + // + // SHUT-UP THE ADLIB + // + for (i=1;i<=0xf5;i++) + alOut(i,0); + Quit(NULL); + } + + DrawAllPlayBorder(); + WindowH=200; + fontnumber=0; + return 1; + } + + return 0; +} + + +//////////////////////////////////////////////////////////////////// +// +// END THE CURRENT GAME +// +//////////////////////////////////////////////////////////////////// +int CP_EndGame(void) +{ +#ifdef JAPAN + if (!GetYorN(7,8,C_JAPQUITPIC)) +#else + if (!Confirm(ENDGAMESTR)) +#endif + return 0; + + pickquick = gamestate.lives = 0; + playstate = ex_died; + + #pragma warn -sus + MainMenu[savegame].active = 0; + MainMenu[viewscores].routine=CP_ViewScores; + #ifndef JAPAN + _fstrcpy(MainMenu[viewscores].string,STR_VS); + #endif + #pragma warn +sus + + return 1; +} + + +//////////////////////////////////////////////////////////////////// +// +// VIEW THE HIGH SCORES +// +//////////////////////////////////////////////////////////////////// +void CP_ViewScores(void) +{ + fontnumber=0; + +#ifdef SPEAR + UnCacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); + StartCPMusic (XAWARD_MUS); +#else + StartCPMusic (ROSTER_MUS); +#endif + + DrawHighScores (); + VW_UpdateScreen (); + MenuFadeIn(); + fontnumber=1; + + IN_Ack(); + + StartCPMusic(MENUSONG); + MenuFadeOut(); + +#ifdef SPEAR + CacheLump (BACKDROP_LUMP_START,BACKDROP_LUMP_END); + CacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); +#endif +} + + +//////////////////////////////////////////////////////////////////// +// +// START A NEW GAME +// +//////////////////////////////////////////////////////////////////// +void CP_NewGame(void) +{ + int which,episode; + +#ifdef SPEAR + UnCacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); +#endif + + +#ifndef SPEAR +firstpart: + + DrawNewEpisode(); + do + { + which=HandleMenu(&NewEitems,&NewEmenu[0],NULL); + switch(which) + { + case -1: + MenuFadeOut(); + return; + + default: + if (!EpisodeSelect[which/2]) + { + SD_PlaySound (NOWAYSND); + Message("Please select \"Read This!\"\n" + "from the Options menu to\n" + "find out how to order this\n" + "episode from Apogee."); + IN_ClearKeysDown(); + IN_Ack(); + DrawNewEpisode(); + which = 0; + } + else + { + episode = which/2; + which = 1; + } + break; + } + + } while (!which); + + ShootSnd(); + + // + // ALREADY IN A GAME? + // + if (ingame) + #ifdef JAPAN + if (!GetYorN(7,8,C_JAPNEWGAMEPIC)) + #else + if (!Confirm(CURGAME)) + #endif + { + MenuFadeOut(); + return; + } + + MenuFadeOut(); + +#else + episode = 0; + + // + // ALREADY IN A GAME? + // + CacheLump (NEWGAME_LUMP_START,NEWGAME_LUMP_END); + DrawNewGame(); + if (ingame) + if (!Confirm(CURGAME)) + { + MenuFadeOut(); + UnCacheLump (NEWGAME_LUMP_START,NEWGAME_LUMP_END); + CacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); + return; + } + +#endif + + DrawNewGame(); + which=HandleMenu(&NewItems,&NewMenu[0],DrawNewGameDiff); + if (which<0) + { + MenuFadeOut(); + #ifndef SPEAR + goto firstpart; + #else + UnCacheLump (NEWGAME_LUMP_START,NEWGAME_LUMP_END); + CacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); + return; + #endif + } + + ShootSnd(); + NewGame(which,episode); + StartGame=1; + MenuFadeOut(); + + // + // CHANGE "READ THIS!" TO NORMAL COLOR + // + #ifndef SPEAR + #ifndef GOODTIMES + MainMenu[readthis].active=1; + #endif + #endif + + pickquick = 0; + +#ifdef SPEAR + UnCacheLump (NEWGAME_LUMP_START,NEWGAME_LUMP_END); + CacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); +#endif +} + + +#ifndef SPEAR +///////////////////// +// +// DRAW NEW EPISODE MENU +// +void DrawNewEpisode(void) +{ + int i; + +#ifdef JAPAN + CA_CacheScreen(S_EPISODEPIC); +#else + ClearMScreen(); + VWB_DrawPic(112,184,C_MOUSELBACKPIC); + + DrawWindow(NE_X-4,NE_Y-4,NE_W+8,NE_H+8,BKGDCOLOR); + SETFONTCOLOR(READHCOLOR,BKGDCOLOR); + PrintY=2; + WindowX=0; + #ifdef SPANISH + US_CPrint("Cual episodio jugar?"); + #else + US_CPrint("Which episode to play?"); + #endif +#endif + + SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR); + DrawMenu(&NewEitems,&NewEmenu[0]); + + for (i=0;i<6;i++) + VWB_DrawPic(NE_X+32,NE_Y+i*26,C_EPISODE1PIC+i); + + VW_UpdateScreen(); + MenuFadeIn(); + WaitKeyUp(); +} +#endif + +///////////////////// +// +// DRAW NEW GAME MENU +// +void DrawNewGame(void) +{ +#ifdef JAPAN + CA_CacheScreen(S_SKILLPIC); +#else + ClearMScreen(); + VWB_DrawPic(112,184,C_MOUSELBACKPIC); + + SETFONTCOLOR(READHCOLOR,BKGDCOLOR); + PrintX=NM_X+20; + PrintY=NM_Y-32; + +#ifndef SPEAR + #ifdef SPANISH + US_Print("Eres macho?"); + #else + US_Print("How tough are you?"); + #endif +#else + VWB_DrawPic (PrintX,PrintY,C_HOWTOUGHPIC); +#endif + + DrawWindow(NM_X-5,NM_Y-10,NM_W,NM_H,BKGDCOLOR); +#endif + + DrawMenu(&NewItems,&NewMenu[0]); + DrawNewGameDiff(NewItems.curpos); + VW_UpdateScreen(); + MenuFadeIn(); + WaitKeyUp(); +} + + +//////////////////////// +// +// DRAW NEW GAME GRAPHIC +// +void DrawNewGameDiff(int w) +{ + VWB_DrawPic(NM_X+185,NM_Y+7,w+C_BABYMODEPIC); +} + + +//////////////////////////////////////////////////////////////////// +// +// HANDLE SOUND MENU +// +//////////////////////////////////////////////////////////////////// +void CP_Sound(void) +{ + int which,i; + + +#ifdef SPEAR + UnCacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); + CacheLump (SOUND_LUMP_START,SOUND_LUMP_END); +#endif + + DrawSoundMenu(); + MenuFadeIn(); + WaitKeyUp(); + + do + { + which=HandleMenu(&SndItems,&SndMenu[0],NULL); + // + // HANDLE MENU CHOICES + // + switch(which) + { + // + // SOUND EFFECTS + // + case 0: + if (SoundMode!=sdm_Off) + { + SD_WaitSoundDone(); + SD_SetSoundMode(sdm_Off); + DrawSoundMenu(); + } + break; + case 1: + if (SoundMode!=sdm_PC) + { + SD_WaitSoundDone(); + SD_SetSoundMode(sdm_PC); + CA_LoadAllSounds(); + DrawSoundMenu(); + ShootSnd(); + } + break; + case 2: + if (SoundMode!=sdm_AdLib) + { + SD_WaitSoundDone(); + SD_SetSoundMode(sdm_AdLib); + CA_LoadAllSounds(); + DrawSoundMenu(); + ShootSnd(); + } + break; + + // + // DIGITIZED SOUND + // + case 5: + if (DigiMode!=sds_Off) + { + SD_SetDigiDevice(sds_Off); + DrawSoundMenu(); + } + break; + case 6: + if (DigiMode!=sds_SoundSource) + { + SD_SetDigiDevice(sds_SoundSource); + DrawSoundMenu(); + ShootSnd(); + } + break; + case 7: + if (DigiMode!=sds_SoundBlaster) + { + SD_SetDigiDevice(sds_SoundBlaster); + DrawSoundMenu(); + ShootSnd(); + } + break; + + // + // MUSIC + // + case 10: + if (MusicMode!=smm_Off) + { + SD_SetMusicMode(smm_Off); + DrawSoundMenu(); + ShootSnd(); + } + break; + case 11: + if (MusicMode!=smm_AdLib) + { + SD_SetMusicMode(smm_AdLib); + DrawSoundMenu(); + ShootSnd(); + StartCPMusic(MENUSONG); + } + break; + } + } while(which>=0); + + MenuFadeOut(); + +#ifdef SPEAR + UnCacheLump (SOUND_LUMP_START,SOUND_LUMP_END); + CacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); +#endif +} + + +////////////////////// +// +// DRAW THE SOUND MENU +// +void DrawSoundMenu(void) +{ + int i,on; + + +#ifdef JAPAN + CA_CacheScreen(S_SOUNDPIC); +#else + // + // DRAW SOUND MENU + // + ClearMScreen(); + VWB_DrawPic(112,184,C_MOUSELBACKPIC); + + DrawWindow(SM_X-8,SM_Y1-3,SM_W,SM_H1,BKGDCOLOR); + DrawWindow(SM_X-8,SM_Y2-3,SM_W,SM_H2,BKGDCOLOR); + DrawWindow(SM_X-8,SM_Y3-3,SM_W,SM_H3,BKGDCOLOR); +#endif + + // + // IF NO ADLIB, NON-CHOOSENESS! + // + if (!AdLibPresent && !SoundBlasterPresent) + { + SndMenu[2].active=SndMenu[10].active=SndMenu[11].active=0; + } + + if (!SoundSourcePresent) + SndMenu[6].active=0; + + if (!SoundBlasterPresent) + SndMenu[7].active=0; + + if (!SoundSourcePresent && !SoundBlasterPresent) + SndMenu[5].active=0; + + DrawMenu(&SndItems,&SndMenu[0]); +#ifndef JAPAN + VWB_DrawPic(100,SM_Y1-20,C_FXTITLEPIC); + VWB_DrawPic(100,SM_Y2-20,C_DIGITITLEPIC); + VWB_DrawPic(100,SM_Y3-20,C_MUSICTITLEPIC); +#endif + + for (i=0;i=0 && SaveGamesAvail[which]) + { + ShootSnd(); + name[7]=which+'0'; + + handle=open(name,O_BINARY); + lseek(handle,32,SEEK_SET); + + DrawLSAction(0); + loadedgame=true; + + LoadTheGame(handle,LSA_X+8,LSA_Y+5); + close(handle); + + StartGame=1; + ShootSnd(); + // + // CHANGE "READ THIS!" TO NORMAL COLOR + // + + #ifndef SPEAR + #ifndef GOODTIMES + MainMenu[readthis].active=1; + #endif + #endif + + exit=1; + break; + } + + } while(which>=0); + + MenuFadeOut(); + +#ifdef SPEAR + UnCacheLump (LOADSAVE_LUMP_START,LOADSAVE_LUMP_END); + CacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); +#endif + + return exit; +} + + +/////////////////////////////////// +// +// HIGHLIGHT CURRENT SELECTED ENTRY +// +void TrackWhichGame(int w) +{ + static int lastgameon=0; + + PrintLSEntry(lastgameon,TEXTCOLOR); + PrintLSEntry(w,HIGHLIGHT); + + lastgameon=w; +} + + +//////////////////////////// +// +// DRAW THE LOAD/SAVE SCREEN +// +void DrawLoadSaveScreen(int loadsave) +{ + #define DISKX 100 + #define DISKY 0 + + int i; + + + ClearMScreen(); + fontnumber=1; + VWB_DrawPic(112,184,C_MOUSELBACKPIC); + DrawWindow(LSM_X-10,LSM_Y-5,LSM_W,LSM_H,BKGDCOLOR); + DrawStripes(10); + + if (!loadsave) + VWB_DrawPic(60,0,C_LOADGAMEPIC); + else + VWB_DrawPic(60,0,C_SAVEGAMEPIC); + + for (i=0;i<10;i++) + PrintLSEntry(i,TEXTCOLOR); + + DrawMenu(&LSItems,&LSMenu[0]); + VW_UpdateScreen(); + MenuFadeIn(); + WaitKeyUp(); +} + + +/////////////////////////////////////////// +// +// PRINT LOAD/SAVE GAME ENTRY W/BOX OUTLINE +// +void PrintLSEntry(int w,int color) +{ + SETFONTCOLOR(color,BKGDCOLOR); + DrawOutline(LSM_X+LSItems.indent,LSM_Y+w*13,LSM_W-LSItems.indent-15,11,color,color); + PrintX=LSM_X+LSItems.indent+2; + PrintY=LSM_Y+w*13+1; + fontnumber=0; + + if (SaveGamesAvail[w]) + US_Print(SaveGameNames[w]); + else + US_Print(" - "STR_EMPTY" -"); + + fontnumber=1; +} + + +//////////////////////////////////////////////////////////////////// +// +// SAVE CURRENT GAME +// +//////////////////////////////////////////////////////////////////// +int CP_SaveGame(int quick) +{ + int handle,which,exit=0; + unsigned nwritten; + char name[13],input[32]; + + + strcpy(name,SaveName); + + // + // QUICKSAVE? + // + if (quick) + { + which=LSItems.curpos; + + if (SaveGamesAvail[which]) + { + name[7]=which+'0'; + unlink(name); + handle=creat(name,S_IREAD|S_IWRITE); + + strcpy(input,&SaveGameNames[which][0]); + + _dos_write(handle,(void far *)input,32,&nwritten); + lseek(handle,32,SEEK_SET); + SaveTheGame(handle,0,0); + close(handle); + + return 1; + } + } + + +#ifdef SPEAR + UnCacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); + CacheLump (LOADSAVE_LUMP_START,LOADSAVE_LUMP_END); +#endif + + DrawLoadSaveScreen(1); + + do + { + which=HandleMenu(&LSItems,&LSMenu[0],TrackWhichGame); + if (which>=0) + { + // + // OVERWRITE EXISTING SAVEGAME? + // + if (SaveGamesAvail[which]) + #ifdef JAPAN + if (!GetYorN(7,8,C_JAPSAVEOVERPIC)) + #else + if (!Confirm(GAMESVD)) + #endif + { + DrawLoadSaveScreen(1); + continue; + } + else + { + DrawLoadSaveScreen(1); + PrintLSEntry(which,HIGHLIGHT); + VW_UpdateScreen(); + } + + ShootSnd(); + + strcpy(input,&SaveGameNames[which][0]); + name[7]=which+'0'; + + fontnumber=0; + if (!SaveGamesAvail[which]) + VWB_Bar(LSM_X+LSItems.indent+1,LSM_Y+which*13+1,LSM_W-LSItems.indent-16,10,BKGDCOLOR); + VW_UpdateScreen(); + + if (US_LineInput(LSM_X+LSItems.indent+2,LSM_Y+which*13+1,input,input,true,31,LSM_W-LSItems.indent-30)) + { + SaveGamesAvail[which]=1; + strcpy(&SaveGameNames[which][0],input); + + unlink(name); + handle=creat(name,S_IREAD|S_IWRITE); + _dos_write(handle,(void far *)input,32,&nwritten); + lseek(handle,32,SEEK_SET); + + DrawLSAction(1); + SaveTheGame(handle,LSA_X+8,LSA_Y+5); + + close(handle); + + ShootSnd(); + exit=1; + } + else + { + VWB_Bar(LSM_X+LSItems.indent+1,LSM_Y+which*13+1,LSM_W-LSItems.indent-16,10,BKGDCOLOR); + PrintLSEntry(which,HIGHLIGHT); + VW_UpdateScreen(); + SD_PlaySound(ESCPRESSEDSND); + continue; + } + + fontnumber=1; + break; + } + + } while(which>=0); + + MenuFadeOut(); + +#ifdef SPEAR + UnCacheLump (LOADSAVE_LUMP_START,LOADSAVE_LUMP_END); + CacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); +#endif + + return exit; +} + + +//////////////////////////////////////////////////////////////////// +// +// CALIBRATE JOYSTICK +// +//////////////////////////////////////////////////////////////////// +int CalibrateJoystick(void) +{ + #define CALX 85 + #define CALY 40 + #define CALW 158 + #define CALH 140 + + unsigned xmin,ymin,xmax,ymax,jb; + + + + #ifdef JAPAN + VWB_DrawPic(CALX,CALY,C_JOY0PIC); + #else + DrawWindow(CALX-5,CALY-5,CALW,CALH,TEXTCOLOR); + DrawOutline(CALX-5,CALY-5,CALW,CALH,0,HIGHLIGHT); + SETFONTCOLOR(0,TEXTCOLOR); + + WindowX = PrintX = CALX; + WindowW = CALW; + WindowH = CALH; + WindowY = PrintY = CALY; + US_Print(" "STR_CALIB"\n "STR_JOYST"\n"); + VWB_DrawPic(CALX+40,CALY+30,C_JOY1PIC); + PrintY = CALY+80; + US_Print(STR_MOVEJOY); + SETFONTCOLOR(BKGDCOLOR,TEXTCOLOR); + US_Print(" "STR_ESCEXIT); + #endif + VW_UpdateScreen(); + + do + { + jb=IN_JoyButtons(); + if (Keyboard[sc_Escape]) + return 0; + #ifndef SPEAR + if (Keyboard[sc_Tab] && Keyboard[sc_P] && MS_CheckParm("goobers")) + PicturePause(); + #endif + + } while(!(jb&1)); + + SD_PlaySound(SHOOTSND); + IN_GetJoyAbs(joystickport,&xmin,&ymin); + + + #ifdef JAPAN + VWB_DrawPic(CALX,CALY,C_JOY1PIC); + #else + DrawWindow(CALX-5,CALY-5,CALW,CALH,TEXTCOLOR); + DrawOutline(CALX-5,CALY-5,CALW,CALH,0,HIGHLIGHT); + SETFONTCOLOR(0,TEXTCOLOR); + + PrintX = CALX; + PrintY = CALY; + US_Print(" "STR_CALIB"\n "STR_JOYST"\n"); + VWB_DrawPic(CALX+40,CALY+30,C_JOY2PIC); + PrintY = CALY+80; + US_Print(STR_MOVEJOY2); + SETFONTCOLOR(BKGDCOLOR,TEXTCOLOR); + US_Print(" "STR_ESCEXIT); + #endif + VW_UpdateScreen(); + + do + { + jb=IN_JoyButtons(); + if (Keyboard[sc_Escape]) + return 0; + #ifndef SPEAR + if (Keyboard[sc_Tab] && Keyboard[sc_P] && MS_CheckParm("goobers")) + PicturePause(); + #endif + } while(!(jb&2)); + + IN_GetJoyAbs(joystickport,&xmax,&ymax); + SD_PlaySound(SHOOTSND); + + while (IN_JoyButtons()); + + // + // ASSIGN ACTUAL VALUES HERE + // + if ((xmin != xmax) && (ymin != ymax)) + IN_SetupJoy(joystickport,xmin,xmax,ymin,ymax); + else + return 0; + + return 1; +} + + +//////////////////////////////////////////////////////////////////// +// +// DEFINE CONTROLS +// +//////////////////////////////////////////////////////////////////// +void CP_Control(void) +{ + #define CTL_SPC 70 + enum {MOUSEENABLE,JOYENABLE,USEPORT2,PADENABLE,MOUSESENS,CUSTOMIZE}; + int i,which; + + +#ifdef SPEAR + UnCacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); + CacheLump (CONTROL_LUMP_START,CONTROL_LUMP_END); +#endif + + DrawCtlScreen(); + MenuFadeIn(); + WaitKeyUp(); + + do + { + which=HandleMenu(&CtlItems,&CtlMenu[0],NULL); + switch(which) + { + case MOUSEENABLE: + mouseenabled^=1; + _CX=_DX=CENTER; + Mouse(4); + DrawCtlScreen(); + CusItems.curpos=-1; + ShootSnd(); + break; + + case JOYENABLE: + joystickenabled^=1; + if (joystickenabled) + if (!CalibrateJoystick()) + joystickenabled = 0; + DrawCtlScreen(); + CusItems.curpos=-1; + ShootSnd(); + break; + + case USEPORT2: + joystickport^=1; + DrawCtlScreen(); + ShootSnd(); + break; + + case PADENABLE: + joypadenabled^=1; + DrawCtlScreen(); + ShootSnd(); + break; + + case MOUSESENS: + case CUSTOMIZE: + DrawCtlScreen(); + MenuFadeIn(); + WaitKeyUp(); + break; + } + } while(which>=0); + + MenuFadeOut(); + +#ifdef SPEAR + UnCacheLump (CONTROL_LUMP_START,CONTROL_LUMP_END); + CacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); +#endif +} + + +//////////////////////////////// +// +// DRAW MOUSE SENSITIVITY SCREEN +// +void DrawMouseSens(void) +{ +#ifdef JAPAN + CA_CacheScreen(S_MOUSESENSPIC); +#else + ClearMScreen(); + VWB_DrawPic(112,184,C_MOUSELBACKPIC); + #ifdef SPANISH + DrawWindow(10,80,300,43,BKGDCOLOR); + #else + DrawWindow(10,80,300,30,BKGDCOLOR); + #endif + + WindowX=0; + WindowW=320; + PrintY=82; + SETFONTCOLOR(READCOLOR,BKGDCOLOR); + US_CPrint(STR_MOUSEADJ); + + SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR); + #ifdef SPANISH + PrintX=14; + PrintY=95+13; + US_Print(STR_SLOW); + PrintX=252; + US_Print(STR_FAST); + #else + PrintX=14; + PrintY=95; + US_Print(STR_SLOW); + PrintX=269; + US_Print(STR_FAST); + #endif +#endif + + VWB_Bar(60,97,200,10,TEXTCOLOR); + DrawOutline(60,97,200,10,0,HIGHLIGHT); + DrawOutline(60+20*mouseadjustment,97,20,10,0,READCOLOR); + VWB_Bar(61+20*mouseadjustment,98,19,9,READHCOLOR); + + VW_UpdateScreen(); + MenuFadeIn(); +} + + +/////////////////////////// +// +// ADJUST MOUSE SENSITIVITY +// +void MouseSensitivity(void) +{ + ControlInfo ci; + int exit=0,oldMA; + + + oldMA=mouseadjustment; + DrawMouseSens(); + do + { + ReadAnyControl(&ci); + switch(ci.dir) + { + case dir_North: + case dir_West: + if (mouseadjustment) + { + mouseadjustment--; + VWB_Bar(60,97,200,10,TEXTCOLOR); + DrawOutline(60,97,200,10,0,HIGHLIGHT); + DrawOutline(60+20*mouseadjustment,97,20,10,0,READCOLOR); + VWB_Bar(61+20*mouseadjustment,98,19,9,READHCOLOR); + VW_UpdateScreen(); + SD_PlaySound(MOVEGUN1SND); + while(Keyboard[sc_LeftArrow]); + WaitKeyUp(); + } + break; + + case dir_South: + case dir_East: + if (mouseadjustment<9) + { + mouseadjustment++; + VWB_Bar(60,97,200,10,TEXTCOLOR); + DrawOutline(60,97,200,10,0,HIGHLIGHT); + DrawOutline(60+20*mouseadjustment,97,20,10,0,READCOLOR); + VWB_Bar(61+20*mouseadjustment,98,19,9,READHCOLOR); + VW_UpdateScreen(); + SD_PlaySound(MOVEGUN1SND); + while(Keyboard[sc_RightArrow]); + WaitKeyUp(); + } + break; + } + + #ifndef SPEAR + if (Keyboard[sc_Tab] && Keyboard[sc_P] && MS_CheckParm("goobers")) + #else + if (Keyboard[sc_Tab] && Keyboard[sc_P] && MS_CheckParm("debugmode")) + #endif + PicturePause(); + + if (ci.button0 || Keyboard[sc_Space] || Keyboard[sc_Enter]) + exit=1; + else + if (ci.button1 || Keyboard[sc_Escape]) + exit=2; + + } while(!exit); + + if (exit==2) + { + mouseadjustment=oldMA; + SD_PlaySound(ESCPRESSEDSND); + } + else + SD_PlaySound(SHOOTSND); + + WaitKeyUp(); + MenuFadeOut(); +} + + +/////////////////////////// +// +// DRAW CONTROL MENU SCREEN +// +void DrawCtlScreen(void) +{ + int i,x,y; + + +#ifdef JAPAN + CA_CacheScreen(S_CONTROLPIC); +#else + ClearMScreen(); + DrawStripes(10); + VWB_DrawPic(80,0,C_CONTROLPIC); + VWB_DrawPic(112,184,C_MOUSELBACKPIC); + DrawWindow(CTL_X-8,CTL_Y-5,CTL_W,CTL_H,BKGDCOLOR); +#endif + WindowX=0; + WindowW=320; + SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR); + + if (JoysPresent[0]) + CtlMenu[1].active= + CtlMenu[2].active= + CtlMenu[3].active=1; + + CtlMenu[2].active=CtlMenu[3].active=joystickenabled; + + if (MousePresent) + { + CtlMenu[4].active= + CtlMenu[0].active=1; + } + + CtlMenu[4].active=mouseenabled; + + + DrawMenu(&CtlItems,&CtlMenu[0]); + + + x=CTL_X+CtlItems.indent-24; + y=CTL_Y+3; + if (mouseenabled) + VWB_DrawPic(x,y,C_SELECTEDPIC); + else + VWB_DrawPic(x,y,C_NOTSELECTEDPIC); + + y=CTL_Y+16; + if (joystickenabled) + VWB_DrawPic(x,y,C_SELECTEDPIC); + else + VWB_DrawPic(x,y,C_NOTSELECTEDPIC); + + y=CTL_Y+29; + if (joystickport) + VWB_DrawPic(x,y,C_SELECTEDPIC); + else + VWB_DrawPic(x,y,C_NOTSELECTEDPIC); + + y=CTL_Y+42; + if (joypadenabled) + VWB_DrawPic(x,y,C_SELECTEDPIC); + else + VWB_DrawPic(x,y,C_NOTSELECTEDPIC); + + // + // PICK FIRST AVAILABLE SPOT + // + if (CtlItems.curpos<0 || !CtlMenu[CtlItems.curpos].active) + for (i=0;i<6;i++) + if (CtlMenu[i].active) + { + CtlItems.curpos=i; + break; + } + + DrawMenuGun(&CtlItems); + VW_UpdateScreen(); +} + + +//////////////////////////////////////////////////////////////////// +// +// CUSTOMIZE CONTROLS +// +//////////////////////////////////////////////////////////////////// +enum {FIRE,STRAFE,RUN,OPEN}; +char mbarray[4][3]={"b0","b1","b2","b3"}, + order[4]={RUN,OPEN,FIRE,STRAFE}; + + +void CustomControls(void) +{ + int which; + + + DrawCustomScreen(); + do + { + which=HandleMenu(&CusItems,&CusMenu[0],FixupCustom); + switch(which) + { + case 0: + DefineMouseBtns(); + DrawCustMouse(1); + break; + case 3: + DefineJoyBtns(); + DrawCustJoy(0); + break; + case 6: + DefineKeyBtns(); + DrawCustKeybd(0); + break; + case 8: + DefineKeyMove(); + DrawCustKeys(0); + } + } while(which>=0); + + + + MenuFadeOut(); +} + + +//////////////////////// +// +// DEFINE THE MOUSE BUTTONS +// +void DefineMouseBtns(void) +{ + CustomCtrls mouseallowed={0,1,1,1}; + EnterCtrlData(2,&mouseallowed,DrawCustMouse,PrintCustMouse,MOUSE); +} + + +//////////////////////// +// +// DEFINE THE JOYSTICK BUTTONS +// +void DefineJoyBtns(void) +{ + CustomCtrls joyallowed={1,1,1,1}; + EnterCtrlData(5,&joyallowed,DrawCustJoy,PrintCustJoy,JOYSTICK); +} + + +//////////////////////// +// +// DEFINE THE KEYBOARD BUTTONS +// +void DefineKeyBtns(void) +{ + CustomCtrls keyallowed={1,1,1,1}; + EnterCtrlData(8,&keyallowed,DrawCustKeybd,PrintCustKeybd,KEYBOARDBTNS); +} + + +//////////////////////// +// +// DEFINE THE KEYBOARD BUTTONS +// +void DefineKeyMove(void) +{ + CustomCtrls keyallowed={1,1,1,1}; + EnterCtrlData(10,&keyallowed,DrawCustKeys,PrintCustKeys,KEYBOARDMOVE); +} + + +//////////////////////// +// +// ENTER CONTROL DATA FOR ANY TYPE OF CONTROL +// +enum {FWRD,RIGHT,BKWD,LEFT}; +int moveorder[4]={LEFT,RIGHT,FWRD,BKWD}; + +void EnterCtrlData(int index,CustomCtrls *cust,void (*DrawRtn)(int),void (*PrintRtn)(int),int type) +{ + int j,exit,tick,redraw,which,x,picked; + ControlInfo ci; + + + ShootSnd(); + PrintY=CST_Y+13*index; + IN_ClearKeysDown(); + exit=0; + redraw=1; + // + // FIND FIRST SPOT IN ALLOWED ARRAY + // + for (j=0;j<4;j++) + if (cust->allowed[j]) + { + which=j; + break; + } + + do + { + if (redraw) + { + x=CST_START+CST_SPC*which; + DrawWindow(5,PrintY-1,310,13,BKGDCOLOR); + + DrawRtn(1); + DrawWindow(x-2,PrintY,CST_SPC,11,TEXTCOLOR); + DrawOutline(x-2,PrintY,CST_SPC,11,0,HIGHLIGHT); + SETFONTCOLOR(0,TEXTCOLOR); + PrintRtn(which); + PrintX=x; + SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR); + VW_UpdateScreen(); + WaitKeyUp(); + redraw=0; + } + + ReadAnyControl(&ci); + + if (type==MOUSE || type==JOYSTICK) + if (IN_KeyDown(sc_Enter)||IN_KeyDown(sc_Control)||IN_KeyDown(sc_Alt)) + { + IN_ClearKeysDown(); + ci.button0=ci.button1=false; + } + + // + // CHANGE BUTTON VALUE? + // + if ((ci.button0|ci.button1|ci.button2|ci.button3)|| + ((type==KEYBOARDBTNS||type==KEYBOARDMOVE) && LastScan==sc_Enter)) + { + tick=TimeCount=picked=0; + SETFONTCOLOR(0,TEXTCOLOR); + + do + { + int button,result=0; + + + if (type==KEYBOARDBTNS||type==KEYBOARDMOVE) + IN_ClearKeysDown(); + + // + // FLASH CURSOR + // + if (TimeCount>10) + { + switch(tick) + { + case 0: + VWB_Bar(x,PrintY+1,CST_SPC-2,10,TEXTCOLOR); + break; + case 1: + PrintX=x; + US_Print("?"); + SD_PlaySound(HITWALLSND); + } + tick^=1; + TimeCount=0; + VW_UpdateScreen(); + } + + // + // WHICH TYPE OF INPUT DO WE PROCESS? + // + switch(type) + { + case MOUSE: + Mouse(3); + button=_BX; + switch(button) + { + case 1: result=1; break; + case 2: result=2; break; + case 4: result=3; break; + } + + if (result) + { + int z; + + + for (z=0;z<4;z++) + if (order[which]==buttonmouse[z]) + { + buttonmouse[z]=bt_nobutton; + break; + } + + buttonmouse[result-1]=order[which]; + picked=1; + SD_PlaySound(SHOOTDOORSND); + } + break; + + case JOYSTICK: + if (ci.button0) result=1; + else + if (ci.button1) result=2; + else + if (ci.button2) result=3; + else + if (ci.button3) result=4; + + if (result) + { + int z; + + + for (z=0;z<4;z++) + if (order[which]==buttonjoy[z]) + { + buttonjoy[z]=bt_nobutton; + break; + } + + buttonjoy[result-1]=order[which]; + picked=1; + SD_PlaySound(SHOOTDOORSND); + } + break; + + case KEYBOARDBTNS: + if (LastScan) + { + buttonscan[order[which]]=LastScan; + picked=1; + ShootSnd(); + IN_ClearKeysDown(); + } + break; + + case KEYBOARDMOVE: + if (LastScan) + { + dirscan[moveorder[which]]=LastScan; + picked=1; + ShootSnd(); + IN_ClearKeysDown(); + } + break; + } + + // + // EXIT INPUT? + // + if (IN_KeyDown(sc_Escape)) + { + picked=1; + continue; + } + + } while(!picked); + + SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR); + redraw=1; + WaitKeyUp(); + continue; + } + + if (ci.button1 || IN_KeyDown(sc_Escape)) + exit=1; + + // + // MOVE TO ANOTHER SPOT? + // + switch(ci.dir) + { + case dir_West: + do + { + which--; + if (which<0) + which=3; + } while(!cust->allowed[which]); + redraw=1; + SD_PlaySound(MOVEGUN1SND); + while(ReadAnyControl(&ci),ci.dir!=dir_None); + IN_ClearKeysDown(); + break; + + case dir_East: + do + { + which++; + if (which>3) + which=0; + } while(!cust->allowed[which]); + redraw=1; + SD_PlaySound(MOVEGUN1SND); + while(ReadAnyControl(&ci),ci.dir!=dir_None); + IN_ClearKeysDown(); + break; + case dir_North: + case dir_South: + exit=1; + } + } while(!exit); + + SD_PlaySound(ESCPRESSEDSND); + WaitKeyUp(); + DrawWindow(5,PrintY-1,310,13,BKGDCOLOR); +} + + +//////////////////////// +// +// FIXUP GUN CURSOR OVERDRAW SHIT +// +void FixupCustom(int w) +{ + static int lastwhich=-1; + int y=CST_Y+26+w*13; + + + VWB_Hlin(7,32,y-1,DEACTIVE); + VWB_Hlin(7,32,y+12,BORD2COLOR); +#ifndef SPEAR + VWB_Hlin(7,32,y-2,BORDCOLOR); + VWB_Hlin(7,32,y+13,BORDCOLOR); +#else + VWB_Hlin(7,32,y-2,BORD2COLOR); + VWB_Hlin(7,32,y+13,BORD2COLOR); +#endif + + switch(w) + { + case 0: DrawCustMouse(1); break; + case 3: DrawCustJoy(1); break; + case 6: DrawCustKeybd(1); break; + case 8: DrawCustKeys(1); + } + + + if (lastwhich>=0) + { + y=CST_Y+26+lastwhich*13; + VWB_Hlin(7,32,y-1,DEACTIVE); + VWB_Hlin(7,32,y+12,BORD2COLOR); +#ifndef SPEAR + VWB_Hlin(7,32,y-2,BORDCOLOR); + VWB_Hlin(7,32,y+13,BORDCOLOR); +#else + VWB_Hlin(7,32,y-2,BORD2COLOR); + VWB_Hlin(7,32,y+13,BORD2COLOR); +#endif + + if (lastwhich!=w) + switch(lastwhich) + { + case 0: DrawCustMouse(0); break; + case 3: DrawCustJoy(0); break; + case 6: DrawCustKeybd(0); break; + case 8: DrawCustKeys(0); + } + } + + lastwhich=w; +} + + +//////////////////////// +// +// DRAW CUSTOMIZE SCREEN +// +void DrawCustomScreen(void) +{ + int i; + + +#ifdef JAPAN + CA_CacheScreen(S_CUSTOMPIC); + fontnumber=1; + + PrintX=CST_START; + PrintY = CST_Y+26; + DrawCustMouse(0); + + PrintX=CST_START; + US_Print("\n\n\n"); + DrawCustJoy(0); + + PrintX=CST_START; + US_Print("\n\n\n"); + DrawCustKeybd(0); + + PrintX=CST_START; + US_Print("\n\n\n"); + DrawCustKeys(0); +#else + ClearMScreen(); + WindowX=0; + WindowW=320; + VWB_DrawPic(112,184,C_MOUSELBACKPIC); + DrawStripes(10); + VWB_DrawPic(80,0,C_CUSTOMIZEPIC); + + // + // MOUSE + // + SETFONTCOLOR(READCOLOR,BKGDCOLOR); + WindowX=0; + WindowW=320; + +#ifndef SPEAR + PrintY=CST_Y; + US_CPrint("Mouse\n"); +#else + PrintY = CST_Y+13; + VWB_DrawPic (128,48,C_MOUSEPIC); +#endif + + SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR); + #ifdef SPANISH + PrintX=CST_START-16; + US_Print(STR_CRUN); + PrintX=CST_START-16+CST_SPC*1; + US_Print(STR_COPEN); + PrintX=CST_START-16+CST_SPC*2; + US_Print(STR_CFIRE); + PrintX=CST_START-16+CST_SPC*3; + US_Print(STR_CSTRAFE"\n"); + #else + PrintX=CST_START; + US_Print(STR_CRUN); + PrintX=CST_START+CST_SPC*1; + US_Print(STR_COPEN); + PrintX=CST_START+CST_SPC*2; + US_Print(STR_CFIRE); + PrintX=CST_START+CST_SPC*3; + US_Print(STR_CSTRAFE"\n"); + #endif + + DrawWindow(5,PrintY-1,310,13,BKGDCOLOR); + DrawCustMouse(0); + US_Print("\n"); + + + // + // JOYSTICK/PAD + // +#ifndef SPEAR + SETFONTCOLOR(READCOLOR,BKGDCOLOR); + US_CPrint("Joystick/Gravis GamePad\n"); +#else + PrintY += 13; + VWB_DrawPic (40,88,C_JOYSTICKPIC); +#endif + +#ifdef SPEAR + VWB_DrawPic (112,120,C_KEYBOARDPIC); +#endif + + SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR); + #ifdef SPANISH + PrintX=CST_START-16; + US_Print(STR_CRUN); + PrintX=CST_START-16+CST_SPC*1; + US_Print(STR_COPEN); + PrintX=CST_START-16+CST_SPC*2; + US_Print(STR_CFIRE); + PrintX=CST_START-16+CST_SPC*3; + US_Print(STR_CSTRAFE"\n"); + #else + PrintX=CST_START; + US_Print(STR_CRUN); + PrintX=CST_START+CST_SPC*1; + US_Print(STR_COPEN); + PrintX=CST_START+CST_SPC*2; + US_Print(STR_CFIRE); + PrintX=CST_START+CST_SPC*3; + US_Print(STR_CSTRAFE"\n"); + #endif + DrawWindow(5,PrintY-1,310,13,BKGDCOLOR); + DrawCustJoy(0); + US_Print("\n"); + + + // + // KEYBOARD + // +#ifndef SPEAR + SETFONTCOLOR(READCOLOR,BKGDCOLOR); + US_CPrint("Keyboard\n"); +#else + PrintY += 13; +#endif + SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR); + #ifdef SPANISH + PrintX=CST_START-16; + US_Print(STR_CRUN); + PrintX=CST_START-16+CST_SPC*1; + US_Print(STR_COPEN); + PrintX=CST_START-16+CST_SPC*2; + US_Print(STR_CFIRE); + PrintX=CST_START-16+CST_SPC*3; + US_Print(STR_CSTRAFE"\n"); + #else + PrintX=CST_START; + US_Print(STR_CRUN); + PrintX=CST_START+CST_SPC*1; + US_Print(STR_COPEN); + PrintX=CST_START+CST_SPC*2; + US_Print(STR_CFIRE); + PrintX=CST_START+CST_SPC*3; + US_Print(STR_CSTRAFE"\n"); + #endif + DrawWindow(5,PrintY-1,310,13,BKGDCOLOR); + DrawCustKeybd(0); + US_Print("\n"); + + + // + // KEYBOARD MOVE KEYS + // + SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR); + #ifdef SPANISH + PrintX=4; + US_Print(STR_LEFT); + US_Print("/"); + US_Print(STR_RIGHT); + US_Print("/"); + US_Print(STR_FRWD); + US_Print("/"); + US_Print(STR_BKWD"\n"); + #else + PrintX=CST_START; + US_Print(STR_LEFT); + PrintX=CST_START+CST_SPC*1; + US_Print(STR_RIGHT); + PrintX=CST_START+CST_SPC*2; + US_Print(STR_FRWD); + PrintX=CST_START+CST_SPC*3; + US_Print(STR_BKWD"\n"); + #endif + DrawWindow(5,PrintY-1,310,13,BKGDCOLOR); + DrawCustKeys(0); +#endif + // + // PICK STARTING POINT IN MENU + // + if (CusItems.curpos<0) + for (i=0;i19) + newview=19; + ShowViewSize(newview); + VW_UpdateScreen(); + SD_PlaySound(HITWALLSND); + TicDelay(10); + break; + } + + #ifndef SPEAR + if (Keyboard[sc_Tab] && Keyboard[sc_P] && MS_CheckParm("goobers")) + #else + if (Keyboard[sc_Tab] && Keyboard[sc_P] && MS_CheckParm("debugmode")) + #endif + PicturePause(); + + if (ci.button0 || Keyboard[sc_Enter]) + exit=1; + else + if (ci.button1 || Keyboard[sc_Escape]) + { + viewwidth=oldview*16; + SD_PlaySound(ESCPRESSEDSND); + MenuFadeOut(); + return; + } + + } while(!exit); + + + if (oldview!=newview) + { + SD_PlaySound (SHOOTSND); + Message(STR_THINK"..."); + NewViewSize(newview); + } + + ShootSnd(); + MenuFadeOut(); +} + + +///////////////////////////// +// +// DRAW THE CHANGEVIEW SCREEN +// +void DrawChangeView(int view) +{ +#ifdef JAPAN + CA_CacheScreen(S_CHANGEPIC); + + ShowViewSize(view); +#else + VWB_Bar(0,160,320,40,VIEWCOLOR); + ShowViewSize(view); + + PrintY=161; + WindowX=0; + WindowY=320; + SETFONTCOLOR(HIGHLIGHT,BKGDCOLOR); + + US_CPrint(STR_SIZE1"\n"); + US_CPrint(STR_SIZE2"\n"); + US_CPrint(STR_SIZE3); +#endif + VW_UpdateScreen(); + + MenuFadeIn(); +} + + +//////////////////////////////////////////////////////////////////// +// +// QUIT THIS INFERNAL GAME! +// +//////////////////////////////////////////////////////////////////// +void CP_Quit(void) +{ + int i; + + + #ifdef JAPAN + if (GetYorN(7,11,C_QUITMSGPIC)) + #else + + #ifdef SPANISH + if (Confirm(ENDGAMESTR)) + #else + if (Confirm(endStrings[US_RndT()&0x7+(US_RndT()&1)])) + #endif + + #endif + { + VW_UpdateScreen(); + SD_MusicOff(); + SD_StopSound(); + MenuFadeOut(); + // + // SHUT-UP THE ADLIB + // + for (i=1;i<=0xf5;i++) + alOut(i,0); + Quit(NULL); + } + + DrawMainMenu(); +} + + +//////////////////////////////////////////////////////////////////// +// +// HANDLE INTRO SCREEN (SYSTEM CONFIG) +// +//////////////////////////////////////////////////////////////////// +void IntroScreen(void) +{ +#ifdef SPEAR + +#define MAINCOLOR 0x4f +#define EMSCOLOR 0x4f +#define XMSCOLOR 0x4f + +#else + +#define MAINCOLOR 0x6c +#define EMSCOLOR 0x6c +#define XMSCOLOR 0x6c + +#endif +#define FILLCOLOR 14 + + long memory,emshere,xmshere; + int i,num,ems[10]={100,200,300,400,500,600,700,800,900,1000}, + xms[10]={100,200,300,400,500,600,700,800,900,1000}, + main[10]={32,64,96,128,160,192,224,256,288,320}; + + + // + // DRAW MAIN MEMORY + // + memory=(1023l+mminfo.nearheap+mminfo.farheap)/1024l; + for (i=0;i<10;i++) + if (memory>=main[i]) + VWB_Bar(49,163-8*i,6,5,MAINCOLOR-i); + + + // + // DRAW EMS MEMORY + // + if (EMSPresent) + { + emshere=4l*EMSPagesAvail; + for (i=0;i<10;i++) + if (emshere>=ems[i]) + VWB_Bar(89,163-8*i,6,5,EMSCOLOR-i); + } + + // + // DRAW XMS MEMORY + // + if (XMSPresent) + { + xmshere=4l*XMSPagesAvail; + for (i=0;i<10;i++) + if (xmshere>=xms[i]) + VWB_Bar(129,163-8*i,6,5,XMSCOLOR-i); + } + + // + // FILL BOXES + // + if (MousePresent) + VWB_Bar(164,82,12,2,FILLCOLOR); + + if (JoysPresent[0] || JoysPresent[1]) + VWB_Bar(164,105,12,2,FILLCOLOR); + + if (AdLibPresent && !SoundBlasterPresent) + VWB_Bar(164,128,12,2,FILLCOLOR); + + if (SoundBlasterPresent) + VWB_Bar(164,151,12,2,FILLCOLOR); + + if (SoundSourcePresent) + VWB_Bar(164,174,12,2,FILLCOLOR); +} + + +//////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////// +// +// SUPPORT ROUTINES +// +//////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////// +// +// Clear Menu screens to dark red +// +//////////////////////////////////////////////////////////////////// +void ClearMScreen(void) +{ +#ifndef SPEAR + VWB_Bar(0,0,320,200,BORDCOLOR); +#else + VWB_DrawPic(0,0,C_BACKDROPPIC); +#endif +} + + +//////////////////////////////////////////////////////////////////// +// +// Un/Cache a LUMP of graphics +// +//////////////////////////////////////////////////////////////////// +void CacheLump(int lumpstart,int lumpend) +{ + int i; + + for (i=lumpstart;i<=lumpend;i++) + CA_CacheGrChunk(i); +} + + +void UnCacheLump(int lumpstart,int lumpend) +{ + int i; + + for (i=lumpstart;i<=lumpend;i++) + if (grsegs[i]) + UNCACHEGRCHUNK(i); +} + + +//////////////////////////////////////////////////////////////////// +// +// Draw a window for a menu +// +//////////////////////////////////////////////////////////////////// +void DrawWindow(int x,int y,int w,int h,int wcolor) +{ + VWB_Bar(x,y,w,h,wcolor); + DrawOutline(x,y,w,h,BORD2COLOR,DEACTIVE); +} + + +void DrawOutline(int x,int y,int w,int h,int color1,int color2) +{ + VWB_Hlin(x,x+w,y,color2); + VWB_Vlin(y,y+h,x,color2); + VWB_Hlin(x,x+w,y+h,color1); + VWB_Vlin(y,y+h,x+w,color1); +} + + +//////////////////////////////////////////////////////////////////// +// +// Setup Control Panel stuff - graphics, etc. +// +//////////////////////////////////////////////////////////////////// +void SetupControlPanel(void) +{ + struct ffblk f; + char name[13]; + int which,i; + + + // + // CACHE GRAPHICS & SOUNDS + // + CA_CacheGrChunk(STARTFONT+1); +#ifndef SPEAR + CacheLump(CONTROLS_LUMP_START,CONTROLS_LUMP_END); +#else + CacheLump(BACKDROP_LUMP_START,BACKDROP_LUMP_END); +#endif + + SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR); + fontnumber=1; + WindowH=200; + + if (!ingame) + CA_LoadAllSounds(); + else + MainMenu[savegame].active=1; + + // + // SEE WHICH SAVE GAME FILES ARE AVAILABLE & READ STRING IN + // + strcpy(name,SaveName); + if (!findfirst(name,&f,0)) + do + { + which=f.ff_name[7]-'0'; + if (which<10) + { + int handle; + char temp[32]; + + SaveGamesAvail[which]=1; + handle=open(f.ff_name,O_BINARY); + read(handle,temp,32); + close(handle); + strcpy(&SaveGameNames[which][0],temp); + } + } while(!findnext(&f)); + + // + // CENTER MOUSE + // + _CX=_DX=CENTER; + Mouse(4); +} + + +//////////////////////////////////////////////////////////////////// +// +// Clean up all the Control Panel stuff +// +//////////////////////////////////////////////////////////////////// +void CleanupControlPanel(void) +{ +#ifndef SPEAR + UnCacheLump(CONTROLS_LUMP_START,CONTROLS_LUMP_END); +#else + UnCacheLump (BACKDROP_LUMP_START,BACKDROP_LUMP_END); +#endif + + fontnumber = 0; +} + + +//////////////////////////////////////////////////////////////////// +// +// Handle moving gun around a menu +// +//////////////////////////////////////////////////////////////////// +int HandleMenu(CP_iteminfo *item_i,CP_itemtype far *items,void (*routine)(int w)) +{ + char key; + static int redrawitem=1,lastitem=-1; + int i,x,y,basey,exit,which,shape,timer; + ControlInfo ci; + + + which=item_i->curpos; + x=item_i->x&-8; + basey=item_i->y-2; + y=basey+which*13; + + VWB_DrawPic(x,y,C_CURSOR1PIC); + SetTextColor(items+which,1); + if (redrawitem) + { + PrintX=item_i->x+item_i->indent; + PrintY=item_i->y+which*13; + US_Print((items+which)->string); + } + // + // CALL CUSTOM ROUTINE IF IT IS NEEDED + // + if (routine) + routine(which); + VW_UpdateScreen(); + + shape=C_CURSOR1PIC; + timer=8; + exit=0; + TimeCount=0; + IN_ClearKeysDown(); + + + do + { + // + // CHANGE GUN SHAPE + // + if (TimeCount>timer) + { + TimeCount=0; + if (shape==C_CURSOR1PIC) + { + shape=C_CURSOR2PIC; + timer=8; + } + else + { + shape=C_CURSOR1PIC; + timer=70; + } + VWB_DrawPic(x,y,shape); + if (routine) + routine(which); + VW_UpdateScreen(); + } + + CheckPause(); + + // + // SEE IF ANY KEYS ARE PRESSED FOR INITIAL CHAR FINDING + // + key=LastASCII; + if (key) + { + int ok=0; + + // + // CHECK FOR SCREEN CAPTURE + // + #ifndef SPEAR + if (Keyboard[sc_Tab] && Keyboard[sc_P] && MS_CheckParm("goobers")) + #else + if (Keyboard[sc_Tab] && Keyboard[sc_P] && MS_CheckParm("debugmode")) + #endif + PicturePause(); + + + if (key>='a') + key-='a'-'A'; + + for (i=which+1;iamount;i++) + if ((items+i)->active && (items+i)->string[0]==key) + { + EraseGun(item_i,items,x,y,which); + which=i; + DrawGun(item_i,items,x,&y,which,basey,routine); + ok=1; + IN_ClearKeysDown(); + break; + } + + // + // DIDN'T FIND A MATCH FIRST TIME THRU. CHECK AGAIN. + // + if (!ok) + { + for (i=0;iactive && (items+i)->string[0]==key) + { + EraseGun(item_i,items,x,y,which); + which=i; + DrawGun(item_i,items,x,&y,which,basey,routine); + IN_ClearKeysDown(); + break; + } + } + } + + // + // GET INPUT + // + ReadAnyControl(&ci); + switch(ci.dir) + { + //////////////////////////////////////////////// + // + // MOVE UP + // + case dir_North: + + EraseGun(item_i,items,x,y,which); + + // + // ANIMATE HALF-STEP + // + if (which && (items+which-1)->active) + { + y-=6; + DrawHalfStep(x,y); + } + + // + // MOVE TO NEXT AVAILABLE SPOT + // + do + { + if (!which) + which=item_i->amount-1; + else + which--; + } while(!(items+which)->active); + + DrawGun(item_i,items,x,&y,which,basey,routine); + // + // WAIT FOR BUTTON-UP OR DELAY NEXT MOVE + // + TicDelay(20); + break; + + //////////////////////////////////////////////// + // + // MOVE DOWN + // + case dir_South: + + EraseGun(item_i,items,x,y,which); + // + // ANIMATE HALF-STEP + // + if (which!=item_i->amount-1 && (items+which+1)->active) + { + y+=6; + DrawHalfStep(x,y); + } + + do + { + if (which==item_i->amount-1) + which=0; + else + which++; + } while(!(items+which)->active); + + DrawGun(item_i,items,x,&y,which,basey,routine); + + // + // WAIT FOR BUTTON-UP OR DELAY NEXT MOVE + // + TicDelay(20); + break; + } + + if (ci.button0 || + Keyboard[sc_Space] || + Keyboard[sc_Enter]) + exit=1; + + if (ci.button1 || + Keyboard[sc_Escape]) + exit=2; + + } while(!exit); + + + IN_ClearKeysDown(); + + // + // ERASE EVERYTHING + // + if (lastitem!=which) + { + VWB_Bar(x-1,y,25,16,BKGDCOLOR); + PrintX=item_i->x+item_i->indent; + PrintY=item_i->y+which*13; + US_Print((items+which)->string); + redrawitem=1; + } + else + redrawitem=0; + + if (routine) + routine(which); + VW_UpdateScreen(); + + item_i->curpos=which; + + lastitem=which; + switch(exit) + { + case 1: + // + // CALL THE ROUTINE + // + if ((items+which)->routine!=NULL) + { + ShootSnd(); + MenuFadeOut(); + (items+which)->routine(0); + } + return which; + + case 2: + SD_PlaySound(ESCPRESSEDSND); + return -1; + } + + return 0; // JUST TO SHUT UP THE ERROR MESSAGES! +} + + +// +// ERASE GUN & DE-HIGHLIGHT STRING +// +void EraseGun(CP_iteminfo *item_i,CP_itemtype far *items,int x,int y,int which) +{ + VWB_Bar(x-1,y,25,16,BKGDCOLOR); + SetTextColor(items+which,0); + + PrintX=item_i->x+item_i->indent; + PrintY=item_i->y+which*13; + US_Print((items+which)->string); + VW_UpdateScreen(); +} + + +// +// DRAW HALF STEP OF GUN TO NEXT POSITION +// +void DrawHalfStep(int x,int y) +{ + VWB_DrawPic(x,y,C_CURSOR1PIC); + VW_UpdateScreen(); + SD_PlaySound(MOVEGUN1SND); + TimeCount=0; + while(TimeCount<8); +} + + +// +// DRAW GUN AT NEW POSITION +// +void DrawGun(CP_iteminfo *item_i,CP_itemtype far *items,int x,int *y,int which,int basey,void (*routine)(int w)) +{ + VWB_Bar(x-1,*y,25,16,BKGDCOLOR); + *y=basey+which*13; + VWB_DrawPic(x,*y,C_CURSOR1PIC); + SetTextColor(items+which,1); + + PrintX=item_i->x+item_i->indent; + PrintY=item_i->y+which*13; + US_Print((items+which)->string); + + // + // CALL CUSTOM ROUTINE IF IT IS NEEDED + // + if (routine) + routine(which); + VW_UpdateScreen(); + SD_PlaySound(MOVEGUN2SND); +} + +//////////////////////////////////////////////////////////////////// +// +// DELAY FOR AN AMOUNT OF TICS OR UNTIL CONTROLS ARE INACTIVE +// +//////////////////////////////////////////////////////////////////// +void TicDelay(int count) +{ + ControlInfo ci; + + + TimeCount=0; + do + { + ReadAnyControl(&ci); + } while(TimeCountcurpos; + + + WindowX=PrintX=item_i->x+item_i->indent; + WindowY=PrintY=item_i->y; + WindowW=320; + WindowH=200; + + for (i=0;iamount;i++) + { + SetTextColor(items+i,which==i); + + PrintY=item_i->y+i*13; + if ((items+i)->active) + US_Print((items+i)->string); + else + { + SETFONTCOLOR(DEACTIVE,BKGDCOLOR); + US_Print((items+i)->string); + SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR); + } + + US_Print("\n"); + } +} + + +//////////////////////////////////////////////////////////////////// +// +// SET TEXT COLOR (HIGHLIGHT OR NO) +// +//////////////////////////////////////////////////////////////////// +void SetTextColor(CP_itemtype far *items,int hlight) +{ + if (hlight) + {SETFONTCOLOR(color_hlite[items->active],BKGDCOLOR);} + else + {SETFONTCOLOR(color_norml[items->active],BKGDCOLOR);} +} + + +//////////////////////////////////////////////////////////////////// +// +// WAIT FOR CTRLKEY-UP OR BUTTON-UP +// +//////////////////////////////////////////////////////////////////// +void WaitKeyUp(void) +{ + ControlInfo ci; + while(ReadAnyControl(&ci), ci.button0| + ci.button1| + ci.button2| + ci.button3| + Keyboard[sc_Space]| + Keyboard[sc_Enter]| + Keyboard[sc_Escape]); +} + + +//////////////////////////////////////////////////////////////////// +// +// READ KEYBOARD, JOYSTICK AND MOUSE FOR INPUT +// +//////////////////////////////////////////////////////////////////// +void ReadAnyControl(ControlInfo *ci) +{ + int mouseactive=0; + + + IN_ReadControl(0,ci); + + if (mouseenabled) + { + int mousey,mousex; + + + // READ MOUSE MOTION COUNTERS + // RETURN DIRECTION + // HOME MOUSE + // CHECK MOUSE BUTTONS + + Mouse(3); + mousex=_CX; + mousey=_DX; + + if (mouseydir=dir_North; + _CX=_DX=CENTER; + Mouse(4); + mouseactive=1; + } + else + if (mousey>CENTER+SENSITIVE) + { + ci->dir=dir_South; + _CX=_DX=CENTER; + Mouse(4); + mouseactive=1; + } + + if (mousexdir=dir_West; + _CX=_DX=CENTER; + Mouse(4); + mouseactive=1; + } + else + if (mousex>CENTER+SENSITIVE) + { + ci->dir=dir_East; + _CX=_DX=CENTER; + Mouse(4); + mouseactive=1; + } + + if (IN_MouseButtons()) + { + ci->button0=IN_MouseButtons()&1; + ci->button1=IN_MouseButtons()&2; + ci->button2=IN_MouseButtons()&4; + ci->button3=false; + mouseactive=1; + } + } + + if (joystickenabled && !mouseactive) + { + int jx,jy,jb; + + + INL_GetJoyDelta(joystickport,&jx,&jy); + if (jy<-SENSITIVE) + ci->dir=dir_North; + else + if (jy>SENSITIVE) + ci->dir=dir_South; + + if (jx<-SENSITIVE) + ci->dir=dir_West; + else + if (jx>SENSITIVE) + ci->dir=dir_East; + + jb=IN_JoyButtons(); + if (jb) + { + ci->button0=jb&1; + ci->button1=jb&2; + if (joypadenabled) + { + ci->button2=jb&4; + ci->button3=jb&8; + } + else + ci->button2=ci->button3=false; + } + } +} + + +//////////////////////////////////////////////////////////////////// +// +// DRAW DIALOG AND CONFIRM YES OR NO TO QUESTION +// +//////////////////////////////////////////////////////////////////// +int Confirm(char far *string) +{ + int xit=0,i,x,y,tick=0,time,whichsnd[2]={ESCPRESSEDSND,SHOOTSND}; + + + Message(string); + IN_ClearKeysDown(); + + // + // BLINK CURSOR + // + x=PrintX; + y=PrintY; + TimeCount=0; + + do + { + if (TimeCount>=10) + { + switch(tick) + { + case 0: + VWB_Bar(x,y,8,13,TEXTCOLOR); + break; + case 1: + PrintX=x; + PrintY=y; + US_Print("_"); + } + VW_UpdateScreen(); + tick^=1; + TimeCount=0; + } + + #ifndef SPEAR + if (Keyboard[sc_Tab] && Keyboard[sc_P] && MS_CheckParm("goobers")) + PicturePause(); + #endif + + #ifdef SPANISH + } while(!Keyboard[sc_S] && !Keyboard[sc_N] && !Keyboard[sc_Escape]); + #else + } while(!Keyboard[sc_Y] && !Keyboard[sc_N] && !Keyboard[sc_Escape]); + #endif + + #ifdef SPANISH + if (Keyboard[sc_S]) + { + xit=1; + ShootSnd(); + } + + while(Keyboard[sc_S] || Keyboard[sc_N] || Keyboard[sc_Escape]); + + #else + + if (Keyboard[sc_Y]) + { + xit=1; + ShootSnd(); + } + + while(Keyboard[sc_Y] || Keyboard[sc_N] || Keyboard[sc_Escape]); + #endif + + IN_ClearKeysDown(); + SD_PlaySound(whichsnd[xit]); + return xit; +} + +#ifdef JAPAN +//////////////////////////////////////////////////////////////////// +// +// DRAW MESSAGE & GET Y OR N +// +//////////////////////////////////////////////////////////////////// +int GetYorN(int x,int y,int pic) +{ + int xit=0,whichsnd[2]={ESCPRESSEDSND,SHOOTSND}; + + + CA_CacheGrChunk(pic); + VWB_DrawPic(x * 8,y * 8,pic); + UNCACHEGRCHUNK(pic); + VW_UpdateScreen(); + IN_ClearKeysDown(); + + do + { + #ifndef SPEAR + if (Keyboard[sc_Tab] && Keyboard[sc_P] && MS_CheckParm("goobers")) + PicturePause(); + #endif + + #ifdef SPANISH + } while(!Keyboard[sc_S] && !Keyboard[sc_N] && !Keyboard[sc_Escape]); + #else + } while(!Keyboard[sc_Y] && !Keyboard[sc_N] && !Keyboard[sc_Escape]); + #endif + + #ifdef SPANISH + if (Keyboard[sc_S]) + { + xit=1; + ShootSnd(); + } + + while(Keyboard[sc_S] || Keyboard[sc_N] || Keyboard[sc_Escape]); + + #else + + if (Keyboard[sc_Y]) + { + xit=1; + ShootSnd(); + } + + while(Keyboard[sc_Y] || Keyboard[sc_N] || Keyboard[sc_Escape]); + #endif + + IN_ClearKeysDown(); + SD_PlaySound(whichsnd[xit]); + return xit; +} +#endif + + +//////////////////////////////////////////////////////////////////// +// +// PRINT A MESSAGE IN A WINDOW +// +//////////////////////////////////////////////////////////////////// +void Message(char far *string) +{ + int h=0,w=0,mw=0,i,x,y,time; + fontstruct _seg *font; + + + CA_CacheGrChunk (STARTFONT+1); + fontnumber=1; + font=grsegs[STARTFONT+fontnumber]; + h=font->height; + for (i=0;i<_fstrlen(string);i++) + if (string[i]=='\n') + { + if (w>mw) + mw=w; + w=0; + h+=font->height; + } + else + w+=font->width[string[i]]; + + if (w+10>mw) + mw=w+10; + + PrintY=(WindowH/2)-h/2; + PrintX=WindowX=160-mw/2; + + DrawWindow(WindowX-5,PrintY-5,mw+10,h+10,TEXTCOLOR); + DrawOutline(WindowX-5,PrintY-5,mw+10,h+10,0,HIGHLIGHT); + SETFONTCOLOR(0,TEXTCOLOR); + US_Print(string); + VW_UpdateScreen(); +} + + +//////////////////////////////////////////////////////////////////// +// +// THIS MAY BE FIXED A LITTLE LATER... +// +//////////////////////////////////////////////////////////////////// +static int lastmusic; + +void StartCPMusic(int song) +{ + musicnames chunk; + + if (audiosegs[STARTMUSIC + lastmusic]) // JDC + MM_FreePtr ((memptr *)&audiosegs[STARTMUSIC + lastmusic]); + lastmusic = song; + + SD_MusicOff(); + chunk = song; + + MM_BombOnError (false); + CA_CacheAudioChunk(STARTMUSIC + chunk); + MM_BombOnError (true); + if (mmerror) + mmerror = false; + else + { + MM_SetLock(&((memptr)audiosegs[STARTMUSIC + chunk]),true); + SD_StartMusic((MusicGroup far *)audiosegs[STARTMUSIC + chunk]); + } +} + +void FreeMusic (void) +{ + if (audiosegs[STARTMUSIC + lastmusic]) // JDC + MM_FreePtr ((memptr *)&audiosegs[STARTMUSIC + lastmusic]); +} + + +/////////////////////////////////////////////////////////////////////////// +// +// IN_GetScanName() - Returns a string containing the name of the +// specified scan code +// +/////////////////////////////////////////////////////////////////////////// +byte * +IN_GetScanName(ScanCode scan) +{ + byte **p; + ScanCode far *s; + + for (s = ExtScanCodes,p = ExtScanNames;*s;p++,s++) + if (*s == scan) + return(*p); + + return(ScanNames[scan]); +} + + +/////////////////////////////////////////////////////////////////////////// +// +// CHECK FOR PAUSE KEY (FOR MUSIC ONLY) +// +/////////////////////////////////////////////////////////////////////////// +void CheckPause(void) +{ + if (Paused) + { + switch(SoundStatus) + { + case 0: SD_MusicOn(); break; + case 1: SD_MusicOff(); break; + } + + SoundStatus^=1; + VW_WaitVBL(3); + IN_ClearKeysDown(); + Paused=false; + } +} + + +/////////////////////////////////////////////////////////////////////////// +// +// DRAW GUN CURSOR AT CORRECT POSITION IN MENU +// +/////////////////////////////////////////////////////////////////////////// +void DrawMenuGun(CP_iteminfo *iteminfo) +{ + int x,y; + + + x=iteminfo->x; + y=iteminfo->y+iteminfo->curpos*13-2; + VWB_DrawPic(x,y,C_CURSOR1PIC); +} + + +/////////////////////////////////////////////////////////////////////////// +// +// DRAW SCREEN TITLE STRIPES +// +/////////////////////////////////////////////////////////////////////////// +void DrawStripes(int y) +{ +#ifndef SPEAR + VWB_Bar(0,y,320,24,0); + VWB_Hlin(0,319,y+22,STRIPE); +#else + VWB_Bar(0,y,320,22,0); + VWB_Hlin(0,319,y+23,0); +#endif +} + +void ShootSnd(void) +{ + SD_PlaySound(SHOOTSND); +} + + +/////////////////////////////////////////////////////////////////////////// +// +// CHECK FOR EPISODES +// +/////////////////////////////////////////////////////////////////////////// +void CheckForEpisodes(void) +{ + struct ffblk f; + +// +// JAPANESE VERSION +// +#ifdef JAPAN +#ifdef JAPDEMO + if (!findfirst("*.WJ1",&f,FA_ARCH)) + { + strcpy(extension,"WJ1"); +#else + if (!findfirst("*.WJ6",&f,FA_ARCH)) + { + strcpy(extension,"WJ6"); +#endif + strcat(configname,extension); + strcat(SaveName,extension); + strcat(PageFileName,extension); + strcat(audioname,extension); + strcat(demoname,extension); + EpisodeSelect[1] = + EpisodeSelect[2] = + EpisodeSelect[3] = + EpisodeSelect[4] = + EpisodeSelect[5] = 1; + } + else + Quit("NO JAPANESE WOLFENSTEIN 3-D DATA FILES to be found!"); +#else + +// +// ENGLISH +// +#ifndef UPLOAD +#ifndef SPEAR + if (!findfirst("*.WL6",&f,FA_ARCH)) + { + strcpy(extension,"WL6"); + NewEmenu[2].active = + NewEmenu[4].active = + NewEmenu[6].active = + NewEmenu[8].active = + NewEmenu[10].active = + EpisodeSelect[1] = + EpisodeSelect[2] = + EpisodeSelect[3] = + EpisodeSelect[4] = + EpisodeSelect[5] = 1; + } + else + if (!findfirst("*.WL3",&f,FA_ARCH)) + { + strcpy(extension,"WL3"); + NewEmenu[2].active = + NewEmenu[4].active = + EpisodeSelect[1] = + EpisodeSelect[2] = 1; + } + else +#endif +#endif + + + +#ifdef SPEAR +#ifndef SPEARDEMO + if (!findfirst("*.SOD",&f,FA_ARCH)) + { + strcpy(extension,"SOD"); + } + else + Quit("NO SPEAR OF DESTINY DATA FILES TO BE FOUND!"); +#else + if (!findfirst("*.SDM",&f,FA_ARCH)) + { + strcpy(extension,"SDM"); + } + else + Quit("NO SPEAR OF DESTINY DEMO DATA FILES TO BE FOUND!"); +#endif + +#else + if (!findfirst("*.WL1",&f,FA_ARCH)) + { + strcpy(extension,"WL1"); + } + else + Quit("NO WOLFENSTEIN 3-D DATA FILES to be found!"); +#endif + + strcat(configname,extension); + strcat(SaveName,extension); + strcat(PageFileName,extension); + strcat(audioname,extension); + strcat(demoname,extension); +#ifndef SPEAR +#ifndef GOODTIMES + strcat(helpfilename,extension); +#endif + strcat(endfilename,extension); +#endif +#endif +} diff --git a/16/sod8086/wl_menu.h b/16/sod8086/wl_menu.h new file mode 100755 index 00000000..dc03400c --- /dev/null +++ b/16/sod8086/wl_menu.h @@ -0,0 +1,234 @@ +// +// WL_MENU.H +// +#ifdef SPEAR + +#define BORDCOLOR 0x99 +#define BORD2COLOR 0x93 +#define DEACTIVE 0x9b +#define BKGDCOLOR 0x9d +//#define STRIPE 0x9c + +#define MenuFadeOut() VL_FadeOut(0,255,0,0,51,10) + +#else + +#define BORDCOLOR 0x29 +#define BORD2COLOR 0x23 +#define DEACTIVE 0x2b +#define BKGDCOLOR 0x2d +#define STRIPE 0x2c + +#define MenuFadeOut() VL_FadeOut(0,255,43,0,0,10) + +#endif + +#define READCOLOR 0x4a +#define READHCOLOR 0x47 +#define VIEWCOLOR 0x7f +#define TEXTCOLOR 0x17 +#define HIGHLIGHT 0x13 +#define MenuFadeIn() VL_FadeIn(0,255,&gamepal,10) + + +#define MENUSONG WONDERIN_MUS + +#ifndef SPEAR +#define INTROSONG NAZI_NOR_MUS +#else +#define INTROSONG XTOWER2_MUS +#endif + +#define SENSITIVE 60 +#define CENTER SENSITIVE*2 + +#define MENU_X 76 +#define MENU_Y 55 +#define MENU_W 178 +#ifndef SPEAR +#define MENU_H 13*10+6 +#else +#define MENU_H 13*9+6 +#endif + +#define SM_X 48 +#define SM_W 250 + +#define SM_Y1 20 +#define SM_H1 4*13-7 +#define SM_Y2 SM_Y1+5*13 +#define SM_H2 4*13-7 +#define SM_Y3 SM_Y2+5*13 +#define SM_H3 3*13-7 + +#define CTL_X 24 +#define CTL_Y 70 +#define CTL_W 284 +#define CTL_H 13*7-7 + +#define LSM_X 85 +#define LSM_Y 55 +#define LSM_W 175 +#define LSM_H 10*13+10 + +#define NM_X 50 +#define NM_Y 100 +#define NM_W 225 +#define NM_H 13*4+15 + +#define NE_X 10 +#define NE_Y 23 +#define NE_W 320-NE_X*2 +#define NE_H 200-NE_Y*2 + +#define CST_X 20 +#define CST_Y 48 +#define CST_START 60 +#define CST_SPC 60 + + +// +// TYPEDEFS +// +typedef struct { + int x,y,amount,curpos,indent; + } CP_iteminfo; + +typedef struct { + int active; + char string[36]; + void (* routine)(int temp1); + } CP_itemtype; + +typedef struct { + int allowed[4]; + } CustomCtrls; + +extern CP_itemtype far MainMenu[],far NewEMenu[]; +extern CP_iteminfo MainItems; + +// +// FUNCTION PROTOTYPES +// +void SetupControlPanel(void); +void CleanupControlPanel(void); + +void DrawMenu(CP_iteminfo *item_i,CP_itemtype far *items); +int HandleMenu(CP_iteminfo *item_i, + CP_itemtype far *items, + void (*routine)(int w)); +void ClearMScreen(void); +void DrawWindow(int x,int y,int w,int h,int wcolor); +void DrawOutline(int x,int y,int w,int h,int color1,int color2); +void WaitKeyUp(void); +void ReadAnyControl(ControlInfo *ci); +void TicDelay(int count); +void CacheLump(int lumpstart,int lumpend); +void UnCacheLump(int lumpstart,int lumpend); +void StartCPMusic(int song); +int Confirm(char far *string); +void Message(char far *string); +void CheckPause(void); +void ShootSnd(void); +void CheckSecretMissions(void); +void BossKey(void); + +void DrawGun(CP_iteminfo *item_i,CP_itemtype far *items,int x,int *y,int which,int basey,void (*routine)(int w)); +void DrawHalfStep(int x,int y); +void EraseGun(CP_iteminfo *item_i,CP_itemtype far *items,int x,int y,int which); +void SetTextColor(CP_itemtype far *items,int hlight); +void DrawMenuGun(CP_iteminfo *iteminfo); +void DrawStripes(int y); + +void DefineMouseBtns(void); +void DefineJoyBtns(void); +void DefineKeyBtns(void); +void DefineKeyMove(void); +void EnterCtrlData(int index,CustomCtrls *cust,void (*DrawRtn)(int),void (*PrintRtn)(int),int type); + +void DrawMainMenu(void); +void DrawSoundMenu(void); +void DrawLoadSaveScreen(int loadsave); +void DrawNewEpisode(void); +void DrawNewGame(void); +void DrawChangeView(int view); +void DrawMouseSens(void); +void DrawCtlScreen(void); +void DrawCustomScreen(void); +void DrawLSAction(int which); +void DrawCustMouse(int hilight); +void DrawCustJoy(int hilight); +void DrawCustKeybd(int hilight); +void DrawCustKeys(int hilight); +void PrintCustMouse(int i); +void PrintCustJoy(int i); +void PrintCustKeybd(int i); +void PrintCustKeys(int i); + +void PrintLSEntry(int w,int color); +void TrackWhichGame(int w); +void DrawNewGameDiff(int w); +void FixupCustom(int w); + +void CP_NewGame(void); +void CP_Sound(void); +int CP_LoadGame(int quick); +int CP_SaveGame(int quick); +void CP_Control(void); +void CP_ChangeView(void); +void CP_ExitOptions(void); +void CP_Quit(void); +void CP_ViewScores(void); +int CP_EndGame(void); +int CP_CheckQuick(unsigned scancode); +void CustomControls(void); +void MouseSensitivity(void); + +void CheckForEpisodes(void); + +// +// VARIABLES +// +extern int SaveGamesAvail[10],StartGame,SoundStatus; +extern char SaveGameNames[10][32],SaveName[13]; + +enum {MOUSE,JOYSTICK,KEYBOARDBTNS,KEYBOARDMOVE}; // FOR INPUT TYPES + +#ifndef USO_FIX1 +extern +#endif +enum +{ + newgame, + soundmenu, + control, + loadgame, + savegame, + changeview, + +#ifndef GOODTIMES +#ifndef SPEAR + readthis, +#endif +#endif + + viewscores, + backtodemo, + quit +} menuitems; + +// +// WL_INTER +// +typedef struct { + int kill,secret,treasure; + long time; + } LRstruct; + +extern LRstruct LevelRatios[]; + +void Write (int x,int y,char *string); +void NonShareware(void); +int GetYorN(int x,int y,int pic); + + diff --git a/16/sod8086/wl_play.c b/16/sod8086/wl_play.c new file mode 100755 index 00000000..447c8937 --- /dev/null +++ b/16/sod8086/wl_play.c @@ -0,0 +1,1473 @@ +// WL_PLAY.C + +#include "WL_DEF.H" +#pragma hdrstop + + +/* +============================================================================= + + LOCAL CONSTANTS + +============================================================================= +*/ + +#define sc_Question 0x35 + +/* +============================================================================= + + GLOBAL VARIABLES + +============================================================================= +*/ + +boolean madenoise; // true when shooting or screaming + +exit_t playstate; + +int DebugOk; + +objtype objlist[MAXACTORS],*new,*obj,*player,*lastobj, + *objfreelist,*killerobj; + +unsigned farmapylookup[MAPSIZE]; +byte *nearmapylookup[MAPSIZE]; + +boolean singlestep,godmode,noclip; +int extravbls; + +byte tilemap[MAPSIZE][MAPSIZE]; // wall values only +byte spotvis[MAPSIZE][MAPSIZE]; +objtype *actorat[MAPSIZE][MAPSIZE]; + +// +// replacing refresh manager +// +unsigned mapwidth,mapheight,tics; +boolean compatability; +byte *updateptr; +unsigned mapwidthtable[64]; +unsigned uwidthtable[UPDATEHIGH]; +unsigned blockstarts[UPDATEWIDE*UPDATEHIGH]; +//uso: replace: byte update[UPDATESIZE]; +//uso: is needed? byte update[UPDATEHIGH][UPDATEWIDE]; + +// +// control info +// +boolean mouseenabled,joystickenabled,joypadenabled,joystickprogressive; +int joystickport; +int dirscan[4] = {sc_UpArrow,sc_RightArrow,sc_DownArrow,sc_LeftArrow}; +int buttonscan[NUMBUTTONS] = + {sc_Control,sc_Alt,sc_RShift,sc_Space,sc_1,sc_2,sc_3,sc_4}; +int buttonmouse[4]={bt_attack,bt_strafe,bt_use,bt_nobutton}; +int buttonjoy[4]={bt_attack,bt_strafe,bt_use,bt_run}; + +int viewsize; + +boolean buttonheld[NUMBUTTONS]; + +boolean demorecord,demoplayback; +char far *demoptr, far *lastdemoptr; +memptr demobuffer; + +// +// curent user input +// +int controlx,controly; // range from -100 to 100 per tic +boolean buttonstate[NUMBUTTONS]; + + + +//=========================================================================== + + +void CenterWindow(word w,word h); +void InitObjList (void); +void RemoveObj (objtype *gone); +void PollControls (void); +void StopMusic(void); +void StartMusic(void); +void PlayLoop (void); + +/* +============================================================================= + + LOCAL VARIABLES + +============================================================================= +*/ + + +objtype dummyobj; + +// +// LIST OF SONGS FOR EACH VERSION +// +int songs[]= +{ +#ifndef SPEAR + // + // Episode One + // + GETTHEM_MUS, + SEARCHN_MUS, + POW_MUS, + SUSPENSE_MUS, + GETTHEM_MUS, + SEARCHN_MUS, + POW_MUS, + SUSPENSE_MUS, + + WARMARCH_MUS, // Boss level + CORNER_MUS, // Secret level + + // + // Episode Two + // + NAZI_OMI_MUS, + PREGNANT_MUS, + GOINGAFT_MUS, + HEADACHE_MUS, + NAZI_OMI_MUS, + PREGNANT_MUS, + HEADACHE_MUS, + GOINGAFT_MUS, + + WARMARCH_MUS, // Boss level + DUNGEON_MUS, // Secret level + + // + // Episode Three + // + INTROCW3_MUS, + NAZI_RAP_MUS, + TWELFTH_MUS, + ZEROHOUR_MUS, + INTROCW3_MUS, + NAZI_RAP_MUS, + TWELFTH_MUS, + ZEROHOUR_MUS, + + ULTIMATE_MUS, // Boss level + PACMAN_MUS, // Secret level + + // + // Episode Four + // + GETTHEM_MUS, + SEARCHN_MUS, + POW_MUS, + SUSPENSE_MUS, + GETTHEM_MUS, + SEARCHN_MUS, + POW_MUS, + SUSPENSE_MUS, + + WARMARCH_MUS, // Boss level + CORNER_MUS, // Secret level + + // + // Episode Five + // + NAZI_OMI_MUS, + PREGNANT_MUS, + GOINGAFT_MUS, + HEADACHE_MUS, + NAZI_OMI_MUS, + PREGNANT_MUS, + HEADACHE_MUS, + GOINGAFT_MUS, + + WARMARCH_MUS, // Boss level + DUNGEON_MUS, // Secret level + + // + // Episode Six + // + INTROCW3_MUS, + NAZI_RAP_MUS, + TWELFTH_MUS, + ZEROHOUR_MUS, + INTROCW3_MUS, + NAZI_RAP_MUS, + TWELFTH_MUS, + ZEROHOUR_MUS, + + ULTIMATE_MUS, // Boss level + FUNKYOU_MUS // Secret level +#else + + ////////////////////////////////////////////////////////////// + // + // SPEAR OF DESTINY TRACKS + // + ////////////////////////////////////////////////////////////// + XTIPTOE_MUS, + XFUNKIE_MUS, + XDEATH_MUS, + XGETYOU_MUS, // DON'T KNOW + ULTIMATE_MUS, // Trans Gr”sse + + DUNGEON_MUS, + GOINGAFT_MUS, + POW_MUS, + TWELFTH_MUS, + ULTIMATE_MUS, // Barnacle Wilhelm BOSS + + NAZI_OMI_MUS, + GETTHEM_MUS, + SUSPENSE_MUS, + SEARCHN_MUS, + ZEROHOUR_MUS, + ULTIMATE_MUS, // Super Mutant BOSS + + XPUTIT_MUS, + ULTIMATE_MUS, // Death Knight BOSS + + XJAZNAZI_MUS, // Secret level + XFUNKIE_MUS, // Secret level (DON'T KNOW) + + XEVIL_MUS // Angel of Death BOSS + +#endif +}; + + +/* +============================================================================= + + USER CONTROL + +============================================================================= +*/ + + +#define BASEMOVE 35 +#define RUNMOVE 70 +#define BASETURN 35 +#define RUNTURN 70 + +#define JOYSCALE 2 + +/* +=================== += += PollKeyboardButtons += +=================== +*/ + +void PollKeyboardButtons (void) +{ + int i; + + for (i=0;i 64) + controlx += (joyx-64)*JOYSCALE*tics; + else if (joyx < -64) + controlx -= (-joyx-64)*JOYSCALE*tics; + if (joyy > 64) + controlx += (joyy-64)*JOYSCALE*tics; + else if (joyy < -64) + controly -= (-joyy-64)*JOYSCALE*tics; + } + else if (buttonstate[bt_run]) + { + if (joyx > 64) + controlx += RUNMOVE*tics; + else if (joyx < -64) + controlx -= RUNMOVE*tics; + if (joyy > 64) + controly += RUNMOVE*tics; + else if (joyy < -64) + controly -= RUNMOVE*tics; + } + else + { + if (joyx > 64) + controlx += BASEMOVE*tics; + else if (joyx < -64) + controlx -= BASEMOVE*tics; + if (joyy > 64) + controly += BASEMOVE*tics; + else if (joyy < -64) + controly -= BASEMOVE*tics; + } +} + + +/* +=================== += += PollControls += += Gets user or demo input, call once each frame += += controlx set between -100 and 100 per tic += controly += buttonheld[] the state of the buttons LAST frame += buttonstate[] the state of the buttons THIS frame += +=================== +*/ + +void PollControls (void) +{ + int max,min,i; + byte buttonbits; + +// +// get timing info for last frame +// + if (demoplayback) + { + while (TimeCount>= 1; + } + + controlx = *demoptr++; + controly = *demoptr++; + + if (demoptr == lastdemoptr) + playstate = ex_completed; // demo is done + + controlx *= (int)tics; + controly *= (int)tics; + + return; + } + + +// +// get button states +// + PollKeyboardButtons (); + + if (mouseenabled) + PollMouseButtons (); + + if (joystickenabled) + PollJoystickButtons (); + +// +// get movements +// + PollKeyboardMove (); + + if (mouseenabled) + PollMouseMove (); + + if (joystickenabled) + PollJoystickMove (); + +// +// bound movement to a maximum +// + max = 100*tics; + min = -max; + if (controlx > max) + controlx = max; + else if (controlx < min) + controlx = min; + + if (controly > max) + controly = max; + else if (controly < min) + controly = min; + + if (demorecord) + { + // + // save info out to demo buffer + // + controlx /= (int)tics; + controly /= (int)tics; + + buttonbits = 0; + + for (i=NUMBUTTONS-1;i>=0;i--) + { + buttonbits <<= 1; + if (buttonstate[i]) + buttonbits |= 1; + } + + *demoptr++ = buttonbits; + *demoptr++ = controlx; + *demoptr++ = controly; + + if (demoptr >= lastdemoptr) + Quit ("Demo buffer overflowed!"); + + controlx *= (int)tics; + controly *= (int)tics; + } +} + + + +//========================================================================== + + + +/////////////////////////////////////////////////////////////////////////// +// +// CenterWindow() - Generates a window of a given width & height in the +// middle of the screen +// +/////////////////////////////////////////////////////////////////////////// + +#define MAXX 320 +#define MAXY 160 + +void CenterWindow(word w,word h) +{ + FixOfs (); + US_DrawWindow(((MAXX / 8) - w) / 2,((MAXY / 8) - h) / 2,w,h); +} + +//=========================================================================== + + +/* +===================== += += CheckKeys += +===================== +*/ + +void CheckKeys (void) +{ + int i; + byte scan; + unsigned temp; + + + if (screenfaded || demoplayback) // don't do anything with a faded screen + return; + + scan = LastScan; + + + #ifdef SPEAR + // + // SECRET CHEAT CODE: TAB-G-F10 + // + if (Keyboard[sc_Tab] && + Keyboard[sc_G] && + Keyboard[sc_F10]) + { + WindowH = 160; + if (godmode) + { + Message ("God mode OFF"); + SD_PlaySound (NOBONUSSND); + } + else + { + Message ("God mode ON"); + SD_PlaySound (ENDBONUS2SND); + } + + IN_Ack(); + godmode ^= 1; + DrawAllPlayBorderSides (); + IN_ClearKeysDown(); + return; + } + #endif + + + // + // SECRET CHEAT CODE: 'MLI' + // + if (Keyboard[sc_M] && + Keyboard[sc_L] && + Keyboard[sc_I]) + { + gamestate.health = 100; + gamestate.ammo = 99; + gamestate.keys = 3; + gamestate.score = 0; + gamestate.TimeCount += 42000L; + GiveWeapon (wp_chaingun); + + DrawWeapon(); + DrawHealth(); + DrawKeys(); + DrawAmmo(); + DrawScore(); + + ClearMemory (); + CA_CacheGrChunk (STARTFONT+1); + ClearSplitVWB (); + VW_ScreenToScreen (displayofs,bufferofs,80,160); + + Message(STR_CHEATER1"\n" + STR_CHEATER2"\n\n" + STR_CHEATER3"\n" + STR_CHEATER4"\n" + STR_CHEATER5); + + UNCACHEGRCHUNK(STARTFONT+1); + PM_CheckMainMem (); + IN_ClearKeysDown(); + IN_Ack(); + + DrawAllPlayBorder (); + } + + // + // OPEN UP DEBUG KEYS + // +#ifndef SPEAR + if (Keyboard[sc_BackSpace] && + Keyboard[sc_LShift] && + Keyboard[sc_Alt] && + MS_CheckParm("goobers")) +#else + if (Keyboard[sc_BackSpace] && + Keyboard[sc_LShift] && + Keyboard[sc_Alt] && + MS_CheckParm("debugmode")) +#endif + { + ClearMemory (); + CA_CacheGrChunk (STARTFONT+1); + ClearSplitVWB (); + VW_ScreenToScreen (displayofs,bufferofs,80,160); + + Message("Debugging keys are\nnow available!"); + UNCACHEGRCHUNK(STARTFONT+1); + PM_CheckMainMem (); + IN_ClearKeysDown(); + IN_Ack(); + + DrawAllPlayBorderSides (); + DebugOk=1; + } + + // + // TRYING THE KEEN CHEAT CODE! + // + if (Keyboard[sc_B] && + Keyboard[sc_A] && + Keyboard[sc_T]) + { + ClearMemory (); + CA_CacheGrChunk (STARTFONT+1); + ClearSplitVWB (); + VW_ScreenToScreen (displayofs,bufferofs,80,160); + + Message("Commander Keen is also\n" + "available from Apogee, but\n" + "then, you already know\n" + "that - right, Cheatmeister?!"); + + UNCACHEGRCHUNK(STARTFONT+1); + PM_CheckMainMem (); + IN_ClearKeysDown(); + IN_Ack(); + + DrawAllPlayBorder (); + } + +// +// pause key weirdness can't be checked as a scan code +// + if (Paused) + { + bufferofs = displayofs; + LatchDrawPic (20-4,80-2*8,PAUSEDPIC); + SD_MusicOff(); + IN_Ack(); + IN_ClearKeysDown (); + SD_MusicOn(); + Paused = false; + if (MousePresent) + Mouse(MDelta); // Clear accumulated mouse movement + return; + } + + +// +// F1-F7/ESC to enter control panel +// + if ( +#ifndef DEBCHECK + scan == sc_F10 || +#endif + scan == sc_F9 || + scan == sc_F7 || + scan == sc_F8) // pop up quit dialog + { + ClearMemory (); + ClearSplitVWB (); + VW_ScreenToScreen (displayofs,bufferofs,80,160); + US_ControlPanel(scan); + + DrawAllPlayBorderSides (); + + if (scan == sc_F9) + StartMusic (); + + PM_CheckMainMem (); + SETFONTCOLOR(0,15); + IN_ClearKeysDown(); + return; + } + + if ( (scan >= sc_F1 && scan <= sc_F9) || scan == sc_Escape) + { + StopMusic (); + ClearMemory (); + VW_FadeOut (); + + US_ControlPanel(scan); + + SETFONTCOLOR(0,15); + IN_ClearKeysDown(); + DrawPlayScreen (); + if (!startgame && !loadedgame) + { + VW_FadeIn (); + StartMusic (); + } + if (loadedgame) + playstate = ex_abort; + lasttimecount = TimeCount; + if (MousePresent) + Mouse(MDelta); // Clear accumulated mouse movement + PM_CheckMainMem (); + return; + } + +// +// TAB-? debug keys +// + if (Keyboard[sc_Tab] && DebugOk) + { + CA_CacheGrChunk (STARTFONT); + fontnumber=0; + SETFONTCOLOR(0,15); + DebugKeys(); + if (MousePresent) + Mouse(MDelta); // Clear accumulated mouse movement + lasttimecount = TimeCount; + return; + } + +} + + +//=========================================================================== + +/* +############################################################################# + + The objlist data structure + +############################################################################# + +objlist containt structures for every actor currently playing. The structure +is accessed as a linked list starting at *player, ending when ob->next == +NULL. GetNewObj inserts a new object at the end of the list, meaning that +if an actor spawn another actor, the new one WILL get to think and react the +same frame. RemoveObj unlinks the given object and returns it to the free +list, but does not damage the objects ->next pointer, so if the current object +removes itself, a linked list following loop can still safely get to the +next element. + + + +############################################################################# +*/ + + +/* +========================= += += InitActorList += += Call to clear out the actor object lists returning them all to the free += list. Allocates a special spot for the player. += +========================= +*/ + +int objcount; + +void InitActorList (void) +{ + int i; + +// +// init the actor lists +// + for (i=0;iprev; + memset (new,0,sizeof(*new)); + + if (lastobj) + lastobj->next = new; + new->prev = lastobj; // new->next is allready NULL from memset + + new->active = false; + lastobj = new; + + objcount++; +} + +//=========================================================================== + +/* +========================= += += RemoveObj += += Add the given object back into the free list, and unlink it from it's += neighbors += +========================= +*/ + +void RemoveObj (objtype *gone) +{ + objtype **spotat; + + if (gone == player) + Quit ("RemoveObj: Tried to remove the player!"); + + gone->state = NULL; + +// +// fix the next object's back link +// + if (gone == lastobj) + lastobj = (objtype *)gone->prev; + else + gone->next->prev = gone->prev; + +// +// fix the previous object's forward link +// + gone->prev->next = gone->next; + +// +// add it back in to the free list +// + gone->prev = objfreelist; + objfreelist = gone; + + objcount--; +} + +/* +============================================================================= + + MUSIC STUFF + +============================================================================= +*/ + + +/* +================= += += StopMusic += +================= +*/ + +void StopMusic(void) +{ + int i; + + SD_MusicOff(); + for (i = 0;i < LASTMUSIC;i++) + if (audiosegs[STARTMUSIC + i]) + { + MM_SetPurge(&((memptr)audiosegs[STARTMUSIC + i]),3); + MM_SetLock(&((memptr)audiosegs[STARTMUSIC + i]),false); + } +} + +//========================================================================== + + +/* +================= += += StartMusic += +================= +*/ + +void StartMusic(void) +{ + musicnames chunk; + + SD_MusicOff(); + chunk = songs[gamestate.mapon+gamestate.episode*10]; + +// if ((chunk == -1) || (MusicMode != smm_AdLib)) +//DEBUG control panel return; + + MM_BombOnError (false); + CA_CacheAudioChunk(STARTMUSIC + chunk); + MM_BombOnError (true); + if (mmerror) + mmerror = false; + else + { + MM_SetLock(&((memptr)audiosegs[STARTMUSIC + chunk]),true); + SD_StartMusic((MusicGroup far *)audiosegs[STARTMUSIC + chunk]); + } +} + + +/* +============================================================================= + + PALETTE SHIFTING STUFF + +============================================================================= +*/ + +#define NUMREDSHIFTS 6 +#define REDSTEPS 8 + +#define NUMWHITESHIFTS 3 +#define WHITESTEPS 20 +#define WHITETICS 6 + + +byte far redshifts[NUMREDSHIFTS][768]; +byte far whiteshifts[NUMREDSHIFTS][768]; + +int damagecount,bonuscount; +boolean palshifted; + +extern byte far gamepal; + +/* +===================== += += InitRedShifts += +===================== +*/ + +void InitRedShifts (void) +{ + byte far *workptr, far *baseptr; + int i,j,delta; + + +// +// fade through intermediate frames +// + for (i=1;i<=NUMREDSHIFTS;i++) + { + workptr = (byte far *)&redshifts[i-1][0]; + baseptr = &gamepal; + + for (j=0;j<=255;j++) + { + delta = 64-*baseptr; + *workptr++ = *baseptr++ + delta * i / REDSTEPS; + delta = -*baseptr; + *workptr++ = *baseptr++ + delta * i / REDSTEPS; + delta = -*baseptr; + *workptr++ = *baseptr++ + delta * i / REDSTEPS; + } + } + + for (i=1;i<=NUMWHITESHIFTS;i++) + { + workptr = (byte far *)&whiteshifts[i-1][0]; + baseptr = &gamepal; + + for (j=0;j<=255;j++) + { + delta = 64-*baseptr; + *workptr++ = *baseptr++ + delta * i / WHITESTEPS; + delta = 62-*baseptr; + *workptr++ = *baseptr++ + delta * i / WHITESTEPS; + delta = 0-*baseptr; + *workptr++ = *baseptr++ + delta * i / WHITESTEPS; + } + } +} + + +/* +===================== += += ClearPaletteShifts += +===================== +*/ + +void ClearPaletteShifts (void) +{ + bonuscount = damagecount = 0; +} + + +/* +===================== += += StartBonusFlash += +===================== +*/ + +void StartBonusFlash (void) +{ + bonuscount = NUMWHITESHIFTS*WHITETICS; // white shift palette +} + + +/* +===================== += += StartDamageFlash += +===================== +*/ + +void StartDamageFlash (int damage) +{ + damagecount += damage; +} + + +/* +===================== += += UpdatePaletteShifts += +===================== +*/ + +void UpdatePaletteShifts (void) +{ + int red,white; + + if (bonuscount) + { + white = bonuscount/WHITETICS +1; + if (white>NUMWHITESHIFTS) + white = NUMWHITESHIFTS; + bonuscount -= tics; + if (bonuscount < 0) + bonuscount = 0; + } + else + white = 0; + + + if (damagecount) + { + red = damagecount/10 +1; + if (red>NUMREDSHIFTS) + red = NUMREDSHIFTS; + + damagecount -= tics; + if (damagecount < 0) + damagecount = 0; + } + else + red = 0; + + if (red) + { + VW_WaitVBL(1); + VL_SetPalette (redshifts[red-1]); + palshifted = true; + } + else if (white) + { + VW_WaitVBL(1); + VL_SetPalette (whiteshifts[white-1]); + palshifted = true; + } + else if (palshifted) + { + VW_WaitVBL(1); + VL_SetPalette (&gamepal); // back to normal + palshifted = false; + } +} + + +/* +===================== += += FinishPaletteShifts += += Resets palette to normal if needed += +===================== +*/ + +void FinishPaletteShifts (void) +{ + if (palshifted) + { + palshifted = 0; + VW_WaitVBL(1); + VL_SetPalette (&gamepal); + } +} + + +/* +============================================================================= + + CORE PLAYLOOP + +============================================================================= +*/ + + +/* +===================== += += DoActor += +===================== +*/ + +void DoActor (objtype *ob) +{ + void (*think)(objtype *); + + if (!ob->active && !areabyplayer[ob->areanumber]) + return; + + if (!(ob->flags&(FL_NONMARK|FL_NEVERMARK)) ) + actorat[ob->tilex][ob->tiley] = NULL; + +// +// non transitional object +// + + if (!ob->ticcount) + { + think = ob->state->think; + if (think) + { + think (ob); + if (!ob->state) + { + RemoveObj (ob); + return; + } + } + + if (ob->flags&FL_NEVERMARK) + return; + + if ( (ob->flags&FL_NONMARK) && actorat[ob->tilex][ob->tiley]) + return; + + actorat[ob->tilex][ob->tiley] = ob; + return; + } + +// +// transitional object +// + ob->ticcount-=tics; + while ( ob->ticcount <= 0) + { + think = ob->state->action; // end of state action + if (think) + { + think (ob); + if (!ob->state) + { + RemoveObj (ob); + return; + } + } + + ob->state = ob->state->next; + + if (!ob->state) + { + RemoveObj (ob); + return; + } + + if (!ob->state->tictime) + { + ob->ticcount = 0; + goto think; + } + + ob->ticcount += ob->state->tictime; + } + +think: + // + // think + // + think = ob->state->think; + if (think) + { + think (ob); + if (!ob->state) + { + RemoveObj (ob); + return; + } + } + + if (ob->flags&FL_NEVERMARK) + return; + + if ( (ob->flags&FL_NONMARK) && actorat[ob->tilex][ob->tiley]) + return; + + actorat[ob->tilex][ob->tiley] = ob; +} + +//========================================================================== + + +/* +=================== += += PlayLoop += +=================== +*/ +long funnyticount; + + +void PlayLoop (void) +{ + int give; + int helmetangle; + + playstate = TimeCount = lasttimecount = 0; + frameon = 0; + running = false; + anglefrac = 0; + facecount = 0; + funnyticount = 0; + memset (buttonstate,0,sizeof(buttonstate)); + ClearPaletteShifts (); + + if (MousePresent) + Mouse(MDelta); // Clear accumulated mouse movement + + if (demoplayback) + IN_StartAck (); + + do + { + if (virtualreality) + { + helmetangle = peek (0x40,0xf0); + player->angle += helmetangle; + if (player->angle >= ANGLES) + player->angle -= ANGLES; + } + + + PollControls(); + +// +// actor thinking +// + madenoise = false; + + MoveDoors (); + MovePWalls (); + + for (obj = player;obj;obj = obj->next) + DoActor (obj); + + UpdatePaletteShifts (); + + ThreeDRefresh (); + + // + // MAKE FUNNY FACE IF BJ DOESN'T MOVE FOR AWHILE + // + #ifdef SPEAR + funnyticount += tics; + if (funnyticount > 30l*70) + { + funnyticount = 0; + StatusDrawPic (17,4,BJWAITING1PIC+(US_RndT()&1)); + facecount = 0; + } + #endif + + gamestate.TimeCount+=tics; + + SD_Poll (); + UpdateSoundLoc(); // JAB + + if (screenfaded) + VW_FadeIn (); + + CheckKeys(); + +// +// debug aids +// + if (singlestep) + { + VW_WaitVBL(14); + lasttimecount = TimeCount; + } + if (extravbls) + VW_WaitVBL(extravbls); + + if (demoplayback) + { + if (IN_CheckAck ()) + { + IN_ClearKeysDown (); + playstate = ex_abort; + } + } + + + if (virtualreality) + { + player->angle -= helmetangle; + if (player->angle < 0) + player->angle += ANGLES; + } + + }while (!playstate && !startgame); + + if (playstate != ex_died) + FinishPaletteShifts (); +} + diff --git a/16/sod8086/wl_scale.c b/16/sod8086/wl_scale.c new file mode 100755 index 00000000..9c1e102f --- /dev/null +++ b/16/sod8086/wl_scale.c @@ -0,0 +1,741 @@ +// WL_SCALE.C + +#include "WL_DEF.H" +#pragma hdrstop + +#define OP_RETF 0xcb + +/* +============================================================================= + + GLOBALS + +============================================================================= +*/ + +t_compscale _seg *scaledirectory[MAXSCALEHEIGHT+1]; +long fullscalefarcall[MAXSCALEHEIGHT+1]; + +int maxscale,maxscaleshl2; + +boolean insetupscaling; + +/* +============================================================================= + + LOCALS + +============================================================================= +*/ + +t_compscale _seg *work; +unsigned BuildCompScale (int height, memptr *finalspot); + +int stepbytwo; + +//=========================================================================== + +/* +============== += += BadScale += +============== +*/ + +void far BadScale (void) +{ + Quit ("BadScale called!"); +} + + +/* +========================== += += SetupScaling += +========================== +*/ + +void SetupScaling (int maxscaleheight) +{ + int i,x,y; + byte far *dest; + + insetupscaling = true; + + maxscaleheight/=2; // one scaler every two pixels + + maxscale = maxscaleheight-1; + maxscaleshl2 = maxscale<<2; + +// +// free up old scalers +// + for (i=1;i=stepbytwo) + i += 2; + } + memset (scaledirectory,0,sizeof(scaledirectory)); + + MM_SortMem (); + +// +// build the compiled scalers +// + stepbytwo = viewheight/2; // save space by double stepping + MM_GetPtr (&(memptr)work,20000); + + for (i=1;i<=maxscaleheight;i++) + { + BuildCompScale (i*2,&(memptr)scaledirectory[i]); + if (i>=stepbytwo) + i+= 2; + } + MM_FreePtr (&(memptr)work); + +// +// compact memory and lock down scalers +// + MM_SortMem (); + for (i=1;i<=maxscaleheight;i++) + { + MM_SetLock (&(memptr)scaledirectory[i],true); + fullscalefarcall[i] = (unsigned)scaledirectory[i]; + fullscalefarcall[i] <<=16; + fullscalefarcall[i] += scaledirectory[i]->codeofs[0]; + if (i>=stepbytwo) + { + scaledirectory[i+1] = scaledirectory[i]; + fullscalefarcall[i+1] = fullscalefarcall[i]; + scaledirectory[i+2] = scaledirectory[i]; + fullscalefarcall[i+2] = fullscalefarcall[i]; + i+=2; + } + } + scaledirectory[0] = scaledirectory[1]; + fullscalefarcall[0] = fullscalefarcall[1]; + +// +// check for oversize wall drawing +// + for (i=maxscaleheight;icode[0]; + toppix = (viewheight-height)/2; + fix = 0; + + for (src=0;src<=64;src++) + { + startpix = fix>>16; + fix += step; + endpix = fix>>16; + + if (endpix>startpix) + work->width[src] = endpix-startpix; + else + work->width[src] = 0; + +// +// mark the start of the code +// + work->codeofs[src] = FP_OFF(code); + +// +// compile some code if the source pixel generates any screen pixels +// + startpix+=toppix; + endpix+=toppix; + + if (startpix == endpix || endpix < 0 || startpix >= viewheight || src == 64) + continue; + + // + // mov al,[si+src] + // + *code++ = 0x8a; + *code++ = 0x44; + *code++ = src; + + for (;startpix= viewheight) + break; // off the bottom of the view area + if (startpix < 0) + continue; // not into the view area + + // + // mov [es:di+heightofs],al + // + *code++ = 0x26; + *code++ = 0x88; + *code++ = 0x85; + *((unsigned far *)code)++ = startpix*SCREENBWIDE; + } + + } + +// +// retf +// + *code++ = 0xcb; + + totalsize = FP_OFF(code); + MM_GetPtr (finalspot,totalsize); + _fmemcpy ((byte _seg *)(*finalspot),(byte _seg *)work,totalsize); + + return totalsize; +} + + +/* +======================= += += ScaleLine += += linescale should have the high word set to the segment of the scaler += +======================= +*/ + +extern int slinex,slinewidth; +extern unsigned far *linecmds; +extern long linescale; +extern unsigned maskword; + +byte mask1,mask2,mask3; + + +void near ScaleLine (void) +{ +asm mov cx,WORD PTR [linescale+2] +asm mov es,cx // segment of scaler + +asm mov bp,WORD PTR [linecmds] +asm mov dx,SC_INDEX+1 // to set SC_MAPMASK + +asm mov bx,[slinex] +asm mov di,bx +asm shr di,1 // X in bytes +asm shr di,1 +asm add di,[bufferofs] +asm and bx,3 +/* begin 8086 hack +asm shl bx,3 +*/ +asm push cx +asm mov cl,3 +asm shl bx,cl +asm pop cx +/* end 8086 hack */ +asm add bx,[slinewidth] // bx = (pixel*8+pixwidth) +asm mov al,BYTE [mapmasks3-1+bx] // -1 because pixwidth of 1 is first +asm mov ds,WORD PTR [linecmds+2] +asm or al,al +asm jz notthreebyte // scale across three bytes +asm jmp threebyte +notthreebyte: +asm mov al,BYTE PTR ss:[mapmasks2-1+bx] // -1 because pixwidth of 1 is first +asm or al,al +asm jnz twobyte // scale across two bytes + +// +// one byte scaling +// +asm mov al,BYTE PTR ss:[mapmasks1-1+bx] // -1 because pixwidth of 1 is first +asm out dx,al // set map mask register + +scalesingle: + +asm mov bx,[ds:bp] // table location of rtl to patch +asm or bx,bx +asm jz linedone // 0 signals end of segment list +asm mov bx,[es:bx] +asm mov dl,[es:bx] // save old value +asm mov BYTE PTR es:[bx],OP_RETF // patch a RETF in +asm mov si,[ds:bp+4] // table location of entry spot +asm mov ax,[es:si] +asm mov WORD PTR ss:[linescale],ax // call here to start scaling +asm mov si,[ds:bp+2] // corrected top of shape for this segment +asm add bp,6 // next segment list + +asm mov ax,SCREENSEG +asm mov es,ax +asm call ss:[linescale] // scale the segment of pixels + +asm mov es,cx // segment of scaler +asm mov BYTE PTR es:[bx],dl // unpatch the RETF +asm jmp scalesingle // do the next segment + + +// +// done +// +linedone: +asm mov ax,ss +asm mov ds,ax +return; + +// +// two byte scaling +// +twobyte: +asm mov ss:[mask2],al +asm mov al,BYTE PTR ss:[mapmasks1-1+bx] // -1 because pixwidth of 1 is first +asm mov ss:[mask1],al + +scaledouble: + +asm mov bx,[ds:bp] // table location of rtl to patch +asm or bx,bx +asm jz linedone // 0 signals end of segment list +asm mov bx,[es:bx] +asm mov cl,[es:bx] // save old value +asm mov BYTE PTR es:[bx],OP_RETF // patch a RETF in +asm mov si,[ds:bp+4] // table location of entry spot +asm mov ax,[es:si] +asm mov WORD PTR ss:[linescale],ax // call here to start scaling +asm mov si,[ds:bp+2] // corrected top of shape for this segment +asm add bp,6 // next segment list + +asm mov ax,SCREENSEG +asm mov es,ax +asm mov al,ss:[mask1] +asm out dx,al // set map mask register +asm call ss:[linescale] // scale the segment of pixels +asm inc di +asm mov al,ss:[mask2] +asm out dx,al // set map mask register +asm call ss:[linescale] // scale the segment of pixels +asm dec di + +asm mov es,WORD PTR ss:[linescale+2] // segment of scaler +asm mov BYTE PTR es:[bx],cl // unpatch the RETF +asm jmp scaledouble // do the next segment + + +// +// three byte scaling +// +threebyte: +asm mov ss:[mask3],al +asm mov al,BYTE PTR ss:[mapmasks2-1+bx] // -1 because pixwidth of 1 is first +asm mov ss:[mask2],al +asm mov al,BYTE PTR ss:[mapmasks1-1+bx] // -1 because pixwidth of 1 is first +asm mov ss:[mask1],al + +scaletriple: + +asm mov bx,[ds:bp] // table location of rtl to patch +asm or bx,bx +asm jz linedone // 0 signals end of segment list +asm mov bx,[es:bx] +asm mov cl,[es:bx] // save old value +asm mov BYTE PTR es:[bx],OP_RETF // patch a RETF in +asm mov si,[ds:bp+4] // table location of entry spot +asm mov ax,[es:si] +asm mov WORD PTR ss:[linescale],ax // call here to start scaling +asm mov si,[ds:bp+2] // corrected top of shape for this segment +asm add bp,6 // next segment list + +asm mov ax,SCREENSEG +asm mov es,ax +asm mov al,ss:[mask1] +asm out dx,al // set map mask register +asm call ss:[linescale] // scale the segment of pixels +asm inc di +asm mov al,ss:[mask2] +asm out dx,al // set map mask register +asm call ss:[linescale] // scale the segment of pixels +asm inc di +asm mov al,ss:[mask3] +asm out dx,al // set map mask register +asm call ss:[linescale] // scale the segment of pixels +asm dec di +asm dec di + +asm mov es,WORD PTR ss:[linescale+2] // segment of scaler +asm mov BYTE PTR es:[bx],cl // unpatch the RETF +asm jmp scaletriple // do the next segment + + +} + + +/* +======================= += += ScaleShape += += Draws a compiled shape at [scale] pixels high += += each vertical line of the shape has a pointer to segment data: += end of segment pixel*2 (0 terminates line) used to patch rtl in scaler += top of virtual line with segment in proper place += start of segment pixel*2, used to jsl into compiled scaler += += += Setup for call += -------------- += GC_MODE read mode 1, write mode 2 += GC_COLORDONTCARE set to 0, so all reads from video memory return 0xff += GC_INDEX pointing at GC_BITMASK += +======================= +*/ + +static long longtemp; + +void ScaleShape (int xcenter, int shapenum, unsigned height) +{ + t_compshape _seg *shape; + t_compscale _seg *comptable; + unsigned scale,srcx,stopx,tempx; + int t; + unsigned far *cmdptr; + boolean leftvis,rightvis; + + + shape = PM_GetSpritePage (shapenum); + + scale = height>>3; // low three bits are fractional + if (!scale || scale>maxscale) + return; // too close or far away + comptable = scaledirectory[scale]; + + *(((unsigned *)&linescale)+1)=(unsigned)comptable; // seg of far call + *(((unsigned *)&linecmds)+1)=(unsigned)shape; // seg of shape + +// +// scale to the left (from pixel 31 to shape->leftpix) +// + srcx = 32; + slinex = xcenter; + stopx = shape->leftpix; + cmdptr = &shape->dataofs[31-stopx]; + + while ( --srcx >=stopx && slinex>0) + { + (unsigned)linecmds = *cmdptr--; + if ( !(slinewidth = comptable->width[srcx]) ) + continue; + + if (slinewidth == 1) + { + slinex--; + if (slinex= height) + continue; // obscured by closer wall + ScaleLine (); + } + continue; + } + + // + // handle multi pixel lines + // + if (slinex>viewwidth) + { + slinex -= slinewidth; + slinewidth = viewwidth-slinex; + if (slinewidth<1) + continue; // still off the right side + } + else + { + if (slinewidth>slinex) + slinewidth = slinex; + slinex -= slinewidth; + } + + + leftvis = (wallheight[slinex] < height); + rightvis = (wallheight[slinex+slinewidth-1] < height); + + if (leftvis) + { + if (rightvis) + ScaleLine (); + else + { + while (wallheight[slinex+slinewidth-1] >= height) + slinewidth--; + ScaleLine (); + } + } + else + { + if (!rightvis) + continue; // totally obscured + + while (wallheight[slinex] >= height) + { + slinex++; + slinewidth--; + } + ScaleLine (); + break; // the rest of the shape is gone + } + } + + +// +// scale to the right +// + slinex = xcenter; + stopx = shape->rightpix; + if (shape->leftpix<31) + { + srcx = 31; + cmdptr = &shape->dataofs[32-shape->leftpix]; + } + else + { + srcx = shape->leftpix-1; + cmdptr = &shape->dataofs[0]; + } + slinewidth = 0; + + while ( ++srcx <= stopx && (slinex+=slinewidth)width[srcx]) ) + continue; + + if (slinewidth == 1) + { + if (slinex>=0 && wallheight[slinex] < height) + { + ScaleLine (); + } + continue; + } + + // + // handle multi pixel lines + // + if (slinex<0) + { + if (slinewidth <= -slinex) + continue; // still off the left edge + + slinewidth += slinex; + slinex = 0; + } + else + { + if (slinex + slinewidth > viewwidth) + slinewidth = viewwidth-slinex; + } + + + leftvis = (wallheight[slinex] < height); + rightvis = (wallheight[slinex+slinewidth-1] < height); + + if (leftvis) + { + if (rightvis) + { + ScaleLine (); + } + else + { + while (wallheight[slinex+slinewidth-1] >= height) + slinewidth--; + ScaleLine (); + break; // the rest of the shape is gone + } + } + else + { + if (rightvis) + { + while (wallheight[slinex] >= height) + { + slinex++; + slinewidth--; + } + ScaleLine (); + } + else + continue; // totally obscured + } + } +} + + + +/* +======================= += += SimpleScaleShape += += NO CLIPPING, height in pixels += += Draws a compiled shape at [scale] pixels high += += each vertical line of the shape has a pointer to segment data: += end of segment pixel*2 (0 terminates line) used to patch rtl in scaler += top of virtual line with segment in proper place += start of segment pixel*2, used to jsl into compiled scaler += += += Setup for call += -------------- += GC_MODE read mode 1, write mode 2 += GC_COLORDONTCARE set to 0, so all reads from video memory return 0xff += GC_INDEX pointing at GC_BITMASK += +======================= +*/ + +void SimpleScaleShape (int xcenter, int shapenum, unsigned height) +{ + t_compshape _seg *shape; + t_compscale _seg *comptable; + unsigned scale,srcx,stopx,tempx; + int t; + unsigned far *cmdptr; + boolean leftvis,rightvis; + + + shape = PM_GetSpritePage (shapenum); + + scale = height>>1; + comptable = scaledirectory[scale]; + + *(((unsigned *)&linescale)+1)=(unsigned)comptable; // seg of far call + *(((unsigned *)&linecmds)+1)=(unsigned)shape; // seg of shape + +// +// scale to the left (from pixel 31 to shape->leftpix) +// + srcx = 32; + slinex = xcenter; + stopx = shape->leftpix; + cmdptr = &shape->dataofs[31-stopx]; + + while ( --srcx >=stopx ) + { + (unsigned)linecmds = *cmdptr--; + if ( !(slinewidth = comptable->width[srcx]) ) + continue; + + slinex -= slinewidth; + ScaleLine (); + } + + +// +// scale to the right +// + slinex = xcenter; + stopx = shape->rightpix; + if (shape->leftpix<31) + { + srcx = 31; + cmdptr = &shape->dataofs[32-shape->leftpix]; + } + else + { + srcx = shape->leftpix-1; + cmdptr = &shape->dataofs[0]; + } + slinewidth = 0; + + while ( ++srcx <= stopx ) + { + (unsigned)linecmds = *cmdptr++; + if ( !(slinewidth = comptable->width[srcx]) ) + continue; + + ScaleLine (); + slinex+=slinewidth; + } +} + + + + +// +// bit mask tables for drawing scaled strips up to eight pixels wide +// +// down here so the STUPID inline assembler doesn't get confused! +// + + +byte mapmasks1[4][8] = { +{1 ,3 ,7 ,15,15,15,15,15}, +{2 ,6 ,14,14,14,14,14,14}, +{4 ,12,12,12,12,12,12,12}, +{8 ,8 ,8 ,8 ,8 ,8 ,8 ,8} }; + +byte mapmasks2[4][8] = { +{0 ,0 ,0 ,0 ,1 ,3 ,7 ,15}, +{0 ,0 ,0 ,1 ,3 ,7 ,15,15}, +{0 ,0 ,1 ,3 ,7 ,15,15,15}, +{0 ,1 ,3 ,7 ,15,15,15,15} }; + +byte mapmasks3[4][8] = { +{0 ,0 ,0 ,0 ,0 ,0 ,0 ,0}, +{0 ,0 ,0 ,0 ,0 ,0 ,0 ,1}, +{0 ,0 ,0 ,0 ,0 ,0 ,1 ,3}, +{0 ,0 ,0 ,0 ,0 ,1 ,3 ,7} }; + + +unsigned wordmasks[8][8] = { +{0x0080,0x00c0,0x00e0,0x00f0,0x00f8,0x00fc,0x00fe,0x00ff}, +{0x0040,0x0060,0x0070,0x0078,0x007c,0x007e,0x007f,0x807f}, +{0x0020,0x0030,0x0038,0x003c,0x003e,0x003f,0x803f,0xc03f}, +{0x0010,0x0018,0x001c,0x001e,0x001f,0x801f,0xc01f,0xe01f}, +{0x0008,0x000c,0x000e,0x000f,0x800f,0xc00f,0xe00f,0xf00f}, +{0x0004,0x0006,0x0007,0x8007,0xc007,0xe007,0xf007,0xf807}, +{0x0002,0x0003,0x8003,0xc003,0xe003,0xf003,0xf803,0xfc03}, +{0x0001,0x8001,0xc001,0xe001,0xf001,0xf801,0xfc01,0xfe01} }; + +int slinex,slinewidth; +unsigned far *linecmds; +long linescale; +unsigned maskword; + diff --git a/16/sod8086/wl_state.c b/16/sod8086/wl_state.c new file mode 100755 index 00000000..ad534ba9 --- /dev/null +++ b/16/sod8086/wl_state.c @@ -0,0 +1,1480 @@ +// WL_STATE.C + +#include "WL_DEF.H" +#pragma hdrstop + +/* +============================================================================= + + LOCAL CONSTANTS + +============================================================================= +*/ + + +/* +============================================================================= + + GLOBAL VARIABLES + +============================================================================= +*/ + + +dirtype opposite[9] = + {west,southwest,south,southeast,east,northeast,north,northwest,nodir}; + +dirtype diagonal[9][9] = +{ +/* east */ {nodir,nodir,northeast,nodir,nodir,nodir,southeast,nodir,nodir}, + {nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir}, +/* north */ {northeast,nodir,nodir,nodir,northwest,nodir,nodir,nodir,nodir}, + {nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir}, +/* west */ {nodir,nodir,northwest,nodir,nodir,nodir,southwest,nodir,nodir}, + {nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir}, +/* south */ {southeast,nodir,nodir,nodir,southwest,nodir,nodir,nodir,nodir}, + {nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir}, + {nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir} +}; + + + +void SpawnNewObj (unsigned tilex, unsigned tiley, statetype *state); +void NewState (objtype *ob, statetype *state); + +boolean TryWalk (objtype *ob); +void MoveObj (objtype *ob, long move); + +void KillActor (objtype *ob); +void DamageActor (objtype *ob, unsigned damage); + +boolean CheckLine (objtype *ob); +void FirstSighting (objtype *ob); +boolean CheckSight (objtype *ob); + +/* +============================================================================= + + LOCAL VARIABLES + +============================================================================= +*/ + + + +//=========================================================================== + + +/* +=================== += += SpawnNewObj += += Spaws a new actor at the given TILE coordinates, with the given state, and += the given size in GLOBAL units. += += new = a pointer to an initialized new actor += +=================== +*/ + +void SpawnNewObj (unsigned tilex, unsigned tiley, statetype *state) +{ + GetNewActor (); + new->state = state; + if (state->tictime) + new->ticcount = US_RndT () % state->tictime; + else + new->ticcount = 0; + + new->tilex = tilex; + new->tiley = tiley; + new->x = ((long)tilex<y = ((long)tiley<dir = nodir; + + actorat[tilex][tiley] = new; + new->areanumber = + *(mapsegs[0] + farmapylookup[new->tiley]+new->tilex) - AREATILE; +} + + + +/* +=================== += += NewState += += Changes ob to a new state, setting ticcount to the max for that state += +=================== +*/ + +void NewState (objtype *ob, statetype *state) +{ + ob->state = state; + ob->ticcount = state->tictime; +} + + + +/* +============================================================================= + + ENEMY TILE WORLD MOVEMENT CODE + +============================================================================= +*/ + + +/* +================================== += += TryWalk += += Attempts to move ob in its current (ob->dir) direction. += += If blocked by either a wall or an actor returns FALSE += += If move is either clear or blocked only by a door, returns TRUE and sets += += ob->tilex = new destination += ob->tiley += ob->areanumber = the floor tile number (0-(NUMAREAS-1)) of destination += ob->distance = TILEGLOBAl, or -doornumber if a door is blocking the way += += If a door is in the way, an OpenDoor call is made to start it opening. += The actor code should wait until += doorobjlist[-ob->distance].action = dr_open, meaning the door has been += fully opened += +================================== +*/ + +#define CHECKDIAG(x,y) \ +{ \ + temp=(unsigned)actorat[x][y]; \ + if (temp) \ + { \ + if (temp<256) \ + return false; \ + if (((objtype *)temp)->flags&FL_SHOOTABLE) \ + return false; \ + } \ +} + +#define CHECKSIDE(x,y) \ +{ \ + temp=(unsigned)actorat[x][y]; \ + if (temp) \ + { \ + if (temp<128) \ + return false; \ + if (temp<256) \ + doornum = temp&63; \ + else if (((objtype *)temp)->flags&FL_SHOOTABLE)\ + return false; \ + } \ +} + + +boolean TryWalk (objtype *ob) +{ + int doornum; + unsigned temp; + + doornum = -1; + + if (ob->obclass == inertobj) + { + switch (ob->dir) + { + case north: + ob->tiley--; + break; + + case northeast: + ob->tilex++; + ob->tiley--; + break; + + case east: + ob->tilex++; + break; + + case southeast: + ob->tilex++; + ob->tiley++; + break; + + case south: + ob->tiley++; + break; + + case southwest: + ob->tilex--; + ob->tiley++; + break; + + case west: + ob->tilex--; + break; + + case northwest: + ob->tilex--; + ob->tiley--; + break; + } + } + else + switch (ob->dir) + { + case north: + if (ob->obclass == dogobj || ob->obclass == fakeobj) + { + CHECKDIAG(ob->tilex,ob->tiley-1); + } + else + { + CHECKSIDE(ob->tilex,ob->tiley-1); + } + ob->tiley--; + break; + + case northeast: + CHECKDIAG(ob->tilex+1,ob->tiley-1); + CHECKDIAG(ob->tilex+1,ob->tiley); + CHECKDIAG(ob->tilex,ob->tiley-1); + ob->tilex++; + ob->tiley--; + break; + + case east: + if (ob->obclass == dogobj || ob->obclass == fakeobj) + { + CHECKDIAG(ob->tilex+1,ob->tiley); + } + else + { + CHECKSIDE(ob->tilex+1,ob->tiley); + } + ob->tilex++; + break; + + case southeast: + CHECKDIAG(ob->tilex+1,ob->tiley+1); + CHECKDIAG(ob->tilex+1,ob->tiley); + CHECKDIAG(ob->tilex,ob->tiley+1); + ob->tilex++; + ob->tiley++; + break; + + case south: + if (ob->obclass == dogobj || ob->obclass == fakeobj) + { + CHECKDIAG(ob->tilex,ob->tiley+1); + } + else + { + CHECKSIDE(ob->tilex,ob->tiley+1); + } + ob->tiley++; + break; + + case southwest: + CHECKDIAG(ob->tilex-1,ob->tiley+1); + CHECKDIAG(ob->tilex-1,ob->tiley); + CHECKDIAG(ob->tilex,ob->tiley+1); + ob->tilex--; + ob->tiley++; + break; + + case west: + if (ob->obclass == dogobj || ob->obclass == fakeobj) + { + CHECKDIAG(ob->tilex-1,ob->tiley); + } + else + { + CHECKSIDE(ob->tilex-1,ob->tiley); + } + ob->tilex--; + break; + + case northwest: + CHECKDIAG(ob->tilex-1,ob->tiley-1); + CHECKDIAG(ob->tilex-1,ob->tiley); + CHECKDIAG(ob->tilex,ob->tiley-1); + ob->tilex--; + ob->tiley--; + break; + + case nodir: + return false; + + default: + Quit ("Walk: Bad dir"); + } + + if (doornum != -1) + { + OpenDoor (doornum); + ob->distance = -doornum-1; + return true; + } + + + ob->areanumber = + *(mapsegs[0] + farmapylookup[ob->tiley]+ob->tilex) - AREATILE; + + ob->distance = TILEGLOBAL; + return true; +} + + + +/* +================================== += += SelectDodgeDir += += Attempts to choose and initiate a movement for ob that sends it towards += the player while dodging += += If there is no possible move (ob is totally surrounded) += += ob->dir = nodir += += Otherwise += += ob->dir = new direction to follow += ob->distance = TILEGLOBAL or -doornumber += ob->tilex = new destination += ob->tiley += ob->areanumber = the floor tile number (0-(NUMAREAS-1)) of destination += +================================== +*/ + +void SelectDodgeDir (objtype *ob) +{ + int deltax,deltay,i; + unsigned absdx,absdy; + dirtype dirtry[5]; + dirtype turnaround,tdir; + + if (ob->flags & FL_FIRSTATTACK) + { + // + // turning around is only ok the very first time after noticing the + // player + // + turnaround = nodir; + ob->flags &= ~FL_FIRSTATTACK; + } + else + turnaround=opposite[ob->dir]; + + deltax = player->tilex - ob->tilex; + deltay = player->tiley - ob->tiley; + +// +// arange 5 direction choices in order of preference +// the four cardinal directions plus the diagonal straight towards +// the player +// + + if (deltax>0) + { + dirtry[1]= east; + dirtry[3]= west; + } + else + { + dirtry[1]= west; + dirtry[3]= east; + } + + if (deltay>0) + { + dirtry[2]= south; + dirtry[4]= north; + } + else + { + dirtry[2]= north; + dirtry[4]= south; + } + +// +// randomize a bit for dodging +// + absdx = abs(deltax); + absdy = abs(deltay); + + if (absdx > absdy) + { + tdir = dirtry[1]; + dirtry[1] = dirtry[2]; + dirtry[2] = tdir; + tdir = dirtry[3]; + dirtry[3] = dirtry[4]; + dirtry[4] = tdir; + } + + if (US_RndT() < 128) + { + tdir = dirtry[1]; + dirtry[1] = dirtry[2]; + dirtry[2] = tdir; + tdir = dirtry[3]; + dirtry[3] = dirtry[4]; + dirtry[4] = tdir; + } + + dirtry[0] = diagonal [ dirtry[1] ] [ dirtry[2] ]; + +// +// try the directions util one works +// + for (i=0;i<5;i++) + { + if ( dirtry[i] == nodir || dirtry[i] == turnaround) + continue; + + ob->dir = dirtry[i]; + if (TryWalk(ob)) + return; + } + +// +// turn around only as a last resort +// + if (turnaround != nodir) + { + ob->dir = turnaround; + + if (TryWalk(ob)) + return; + } + + ob->dir = nodir; +} + + +/* +============================ += += SelectChaseDir += += As SelectDodgeDir, but doesn't try to dodge += +============================ +*/ + +void SelectChaseDir (objtype *ob) +{ + int deltax,deltay,i; + dirtype d[3]; + dirtype tdir, olddir, turnaround; + + + olddir=ob->dir; + turnaround=opposite[olddir]; + + deltax=player->tilex - ob->tilex; + deltay=player->tiley - ob->tiley; + + d[1]=nodir; + d[2]=nodir; + + if (deltax>0) + d[1]= east; + else if (deltax<0) + d[1]= west; + if (deltay>0) + d[2]=south; + else if (deltay<0) + d[2]=north; + + if (abs(deltay)>abs(deltax)) + { + tdir=d[1]; + d[1]=d[2]; + d[2]=tdir; + } + + if (d[1]==turnaround) + d[1]=nodir; + if (d[2]==turnaround) + d[2]=nodir; + + + if (d[1]!=nodir) + { + ob->dir=d[1]; + if (TryWalk(ob)) + return; /*either moved forward or attacked*/ + } + + if (d[2]!=nodir) + { + ob->dir=d[2]; + if (TryWalk(ob)) + return; + } + +/* there is no direct path to the player, so pick another direction */ + + if (olddir!=nodir) + { + ob->dir=olddir; + if (TryWalk(ob)) + return; + } + + if (US_RndT()>128) /*randomly determine direction of search*/ + { + for (tdir=north;tdir<=west;tdir++) + { + if (tdir!=turnaround) + { + ob->dir=tdir; + if ( TryWalk(ob) ) + return; + } + } + } + else + { + for (tdir=west;tdir>=north;tdir--) + { + if (tdir!=turnaround) + { + ob->dir=tdir; + if ( TryWalk(ob) ) + return; + } + } + } + + if (turnaround != nodir) + { + ob->dir=turnaround; + if (ob->dir != nodir) + { + if ( TryWalk(ob) ) + return; + } + } + + ob->dir = nodir; // can't move +} + + +/* +============================ += += SelectRunDir += += Run Away from player += +============================ +*/ + +void SelectRunDir (objtype *ob) +{ + int deltax,deltay,i; + dirtype d[3]; + dirtype tdir, olddir, turnaround; + + + deltax=player->tilex - ob->tilex; + deltay=player->tiley - ob->tiley; + + if (deltax<0) + d[1]= east; + else + d[1]= west; + if (deltay<0) + d[2]=south; + else + d[2]=north; + + if (abs(deltay)>abs(deltax)) + { + tdir=d[1]; + d[1]=d[2]; + d[2]=tdir; + } + + ob->dir=d[1]; + if (TryWalk(ob)) + return; /*either moved forward or attacked*/ + + ob->dir=d[2]; + if (TryWalk(ob)) + return; + +/* there is no direct path to the player, so pick another direction */ + + if (US_RndT()>128) /*randomly determine direction of search*/ + { + for (tdir=north;tdir<=west;tdir++) + { + ob->dir=tdir; + if ( TryWalk(ob) ) + return; + } + } + else + { + for (tdir=west;tdir>=north;tdir--) + { + ob->dir=tdir; + if ( TryWalk(ob) ) + return; + } + } + + ob->dir = nodir; // can't move +} + + +/* +================= += += MoveObj += += Moves ob be move global units in ob->dir direction += Actors are not allowed to move inside the player += Does NOT check to see if the move is tile map valid += += ob->x = adjusted for new position += ob->y += +================= +*/ + +void MoveObj (objtype *ob, long move) +{ + long deltax,deltay; + + switch (ob->dir) + { + case north: + ob->y -= move; + break; + case northeast: + ob->x += move; + ob->y -= move; + break; + case east: + ob->x += move; + break; + case southeast: + ob->x += move; + ob->y += move; + break; + case south: + ob->y += move; + break; + case southwest: + ob->x -= move; + ob->y += move; + break; + case west: + ob->x -= move; + break; + case northwest: + ob->x -= move; + ob->y -= move; + break; + + case nodir: + return; + + default: + Quit ("MoveObj: bad dir!"); + } + +// +// check to make sure it's not on top of player +// + if (areabyplayer[ob->areanumber]) + { + deltax = ob->x - player->x; + if (deltax < -MINACTORDIST || deltax > MINACTORDIST) + goto moveok; + deltay = ob->y - player->y; + if (deltay < -MINACTORDIST || deltay > MINACTORDIST) + goto moveok; + + if (ob->obclass == ghostobj || ob->obclass == spectreobj) + TakeDamage (tics*2,ob); + + // + // back up + // + switch (ob->dir) + { + case north: + ob->y += move; + break; + case northeast: + ob->x -= move; + ob->y += move; + break; + case east: + ob->x -= move; + break; + case southeast: + ob->x -= move; + ob->y -= move; + break; + case south: + ob->y -= move; + break; + case southwest: + ob->x += move; + ob->y -= move; + break; + case west: + ob->x += move; + break; + case northwest: + ob->x += move; + ob->y += move; + break; + + case nodir: + return; + } + return; + } +moveok: + ob->distance -=move; +} + +/* +============================================================================= + + STUFF + +============================================================================= +*/ + +/* +=============== += += DropItem += += Tries to drop a bonus item somewhere in the tiles surrounding the += given tilex/tiley += +=============== +*/ + +void DropItem (stat_t itemtype, int tilex, int tiley) +{ + int x,y,xl,xh,yl,yh; + +// +// find a free spot to put it in +// + if (!actorat[tilex][tiley]) + { + PlaceItemType (itemtype, tilex,tiley); + return; + } + + xl = tilex-1; + xh = tilex+1; + yl = tiley-1; + yh = tiley+1; + + for (x=xl ; x<= xh ; x++) + for (y=yl ; y<= yh ; y++) + if (!actorat[x][y]) + { + PlaceItemType (itemtype, x,y); + return; + } +} + + + +/* +=============== += += KillActor += +=============== +*/ + +void KillActor (objtype *ob) +{ + int tilex,tiley; + + tilex = ob->tilex = ob->x >> TILESHIFT; // drop item on center + tiley = ob->tiley = ob->y >> TILESHIFT; + + switch (ob->obclass) + { + case guardobj: + GivePoints (100); + NewState (ob,&s_grddie1); + PlaceItemType (bo_clip2,tilex,tiley); + break; + + case officerobj: + GivePoints (400); + NewState (ob,&s_ofcdie1); + PlaceItemType (bo_clip2,tilex,tiley); + break; + + case mutantobj: + GivePoints (700); + NewState (ob,&s_mutdie1); + PlaceItemType (bo_clip2,tilex,tiley); + break; + + case ssobj: + GivePoints (500); + NewState (ob,&s_ssdie1); + if (gamestate.bestweapon < wp_machinegun) + PlaceItemType (bo_machinegun,tilex,tiley); + else + PlaceItemType (bo_clip2,tilex,tiley); + break; + + case dogobj: + GivePoints (200); + NewState (ob,&s_dogdie1); + break; + +#ifndef SPEAR + case bossobj: + GivePoints (5000); + NewState (ob,&s_bossdie1); + PlaceItemType (bo_key1,tilex,tiley); + break; + + case gretelobj: + GivePoints (5000); + NewState (ob,&s_greteldie1); + PlaceItemType (bo_key1,tilex,tiley); + break; + + case giftobj: + GivePoints (5000); + gamestate.killx = player->x; + gamestate.killy = player->y; + NewState (ob,&s_giftdie1); + break; + + case fatobj: + GivePoints (5000); + gamestate.killx = player->x; + gamestate.killy = player->y; + NewState (ob,&s_fatdie1); + break; + + case schabbobj: + GivePoints (5000); + gamestate.killx = player->x; + gamestate.killy = player->y; + NewState (ob,&s_schabbdie1); + A_DeathScream(ob); + break; + case fakeobj: + GivePoints (2000); + NewState (ob,&s_fakedie1); + break; + + case mechahitlerobj: + GivePoints (5000); + NewState (ob,&s_mechadie1); + break; + case realhitlerobj: + GivePoints (5000); + gamestate.killx = player->x; + gamestate.killy = player->y; + NewState (ob,&s_hitlerdie1); + A_DeathScream(ob); + break; +#else + case spectreobj: + GivePoints (200); + NewState (ob,&s_spectredie1); + break; + + case angelobj: + GivePoints (5000); + NewState (ob,&s_angeldie1); + break; + + case transobj: + GivePoints (5000); + NewState (ob,&s_transdie0); + PlaceItemType (bo_key1,tilex,tiley); + break; + + case uberobj: + GivePoints (5000); + NewState (ob,&s_uberdie0); + PlaceItemType (bo_key1,tilex,tiley); + break; + + case willobj: + GivePoints (5000); + NewState (ob,&s_willdie1); + PlaceItemType (bo_key1,tilex,tiley); + break; + + case deathobj: + GivePoints (5000); + NewState (ob,&s_deathdie1); + PlaceItemType (bo_key1,tilex,tiley); + break; +#endif + } + + gamestate.killcount++; + ob->flags &= ~FL_SHOOTABLE; + actorat[ob->tilex][ob->tiley] = NULL; + ob->flags |= FL_NONMARK; +} + + + +/* +=================== += += DamageActor += += Called when the player succesfully hits an enemy. += += Does damage points to enemy ob, either putting it into a stun frame or += killing it. += +=================== +*/ + +void DamageActor (objtype *ob, unsigned damage) +{ + madenoise = true; + +// +// do double damage if shooting a non attack mode actor +// + if ( !(ob->flags & FL_ATTACKMODE) ) + damage <<= 1; + + ob->hitpoints -= damage; + + if (ob->hitpoints<=0) + KillActor (ob); + else + { + if (! (ob->flags & FL_ATTACKMODE) ) + FirstSighting (ob); // put into combat mode + + switch (ob->obclass) // dogs only have one hit point + { + case guardobj: + if (ob->hitpoints&1) + NewState (ob,&s_grdpain); + else + NewState (ob,&s_grdpain1); + break; + + case officerobj: + if (ob->hitpoints&1) + NewState (ob,&s_ofcpain); + else + NewState (ob,&s_ofcpain1); + break; + + case mutantobj: + if (ob->hitpoints&1) + NewState (ob,&s_mutpain); + else + NewState (ob,&s_mutpain1); + break; + + case ssobj: + if (ob->hitpoints&1) + NewState (ob,&s_sspain); + else + NewState (ob,&s_sspain1); + + break; + + } + } +} + +/* +============================================================================= + + CHECKSIGHT + +============================================================================= +*/ + + +/* +===================== += += CheckLine += += Returns true if a straight line between the player and ob is unobstructed += +===================== +*/ + +boolean CheckLine (objtype *ob) +{ + int x1,y1,xt1,yt1,x2,y2,xt2,yt2; + int x,y; + int xdist,ydist,xstep,ystep; + int temp; + int partial,delta; + long ltemp; + int xfrac,yfrac,deltafrac; + unsigned value,intercept; + + x1 = ob->x >> UNSIGNEDSHIFT; // 1/256 tile precision + y1 = ob->y >> UNSIGNEDSHIFT; + xt1 = x1 >> 8; + yt1 = y1 >> 8; + + x2 = plux; + y2 = pluy; + xt2 = player->tilex; + yt2 = player->tiley; + + + xdist = abs(xt2-xt1); + + if (xdist > 0) + { + if (xt2 > xt1) + { + partial = 256-(x1&0xff); + xstep = 1; + } + else + { + partial = x1&0xff; + xstep = -1; + } + + deltafrac = abs(x2-x1); + delta = y2-y1; + ltemp = ((long)delta<<8)/deltafrac; + if (ltemp > 0x7fffl) + ystep = 0x7fff; + else if (ltemp < -0x7fffl) + ystep = -0x7fff; + else + ystep = ltemp; + yfrac = y1 + (((long)ystep*partial) >>8); + + x = xt1+xstep; + xt2 += xstep; + do + { + y = yfrac>>8; + yfrac += ystep; + + value = (unsigned)tilemap[x][y]; + x += xstep; + + if (!value) + continue; + + if (value<128 || value>256) + return false; + + // + // see if the door is open enough + // + value &= ~0x80; + intercept = yfrac-ystep/2; + + if (intercept>doorposition[value]) + return false; + + } while (x != xt2); + } + + ydist = abs(yt2-yt1); + + if (ydist > 0) + { + if (yt2 > yt1) + { + partial = 256-(y1&0xff); + ystep = 1; + } + else + { + partial = y1&0xff; + ystep = -1; + } + + deltafrac = abs(y2-y1); + delta = x2-x1; + ltemp = ((long)delta<<8)/deltafrac; + if (ltemp > 0x7fffl) + xstep = 0x7fff; + else if (ltemp < -0x7fffl) + xstep = -0x7fff; + else + xstep = ltemp; + xfrac = x1 + (((long)xstep*partial) >>8); + + y = yt1 + ystep; + yt2 += ystep; + do + { + x = xfrac>>8; + xfrac += xstep; + + value = (unsigned)tilemap[x][y]; + y += ystep; + + if (!value) + continue; + + if (value<128 || value>256) + return false; + + // + // see if the door is open enough + // + value &= ~0x80; + intercept = xfrac-xstep/2; + + if (intercept>doorposition[value]) + return false; + } while (y != yt2); + } + + return true; +} + + + +/* +================ += += CheckSight += += Checks a straight line between player and current object += += If the sight is ok, check alertness and angle to see if they notice += += returns true if the player has been spoted += +================ +*/ + +#define MINSIGHT 0x18000l + +boolean CheckSight (objtype *ob) +{ + long deltax,deltay; + +// +// don't bother tracing a line if the area isn't connected to the player's +// + if (!areabyplayer[ob->areanumber]) + return false; + +// +// if the player is real close, sight is automatic +// + deltax = player->x - ob->x; + deltay = player->y - ob->y; + + if (deltax > -MINSIGHT && deltax < MINSIGHT + && deltay > -MINSIGHT && deltay < MINSIGHT) + return true; + +// +// see if they are looking in the right direction +// + switch (ob->dir) + { + case north: + if (deltay > 0) + return false; + break; + + case east: + if (deltax < 0) + return false; + break; + + case south: + if (deltay < 0) + return false; + break; + + case west: + if (deltax > 0) + return false; + break; + } + +// +// trace a line to check for blocking tiles (corners) +// + return CheckLine (ob); + +} + + + +/* +=============== += += FirstSighting += += Puts an actor into attack mode and possibly reverses the direction += if the player is behind it += +=============== +*/ + +void FirstSighting (objtype *ob) +{ +// +// react to the player +// + switch (ob->obclass) + { + case guardobj: + PlaySoundLocActor(HALTSND,ob); + NewState (ob,&s_grdchase1); + ob->speed *= 3; // go faster when chasing player + break; + + case officerobj: + PlaySoundLocActor(SPIONSND,ob); + NewState (ob,&s_ofcchase1); + ob->speed *= 5; // go faster when chasing player + break; + + case mutantobj: + NewState (ob,&s_mutchase1); + ob->speed *= 3; // go faster when chasing player + break; + + case ssobj: + PlaySoundLocActor(SCHUTZADSND,ob); + NewState (ob,&s_sschase1); + ob->speed *= 4; // go faster when chasing player + break; + + case dogobj: + PlaySoundLocActor(DOGBARKSND,ob); + NewState (ob,&s_dogchase1); + ob->speed *= 2; // go faster when chasing player + break; + +#ifndef SPEAR + case bossobj: + SD_PlaySound(GUTENTAGSND); + NewState (ob,&s_bosschase1); + ob->speed = SPDPATROL*3; // go faster when chasing player + break; + + case gretelobj: + SD_PlaySound(KEINSND); + NewState (ob,&s_gretelchase1); + ob->speed *= 3; // go faster when chasing player + break; + + case giftobj: + SD_PlaySound(EINESND); + NewState (ob,&s_giftchase1); + ob->speed *= 3; // go faster when chasing player + break; + + case fatobj: + SD_PlaySound(ERLAUBENSND); + NewState (ob,&s_fatchase1); + ob->speed *= 3; // go faster when chasing player + break; + + case schabbobj: + SD_PlaySound(SCHABBSHASND); + NewState (ob,&s_schabbchase1); + ob->speed *= 3; // go faster when chasing player + break; + + case fakeobj: + SD_PlaySound(TOT_HUNDSND); + NewState (ob,&s_fakechase1); + ob->speed *= 3; // go faster when chasing player + break; + + case mechahitlerobj: + SD_PlaySound(DIESND); + NewState (ob,&s_mechachase1); + ob->speed *= 3; // go faster when chasing player + break; + + case realhitlerobj: + SD_PlaySound(DIESND); + NewState (ob,&s_hitlerchase1); + ob->speed *= 5; // go faster when chasing player + break; + + case ghostobj: + NewState (ob,&s_blinkychase1); + ob->speed *= 2; // go faster when chasing player + break; +#else + + case spectreobj: + SD_PlaySound(GHOSTSIGHTSND); + NewState (ob,&s_spectrechase1); + ob->speed = 800; // go faster when chasing player + break; + + case angelobj: + SD_PlaySound(ANGELSIGHTSND); + NewState (ob,&s_angelchase1); + ob->speed = 1536; // go faster when chasing player + break; + + case transobj: + SD_PlaySound(TRANSSIGHTSND); + NewState (ob,&s_transchase1); + ob->speed = 1536; // go faster when chasing player + break; + + case uberobj: + NewState (ob,&s_uberchase1); + ob->speed = 3000; // go faster when chasing player + break; + + case willobj: + SD_PlaySound(WILHELMSIGHTSND); + NewState (ob,&s_willchase1); + ob->speed = 2048; // go faster when chasing player + break; + + case deathobj: + SD_PlaySound(KNIGHTSIGHTSND); + NewState (ob,&s_deathchase1); + ob->speed = 2048; // go faster when chasing player + break; + +#endif + } + + if (ob->distance < 0) + ob->distance = 0; // ignore the door opening command + + ob->flags |= FL_ATTACKMODE|FL_FIRSTATTACK; +} + + + +/* +=============== += += SightPlayer += += Called by actors that ARE NOT chasing the player. If the player += is detected (by sight, noise, or proximity), the actor is put into += it's combat frame and true is returned. += += Incorporates a random reaction delay += +=============== +*/ + +boolean SightPlayer (objtype *ob) +{ + if (ob->flags & FL_ATTACKMODE) + Quit ("An actor in ATTACKMODE called SightPlayer!"); + + if (ob->temp2) + { + // + // count down reaction time + // + ob->temp2 -= tics; + if (ob->temp2 > 0) + return false; + ob->temp2 = 0; // time to react + } + else + { + if (!areabyplayer[ob->areanumber]) + return false; + + if (ob->flags & FL_AMBUSH) + { + if (!CheckSight (ob)) + return false; + ob->flags &= ~FL_AMBUSH; + } + else + { + if (!madenoise && !CheckSight (ob)) + return false; + } + + + switch (ob->obclass) + { + case guardobj: + ob->temp2 = 1+US_RndT()/4; + break; + case officerobj: + ob->temp2 = 2; + break; + case mutantobj: + ob->temp2 = 1+US_RndT()/6; + break; + case ssobj: + ob->temp2 = 1+US_RndT()/6; + break; + case dogobj: + ob->temp2 = 1+US_RndT()/8; + break; + + case bossobj: + case schabbobj: + case fakeobj: + case mechahitlerobj: + case realhitlerobj: + case gretelobj: + case giftobj: + case fatobj: + case spectreobj: + case angelobj: + case transobj: + case uberobj: + case willobj: + case deathobj: + ob->temp2 = 1; + break; + } + return false; + } + + FirstSighting (ob); + + return true; +} + + diff --git a/16/sod8086/wl_text.c b/16/sod8086/wl_text.c new file mode 100755 index 00000000..df713f31 --- /dev/null +++ b/16/sod8086/wl_text.c @@ -0,0 +1,862 @@ +// WL_TEXT.C + +#include "WL_DEF.H" +#pragma hdrstop + +/* +============================================================================= + +TEXT FORMATTING COMMANDS +------------------------ +^C Change text color +^E[enter] End of layout (all pages) +^G,,[enter] Draw a graphic and push margins +^P[enter] start new page, must be the first chars in a layout +^L,[ENTER] Locate to a specific spot, x in pixels, y in lines + +============================================================================= +*/ + +/* +============================================================================= + + LOCAL CONSTANTS + +============================================================================= +*/ + +#define BACKCOLOR 0x11 + + +#define WORDLIMIT 80 +#define FONTHEIGHT 10 +#define TOPMARGIN 16 +#define BOTTOMMARGIN 32 +#define LEFTMARGIN 16 +#define RIGHTMARGIN 16 +#define PICMARGIN 8 +#define TEXTROWS ((200-TOPMARGIN-BOTTOMMARGIN)/FONTHEIGHT) +#define SPACEWIDTH 7 +#define SCREENPIXWIDTH 320 +#define SCREENMID (SCREENPIXWIDTH/2) + +/* +============================================================================= + + LOCAL VARIABLES + +============================================================================= +*/ + +int pagenum,numpages; + +unsigned leftmargin[TEXTROWS],rightmargin[TEXTROWS]; +char far *text; +unsigned rowon; + +int picx,picy,picnum,picdelay; +boolean layoutdone; + +//=========================================================================== + +#ifndef JAPAN +/* +===================== += += RipToEOL += +===================== +*/ + +void RipToEOL (void) +{ + while (*text++ != '\n') // scan to end of line + ; +} + + +/* +===================== += += ParseNumber += +===================== +*/ + +int ParseNumber (void) +{ + char ch; + char num[80],*numptr; + +// +// scan until a number is found +// + ch = *text; + while (ch < '0' || ch >'9') + ch = *++text; + +// +// copy the number out +// + numptr = num; + do + { + *numptr++ = ch; + ch = *++text; + } while (ch >= '0' && ch <= '9'); + *numptr = 0; + + return atoi (num); +} + + + +/* +===================== += += ParsePicCommand += += Call with text pointing just after a ^P += Upon exit text points to the start of next line += +===================== +*/ + +void ParsePicCommand (void) +{ + picy=ParseNumber(); + picx=ParseNumber(); + picnum=ParseNumber(); + RipToEOL (); +} + + +void ParseTimedCommand (void) +{ + picy=ParseNumber(); + picx=ParseNumber(); + picnum=ParseNumber(); + picdelay=ParseNumber(); + RipToEOL (); +} + + +/* +===================== += += TimedPicCommand += += Call with text pointing just after a ^P += Upon exit text points to the start of next line += +===================== +*/ + +void TimedPicCommand (void) +{ + ParseTimedCommand (); + +// +// update the screen, and wait for time delay +// + VW_UpdateScreen (); + +// +// wait for time +// + TimeCount = 0; + while (TimeCount < picdelay) + ; + +// +// draw pic +// + VWB_DrawPic (picx&~7,picy,picnum); +} + + +/* +===================== += += HandleCommand += +===================== +*/ + +void HandleCommand (void) +{ + int i,margin,top,bottom; + int picwidth,picheight,picmid; + + switch (toupper(*++text)) + { + case 'B': + picy=ParseNumber(); + picx=ParseNumber(); + picwidth=ParseNumber(); + picheight=ParseNumber(); + VWB_Bar(picx,picy,picwidth,picheight,BACKCOLOR); + RipToEOL(); + break; + case ';': // comment + RipToEOL(); + break; + case 'P': // ^P is start of next page, ^E is end of file + case 'E': + layoutdone = true; + text--; // back up to the '^' + break; + + case 'C': // ^c changes text color + i = toupper(*++text); + if (i>='0' && i<='9') + fontcolor = i-'0'; + else if (i>='A' && i<='F') + fontcolor = i-'A'+10; + + fontcolor *= 16; + i = toupper(*++text); + if (i>='0' && i<='9') + fontcolor += i-'0'; + else if (i>='A' && i<='F') + fontcolor += i-'A'+10; + text++; + break; + + case '>': + px = 160; + text++; + break; + + case 'L': + py=ParseNumber(); + rowon = (py-TOPMARGIN)/FONTHEIGHT; + py = TOPMARGIN+rowon*FONTHEIGHT; + px=ParseNumber(); + while (*text++ != '\n') // scan to end of line + ; + break; + + case 'T': // ^Tyyy,xxx,ppp,ttt waits ttt tics, then draws pic + TimedPicCommand (); + break; + + case 'G': // ^Gyyy,xxx,ppp draws graphic + ParsePicCommand (); + VWB_DrawPic (picx&~7,picy,picnum); + picwidth = pictable[picnum-STARTPICS].width; + picheight = pictable[picnum-STARTPICS].height; + // + // adjust margins + // + picmid = picx + picwidth/2; + if (picmid > SCREENMID) + margin = picx-PICMARGIN; // new right margin + else + margin = picx+picwidth+PICMARGIN; // new left margin + + top = (picy-TOPMARGIN)/FONTHEIGHT; + if (top<0) + top = 0; + bottom = (picy+picheight-TOPMARGIN)/FONTHEIGHT; + if (bottom>=TEXTROWS) + bottom = TEXTROWS-1; + + for (i=top;i<=bottom;i++) + if (picmid > SCREENMID) + rightmargin[i] = margin; + else + leftmargin[i] = margin; + + // + // adjust this line if needed + // + if (px < leftmargin[rowon]) + px = leftmargin[rowon]; + break; + } +} + + +/* +===================== += += NewLine += +===================== +*/ + +void NewLine (void) +{ + char ch; + + if (++rowon == TEXTROWS) + { + // + // overflowed the page, so skip until next page break + // + layoutdone = true; + do + { + if (*text == '^') + { + ch = toupper(*(text+1)); + if (ch == 'E' || ch == 'P') + { + layoutdone = true; + return; + } + } + text++; + + } while (1); + + } + px = leftmargin[rowon]; + py+= FONTHEIGHT; +} + + + +/* +===================== += += HandleCtrls += +===================== +*/ + +void HandleCtrls (void) +{ + char ch; + + ch = *text++; // get the character and advance + + if (ch == '\n') + { + NewLine (); + return; + } + +} + + +/* +===================== += += HandleWord += +===================== +*/ + +void HandleWord (void) +{ + char word[WORDLIMIT]; + int i,wordindex; + unsigned wwidth,wheight,newpos; + + + // + // copy the next word into [word] + // + word[0] = *text++; + wordindex = 1; + while (*text>32) + { + word[wordindex] = *text++; + if (++wordindex == WORDLIMIT) + Quit ("PageLayout: Word limit exceeded"); + } + word[wordindex] = 0; // stick a null at end for C + + // + // see if it fits on this line + // + VW_MeasurePropString (word,&wwidth,&wheight); + + while (px+wwidth > rightmargin[rowon]) + { + NewLine (); + if (layoutdone) + return; // overflowed page + } + + // + // print it + // + newpos = px+wwidth; + VWB_DrawPropString (word); + px = newpos; + + // + // suck up any extra spaces + // + while (*text == ' ') + { + px += SPACEWIDTH; + text++; + } +} + +/* +===================== += += PageLayout += += Clears the screen, draws the pics on the page, and word wraps the text. += Returns a pointer to the terminating command += +===================== +*/ + +void PageLayout (boolean shownumber) +{ + int i,oldfontcolor; + char ch; + + oldfontcolor = fontcolor; + + fontcolor = 0; + +// +// clear the screen +// + VWB_Bar (0,0,320,200,BACKCOLOR); +#ifndef SPEAR + VWB_DrawPic (0,0,H_TOPWINDOWPIC); + VWB_DrawPic (0,8,H_LEFTWINDOWPIC); + VWB_DrawPic (312,8,H_RIGHTWINDOWPIC); + VWB_DrawPic (8,176,H_BOTTOMINFOPIC); +#endif + + for (i=0;i1) + { + #ifndef JAPAN + BackPage (); + BackPage (); + #else + pagenum--; + #endif + newpage = true; + } + break; + + case sc_Enter: + case sc_DownArrow: + case sc_PgDn: + case sc_RightArrow: // the text allready points at next page + if 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 RJBoVVZ_B|wEhH)P{{RI5maYH* literal 0 HcmV?d00001 diff --git a/16/sod8086/wolf.obr b/16/sod8086/wolf.obr new file mode 100755 index 0000000000000000000000000000000000000000..d51eda791f38af94fa3c32e2693aa06180bfceeb GIT binary patch literal 467 zcmZ=N$}cZYEm8OzGjwq-kxRFVDb7eN&r6Rf&Mz%WPK_xj&PdJ4i7ANBP0Y;GOJ+EO0@AG*&S2L7 zRj3HGRu_nkpcv!;D0e^@( TgOrg7Kq2~os0?m-Xg)6E|yI*Cl$t-(U5wyHC%Y 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 qu@Ux;uuH3E*a2N@iZwt(DJST literal 0 HcmV?d00001 diff --git a/16/sod8086/wolfgtv.h b/16/sod8086/wolfgtv.h new file mode 100755 index 00000000..05abb0e5 --- /dev/null +++ b/16/sod8086/wolfgtv.h @@ -0,0 +1,10 @@ +//#define SPEAR +//#define JAPAN +#define GOODTIMES +#define ARTSEXTERN +#define DEMOSEXTERN +//#define MYPROFILE +//#define DEBCHECK +#define CARMACIZED +//#define UPLOAD + \ No newline at end of file diff --git a/16/sod8086/wolfhack.c b/16/sod8086/wolfhack.c new file mode 100755 index 00000000..343d3b9f --- /dev/null +++ b/16/sod8086/wolfhack.c @@ -0,0 +1,186 @@ +// WOLFHACK.C + +#include "WL_DEF.H" + +#define MAXVIEWHEIGHT 200 + +int spanstart[MAXVIEWHEIGHT/2]; + +fixed stepscale[MAXVIEWHEIGHT/2]; +fixed basedist[MAXVIEWHEIGHT/2]; + +extern char far planepics[8192]; // 4k of ceiling, 4k of floor + +int halfheight = 0; + +byte far *planeylookup[MAXVIEWHEIGHT/2]; +unsigned mirrorofs[MAXVIEWHEIGHT/2]; + +fixed psin, pcos; + +fixed FixedMul (fixed a, fixed b) +{ + return (a>>8)*(b>>8); +} + + +int mr_rowofs; +int mr_count; +int mr_xstep; +int mr_ystep; +int mr_xfrac; +int mr_yfrac; +int mr_dest; + + +/* +============== += += DrawSpans += += Height ranges from 0 (infinity) to viewheight/2 (nearest) +============== +*/ + +void DrawSpans (int x1, int x2, int height) +{ + fixed length; + int ofs; + int prestep; + fixed startxfrac, startyfrac; + + int x, startx, count, plane, startplane; + byte far *toprow, far *dest; + + toprow = planeylookup[height]+bufferofs; + mr_rowofs = mirrorofs[height]; + + mr_xstep = (psin<<1)/height; + mr_ystep = (pcos<<1)/height; + + length = basedist[height]; + startxfrac = (viewx + FixedMul(length,pcos)); + startyfrac = (viewy - FixedMul(length,psin)); + +// draw two spans simultaniously + + plane = startplane = x1&3; + prestep = viewwidth/2 - x1; + do + { + outportb (SC_INDEX+1,1<>2)*prestep; + mr_yfrac = startyfrac - (mr_ystep>>2)*prestep; + + startx = x1>>2; + mr_dest = (unsigned)toprow + startx; + mr_count = ((x2-plane)>>2) - startx + 1; + x1++; + prestep--; + if (mr_count) + MapRow (); + plane = (plane+1)&3; + } while (plane != startplane); + +} + + + + +/* +=================== += += SetPlaneViewSize += +=================== +*/ + +void SetPlaneViewSize (void) +{ + int x,y; + byte far *dest, far *src; + + halfheight = viewheight>>1; + + + for (y=0 ; y0) + basedist[y] = GLOBAL1/2*scale/y; + } + + src = PM_GetPage(0); + dest = planepics; + for (x=0 ; x<4096 ; x++) + { + *dest = *src++; + dest += 2; + } + src = PM_GetPage(1); + dest = planepics+1; + for (x=0 ; x<4096 ; x++) + { + *dest = *src++; + dest += 2; + } + +} + + +/* +=================== += += DrawPlanes += +=================== +*/ + +void DrawPlanes (void) +{ + int height, lastheight; + int x; + + if (viewheight>>1 != halfheight) + SetPlaneViewSize (); // screen size has changed + + + psin = viewsin; + if (psin < 0) + psin = -(psin&0xffff); + pcos = viewcos; + if (pcos < 0) + pcos = -(pcos&0xffff); + +// +// loop over all columns +// + lastheight = halfheight; + + for (x=0 ; x>3; + if (height < lastheight) + { // more starts + do + { + spanstart[--lastheight] = x; + } while (lastheight > height); + } + else if (height > lastheight) + { // draw spans + if (height > halfheight) + height = halfheight; + for ( ; lastheight < height ; lastheight++) + DrawSpans (spanstart[lastheight], x-1, lastheight); + } + } + + height = halfheight; + for ( ; lastheight < height ; lastheight++) + DrawSpans (spanstart[lastheight], x-1, lastheight); +} + diff --git a/16/sod8086/wolfjver.h b/16/sod8086/wolfjver.h new file mode 100755 index 00000000..c5510ba7 --- /dev/null +++ b/16/sod8086/wolfjver.h @@ -0,0 +1,8 @@ +//#define SPEAR +#define JAPAN +#define ARTSEXTERN +#define DEMOSEXTERN +//#define MYPROFILE +//#define DEBCHECK +#define CARMACIZED +//#define UPLOAD diff --git a/16/sod8086/wolfver.h b/16/sod8086/wolfver.h new file mode 100755 index 00000000..1208b35d --- /dev/null +++ b/16/sod8086/wolfver.h @@ -0,0 +1,7 @@ +//#define SPEAR +#define ARTSEXTERN +#define DEMOSEXTERN +//#define MYPROFILE +//#define DEBCHECK +#define CARMACIZED +//#define UPLOAD diff --git a/16/wf3d8086/c0.asm b/16/wf3d8086/c0.asm index f93f9213..8adb36b1 100755 --- a/16/wf3d8086/c0.asm +++ b/16/wf3d8086/c0.asm @@ -204,14 +204,14 @@ IFDEF __BOSS__ ; JNE InRealMode .286P -IFE LDATA +IFE LDATA mov dx, ds ; ; LSL AX, DX ; ; DEC AX ; MOV AX, 0FFFEh ; MOV SP, AX ; MOV SS, DX ; -ENDIF +ENDIF .8086 ; JMP BossSkip @@ -236,7 +236,7 @@ IFDEF __BOSS__ InitFailed: jmp near ptr _abort InitOK: ENDIF - + inc bx ; BX = Nb environment variables cmp es:[di], al jne @@EnvLoop ; Next variable ... @@ -410,7 +410,7 @@ ENDIF mov es,ax ; at 40:70 mov bx,70h mov byte ptr es:[bx],1 - + @@NotMidnight: xor bp,bp ; set BP to 0 for overlay mgr @@ -565,9 +565,9 @@ SaveVectors ENDP ;-------------------------------------------------------------------------- ; _restorezero() puts back all the vectors that SaveVectors took. ; -;NOTE : TSRs must BE AWARE that signal() functions which take these +;NOTE : TSRs must BE AWARE that signal() functions which take these ; vectors will be deactivated if the keep() function is executed. -; If a TSR wants to use the signal functions when it is active it +; If a TSR wants to use the signal functions when it is active it ; will have to save/restore these vectors itself when activated and ; deactivated. ;-------------------------------------------------------------------------- @@ -607,7 +607,7 @@ ENDIF ENDP ;------------------------------------------------------------------ -; Loop through a startup/exit (SE) table, +; Loop through a startup/exit (SE) table, ; calling functions in order of priority. ; ES:SI is assumed to point to the beginning of the SE table ; ES:DI is assumed to point to the end of the SE table @@ -750,12 +750,12 @@ lgth_no286MSG equ $ - no286MSG ; ; Interrupt vector save areas -; +; ; Interrupt vectors 0,4,5 & 6 are saved at startup and then restored ; when the program terminates. The signal/raise functions might ; steal these vectors during execution. ; -; Note: These vectors save area must not be altered +; Note: These vectors save area must not be altered ; without changing the save/restore logic. ; PubSym@ _Int0Vector

, __CDECL__ @@ -764,7 +764,7 @@ PubSym@ _Int5Vector
, __CDECL__ PubSym@ _Int6Vector
, __CDECL__ ; ; Miscellaneous variables -; +; PubSym@ _C0argc, , __CDECL__ dPtrPub@ _C0argv, 0, __CDECL__ dPtrPub@ _C0environ, 0, __CDECL__ diff --git a/16/wf3d8086/c0.bak b/16/wf3d8086/c0.bak new file mode 100755 index 00000000..8adb36b1 --- /dev/null +++ b/16/wf3d8086/c0.bak @@ -0,0 +1,843 @@ + NAME c0 + PAGE 60,132 + LOCALS +;[]------------------------------------------------------------[] +;| C0.ASM -- Start Up Code | +;| | +;| Turbo C++ Run Time Library | +;| | +;| Copyright (c) 1987, 1991 by Borland International Inc. | +;| All Rights Reserved. | +;[]------------------------------------------------------------[] + + __C0__ = 1 +INCLUDE RULES.ASI + +; Segment and Group declarations + +_TEXT SEGMENT BYTE PUBLIC 'CODE' + ENDS +_FARDATA SEGMENT PARA PUBLIC 'FAR_DATA' + ENDS +_FARBSS SEGMENT PARA PUBLIC 'FAR_BSS' + ENDS +IFNDEF __TINY__ +_OVERLAY_ SEGMENT PARA PUBLIC 'OVRINFO' + ENDS +_1STUB_ SEGMENT PARA PUBLIC 'STUBSEG' + ENDS +ENDIF +_DATA SEGMENT PARA PUBLIC 'DATA' + ENDS +_INIT_ SEGMENT WORD PUBLIC 'INITDATA' +InitStart label byte + ENDS +_INITEND_ SEGMENT BYTE PUBLIC 'INITDATA' +InitEnd label byte + ENDS +_EXIT_ SEGMENT WORD PUBLIC 'EXITDATA' +ExitStart label byte + ENDS +_EXITEND_ SEGMENT BYTE PUBLIC 'EXITDATA' +ExitEnd label byte + ENDS +_CVTSEG SEGMENT WORD PUBLIC 'DATA' + ENDS +_SCNSEG SEGMENT WORD PUBLIC 'DATA' + ENDS +IFNDEF __HUGE__ + _BSS SEGMENT WORD PUBLIC 'BSS' + ENDS + _BSSEND SEGMENT BYTE PUBLIC 'BSSEND' + ENDS +ENDIF +IFNDEF __TINY__ + _STACK SEGMENT STACK 'STACK' + ENDS +ENDIF + + ASSUME CS:_TEXT, DS:DGROUP + +; External References + +extrn _main:DIST +extrn _exit:DIST +extrn __exit:DIST +extrn __nfile:word +extrn __setupio:near ;required! +extrn __stklen:word +IF LDATA EQ false +extrn __heaplen:word +ENDIF + + SUBTTL Start Up Code + PAGE +;/* */ +;/*-----------------------------------------------------*/ +;/* */ +;/* Start Up Code */ +;/* ------------- */ +;/* */ +;/*-----------------------------------------------------*/ +;/* */ +PSPHigh equ 00002h +PSPEnv equ 0002ch +PSPCmd equ 00080h + + public __AHINCR +__AHINCR equ 1000h + public __AHSHIFT +__AHSHIFT equ 12 + +IFDEF __NOFLOAT__ +MINSTACK equ 128 ; minimal stack size in words +ELSE +MINSTACK equ 256 ; minimal stack size in words +ENDIF +; +; At the start, DS and ES both point to the segment prefix. +; SS points to the stack segment except in TINY model where +; SS is equal to CS +; +_TEXT SEGMENT +IFDEF __TINY__ + ORG 100h +ENDIF +STARTX PROC NEAR +; Save general information, such as : +; DGROUP segment address +; DOS version number +; Program Segment Prefix address +; Environment address +; Top of far heap + +IFDEF __TINY__ + mov dx, cs ; DX = GROUP Segment address +ELSE + mov dx, DGROUP ; DX = GROUP Segment address +ENDIF +IFNDEF __BOSS__ + mov cs:DGROUP@@, dx ; __BOSS__ +ENDIF + mov ah, 30h + int 21h ; get DOS version number + mov bp, ds:[PSPHigh]; BP = Highest Memory Segment Addr + mov bx, ds:[PSPEnv] ; BX = Environment Segment address + mov ds, dx + mov _version@, ax ; Keep major and minor version number + mov _psp@, es ; Keep Program Segment Prefix address + mov _envseg@, bx ; Keep Environment Segment address + mov word ptr _heaptop@ + 2, bp +; +; Save several vectors and install default divide by zero handler. +; + call SaveVectors + +;=================== +; +; IDsoft - Check to make sure that we're running on a 286 or better + + pushf ; Save original flags + xor ax,ax ; Clear AX + push ax + popf ; Try to pop the 0 + pushf + pop ax ; Get results of popping 0 into flags + popf ; Restore original flags + or ax,ax + ;begin 8086 hack + ;jns @@Have286 ; If no sign bit, have a 286 + jmp @@Have286 + + mov cx, lgth_no286MSG + mov dx, offset DGROUP: no286MSG + jmp MsgExit3 + +@@Have286: +; IDsoft - End of modifications (there's also a code segment string) +; +;=================== + +IFDEF __BOSS__ +; Determine if in real mode + mov ax,0FB42h ; find out if DPMI loader is here + mov bx,1 ; get info function + int 2fh ; + + push ax ; + mov ax, cs ; now, save DGROUP + add ax, cx ; + mov es, ax ; + mov dx, ds ; + mov es:DGROUP@@, dx ; + mov es:CSalias@@, ax ; + pop ax ; + +; cmp ax,0001h ; if not "TRUE" +; JNE InRealMode + +; 8 is the value of the alias selector +; in this system + MOV _protected@, cx + MOV _hugeincval@, cx + clc + mov ax, cx + xor cx, cx + or ax, ax + je @@gotshift +@@shiftcnt: + rcr ax,1 + jc @@gotshift + inc cx + jmp @@shiftcnt +@@gotshift: + mov _shiftcount@,cx + +; used by emulator +; PUSH DS +; MOV AX, 0E502H ; prot kernel function, get LDT alias +; INT 21H +; POP DS +; MOV _LDT@, AX + +; cmp _protected@,0001h ; if not "TRUE" +; JNE InRealMode + + .286P +IFE LDATA + mov dx, ds ; +; LSL AX, DX ; +; DEC AX ; + MOV AX, 0FFFEh ; + MOV SP, AX ; + MOV SS, DX ; +ENDIF + .8086 +; JMP BossSkip + +InRealMode label near + +ENDIF + +; Count the number of environment variables and compute the size. +; Each variable is ended by a 0 and a zero-length variable stops +; the environment. The environment can NOT be greater than 32k. + + les di, dword ptr _envLng@ + mov ax, di + mov bx, ax + mov cx, 07FFFh ; Environment cannot be > 32 Kbytes + cld +@@EnvLoop: + repnz scasb + jcxz InitFailed ; Bad environment !!! +IFDEF __BOSS__ + jmp InitOK +InitFailed: jmp near ptr _abort +InitOK: +ENDIF + + inc bx ; BX = Nb environment variables + cmp es:[di], al + jne @@EnvLoop ; Next variable ... + or ch, 10000000b + neg cx + mov _envLng@, cx ; Save Environment size + mov cx, dPtrSize / 2 + shl bx, cl + add bx, dPtrSize * 4 + and bx, not ((dPtrSize * 4) - 1) + mov _envSize@, bx ; Save Environment Variables Nb. + +IFNDEF __BOSS__ + +; Determine the amount of memory that we need to keep + +IFDEF _DSSTACK_ + mov dx, ds +ELSE + mov dx, ss +ENDIF + sub bp, dx ; BP = remaining size in paragraphs +IF LDATA + mov di, seg __stklen + mov es, di + mov di, es:__stklen ; DI = Requested stack size +ELSE + mov di, __stklen ; DI = Requested stack size +ENDIF +; +; Make sure that the requested stack size is at least MINSTACK words. +; + cmp di, 2*MINSTACK ; requested stack big enough ? + jae AskedStackOK + mov di, 2*MINSTACK ; no --> use minimal value +IF LDATA + mov es:__stklen, di ; override requested stack size +ELSE + mov __stklen, di ; override requested stack size +ENDIF + +AskedStackOK label near +IFDEF _DSSTACK_ + add di, offset DGROUP: edata@ + jb InitFailed ; DATA segment can NOT be > 64 Kbytes +ENDIF +IF LDATA EQ false + add di, __heaplen + jb InitFailed ; DATA segment can NOT be > 64 Kbytes +ENDIF + mov cl, 4 + shr di, cl ; $$$ Do not destroy CL $$$ + inc di ; DI = DS size in paragraphs + cmp bp, di +IF LDATA EQ false + jb InitFailed ; Not enough memory + cmp __stklen, 0 + je ExpandDS ; Expand DS up to 64 Kb + cmp __heaplen, 0 + jne ExcessOfMemory ; Much more available than needed +ExpandDS label near + mov di, 1000h + cmp bp, di + ja ExcessOfMemory ; Enough to run the program + mov di, bp + jmp short ExcessOfMemory ; Enough to run the program +ELSE + jnb ExcessOfMemory ; Much more available than needed +ENDIF + +; All initialization errors arrive here + +InitFailed label near + jmp near ptr _abort + +; Return to DOS the amount of memory in excess +; Set far heap base and pointer + +ExcessOfMemory label near + mov bx, di + add bx, dx + mov word ptr _heapbase@ + 2, bx + mov word ptr _brklvl@ + 2, bx + mov ax, _psp@ + sub bx, ax ; BX = Number of paragraphs to keep + mov es, ax ; ES = Program Segment Prefix address + mov ah, 04Ah + push di ; preserve DI + int 021h ; this call clobbers SI,DI,BP !!!!!! + pop di ; restore DI + + shl di, cl ; $$$ CX is still equal to 4 $$$ + + cli ; req'd for pre-1983 88/86s + mov ss, dx ; Set the program stack + mov sp, di + sti + +IFNDEF _DSSTACK_ + mov ax, seg __stklen + mov es, ax + mov es:__stklen, di ; If separate stack segment, save size +ENDIF + +ENDIF ; __BOSS__ + +IFNDEF __HUGE__ + +; Reset uninitialized data area + + xor ax, ax + mov es, cs:DGROUP@@ + mov di, offset DGROUP: bdata@ + mov cx, offset DGROUP: edata@ + sub cx, di + cld + rep stosb +ENDIF + +; If default number of file handles have changed then tell DOS + cmp __nfile, 20 + jbe @@NoChange + + cmp _osmajor@, 3 ; Check for >= DOS 3.3 + jb @@NoChange + ja @@DoChange + cmp _osminor@, 1Eh + jb @@NoChange +@@DoChange: + mov ax, 5801h ; Set last fit allocation + mov bx, 2 + int 21h + jc @@BadInit + + mov ah, 67h ; Expand handle table + mov bx, __nfile + int 21h + jc @@BadInit + + mov ah, 48h ; Allocate 16 bytes to find new + mov bx, 1 ; top of memory address + int 21h + jc @@BadInit + inc ax ; Adjust address to point after block + mov word ptr _heaptop@ + 2, ax + + dec ax ; Change back and release block + mov es, ax + mov ah, 49h + int 21h + jc @@BadInit + + mov ax, 5801h ; Set first fit allocation + mov bx, 0 + int 21h + jnc @@NoChange + +@@BadInit: jmp near ptr _abort + +@@NoChange: + +; Prepare main arguments + + mov ah, 0 + int 1ah ; get current BIOS time in ticks + mov word ptr _StartTime@,dx ; save it for clock() fn + mov word ptr _StartTime@+2,cx + or al,al ; was midnight flag set? + jz @@NotMidnight + mov ax,40h ; set BIOS midnight flag + mov es,ax ; at 40:70 + mov bx,70h + mov byte ptr es:[bx],1 + +@@NotMidnight: + xor bp,bp ; set BP to 0 for overlay mgr + + mov es, cs:DGROUP@@ + mov si,offset DGROUP:InitStart ;si = start of table + mov di,offset DGROUP:InitEnd ;di = end of table + call StartExit + +; ExitCode = main(argc,argv,envp); + +IF LDATA + push word ptr __C0environ+2 + push word ptr __C0environ + push word ptr __C0argv+2 + push word ptr __C0argv +ELSE + push word ptr __C0environ + push word ptr __C0argv +ENDIF + push __C0argc + call _main + +; Flush and close streams and files + + push ax + call _exit + +;--------------------------------------------------------------------------- +; _cleanup() call all #pragma exit cleanup routines. +; _checknull() check for null pointer zapping copyright message +; _terminate(int) exit program with error code +; +; These functions are called by exit(), _exit(), _cexit(), +; and _c_exit(). +;--------------------------------------------------------------------------- + +; Call cleanup routines + +__cleanup PROC DIST + PUBLIC __cleanup + + mov es, cs:DGROUP@@ + push si + push di + mov si,offset DGROUP:ExitStart + mov di,offset DGROUP:ExitEnd + call StartExit + pop di + pop si + ret +__cleanup ENDP + +; Check for null pointers before exit + +__checknull PROC DIST + PUBLIC __checknull + +IF LDATA EQ false + IFNDEF __TINY__ + push si + push di + mov es, cs:DGROUP@@ + xor ax, ax + mov si, ax + mov cx, lgth_CopyRight +ComputeChecksum label near + add al, es:[si] + adc ah, 0 + inc si + loop ComputeChecksum + sub ax, CheckSum + jz @@SumOk + mov cx, lgth_NullCheck + mov dx, offset DGROUP: NullCheck + call ErrorDisplay +@@SumOK: pop di + pop si + ENDIF +ENDIF + ret +__checknull ENDP + +; Exit to DOS + +__terminate PROC DIST + PUBLIC __terminate + mov bp,sp + mov ah,4Ch + mov al,[bp+cPtrSize] + int 21h ; Exit to DOS +__terminate ENDP + +STARTX ENDP + + SUBTTL Vector save/restore & default Zero divide routines + PAGE +;[]------------------------------------------------------------[] +;| | +;| Interrupt Save/Restore routines and default divide by zero | +;| handler. | +;| | +;[]------------------------------------------------------------[] + +ZeroDivision PROC FAR + mov cx, lgth_ZeroDivMSG + mov dx, offset DGROUP: ZeroDivMSG + jmp MsgExit3 +ZeroDivision ENDP + +;-------------------------------------------------------------------------- +; savevectors() +; +; Save vectors for 0, 4, 5 & 6 interrupts. This is for extended +; signal()/raise() support as the signal functions can steal these +; vectors during runtime. +;-------------------------------------------------------------------------- +SaveVectors PROC NEAR + push ds +; Save INT 0 + mov ax, 3500h + int 021h + mov word ptr _Int0Vector@, bx + mov word ptr _Int0Vector@+2, es +; Save INT 4 + mov ax, 3504h + int 021h + mov word ptr _Int4Vector@, bx + mov word ptr _Int4Vector@+2, es +; Save INT 5 + mov ax, 3505h + int 021h + mov word ptr _Int5Vector@, bx + mov word ptr _Int5Vector@+2, es +; Save INT 6 + mov ax, 3506h + int 021h + mov word ptr _Int6Vector@, bx + mov word ptr _Int6Vector@+2, es +; +; Install default divide by zero handler. +; + mov ax, 2500h + mov dx, cs + mov ds, dx + mov dx, offset ZeroDivision + int 21h + + pop ds + ret +SaveVectors ENDP + +;-------------------------------------------------------------------------- +; _restorezero() puts back all the vectors that SaveVectors took. +; +;NOTE : TSRs must BE AWARE that signal() functions which take these +; vectors will be deactivated if the keep() function is executed. +; If a TSR wants to use the signal functions when it is active it +; will have to save/restore these vectors itself when activated and +; deactivated. +;-------------------------------------------------------------------------- +__restorezero PROC DIST + PUBLIC __restorezero +IFDEF __HUGE__ + push ds + mov ds, cs: DGROUP@@ +ENDIF + push ds + mov ax, 2500h + lds dx, _Int0Vector@ + int 21h + pop ds + + push ds + mov ax, 2504h + lds dx, _Int4Vector@ + int 21h + pop ds + + push ds + mov ax, 2505h + lds dx, _Int5Vector@ + int 21h + pop ds + +IFNDEF __HUGE__ + push ds +ENDIF + mov ax, 2506h + lds dx, _Int6Vector@ + int 21h + pop ds + + ret + ENDP + +;------------------------------------------------------------------ +; Loop through a startup/exit (SE) table, +; calling functions in order of priority. +; ES:SI is assumed to point to the beginning of the SE table +; ES:DI is assumed to point to the end of the SE table +; First 64 priorities are reserved by Borland +;------------------------------------------------------------------ +PNEAR EQU 0 +PFAR EQU 1 +NOTUSED EQU 0ffh + +SE STRUC +calltype db ? ; 0=near,1=far,ff=not used +priority db ? ; 0=highest,ff=lowest +addrlow dw ? +addrhigh dw ? +SE ENDS + +StartExit proc near +@@Start: cmp si,offset DGROUP:InitStart ; startup or exit? + je @@StartLow ; it's startup + xor ah,ah ; start with high priority + jmp short @@SaveEnd +@@StartLow: mov ah,0ffh ;start with lowest priority +@@SaveEnd: mov dx,di ;set sentinel to end of table + mov bx,si ;bx = start of table + +@@TopOfTable: cmp bx,di ;and the end of the table? + je @@EndOfTable ;yes, exit the loop + cmp es:[bx.calltype],NOTUSED;check the call type + je @@Next + cmp si,offset DGROUP:InitStart ; startup or exit? + je @@CompareHigh ; it's startup + cmp ah,es:[bx.priority] ; it's exit + jmp short @@CheckPrior ; if priority too low, skip +@@CompareHigh: cmp es:[bx.priority],ah ;check the priority +@@CheckPrior: ja @@Next ;too high? skip + mov ah,es:[bx.priority] ;keep priority + mov dx,bx ;keep index in dx +@@Next: add bx,SIZE SE ;bx = next item in table + jmp @@TopOfTable + +@@EndOfTable: cmp dx,di ;did we exhaust the table? + je @@Done ;yes, quit + mov bx,dx ;bx = highest priority item + cmp es:[bx.calltype],PNEAR ;is it near or far? + mov es:[bx.calltype],NOTUSED;wipe the call type + push es ;save es + je @@NearCall + +@@FarCall: call DWORD PTR es:[bx.addrlow] + pop es ;restore es + jmp short @@Start + +@@NearCall: call WORD PTR es:[bx.addrlow] + pop es ;restore es + jmp short @@Start + +@@Done: ret + endp + +;------------------------------------------------------------------ + +ErrorDisplay PROC NEAR + mov ah, 040h + mov bx, 2 + int 021h + ret +ErrorDisplay ENDP + +_abort PROC DIST + PUBLIC _abort + mov cx, lgth_abortMSG + mov dx, offset DGROUP: abortMSG +MsgExit3 label near + mov ds, cs: DGROUP@@ + call ErrorDisplay +CallExit3 label near + mov ax, 3 + push ax + call __exit ; _exit(3); + ENDP + +; The DGROUP@ variable is used to reload DS with DGROUP + +PubSym@ DGROUP@, , __PASCAL__ + +IFDEF __BOSS__ +PubSym@ CSalias@,, __PASCAL__ +ENDIF + + +; __MMODEL is used to determine the memory model or the default +; pointer types at run time. + + public __MMODEL +__MMODEL dw MMODEL + +_TEXT ENDS + + SUBTTL Start Up Data Area + PAGE +;[]------------------------------------------------------------[] +;| Start Up Data Area | +;| | +;| WARNING Do not move any variables in the data | +;| segment unless you're absolutely sure | +;| that it does not matter. | +;[]------------------------------------------------------------[] + +_DATA SEGMENT + +; Magic symbol used by the debug info to locate the data segment + public DATASEG@ +DATASEG@ label byte + +; The CopyRight string must NOT be moved or changed without +; changing the null pointer check logic + +CopyRight db 4 dup(0) + db 'Borland C++ - Copyright 1991 Borland Intl.',0 +lgth_CopyRight equ $ - CopyRight + +IF LDATA EQ false +IFNDEF __TINY__ +CheckSum equ 00D5Ch +NullCheck db 'Null pointer assignment', 13, 10 +lgth_NullCheck equ $ - NullCheck +ENDIF +ENDIF + +ZeroDivMSG db 'Divide error', 13, 10 +lgth_ZeroDivMSG equ $ - ZeroDivMSG + +abortMSG db 'Abnormal program termination', 13, 10 +lgth_abortMSG equ $ - abortMSG + +; JAB - Added string for no 286 +no286MSG db 'Sorry, this program requires a 286 or better.', 13, 10 +lgth_no286MSG equ $ - no286MSG +; JAB - End of modifications + +; +; Interrupt vector save areas +; +; Interrupt vectors 0,4,5 & 6 are saved at startup and then restored +; when the program terminates. The signal/raise functions might +; steal these vectors during execution. +; +; Note: These vectors save area must not be altered +; without changing the save/restore logic. +; +PubSym@ _Int0Vector
, __CDECL__ +PubSym@ _Int4Vector
, __CDECL__ +PubSym@ _Int5Vector
, __CDECL__ +PubSym@ _Int6Vector
, __CDECL__ +; +; Miscellaneous variables +; +PubSym@ _C0argc, , __CDECL__ +dPtrPub@ _C0argv, 0, __CDECL__ +dPtrPub@ _C0environ, 0, __CDECL__ +PubSym@ _envLng, , __CDECL__ +PubSym@ _envseg, , __CDECL__ +PubSym@ _envSize, , __CDECL__ +PubSym@ _psp, , __CDECL__ +PubSym@ _version,
, __CDECL__ +PubSym@ _brklvl,
, __CDECL__ +PubSym@ _heaptop,
, __CDECL__ + +; If stack in DS and Large data model then override location of __emu + +IFDEF _DSSTACK_ +IF LDATA +public __emu +__emu db 044h DUP (0) + db 0CCh DUP (?) +ENDIF +ENDIF + +_DATA ENDS + + +_CVTSEG SEGMENT +PubSym@ _RealCvtVector,