From 47f4a458d636a889e955e68f896708f1276febc0 Mon Sep 17 00:00:00 2001 From: Dave Chapman Date: Tue, 28 Mar 2006 15:44:01 +0000 Subject: [PATCH] Patch #2969 - Doom! Currently only working on the H300. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@9312 a1c6a512-1295-4272-9138-f99709370657 --- apps/plugin.c | 6 + apps/plugin.h | 7 +- apps/plugins/Makefile | 5 + apps/plugins/doom/Changelog | 47 + apps/plugins/doom/Makefile | 145 + apps/plugins/doom/am_map.c | 1702 +++++++++++ apps/plugins/doom/am_map.h | 106 + apps/plugins/doom/d_englsh.h | 705 +++++ apps/plugins/doom/d_event.h | 128 + apps/plugins/doom/d_french.h | 437 +++ apps/plugins/doom/d_items.c | 138 + apps/plugins/doom/d_items.h | 57 + apps/plugins/doom/d_main.c | 844 ++++++ apps/plugins/doom/d_main.h | 74 + apps/plugins/doom/d_net.c | 149 + apps/plugins/doom/d_net.h | 213 ++ apps/plugins/doom/d_player.h | 232 ++ apps/plugins/doom/d_think.h | 92 + apps/plugins/doom/d_ticcmd.h | 57 + apps/plugins/doom/doomdata.h | 187 ++ apps/plugins/doom/doomdef.c | 39 + apps/plugins/doom/doomdef.h | 306 ++ apps/plugins/doom/doomstat.c | 104 + apps/plugins/doom/doomstat.h | 373 +++ apps/plugins/doom/doomtype.h | 85 + apps/plugins/doom/dstrings.c | 83 + apps/plugins/doom/dstrings.h | 73 + apps/plugins/doom/f_finale.c | 682 +++++ apps/plugins/doom/f_finale.h | 54 + apps/plugins/doom/f_wipe.c | 193 ++ apps/plugins/doom/f_wipe.h | 43 + apps/plugins/doom/g_game.c | 2818 +++++++++++++++++ apps/plugins/doom/g_game.h | 192 ++ apps/plugins/doom/hu_lib.c | 770 +++++ apps/plugins/doom/hu_lib.h | 264 ++ apps/plugins/doom/hu_stuff.c | 1753 +++++++++++ apps/plugins/doom/hu_stuff.h | 92 + apps/plugins/doom/i_sound.c | 607 ++++ apps/plugins/doom/i_sound.h | 126 + apps/plugins/doom/i_system.c | 134 + apps/plugins/doom/i_system.h | 65 + apps/plugins/doom/i_video.c | 454 +++ apps/plugins/doom/i_video.h | 56 + apps/plugins/doom/info.c | 5185 ++++++++++++++++++++++++++++++++ apps/plugins/doom/info.h | 1454 +++++++++ apps/plugins/doom/m_argv.c | 53 + apps/plugins/doom/m_argv.h | 45 + apps/plugins/doom/m_bbox.c | 58 + apps/plugins/doom/m_bbox.h | 54 + apps/plugins/doom/m_cheat.c | 104 + apps/plugins/doom/m_cheat.h | 63 + apps/plugins/doom/m_fixed.h | 94 + apps/plugins/doom/m_menu.c | 1848 ++++++++++++ apps/plugins/doom/m_menu.h | 121 + apps/plugins/doom/m_misc.c | 1077 +++++++ apps/plugins/doom/m_misc.h | 112 + apps/plugins/doom/m_random.c | 136 + apps/plugins/doom/m_random.h | 148 + apps/plugins/doom/m_swap.h | 104 + apps/plugins/doom/p_ceilng.c | 468 +++ apps/plugins/doom/p_doors.c | 672 +++++ apps/plugins/doom/p_enemy.c | 2623 ++++++++++++++++ apps/plugins/doom/p_enemy.h | 50 + apps/plugins/doom/p_floor.c | 1035 +++++++ apps/plugins/doom/p_genlin.c | 1154 +++++++ apps/plugins/doom/p_inter.c | 904 ++++++ apps/plugins/doom/p_inter.h | 77 + apps/plugins/doom/p_lights.c | 437 +++ apps/plugins/doom/p_map.c | 2207 ++++++++++++++ apps/plugins/doom/p_map.h | 90 + apps/plugins/doom/p_maputl.c | 700 +++++ apps/plugins/doom/p_maputl.h | 91 + apps/plugins/doom/p_mobj.c | 1394 +++++++++ apps/plugins/doom/p_mobj.h | 409 +++ apps/plugins/doom/p_plats.c | 434 +++ apps/plugins/doom/p_pspr.c | 853 ++++++ apps/plugins/doom/p_pspr.h | 93 + apps/plugins/doom/p_saveg.c | 987 ++++++ apps/plugins/doom/p_saveg.h | 63 + apps/plugins/doom/p_setup.c | 1255 ++++++++ apps/plugins/doom/p_setup.h | 55 + apps/plugins/doom/p_sight.c | 346 +++ apps/plugins/doom/p_spec.c | 3255 ++++++++++++++++++++ apps/plugins/doom/p_spec.h | 1148 +++++++ apps/plugins/doom/p_switch.c | 1138 +++++++ apps/plugins/doom/p_telept.c | 322 ++ apps/plugins/doom/p_tick.c | 255 ++ apps/plugins/doom/p_tick.h | 66 + apps/plugins/doom/p_user.c | 420 +++ apps/plugins/doom/p_user.h | 45 + apps/plugins/doom/r_bsp.c | 576 ++++ apps/plugins/doom/r_bsp.h | 78 + apps/plugins/doom/r_data.c | 975 ++++++ apps/plugins/doom/r_data.h | 105 + apps/plugins/doom/r_defs.h | 422 +++ apps/plugins/doom/r_draw.c | 677 +++++ apps/plugins/doom/r_draw.h | 99 + apps/plugins/doom/r_main.c | 531 ++++ apps/plugins/doom/r_main.h | 125 + apps/plugins/doom/r_plane.c | 434 +++ apps/plugins/doom/r_plane.h | 65 + apps/plugins/doom/r_segs.c | 843 ++++++ apps/plugins/doom/r_segs.h | 42 + apps/plugins/doom/r_sky.c | 53 + apps/plugins/doom/r_sky.h | 53 + apps/plugins/doom/r_state.h | 140 + apps/plugins/doom/r_things.c | 976 ++++++ apps/plugins/doom/r_things.h | 80 + apps/plugins/doom/rockdoom.c | 706 +++++ apps/plugins/doom/rockmacros.h | 93 + apps/plugins/doom/s_sound.c | 608 ++++ apps/plugins/doom/s_sound.h | 96 + apps/plugins/doom/sounds.c | 240 ++ apps/plugins/doom/sounds.h | 303 ++ apps/plugins/doom/st_lib.c | 372 +++ apps/plugins/doom/st_lib.h | 207 ++ apps/plugins/doom/st_stuff.c | 1153 +++++++ apps/plugins/doom/st_stuff.h | 101 + apps/plugins/doom/tables.c | 2196 ++++++++++++++ apps/plugins/doom/tables.h | 103 + apps/plugins/doom/v_video.c | 700 +++++ apps/plugins/doom/v_video.h | 185 ++ apps/plugins/doom/w_wad.c | 683 +++++ apps/plugins/doom/w_wad.h | 164 + apps/plugins/doom/wi_stuff.c | 1989 ++++++++++++ apps/plugins/doom/wi_stuff.h | 62 + apps/plugins/doom/z_bmalloc.c | 117 + apps/plugins/doom/z_bmalloc.h | 51 + apps/plugins/doom/z_zone.c | 666 ++++ apps/plugins/doom/z_zone.h | 117 + 130 files changed, 65584 insertions(+), 1 deletion(-) create mode 100644 apps/plugins/doom/Changelog create mode 100644 apps/plugins/doom/Makefile create mode 100644 apps/plugins/doom/am_map.c create mode 100644 apps/plugins/doom/am_map.h create mode 100644 apps/plugins/doom/d_englsh.h create mode 100644 apps/plugins/doom/d_event.h create mode 100644 apps/plugins/doom/d_french.h create mode 100644 apps/plugins/doom/d_items.c create mode 100644 apps/plugins/doom/d_items.h create mode 100644 apps/plugins/doom/d_main.c create mode 100644 apps/plugins/doom/d_main.h create mode 100644 apps/plugins/doom/d_net.c create mode 100644 apps/plugins/doom/d_net.h create mode 100644 apps/plugins/doom/d_player.h create mode 100644 apps/plugins/doom/d_think.h create mode 100644 apps/plugins/doom/d_ticcmd.h create mode 100644 apps/plugins/doom/doomdata.h create mode 100644 apps/plugins/doom/doomdef.c create mode 100644 apps/plugins/doom/doomdef.h create mode 100644 apps/plugins/doom/doomstat.c create mode 100644 apps/plugins/doom/doomstat.h create mode 100644 apps/plugins/doom/doomtype.h create mode 100644 apps/plugins/doom/dstrings.c create mode 100644 apps/plugins/doom/dstrings.h create mode 100644 apps/plugins/doom/f_finale.c create mode 100644 apps/plugins/doom/f_finale.h create mode 100644 apps/plugins/doom/f_wipe.c create mode 100644 apps/plugins/doom/f_wipe.h create mode 100644 apps/plugins/doom/g_game.c create mode 100644 apps/plugins/doom/g_game.h create mode 100644 apps/plugins/doom/hu_lib.c create mode 100644 apps/plugins/doom/hu_lib.h create mode 100644 apps/plugins/doom/hu_stuff.c create mode 100644 apps/plugins/doom/hu_stuff.h create mode 100644 apps/plugins/doom/i_sound.c create mode 100644 apps/plugins/doom/i_sound.h create mode 100644 apps/plugins/doom/i_system.c create mode 100644 apps/plugins/doom/i_system.h create mode 100644 apps/plugins/doom/i_video.c create mode 100644 apps/plugins/doom/i_video.h create mode 100644 apps/plugins/doom/info.c create mode 100644 apps/plugins/doom/info.h create mode 100644 apps/plugins/doom/m_argv.c create mode 100644 apps/plugins/doom/m_argv.h create mode 100644 apps/plugins/doom/m_bbox.c create mode 100644 apps/plugins/doom/m_bbox.h create mode 100644 apps/plugins/doom/m_cheat.c create mode 100644 apps/plugins/doom/m_cheat.h create mode 100644 apps/plugins/doom/m_fixed.h create mode 100644 apps/plugins/doom/m_menu.c create mode 100644 apps/plugins/doom/m_menu.h create mode 100644 apps/plugins/doom/m_misc.c create mode 100644 apps/plugins/doom/m_misc.h create mode 100644 apps/plugins/doom/m_random.c create mode 100644 apps/plugins/doom/m_random.h create mode 100644 apps/plugins/doom/m_swap.h create mode 100644 apps/plugins/doom/p_ceilng.c create mode 100644 apps/plugins/doom/p_doors.c create mode 100644 apps/plugins/doom/p_enemy.c create mode 100644 apps/plugins/doom/p_enemy.h create mode 100644 apps/plugins/doom/p_floor.c create mode 100644 apps/plugins/doom/p_genlin.c create mode 100644 apps/plugins/doom/p_inter.c create mode 100644 apps/plugins/doom/p_inter.h create mode 100644 apps/plugins/doom/p_lights.c create mode 100644 apps/plugins/doom/p_map.c create mode 100644 apps/plugins/doom/p_map.h create mode 100644 apps/plugins/doom/p_maputl.c create mode 100644 apps/plugins/doom/p_maputl.h create mode 100644 apps/plugins/doom/p_mobj.c create mode 100644 apps/plugins/doom/p_mobj.h create mode 100644 apps/plugins/doom/p_plats.c create mode 100644 apps/plugins/doom/p_pspr.c create mode 100644 apps/plugins/doom/p_pspr.h create mode 100644 apps/plugins/doom/p_saveg.c create mode 100644 apps/plugins/doom/p_saveg.h create mode 100644 apps/plugins/doom/p_setup.c create mode 100644 apps/plugins/doom/p_setup.h create mode 100644 apps/plugins/doom/p_sight.c create mode 100644 apps/plugins/doom/p_spec.c create mode 100644 apps/plugins/doom/p_spec.h create mode 100644 apps/plugins/doom/p_switch.c create mode 100644 apps/plugins/doom/p_telept.c create mode 100644 apps/plugins/doom/p_tick.c create mode 100644 apps/plugins/doom/p_tick.h create mode 100644 apps/plugins/doom/p_user.c create mode 100644 apps/plugins/doom/p_user.h create mode 100644 apps/plugins/doom/r_bsp.c create mode 100644 apps/plugins/doom/r_bsp.h create mode 100644 apps/plugins/doom/r_data.c create mode 100644 apps/plugins/doom/r_data.h create mode 100644 apps/plugins/doom/r_defs.h create mode 100644 apps/plugins/doom/r_draw.c create mode 100644 apps/plugins/doom/r_draw.h create mode 100644 apps/plugins/doom/r_main.c create mode 100644 apps/plugins/doom/r_main.h create mode 100644 apps/plugins/doom/r_plane.c create mode 100644 apps/plugins/doom/r_plane.h create mode 100644 apps/plugins/doom/r_segs.c create mode 100644 apps/plugins/doom/r_segs.h create mode 100644 apps/plugins/doom/r_sky.c create mode 100644 apps/plugins/doom/r_sky.h create mode 100644 apps/plugins/doom/r_state.h create mode 100644 apps/plugins/doom/r_things.c create mode 100644 apps/plugins/doom/r_things.h create mode 100644 apps/plugins/doom/rockdoom.c create mode 100644 apps/plugins/doom/rockmacros.h create mode 100644 apps/plugins/doom/s_sound.c create mode 100644 apps/plugins/doom/s_sound.h create mode 100644 apps/plugins/doom/sounds.c create mode 100644 apps/plugins/doom/sounds.h create mode 100644 apps/plugins/doom/st_lib.c create mode 100644 apps/plugins/doom/st_lib.h create mode 100644 apps/plugins/doom/st_stuff.c create mode 100644 apps/plugins/doom/st_stuff.h create mode 100644 apps/plugins/doom/tables.c create mode 100644 apps/plugins/doom/tables.h create mode 100644 apps/plugins/doom/v_video.c create mode 100644 apps/plugins/doom/v_video.h create mode 100644 apps/plugins/doom/w_wad.c create mode 100644 apps/plugins/doom/w_wad.h create mode 100644 apps/plugins/doom/wi_stuff.c create mode 100644 apps/plugins/doom/wi_stuff.h create mode 100644 apps/plugins/doom/z_bmalloc.c create mode 100644 apps/plugins/doom/z_bmalloc.h create mode 100644 apps/plugins/doom/z_zone.c create mode 100644 apps/plugins/doom/z_zone.h diff --git a/apps/plugin.c b/apps/plugin.c index d69fbfc3aa..b18ccb0626 100644 --- a/apps/plugin.c +++ b/apps/plugin.c @@ -67,6 +67,8 @@ #include "bmp.h" #endif +#include "backdrop.h" + #ifdef HAVE_REMOTE_LCD #include "lcd-remote.h" #endif @@ -409,6 +411,10 @@ static const struct plugin_api rockbox_api = { i2c_end, i2c_write, #endif + + vsnprintf, + memchr, + load_main_backdrop }; int plugin_load(const char* plugin, void* parameter) diff --git a/apps/plugin.h b/apps/plugin.h index a2182d6f9b..f9cca6ffc3 100644 --- a/apps/plugin.h +++ b/apps/plugin.h @@ -29,6 +29,7 @@ #define MEM 2 #endif +#include #include #include #include @@ -101,7 +102,7 @@ #define PLUGIN_MAGIC 0x526F634B /* RocK */ /* increase this every time the api struct changes */ -#define PLUGIN_API_VERSION 16 +#define PLUGIN_API_VERSION 17 /* update this to latest version if a change to the api struct breaks backwards compatibility (and please take the opportunity to sort in any @@ -479,6 +480,10 @@ struct plugin_api { void (*i2c_end)(void); int (*i2c_write)(int address, unsigned char* buf, int count ); #endif + + int (*vsnprintf)(char *buf, int size, const char *fmt, va_list ap); + void *(*memchr)(const void *s1, int c, size_t n); + bool (*load_main_backdrop)(char* filename); }; /* plugin header */ diff --git a/apps/plugins/Makefile b/apps/plugins/Makefile index 586eb605da..c59033aab4 100644 --- a/apps/plugins/Makefile +++ b/apps/plugins/Makefile @@ -84,6 +84,11 @@ ifneq (,$(strip $(foreach tgt,IPOD_VIDEO IPOD_NANO IPOD_COLOR IRIVER \ SUBDIRS += pacbox endif +# Build Doom for the H300 and color ipods +ifneq (,$(strip $(foreach tgt, IRIVER_H300 IPOD_NANO IPOD_COLOR IPOD_VIDEO,$(findstring $(tgt),$(TARGET))))) + SUBDIRS += doom +endif + .PHONY: $(SUBDIRS) all: $(BUILDDIR)/libplugin.a $(ROCKS) $(SUBDIRS) $(DEPFILE) diff --git a/apps/plugins/doom/Changelog b/apps/plugins/doom/Changelog new file mode 100644 index 0000000000..2663af17ad --- /dev/null +++ b/apps/plugins/doom/Changelog @@ -0,0 +1,47 @@ +Changelog: +Fixed Nightmare mode +Fixed end game +Fixed quit crash +Added more prboom rendering code -> speedup + expanded rendering code -> speedup +Rewrote lowquality renderer and moved option to loader -> adds 1 fps to speed +Changed Default Keys: + DOOM PLAYER + ------ ------ + UP REC + DOWN DOWN + LEFT LEFT + RIGHT RIGHT + SHOOT MODE + OPEN DOWN + ESC ON + ENTER SELECT + WEAPON OFF +Menu Keys now work independent of ingame keys +All code reformatted and warnings reduced (only 6 now) +New Menu code to select options and Base game + doom shareware doom1.wad + doom registered doom.wad + doom retail (ultimate doom) doomu.wad + doom 2 doom2.wad + plutonia plutonia.wad + tnt tnt.wad +Doom directory is now /games/doom/ +Disabled mouse calls -> speedup +Finally have the right timer. -> run is actually usable now +Added a timedemo option for speed testing, only runs with doom shareware, + Ultimate doom, or registered doom saves timedemo information in /games/doom/timedemo.txt +Merged Paul's Ipod changes, hopefully it works now +Added addon code so that additional wadfiles can be added to the startup. + +# Version 0.8 +Extended the addon code to automatically search for wads in /games/doom/addons/ +Changed the memory allocation to use doom's block allocator exclusively this can + be used in other plugins that need malloc, realloc, and calloc (include z_zone.c, z_zone.h) +Included linuxstb's code for the Ipod +Redid the sound code partially from prboom + -> caches all sound at startup + -> helped reduce the number of pauses in the game +All new renderer from prboom -> translucent sprites, dynamic palettes FASTER + more wads work properly (no more graphical errors in halflife) + diff --git a/apps/plugins/doom/Makefile b/apps/plugins/doom/Makefile new file mode 100644 index 0000000000..c45ffe78da --- /dev/null +++ b/apps/plugins/doom/Makefile @@ -0,0 +1,145 @@ +################################################################ +# +# $Id$ +# +# $Log$ +# Revision 1.1 2006/03/28 15:44:01 dave +# Patch #2969 - Doom! Currently only working on the H300. +# +# + +INCLUDES = -I$(APPSDIR) -I.. -I. -I$(FIRMDIR)/include -I$(FIRMDIR)/export \ + -I$(FIRMDIR)/common -I$(FIRMDIR)/drivers -I$(OUTDIR) -I$(BUILDDIR) +CFLAGS = $(GCCOPTS) $(INCLUDES) $(TARGET) $(EXTRA_DEFINES) \ + -DTARGET_ID=$(TARGET_ID) -DMEM=${MEMORYSIZE} -DPLUGIN \ + -Wno-strict-prototypes -O2 + +ifdef APPEXTRA + INCLUDES += $(patsubst %,-I$(APPSDIR)/%,$(subst :, ,$(APPEXTRA))) +endif + +ifneq (,$(strip $(foreach tgt,IPOD_NANO IPOD_COLOR IPOD_VIDEO,$(findstring $(tgt),$(TARGET))))) +ifndef SIMVER + CFLAGS += -mstructure-size-boundary=8 +endif +else +ifndef SIMVER + CFLAGS += -D__BIG_ENDIAN__ +endif +endif + +LINKFILE := $(OBJDIR)/link.lds +DEPFILE = $(OBJDIR)/dep-doom +SRC = info.c doomdef.c doomstat.c dstrings.c tables.c \ + f_finale.c f_wipe.c d_net.c d_items.c g_game.c m_menu.c m_argv.c \ + m_cheat.c m_random.c am_map.c p_ceilng.c p_doors.c p_genlin.c \ + p_enemy.c p_floor.c p_inter.c p_lights.c p_map.c p_maputl.c p_plats.c \ + p_pspr.c p_setup.c p_sight.c p_spec.c p_switch.c p_mobj.c p_telept.c \ + p_tick.c p_saveg.c p_user.c r_bsp.c r_data.c r_draw.c r_main.c \ + r_plane.c r_segs.c r_sky.c r_things.c wi_stuff.c v_video.c st_lib.c \ + st_stuff.c hu_stuff.c hu_lib.c s_sound.c z_zone.c z_bmalloc.c sounds.c \ + d_main.c m_misc.c m_bbox.c i_system.c i_sound.c i_video.c \ + w_wad.c rockdoom.c +# fixmath2.S + +SOURCES = $(SRC) +OBJS := $(SRC:%.c=$(OBJDIR)/%.o) +#OBJS2 := $(SRC:%.c=$(OBJDIR)/%.o) +#OBJS = $(patsubst %.S, $(OBJDIR)/%.o, $(OBJS2)) +DIRS = . + + +ifndef SIMVER +ifneq (,$(findstring RECORDER,$(TARGET))) ## Archos recorder targets + LDS := archos.lds + OUTPUT = $(OUTDIR)/doom.ovl +else ## iRiver target + LDS := ../plugin.lds + OUTPUT = $(OUTDIR)/doom.rock +endif +else ## simulators + OUTPUT = $(OUTDIR)/doom.rock +endif + +all: $(OUTPUT) + +ifndef SIMVER +$(OBJDIR)/doom.elf: $(OBJS) $(LINKFILE) + @echo "LD "`basename $@` + @$(CC) $(GCCOPTS) $(LDFLAGS) -nostdlib -o $@ $(OBJS) -L$(BUILDDIR) -lplugin -lgcc\ + -T$(LINKFILE) -Wl,-Map,$(OBJDIR)/doom.map + +$(OUTPUT): $(OBJDIR)/doom.elf + @echo "OBJCOPY "`basename $@` + @$(OC) -O binary $< $@ +else + +ifeq ($(SIMVER), x11) +################################################### +# This is the X11 simulator version + +$(OUTPUT): $(OBJS) + @echo "LD $@" + @$(CC) $(CFLAGS) -shared $(OBJS) -L$(BUILDDIR) -lplugin -o $@ +ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN) +# 'x' must be kept or you'll have "Win32 error 5" +# $ fgrep 5 /usr/include/w32api/winerror.h | head -1 +# #define ERROR_ACCESS_DENIED 5L +else + @chmod -x $@ +endif + +else # end of x11-simulator +ifeq ($(SIMVER), sdl) +################################################### +# This is the sdl simulator version + +$(OUTPUT): $(OBJS) + @echo "LD $@" + @$(CC) $(CFLAGS) -shared $(OBJS) -L$(BUILDDIR) -lplugin -o $@ +ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN) +# 'x' must be kept or you'll have "Win32 error 5" +# $ fgrep 5 /usr/include/w32api/winerror.h | head -1 +# #define ERROR_ACCESS_DENIED 5L +else + @chmod -x $@ +endif + +else # end of sdl-simulator +################################################### +# This is the win32 simulator version +DLLTOOLFLAGS = --export-all +DLLWRAPFLAGS = -s --entry _DllMain@12 --target=i386-mingw32 -mno-cygwin + +$(OUTPUT): $(OBJS) + @echo "DLL "`basename $@` + @$(DLLTOOL) $(DLLTOOLFLAGS) -z $(OBJDIR)/$*.def $(OBJS) + @$(DLLWRAP) $(DLLWRAPFLAGS) --def $(OBJDIR)/$*.def $(OBJS) \ + $(BUILDDIR)/libplugin.a -o $@ +ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN) +# 'x' must be kept or you'll have "Win32 error 5" +# $ fgrep 5 /usr/include/w32api/winerror.h | head -1 +# #define ERROR_ACCESS_DENIED 5L +else + @chmod -x $@ +endif +endif # end of win32-simulator +endif +endif # end of simulator section + + +include $(TOOLSDIR)/make.inc + +# MEMORYSIZE should be passed on to this makefile with the chosen memory size +# given in number of MB +$(LINKFILE): $(LDS) + @echo "build "`basename $@` + @cat $< | $(CC) -DMEMORYSIZE=$(MEMORYSIZE) $(INCLUDES) $(TARGET) $(DEFINES) \ + -E -P - >$@ + +clean: + @echo "cleaning doom" + @rm -rf $(OBJDIR)/doom + @rm -f $(OBJDIR)/doom.* $(DEPFILE) + +-include $(DEPFILE) diff --git a/apps/plugins/doom/am_map.c b/apps/plugins/doom/am_map.c new file mode 100644 index 0000000000..9bdd4e4e70 --- /dev/null +++ b/apps/plugins/doom/am_map.c @@ -0,0 +1,1702 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * the automap code + * + *----------------------------------------------------------------------------- + */ + +#include "doomstat.h" + +#include "st_stuff.h" +#include "r_main.h" +#include "p_setup.h" +#include "p_maputl.h" +#include "w_wad.h" +#include "v_video.h" +#include "p_spec.h" +#include "am_map.h" +#include "dstrings.h" +//#include "d_deh.h" // Ty 03/27/98 - externalizations +#include "g_game.h" +#include "rockmacros.h" + + +//jff 1/7/98 default automap colors added +int mapcolor_back; // map background +int mapcolor_grid; // grid lines color +int mapcolor_wall; // normal 1s wall color +int mapcolor_fchg; // line at floor height change color +int mapcolor_cchg; // line at ceiling height change color +int mapcolor_clsd; // line at sector with floor=ceiling color +int mapcolor_rkey; // red key color +int mapcolor_bkey; // blue key color +int mapcolor_ykey; // yellow key color +int mapcolor_rdor; // red door color (diff from keys to allow option) +int mapcolor_bdor; // blue door color (of enabling one but not other ) +int mapcolor_ydor; // yellow door color +int mapcolor_tele; // teleporter line color +int mapcolor_secr; // secret sector boundary color +int mapcolor_exit; // jff 4/23/98 add exit line color +int mapcolor_unsn; // computer map unseen line color +int mapcolor_flat; // line with no floor/ceiling changes +int mapcolor_sprt; // general sprite color +int mapcolor_item; // item sprite color +int mapcolor_frnd; // friendly sprite color +int mapcolor_hair; // crosshair color +int mapcolor_sngl; // single player arrow color +int mapcolor_plyr[4] = { 112, 88, 64, 176 }; // colors for player arrows in multiplayer + +//jff 3/9/98 add option to not show secret sectors until entered +int map_secret_after=0; +//jff 4/3/98 add symbols for "no-color" for disable and "black color" for black +#define NC 0 +#define BC 247 + +// drawing stuff +#define FB 0 + +// scale on entry +#define INITSCALEMTOF (.2*FRACUNIT) +// how much the automap moves window per tic in frame-buffer coordinates +// moves 140 pixels in 1 second +#define F_PANINC 4 +// how much zoom-in per tic +// goes to 2x in 1 second +#define M_ZOOMIN ((int) (1.02*FRACUNIT)) +// how much zoom-out per tic +// pulls out to 0.5x in 1 second +#define M_ZOOMOUT ((int) (FRACUNIT/1.02)) + +// translates between frame-buffer and map distances +#define FTOM(x) FixedMul(((x)<<16),scale_ftom) +#define MTOF(x) (FixedMul((x),scale_mtof)>>16) +// translates between frame-buffer and map coordinates +#define CXMTOF(x) (f_x + MTOF((x)-m_x)) +#define CYMTOF(y) (f_y + (f_h - MTOF((y)-m_y))) + +typedef struct +{ + int x, y; +} fpoint_t; + +typedef struct +{ + fpoint_t a, b; +} fline_t; + +typedef struct +{ + mpoint_t a, b; +} mline_t; + +typedef struct +{ + fixed_t slp, islp; +} islope_t; + +// +// The vector graphics for the automap. +// A line drawing of the player pointing right, +// starting from the middle. +// +#define R ((8*PLAYERRADIUS)/7) +mline_t player_arrow[] = + { + { { -R+R/8, 0 }, { R, 0 } }, // ----- + { { R, 0 }, { R-R/2, R/4 } }, // -----> + { { R, 0 }, { R-R/2, -R/4 } }, + { { -R+R/8, 0 }, { -R-R/8, R/4 } }, // >----> + { { -R+R/8, 0 }, { -R-R/8, -R/4 } }, + { { -R+3*R/8, 0 }, { -R+R/8, R/4 } }, // >>---> + { { -R+3*R/8, 0 }, { -R+R/8, -R/4 } } + }; +#undef R +#define NUMPLYRLINES (sizeof(player_arrow)/sizeof(mline_t)) + +#define R ((8*PLAYERRADIUS)/7) +mline_t cheat_player_arrow[] = + { // killough 3/22/98: He's alive, Jim :) + { { -R+R/8, 0 }, { R, 0 } }, // ----- + { { R, 0 }, { R-R/2, R/4 } }, // -----> + { { R, 0 }, { R-R/2, -R/4 } }, + { { -R+R/8, 0 }, { -R-R/8, R/4 } }, // >----> + { { -R+R/8, 0 }, { -R-R/8, -R/4 } }, + { { -R+3*R/8, 0 }, { -R+R/8, R/4 } }, // >>---> + { { -R+3*R/8, 0 }, { -R+R/8, -R/4 } }, + { { -R/10-R/6, R/4}, {-R/10-R/6, -R/4} }, // J + { { -R/10-R/6, -R/4}, {-R/10-R/6-R/8, -R/4} }, + { { -R/10-R/6-R/8, -R/4}, {-R/10-R/6-R/8, -R/8} }, + { { -R/10, R/4}, {-R/10, -R/4}}, // F + { { -R/10, R/4}, {-R/10+R/8, R/4}}, + { { -R/10+R/4, R/4}, {-R/10+R/4, -R/4}}, // F + { { -R/10+R/4, R/4}, {-R/10+R/4+R/8, R/4}}, + }; +#undef R +#define NUMCHEATPLYRLINES (sizeof(cheat_player_arrow)/sizeof(mline_t)) + +#define R (FRACUNIT) +mline_t triangle_guy[] = + { + { { (fixed_t)(-.867*R), (fixed_t)(-.5*R) }, { (fixed_t)( .867*R), (fixed_t)(-.5*R) } }, + { { (fixed_t)( .867*R), (fixed_t)(-.5*R) }, { (fixed_t)(0 ), (fixed_t)( R) } }, + { { (fixed_t)(0 ), (fixed_t)( R) }, { (fixed_t)(-.867*R), (fixed_t)(-.5*R) } } + }; +#undef R +#define NUMTRIANGLEGUYLINES (sizeof(triangle_guy)/sizeof(mline_t)) + +//jff 1/5/98 new symbol for keys on automap +#define R (FRACUNIT) +mline_t cross_mark[] = + { + { { -R, 0 }, { R, 0} }, + { { 0, -R }, { 0, R } }, + }; +#undef R +#define NUMCROSSMARKLINES (sizeof(cross_mark)/sizeof(mline_t)) +//jff 1/5/98 end of new symbol + +#define R (FRACUNIT) +mline_t thintriangle_guy[] = + { + { { (fixed_t)(-.5*R), (fixed_t)(-.7*R) }, { (fixed_t)( R), (fixed_t)( 0) } }, + { { (fixed_t)( R), (fixed_t)( 0) }, { (fixed_t)(-.5*R), (fixed_t)( .7*R) } }, + { { (fixed_t)(-.5*R), (fixed_t)( .7*R) }, { (fixed_t)(-.5*R), (fixed_t)(-.7*R) } } + }; +#undef R +#define NUMTHINTRIANGLEGUYLINES (sizeof(thintriangle_guy)/sizeof(mline_t)) + +int ddt_cheating = 0; // killough 2/7/98: make global, rename to ddt_* + +static int leveljuststarted = 1; // kluge until AM_LevelInit() is called + +enum automapmode_e automapmode; // Mode that the automap is in + +// location of window on screen +static int f_x; +static int f_y; + +// size of window on screen +static int f_w; +static int f_h; + +static mpoint_t m_paninc; // how far the window pans each tic (map coords) +static fixed_t mtof_zoommul; // how far the window zooms each tic (map coords) +static fixed_t ftom_zoommul; // how far the window zooms each tic (fb coords) + +static fixed_t m_x, m_y; // LL x,y window location on the map (map coords) +static fixed_t m_x2, m_y2; // UR x,y window location on the map (map coords) + +// +// width/height of window on map (map coords) +// +static fixed_t m_w; +static fixed_t m_h; + +// based on level size +static fixed_t min_x; +static fixed_t min_y; +static fixed_t max_x; +static fixed_t max_y; + +static fixed_t max_w; // max_x-min_x, +static fixed_t max_h; // max_y-min_y + +// based on player size +static fixed_t min_w; +static fixed_t min_h; + + +static fixed_t min_scale_mtof; // used to tell when to stop zooming out +static fixed_t max_scale_mtof; // used to tell when to stop zooming in + +// old stuff for recovery later +static fixed_t old_m_w, old_m_h; +static fixed_t old_m_x, old_m_y; + +// old location used by the Follower routine +static mpoint_t f_oldloc; + +// used by MTOF to scale from map-to-frame-buffer coords +static fixed_t scale_mtof = (fixed_t)INITSCALEMTOF; +// used by FTOM to scale from frame-buffer-to-map coords (=1/scale_mtof) +static fixed_t scale_ftom; + +static player_t *plr; // the player represented by an arrow + +// killough 2/22/98: Remove limit on automap marks, +// and make variables external for use in savegames. + +mpoint_t *markpoints = NULL; // where the points are +int markpointnum = 0; // next point to be assigned (also number of points now) +int markpointnum_max = 0; // killough 2/22/98 + +static boolean stopped = true; + +// +// AM_getIslope() +// +// Calculates the slope and slope according to the x-axis of a line +// segment in map coordinates (with the upright y-axis n' all) so +// that it can be used with the brain-dead drawing stuff. +// +// Passed the line slope is desired for and an islope_t structure for return +// Returns nothing +// +void AM_getIslope +( mline_t* ml, + islope_t* is ) +{ + int dx, dy; + + dy = ml->a.y - ml->b.y; + dx = ml->b.x - ml->a.x; + if (!dy) + is->islp = (dx<0?-INT_MAX:INT_MAX); + else + is->islp = FixedDiv(dx, dy); + if (!dx) + is->slp = (dy<0?-INT_MAX:INT_MAX); + else + is->slp = FixedDiv(dy, dx); +} + +// +// AM_activateNewScale() +// +// Changes the map scale after zooming or translating +// +// Passed nothing, returns nothing +// +void AM_activateNewScale(void) +{ + m_x += m_w/2; + m_y += m_h/2; + m_w = FTOM(f_w); + m_h = FTOM(f_h); + m_x -= m_w/2; + m_y -= m_h/2; + m_x2 = m_x + m_w; + m_y2 = m_y + m_h; +} + +// +// AM_saveScaleAndLoc() +// +// Saves the current center and zoom +// Affects the variables that remember old scale and loc +// +// Passed nothing, returns nothing +// +void AM_saveScaleAndLoc(void) +{ + old_m_x = m_x; + old_m_y = m_y; + old_m_w = m_w; + old_m_h = m_h; +} + +// +// AM_restoreScaleAndLoc() +// +// restores the center and zoom from locally saved values +// Affects global variables for location and scale +// +// Passed nothing, returns nothing +// +void AM_restoreScaleAndLoc(void) +{ + m_w = old_m_w; + m_h = old_m_h; + if (!(automapmode & am_follow)) + { + m_x = old_m_x; + m_y = old_m_y; + } + else + { + m_x = plr->mo->x - m_w/2; + m_y = plr->mo->y - m_h/2; + } + m_x2 = m_x + m_w; + m_y2 = m_y + m_h; + + // Change the scaling multipliers + scale_mtof = FixedDiv(f_w<= markpointnum_max) + markpoints = realloc(markpoints, + (markpointnum_max = markpointnum_max ? + markpointnum_max*2 : 16) * sizeof(*markpoints)); + + markpoints[markpointnum].x = m_x + m_w/2; + markpoints[markpointnum].y = m_y + m_h/2; + markpointnum++; +} + +// +// AM_findMinMaxBoundaries() +// +// Determines bounding box of all vertices, +// sets global variables controlling zoom range. +// +// Passed nothing, returns nothing +// +void AM_findMinMaxBoundaries(void) +{ + int i; + fixed_t a; + fixed_t b; + + min_x = min_y = INT_MAX; + max_x = max_y = -INT_MAX; + + for (i=0;i max_x) + max_x = vertexes[i].x; + + if (vertexes[i].y < min_y) + min_y = vertexes[i].y; + else if (vertexes[i].y > max_y) + max_y = vertexes[i].y; + } + + max_w = max_x - min_x; + max_h = max_y - min_y; + + min_w = 2*PLAYERRADIUS; // const? never changed? + min_h = 2*PLAYERRADIUS; + + a = FixedDiv(f_w< max_x) + m_x = max_x - m_w/2; + else if (m_x + m_w/2 < min_x) + m_x = min_x - m_w/2; + + if (m_y + m_h/2 > max_y) + m_y = max_y - m_h/2; + else if (m_y + m_h/2 < min_y) + m_y = min_y - m_h/2; + + m_x2 = m_x + m_w; + m_y2 = m_y + m_h; +} + + +// +// AM_initVariables() +// +// Initialize the variables for the automap +// +// Affects the automap global variables +// Status bar is notified that the automap has been entered +// Passed nothing, returns nothing +// +void AM_initVariables(void) +{ + int pnum; + static event_t st_notify = { ev_keyup, AM_MSGENTERED, 0 , 0 }; + + automapmode |= am_active; + + f_oldloc.x = INT_MAX; + + m_paninc.x = m_paninc.y = 0; + ftom_zoommul = FRACUNIT; + mtof_zoommul = FRACUNIT; + + m_w = FTOM(f_w); + m_h = FTOM(f_h); + + // find player to center on initially + if (!playeringame[pnum = consoleplayer]) + for (pnum=0;pnummo->x - m_w/2; + m_y = plr->mo->y - m_h/2; + AM_changeWindowLoc(); + + // for saving & restoring + old_m_x = m_x; + old_m_y = m_y; + old_m_w = m_w; + old_m_h = m_h; + + // inform the status bar of the change + ST_Responder(&st_notify); +} + +// +// AM_loadPics() +// +void AM_loadPics(void) +{ + // cph - mark numbers no longer needed cached +} + +// +// AM_unloadPics() +// +void AM_unloadPics(void) +{ + // cph - mark numbers no longer needed cached +} + +// +// AM_clearMarks() +// +// Sets the number of marks to 0, thereby clearing them from the display +// +// Affects the global variable markpointnum +// Passed nothing, returns nothing +// +void AM_clearMarks(void) +{ + markpointnum = 0; +} + +// +// AM_LevelInit() +// +// Initialize the automap at the start of a new level +// should be called at the start of every level +// +// Passed nothing, returns nothing +// Affects automap's global variables +// +// CPhipps - get status bar height from status bar code +void AM_LevelInit(void) +{ + leveljuststarted = 0; + + f_x = f_y = 0; + f_w = SCREENWIDTH; // killough 2/7/98: get rid of finit_ vars + f_h = SCREENHEIGHT-ST_SCALED_HEIGHT;// to allow runtime setting of width/height + + AM_findMinMaxBoundaries(); + scale_mtof = FixedDiv(min_scale_mtof, (int) (0.7*FRACUNIT)); + if (scale_mtof > max_scale_mtof) + scale_mtof = min_scale_mtof; + scale_ftom = FixedDiv(FRACUNIT, scale_mtof); +} + +// +// AM_Stop() +// +// Cease automap operations, unload patches, notify status bar +// +// Passed nothing, returns nothing +// +void AM_Stop (void) +{ + static event_t st_notify = { 0, ev_keyup, AM_MSGEXITED, 0 }; + + AM_unloadPics(); + automapmode &= ~am_active; + ST_Responder(&st_notify); + stopped = true; +} + +// +// AM_Start() +// +// Start up automap operations, +// if a new level, or game start, (re)initialize level variables +// init map variables +// load mark patches +// +// Passed nothing, returns nothing +// +void AM_Start() +{ + static int lastlevel = -1, lastepisode = -1; + + if (!stopped) + AM_Stop(); + stopped = false; + if (lastlevel != gamemap || lastepisode != gameepisode) + { + AM_LevelInit(); + lastlevel = gamemap; + lastepisode = gameepisode; + } + AM_initVariables(); + AM_loadPics(); +} + +// +// AM_minOutWindowScale() +// +// Set the window scale to the maximum size +// +// Passed nothing, returns nothing +// +void AM_minOutWindowScale() +{ + scale_mtof = min_scale_mtof; + scale_ftom = FixedDiv(FRACUNIT, scale_mtof); + AM_activateNewScale(); +} + +// +// AM_maxOutWindowScale(void) +// +// Set the window scale to the minimum size +// +// Passed nothing, returns nothing +// +void AM_maxOutWindowScale(void) +{ + scale_mtof = max_scale_mtof; + scale_ftom = FixedDiv(FRACUNIT, scale_mtof); + AM_activateNewScale(); +} + +// +// AM_Responder() +// +// Handle events (user inputs) in automap mode +// +// Passed an input event, returns true if its handled +// +boolean AM_Responder +( event_t* ev ) +{ + int rc; + static int cheatstate=0; + static int bigstate=0; + static char buffer[20]; + int ch; // phares + + rc = false; + + if (!(automapmode & am_active)) + { + if (ev->type == ev_keydown && ev->data1 == key_map) // phares + { + AM_Start (); + rc = true; + } + } + else if (ev->type == ev_keydown) + { + rc = true; + ch = ev->data1; // phares + if (ch == key_map_right) // | + if (!(automapmode & am_follow)) // V + m_paninc.x = FTOM(F_PANINC); + else + rc = false; + else if (ch == key_map_left) + if (!(automapmode & am_follow)) + m_paninc.x = -FTOM(F_PANINC); + else + rc = false; + else if (ch == key_map_up) + if (!(automapmode & am_follow)) + m_paninc.y = FTOM(F_PANINC); + else + rc = false; + else if (ch == key_map_down) + if (!(automapmode & am_follow)) + m_paninc.y = -FTOM(F_PANINC); + else + rc = false; + else if (ch == key_map_zoomout) + { + mtof_zoommul = M_ZOOMOUT; + ftom_zoommul = M_ZOOMIN; + } + else if (ch == key_map_zoomin) + { + mtof_zoommul = M_ZOOMIN; + ftom_zoommul = M_ZOOMOUT; + } + else if (ch == key_map) + { + bigstate = 0; + AM_Stop (); + } + else if (ch == key_map_gobig) + { + bigstate = !bigstate; + if (bigstate) + { + AM_saveScaleAndLoc(); + AM_minOutWindowScale(); + } + else + AM_restoreScaleAndLoc(); + } + else if (ch == key_map_follow) + { + automapmode ^= am_follow; // CPhipps - put all automap mode stuff into one enum + f_oldloc.x = INT_MAX; + // Ty 03/27/98 - externalized + plr->message = (automapmode & am_follow) ? AMSTR_FOLLOWON : AMSTR_FOLLOWOFF; + } + else if (ch == key_map_grid) + { + automapmode ^= am_grid; // CPhipps + // Ty 03/27/98 - *not* externalized + plr->message = (automapmode & am_grid) ? AMSTR_GRIDON : AMSTR_GRIDOFF; + } + else if (ch == key_map_mark) + { + // Ty 03/27/98 - *not* externalized + snprintf(buffer, sizeof(buffer), "%s %d", AMSTR_MARKEDSPOT, markpointnum); + plr->message = buffer; + AM_addMark(); + } + else if (ch == key_map_clear) + { + AM_clearMarks(); // Ty 03/27/98 - *not* externalized + plr->message = AMSTR_MARKSCLEARED; // ^ + } // | + else if (ch == key_map_rotate) { + automapmode ^= am_rotate; + plr->message = (automapmode & am_rotate) ? AMSTR_ROTATEON : AMSTR_ROTATEOFF; + } + else if (ch == key_map_overlay) { + automapmode ^= am_overlay; + plr->message = (automapmode & am_overlay) ? AMSTR_OVERLAYON : AMSTR_OVERLAYOFF; + } + else // phares + { + cheatstate=0; + rc = false; + } + } + else if (ev->type == ev_keyup) + { + rc = false; + ch = ev->data1; + if (ch == key_map_right) + { + if (!(automapmode & am_follow)) + m_paninc.x = 0; + } + else if (ch == key_map_left) + { + if (!(automapmode & am_follow)) + m_paninc.x = 0; + } + else if (ch == key_map_up) + { + if (!(automapmode & am_follow)) + m_paninc.y = 0; + } + else if (ch == key_map_down) + { + if (!(automapmode & am_follow)) + m_paninc.y = 0; + } + else if ((ch == key_map_zoomout) || (ch == key_map_zoomin)) + { + mtof_zoommul = FRACUNIT; + ftom_zoommul = FRACUNIT; + } + } + return rc; +} + +// +// AM_rotate() +// +// Rotation in 2D. +// Used to rotate player arrow line character. +// +// Passed the coordinates of a point, and an angle +// Returns the coordinates rotated by the angle +// +// CPhipps - made static & enhanced for automap rotation + +static void AM_rotate(fixed_t* x, fixed_t* y, angle_t a, fixed_t xorig, fixed_t yorig) +{ + fixed_t tmpx; + + tmpx = + FixedMul(*x - xorig,finecosine[a>>ANGLETOFINESHIFT]) + - FixedMul(*y - yorig,finesine[a>>ANGLETOFINESHIFT]); + + *y = yorig + + FixedMul(*x - xorig,finesine[a>>ANGLETOFINESHIFT]) + + FixedMul(*y - yorig,finecosine[a>>ANGLETOFINESHIFT]); + + *x = tmpx + xorig; +} + +// +// AM_changeWindowScale() +// +// Automap zooming +// +// Passed nothing, returns nothing +// +void AM_changeWindowScale(void) +{ + // Change the scaling multipliers + scale_mtof = FixedMul(scale_mtof, mtof_zoommul); + scale_ftom = FixedDiv(FRACUNIT, scale_mtof); + + if (scale_mtof < min_scale_mtof) + AM_minOutWindowScale(); + else if (scale_mtof > max_scale_mtof) + AM_maxOutWindowScale(); + else + AM_activateNewScale(); +} + +// +// AM_doFollowPlayer() +// +// Turn on follow mode - the map scrolls opposite to player motion +// +// Passed nothing, returns nothing +// +void AM_doFollowPlayer(void) +{ + if (f_oldloc.x != plr->mo->x || f_oldloc.y != plr->mo->y) + { + m_x = FTOM(MTOF(plr->mo->x)) - m_w/2; + m_y = FTOM(MTOF(plr->mo->y)) - m_h/2; + m_x2 = m_x + m_w; + m_y2 = m_y + m_h; + f_oldloc.x = plr->mo->x; + f_oldloc.y = plr->mo->y; + } +} + +// +// AM_Ticker() +// +// Updates on gametic - enter follow mode, zoom, or change map location +// +// Passed nothing, returns nothing +// +void AM_Ticker (void) +{ + if (!(automapmode & am_active)) + return; + + if (automapmode & am_follow) + AM_doFollowPlayer(); + + // Change the zoom if necessary + if (ftom_zoommul != FRACUNIT) + AM_changeWindowScale(); + + // Change x,y location + if (m_paninc.x || m_paninc.y) + AM_changeWindowLoc(); +} + +// +// AM_clipMline() +// +// Automap clipping of lines. +// +// Based on Cohen-Sutherland clipping algorithm but with a slightly +// faster reject and precalculated slopes. If the speed is needed, +// use a hash algorithm to handle the common cases. +// +// Passed the line's coordinates on map and in the frame buffer performs +// clipping on them in the lines frame coordinates. +// Returns true if any part of line was not clipped +// +boolean AM_clipMline +( mline_t* ml, + fline_t* fl ) +{ + enum + { + LEFT =1, + RIGHT =2, + BOTTOM =4, + TOP =8 + }; + + register int outcode1 = 0; + register int outcode2 = 0; + register int outside; + + fpoint_t tmp; + int dx; + int dy; + + +#define DOOUTCODE(oc, mx, my) \ + (oc) = 0; \ + if ((my) < 0) (oc) |= TOP; \ + else if ((my) >= f_h) (oc) |= BOTTOM; \ + if ((mx) < 0) (oc) |= LEFT; \ + else if ((mx) >= f_w) (oc) |= RIGHT; + + + // do trivial rejects and outcodes + if (ml->a.y > m_y2) + outcode1 = TOP; + else if (ml->a.y < m_y) + outcode1 = BOTTOM; + + if (ml->b.y > m_y2) + outcode2 = TOP; + else if (ml->b.y < m_y) + outcode2 = BOTTOM; + + if (outcode1 & outcode2) + return false; // trivially outside + + if (ml->a.x < m_x) + outcode1 |= LEFT; + else if (ml->a.x > m_x2) + outcode1 |= RIGHT; + + if (ml->b.x < m_x) + outcode2 |= LEFT; + else if (ml->b.x > m_x2) + outcode2 |= RIGHT; + + if (outcode1 & outcode2) + return false; // trivially outside + + // transform to frame-buffer coordinates. + fl->a.x = CXMTOF(ml->a.x); + fl->a.y = CYMTOF(ml->a.y); + fl->b.x = CXMTOF(ml->b.x); + fl->b.y = CYMTOF(ml->b.y); + + DOOUTCODE(outcode1, fl->a.x, fl->a.y); + DOOUTCODE(outcode2, fl->b.x, fl->b.y); + + if (outcode1 & outcode2) + return false; + + while (outcode1 | outcode2) + { + // may be partially inside box + // find an outside point + if (outcode1) + outside = outcode1; + else + outside = outcode2; + + // clip to each side + if (outside & TOP) + { + dy = fl->a.y - fl->b.y; + dx = fl->b.x - fl->a.x; + tmp.x = fl->a.x + (dx*(fl->a.y))/dy; + tmp.y = 0; + } + else if (outside & BOTTOM) + { + dy = fl->a.y - fl->b.y; + dx = fl->b.x - fl->a.x; + tmp.x = fl->a.x + (dx*(fl->a.y-f_h))/dy; + tmp.y = f_h-1; + } + else if (outside & RIGHT) + { + dy = fl->b.y - fl->a.y; + dx = fl->b.x - fl->a.x; + tmp.y = fl->a.y + (dy*(f_w-1 - fl->a.x))/dx; + tmp.x = f_w-1; + } + else if (outside & LEFT) + { + dy = fl->b.y - fl->a.y; + dx = fl->b.x - fl->a.x; + tmp.y = fl->a.y + (dy*(-fl->a.x))/dx; + tmp.x = 0; + } + + if (outside == outcode1) + { + fl->a = tmp; + DOOUTCODE(outcode1, fl->a.x, fl->a.y); + } + else + { + fl->b = tmp; + DOOUTCODE(outcode2, fl->b.x, fl->b.y); + } + + if (outcode1 & outcode2) + return false; // trivially outside + } + + return true; +} +#undef DOOUTCODE + +// +// AM_drawFline() +// +// Draw a line in the frame buffer. +// Classic Bresenham w/ whatever optimizations needed for speed +// +// Passed the frame coordinates of line, and the color to be drawn +// Returns nothing +// + +void AM_drawFline +( fline_t* fl, + int color ) +{ + register int x; + register int y; + register int dx; + register int dy; + register int sx; + register int sy; + register int ax; + register int ay; + register int d; + +#ifdef RANGECHECK // killough 2/22/98 + static int fuck = 0; + + // For debugging only + if + ( + fl->a.x < 0 || fl->a.x >= f_w + || fl->a.y < 0 || fl->a.y >= f_h + || fl->b.x < 0 || fl->b.x >= f_w + || fl->b.y < 0 || fl->b.y >= f_h + ) + { + //jff 8/3/98 use logical output routine + printf("fuck %d \r", fuck++); + return; + } +#endif + +#define PUTDOT(xx,yy,cc) V_PlotPixel(FB,xx,yy,(byte)cc) + + dx = fl->b.x - fl->a.x; + ax = 2 * (dx<0 ? -dx : dx); + sx = dx<0 ? -1 : 1; + + dy = fl->b.y - fl->a.y; + ay = 2 * (dy<0 ? -dy : dy); + sy = dy<0 ? -1 : 1; + + x = fl->a.x; + y = fl->a.y; + + if (ax > ay) + { + d = ay - ax/2; + while (1) + { + PUTDOT(x,y,color); + if (x == fl->b.x) return; + if (d>=0) + { + y += sy; + d -= ax; + } + x += sx; + d += ay; + } + } + else + { + d = ax - ay/2; + while (1) + { + PUTDOT(x, y, color); + if (y == fl->b.y) return; + if (d >= 0) + { + x += sx; + d -= ay; + } + y += sy; + d += ax; + } + } +} + + +// +// AM_drawMline() +// +// Clip lines, draw visible parts of lines. +// +// Passed the map coordinates of the line, and the color to draw it +// Color -1 is special and prevents drawing. Color 247 is special and +// is translated to black, allowing Color 0 to represent feature disable +// in the defaults file. +// Returns nothing. +// +void AM_drawMline +( mline_t* ml, + int color ) +{ + static fline_t fl; + + if (color==-1) // jff 4/3/98 allow not drawing any sort of line + return; // by setting its color to -1 + if (color==247) // jff 4/3/98 if color is 247 (xparent), use black + color=0; + + if (AM_clipMline(ml, &fl)) + AM_drawFline(&fl, color); // draws it on frame buffer using fb coords +} + +// +// AM_drawGrid() +// +// Draws blockmap aligned grid lines. +// +// Passed the color to draw the grid lines +// Returns nothing +// +void AM_drawGrid(int color) +{ + fixed_t x, y; + fixed_t start, end; + mline_t ml; + + // Figure out start of vertical gridlines + start = m_x; + if ((start-bmaporgx)%(MAPBLOCKUNITS<> LockedKeyShift; + if (!type || type==7) + return 3; //any or all keys + else return (type-1)%3; + } + switch (type) // closed keyed door + { +case 26: case 32: case 99: case 133: + /*bluekey*/ + return 1; +case 27: case 34: case 136: case 137: + /*yellowkey*/ + return 2; +case 28: case 33: case 134: case 135: + /*redkey*/ + return 0; + default: + return -1; //not a keyed door + } + return -1; //not a keyed door +} + +// +// Determines visible lines, draws them. +// This is LineDef based, not LineSeg based. +// +// jff 1/5/98 many changes in this routine +// backward compatibility not needed, so just changes, no ifs +// addition of clauses for: +// doors opening, keyed door id, secret sectors, +// teleports, exit lines, key things +// ability to suppress any of added features or lines with no height changes +// +// support for gamma correction in automap abandoned +// +// jff 4/3/98 changed mapcolor_xxxx=0 as control to disable feature +// jff 4/3/98 changed mapcolor_xxxx=-1 to disable drawing line completely +// +void AM_drawWalls(void) +{ + int i; + static mline_t l; + + // draw the unclipped visible portions of all lines + for (i=0;ix; + l.a.y = lines[i].v1->y; + l.b.x = lines[i].v2->x; + l.b.y = lines[i].v2->y; + + if (automapmode & am_rotate) { + AM_rotate(&l.a.x, &l.a.y, ANG90-plr->mo->angle, plr->mo->x, plr->mo->y); + AM_rotate(&l.b.x, &l.b.y, ANG90-plr->mo->angle, plr->mo->x, plr->mo->y); + } + + // if line has been seen or IDDT has been used + if (ddt_cheating || (lines[i].flags & ML_MAPPED)) + { + if ((lines[i].flags & ML_DONTDRAW) && !ddt_cheating) + continue; + { + /* cph - show keyed doors and lines */ + int amd; + if ((mapcolor_bdor || mapcolor_ydor || mapcolor_rdor) && + !(lines[i].flags & ML_SECRET) && /* non-secret */ + (amd = AM_DoorColor(lines[i].special)) != -1 + ) + { + { + switch (amd) /* closed keyed door */ + { + case 1: + /*bluekey*/ + AM_drawMline(&l, + mapcolor_bdor? mapcolor_bdor : mapcolor_cchg); + continue; + case 2: + /*yellowkey*/ + AM_drawMline(&l, + mapcolor_ydor? mapcolor_ydor : mapcolor_cchg); + continue; + case 0: + /*redkey*/ + AM_drawMline(&l, + mapcolor_rdor? mapcolor_rdor : mapcolor_cchg); + continue; + case 3: + /*any or all*/ + AM_drawMline(&l, + mapcolor_clsd? mapcolor_clsd : mapcolor_cchg); + continue; + } + } + } + } + if /* jff 4/23/98 add exit lines to automap */ + ( + mapcolor_exit && + ( + lines[i].special==11 || + lines[i].special==52 || + lines[i].special==197 || + lines[i].special==51 || + lines[i].special==124 || + lines[i].special==198 + ) + ) { + AM_drawMline(&l, mapcolor_exit); /* exit line */ + continue; + } + + if (!lines[i].backsector) + { + // jff 1/10/98 add new color for 1S secret sector boundary + if (mapcolor_secr && //jff 4/3/98 0 is disable + ( + ( + map_secret_after && + P_WasSecret(lines[i].frontsector) && + !P_IsSecret(lines[i].frontsector) + ) + || + ( + !map_secret_after && + P_WasSecret(lines[i].frontsector) + ) + ) + ) + AM_drawMline(&l, mapcolor_secr); // line bounding secret sector + else //jff 2/16/98 fixed bug + AM_drawMline(&l, mapcolor_wall); // special was cleared + } + else /* now for 2S lines */ + { + // jff 1/10/98 add color change for all teleporter types + if + ( + mapcolor_tele && !(lines[i].flags & ML_SECRET) && + (lines[i].special == 39 || lines[i].special == 97 || + lines[i].special == 125 || lines[i].special == 126) + ) + { // teleporters + AM_drawMline(&l, mapcolor_tele); + } + else if (lines[i].flags & ML_SECRET) // secret door + { + AM_drawMline(&l, mapcolor_wall); // wall color + } + else if + ( + mapcolor_clsd && + !(lines[i].flags & ML_SECRET) && // non-secret closed door + ((lines[i].backsector->floorheight==lines[i].backsector->ceilingheight) || + (lines[i].frontsector->floorheight==lines[i].frontsector->ceilingheight)) + ) + { + AM_drawMline(&l, mapcolor_clsd); // non-secret closed door + } //jff 1/6/98 show secret sector 2S lines + else if + ( + mapcolor_secr && //jff 2/16/98 fixed bug + ( // special was cleared after getting it + (map_secret_after && + ( + (P_WasSecret(lines[i].frontsector) + && !P_IsSecret(lines[i].frontsector)) || + (P_WasSecret(lines[i].backsector) + && !P_IsSecret(lines[i].backsector)) + ) + ) + || //jff 3/9/98 add logic to not show secret til after entered + ( // if map_secret_after is true + !map_secret_after && + (P_WasSecret(lines[i].frontsector) || + P_WasSecret(lines[i].backsector)) + ) + ) + ) + { + AM_drawMline(&l, mapcolor_secr); // line bounding secret sector + } //jff 1/6/98 end secret sector line change + else if (lines[i].backsector->floorheight != + lines[i].frontsector->floorheight) + { + AM_drawMline(&l, mapcolor_fchg); // floor level change + } + else if (lines[i].backsector->ceilingheight != + lines[i].frontsector->ceilingheight) + { + AM_drawMline(&l, mapcolor_cchg); // ceiling level change + } + else if (mapcolor_flat && ddt_cheating) + { + AM_drawMline(&l, mapcolor_flat); //2S lines that appear only in IDDT + } + } + } // now draw the lines only visible because the player has computermap + else if (plr->powers[pw_allmap]) // computermap visible lines + { + if (!(lines[i].flags & ML_DONTDRAW)) // invisible flag lines do not show + { + if + ( + mapcolor_flat + || + !lines[i].backsector + || + lines[i].backsector->floorheight + != lines[i].frontsector->floorheight + || + lines[i].backsector->ceilingheight + != lines[i].frontsector->ceilingheight + ) + AM_drawMline(&l, mapcolor_unsn); + } + } + } +} + +// +// AM_drawLineCharacter() +// +// Draws a vector graphic according to numerous parameters +// +// Passed the structure defining the vector graphic shape, the number +// of vectors in it, the scale to draw it at, the angle to draw it at, +// the color to draw it with, and the map coordinates to draw it at. +// Returns nothing +// +void AM_drawLineCharacter +( mline_t* lineguy, + int lineguylines, + fixed_t scale, + angle_t angle, + int color, + fixed_t x, + fixed_t y ) +{ + int i; + mline_t l; + + if (automapmode & am_rotate) angle -= plr->mo->angle - ANG90; // cph + + for (i=0;imo->angle, + mapcolor_sngl, //jff color + plr->mo->x, + plr->mo->y + ); + else + AM_drawLineCharacter + ( + player_arrow, + NUMPLYRLINES, + 0, + plr->mo->angle, + mapcolor_sngl, //jff color + plr->mo->x, + plr->mo->y); + return; + } + + for (i=0;imo->x, y = p->mo->y; + if (automapmode & am_rotate) + AM_rotate(&x, &y, ANG90-plr->mo->angle, plr->mo->x, plr->mo->y); + + AM_drawLineCharacter (player_arrow, NUMPLYRLINES, 0, p->mo->angle, + p->powers[pw_invisibility] ? 246 /* *close* to black */ + : mapcolor_plyr[i], //jff 1/6/98 use default color + x, y); + } + } +} + +// +// AM_drawThings() +// +// Draws the things on the automap in double IDDT cheat mode +// +// Passed colors and colorrange, no longer used +// Returns nothing +// +void AM_drawThings +( int colors, + int colorrange) +{ + (void)colors; + (void)colorrange; + int i; + mobj_t* t; + + // for all sectors + for (i=0;ix, y = t->y; + + if (automapmode & am_rotate) + AM_rotate(&x, &y, ANG90-plr->mo->angle, plr->mo->x, plr->mo->y); + + //jff 1/5/98 case over doomednum of thing being drawn + if (mapcolor_rkey || mapcolor_ykey || mapcolor_bkey) + { + switch(t->info->doomednum) + { + //jff 1/5/98 treat keys special + case 38: case 13: //jff red key + AM_drawLineCharacter + ( + cross_mark, + NUMCROSSMARKLINES, + 16<angle, + mapcolor_rkey!=-1? mapcolor_rkey : mapcolor_sprt, + x, y + ); + t = t->snext; + continue; + case 39: case 6: //jff yellow key + AM_drawLineCharacter + ( + cross_mark, + NUMCROSSMARKLINES, + 16<angle, + mapcolor_ykey!=-1? mapcolor_ykey : mapcolor_sprt, + x, y + ); + t = t->snext; + continue; + case 40: case 5: //jff blue key + AM_drawLineCharacter + ( + cross_mark, + NUMCROSSMARKLINES, + 16<angle, + mapcolor_bkey!=-1? mapcolor_bkey : mapcolor_sprt, + x, y + ); + t = t->snext; + continue; + default: + break; + } + } + //jff 1/5/98 end added code for keys + //jff previously entire code + AM_drawLineCharacter + ( + thintriangle_guy, + NUMTHINTRIANGLEGUYLINES, + 16<angle, + t->flags & MF_FRIEND && !t->player ? mapcolor_frnd : + /* bbm 2/28/03 Show countable items in yellow. */ + t->flags & MF_COUNTITEM ? mapcolor_item : mapcolor_sprt, + x, y + ); + t = t->snext; + } + } +} + +// +// AM_drawMarks() +// +// Draw the marked locations on the automap +// +// Passed nothing, returns nothing +// +// killough 2/22/98: +// Rewrote AM_drawMarks(). Removed limit on marks. +// +void AM_drawMarks(void) +{ + int i; + for (i=0;imo->angle, plr->mo->x, plr->mo->y); + + fx = CXMTOF(fx); fy = CYMTOF(fy); + + do + { + int d = j % 10; + if (d==1) // killough 2/22/98: less spacing for '1' + fx++; + + if (fx >= f_x && fx < f_w - w && fy >= f_y && fy < f_h - h) { + // cph - construct patch name and draw marker + char namebuf[] = { 'A', 'M', 'M', 'N', 'U', 'M', '0'+d, 0 }; + + V_DrawNamePatch(fx, fy, FB, namebuf, CR_DEFAULT, VPT_NONE); + } + fx -= w-1; // killough 2/22/98: 1 space backwards + j /= 10; + } + while (j>0); + } +} + +// +// AM_drawCrosshair() +// +// Draw the single point crosshair representing map center +// +// Passed the color to draw the pixel with +// Returns nothing +// +// CPhipps - made static inline, and use the general pixel plotter function + +inline static void AM_drawCrosshair(int color) +{ + // single point for now + V_PlotPixel(FB, f_w/2, f_h/2, (byte)color); +} + +// +// AM_Drawer() +// +// Draws the entire automap +// +// Passed nothing, returns nothing +// +void AM_Drawer (void) +{ + // CPhipps - all automap modes put into one enum + if (!(automapmode & am_active)) return; + + if (!(automapmode & am_overlay)) // cph - If not overlay mode, clear background for the automap + V_FillRect(FB, f_x, f_y, f_w, f_h, (byte)mapcolor_back); //jff 1/5/98 background default color + if (automapmode & am_grid) + AM_drawGrid(mapcolor_grid); //jff 1/7/98 grid default color + AM_drawWalls(); + AM_drawPlayers(); + if (ddt_cheating==2) + AM_drawThings(mapcolor_sprt, 0); //jff 1/5/98 default double IDDT sprite + AM_drawCrosshair(mapcolor_hair); //jff 1/7/98 default crosshair color + + AM_drawMarks(); + + V_MarkRect(f_x, f_y, f_w, f_h); +} diff --git a/apps/plugins/doom/am_map.h b/apps/plugins/doom/am_map.h new file mode 100644 index 0000000000..5599a3c400 --- /dev/null +++ b/apps/plugins/doom/am_map.h @@ -0,0 +1,106 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * AutoMap module. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __AMMAP_H__ +#define __AMMAP_H__ + +#include "d_event.h" +#include "m_fixed.h" + +// Used by ST StatusBar stuff. +#define AM_MSGHEADER (('a'<<24)+('m'<<16)) +#define AM_MSGENTERED (AM_MSGHEADER | ('e'<<8)) +#define AM_MSGEXITED (AM_MSGHEADER | ('x'<<8)) + +// Called by main loop. +boolean AM_Responder (event_t* ev); + +// Called by main loop. +void AM_Ticker (void); + +// Called by main loop, +// called instead of view drawer if automap active. +void AM_Drawer (void); + +// Called to force the automap to quit +// if the level is completed while it is up. +void AM_Stop (void); + +// killough 2/22/98: for saving automap information in savegame: + +extern void AM_Start(void); + +//jff 4/16/98 make externally available + +extern void AM_clearMarks(void); + +typedef struct +{ + fixed_t x,y; +} mpoint_t; + +extern mpoint_t *markpoints; +extern int markpointnum, markpointnum_max; + +// end changes -- killough 2/22/98 + +// killough 5/2/98: moved from m_misc.c + +//jff 1/7/98 automap colors added +extern int mapcolor_back; // map background +extern int mapcolor_grid; // grid lines color +extern int mapcolor_wall; // normal 1s wall color +extern int mapcolor_fchg; // line at floor height change color +extern int mapcolor_cchg; // line at ceiling height change color +extern int mapcolor_clsd; // line at sector with floor=ceiling color +extern int mapcolor_rkey; // red key color +extern int mapcolor_bkey; // blue key color +extern int mapcolor_ykey; // yellow key color +extern int mapcolor_rdor; // red door color (diff from keys to allow option) +extern int mapcolor_bdor; // blue door color (of enabling one not other) +extern int mapcolor_ydor; // yellow door color +extern int mapcolor_tele; // teleporter line color +extern int mapcolor_secr; // secret sector boundary color +//jff 4/23/98 +extern int mapcolor_exit; // exit line +extern int mapcolor_unsn; // computer map unseen line color +extern int mapcolor_flat; // line with no floor/ceiling changes +extern int mapcolor_sprt; // general sprite color +extern int mapcolor_item; // item sprite color +extern int mapcolor_frnd; // friendly sprite color +extern int mapcolor_hair; // crosshair color +extern int mapcolor_sngl; // single player arrow color +extern int mapcolor_plyr[4]; // colors for players in multiplayer +extern int mapcolor_me; // consoleplayer's chosen colour +//jff 3/9/98 +extern int map_secret_after; // secrets do not appear til after bagged + +#endif diff --git a/apps/plugins/doom/d_englsh.h b/apps/plugins/doom/d_englsh.h new file mode 100644 index 0000000000..596b8772e8 --- /dev/null +++ b/apps/plugins/doom/d_englsh.h @@ -0,0 +1,705 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Printed strings for translation. + * English language support (default). + * See dstrings.h for suggestions about foreign language BEX support + * + *-----------------------------------------------------------------------------*/ + +#ifndef __D_ENGLSH__ +#define __D_ENGLSH__ + +/* d_main.c */ +#define D_DEVSTR "Development mode ON.\n" +#define D_CDROM "CD-ROM Version: default.cfg from c:\\doomdata\n" + +/* m_menu.c */ +#define PRESSKEY "press a key." +#define PRESSYN "press y or n." +#define QUITMSG "are you sure you want to\nquit this great game?" +#define LOADNET "you can't do load while in a net game!\n\n"PRESSKEY +#define QLOADNET "you can't quickload during a netgame!\n\n"PRESSKEY +#define QSAVESPOT "you haven't picked a quicksave slot yet!\n\n"PRESSKEY +#define SAVEDEAD "you can't save if you aren't playing!\n\n"PRESSKEY +#define QSPROMPT "quicksave over your game named\n\n'%s'?\n\n"PRESSYN +#define QLPROMPT "do you want to quickload the game named\n\n'%s'?\n\n"PRESSYN + +#define NEWGAME \ + "you can't start a new game\n"\ + "while in a network game.\n\n"PRESSKEY + +#define NIGHTMARE \ + "are you sure? this skill level\n"\ + "isn't even remotely fair.\n\n"PRESSYN + +#define SWSTRING \ + "this is the shareware version of doom.\n\n"\ + "you need to order the entire trilogy.\n\n"PRESSKEY + +#define MSGOFF "Messages OFF" +#define MSGON "Messages ON" +#define NETEND "you can't end a netgame!\n\n"PRESSKEY +#define ENDGAME "are you sure you want to end the game?\n\n"PRESSYN +#define RESTARTLEVEL "restart the level?\n\n"PRESSYN + +#define DOSY "(press y to quit)" + +#define DETAILHI "High detail" +#define DETAILLO "Low detail" +#define GAMMALVL0 "Gamma correction OFF" +#define GAMMALVL1 "Gamma correction level 1" +#define GAMMALVL2 "Gamma correction level 2" +#define GAMMALVL3 "Gamma correction level 3" +#define GAMMALVL4 "Gamma correction level 4" +#define EMPTYSTRING "empty slot" + +/* p_inter.c */ +#define GOTARMOR "Picked up the armor." +#define GOTMEGA "Picked up the MegaArmor!" +#define GOTHTHBONUS "Picked up a health bonus." +#define GOTARMBONUS "Picked up an armor bonus." +#define GOTSTIM "Picked up a stimpack." +#define GOTMEDINEED "Picked up a medikit that you REALLY need!" +#define GOTMEDIKIT "Picked up a medikit." +#define GOTSUPER "Supercharge!" + +#define GOTBLUECARD "Picked up a blue keycard." +#define GOTYELWCARD "Picked up a yellow keycard." +#define GOTREDCARD "Picked up a red keycard." +#define GOTBLUESKUL "Picked up a blue skull key." +#define GOTYELWSKUL "Picked up a yellow skull key." +#define GOTREDSKULL "Picked up a red skull key." + +#define GOTINVUL "Invulnerability!" +#define GOTBERSERK "Berserk!" +#define GOTINVIS "Partial Invisibility" +#define GOTSUIT "Radiation Shielding Suit" +#define GOTMAP "Computer Area Map" +#define GOTVISOR "Light Amplification Visor" +#define GOTMSPHERE "MegaSphere!" + +#define GOTCLIP "Picked up a clip." +#define GOTCLIPBOX "Picked up a box of bullets." +#define GOTROCKET "Picked up a rocket." +#define GOTROCKBOX "Picked up a box of rockets." +#define GOTCELL "Picked up an energy cell." +#define GOTCELLBOX "Picked up an energy cell pack." +#define GOTSHELLS "Picked up 4 shotgun shells." +#define GOTSHELLBOX "Picked up a box of shotgun shells." +#define GOTBACKPACK "Picked up a backpack full of ammo!" + +#define GOTBFG9000 "You got the BFG9000! Oh, yes." +#define GOTCHAINGUN "You got the chaingun!" +#define GOTCHAINSAW "A chainsaw! Find some meat!" +#define GOTLAUNCHER "You got the rocket launcher!" +#define GOTPLASMA "You got the plasma gun!" +#define GOTSHOTGUN "You got the shotgun!" +#define GOTSHOTGUN2 "You got the super shotgun!" + +/* p_doors.c */ +#define PD_BLUEO "You need a blue key to activate this object" +#define PD_REDO "You need a red key to activate this object" +#define PD_YELLOWO "You need a yellow key to activate this object" +#define PD_BLUEK "You need a blue key to open this door" +#define PD_REDK "You need a red key to open this door" +#define PD_YELLOWK "You need a yellow key to open this door" +/* jff 02/05/98 Create messages specific to card and skull keys */ +#define PD_BLUEC "You need a blue card to open this door" +#define PD_REDC "You need a red card to open this door" +#define PD_YELLOWC "You need a yellow card to open this door" +#define PD_BLUES "You need a blue skull to open this door" +#define PD_REDS "You need a red skull to open this door" +#define PD_YELLOWS "You need a yellow skull to open this door" +#define PD_ANY "Any key will open this door" +#define PD_ALL3 "You need all three keys to open this door" +#define PD_ALL6 "You need all six keys to open this door" + +/* g_game.c */ +#define GGSAVED "game saved." + +/* hu_stuff.c */ +#define HUSTR_MSGU "[Message unsent]" + +#define HUSTR_E1M1 "E1M1: Hangar" +#define HUSTR_E1M2 "E1M2: Nuclear Plant" +#define HUSTR_E1M3 "E1M3: Toxin Refinery" +#define HUSTR_E1M4 "E1M4: Command Control" +#define HUSTR_E1M5 "E1M5: Phobos Lab" +#define HUSTR_E1M6 "E1M6: Central Processing" +#define HUSTR_E1M7 "E1M7: Computer Station" +#define HUSTR_E1M8 "E1M8: Phobos Anomaly" +#define HUSTR_E1M9 "E1M9: Military Base" + +#define HUSTR_E2M1 "E2M1: Deimos Anomaly" +#define HUSTR_E2M2 "E2M2: Containment Area" +#define HUSTR_E2M3 "E2M3: Refinery" +#define HUSTR_E2M4 "E2M4: Deimos Lab" +#define HUSTR_E2M5 "E2M5: Command Center" +#define HUSTR_E2M6 "E2M6: Halls of the Damned" +#define HUSTR_E2M7 "E2M7: Spawning Vats" +#define HUSTR_E2M8 "E2M8: Tower of Babel" +#define HUSTR_E2M9 "E2M9: Fortress of Mystery" + +#define HUSTR_E3M1 "E3M1: Hell Keep" +#define HUSTR_E3M2 "E3M2: Slough of Despair" +#define HUSTR_E3M3 "E3M3: Pandemonium" +#define HUSTR_E3M4 "E3M4: House of Pain" +#define HUSTR_E3M5 "E3M5: Unholy Cathedral" +#define HUSTR_E3M6 "E3M6: Mt. Erebus" +#define HUSTR_E3M7 "E3M7: Limbo" +#define HUSTR_E3M8 "E3M8: Dis" +#define HUSTR_E3M9 "E3M9: Warrens" + +#define HUSTR_E4M1 "E4M1: Hell Beneath" +#define HUSTR_E4M2 "E4M2: Perfect Hatred" +#define HUSTR_E4M3 "E4M3: Sever The Wicked" +#define HUSTR_E4M4 "E4M4: Unruly Evil" +#define HUSTR_E4M5 "E4M5: They Will Repent" +#define HUSTR_E4M6 "E4M6: Against Thee Wickedly" +#define HUSTR_E4M7 "E4M7: And Hell Followed" +#define HUSTR_E4M8 "E4M8: Unto The Cruel" +#define HUSTR_E4M9 "E4M9: Fear" + +#define HUSTR_1 "level 1: entryway" +#define HUSTR_2 "level 2: underhalls" +#define HUSTR_3 "level 3: the gantlet" +#define HUSTR_4 "level 4: the focus" +#define HUSTR_5 "level 5: the waste tunnels" +#define HUSTR_6 "level 6: the crusher" +#define HUSTR_7 "level 7: dead simple" +#define HUSTR_8 "level 8: tricks and traps" +#define HUSTR_9 "level 9: the pit" +#define HUSTR_10 "level 10: refueling base" +#define HUSTR_11 "level 11: 'o' of destruction!" + +#define HUSTR_12 "level 12: the factory" +#define HUSTR_13 "level 13: downtown" +#define HUSTR_14 "level 14: the inmost dens" +#define HUSTR_15 "level 15: industrial zone" +#define HUSTR_16 "level 16: suburbs" +#define HUSTR_17 "level 17: tenements" +#define HUSTR_18 "level 18: the courtyard" +#define HUSTR_19 "level 19: the citadel" +#define HUSTR_20 "level 20: gotcha!" + +#define HUSTR_21 "level 21: nirvana" +#define HUSTR_22 "level 22: the catacombs" +#define HUSTR_23 "level 23: barrels o' fun" +#define HUSTR_24 "level 24: the chasm" +#define HUSTR_25 "level 25: bloodfalls" +#define HUSTR_26 "level 26: the abandoned mines" +#define HUSTR_27 "level 27: monster condo" +#define HUSTR_28 "level 28: the spirit world" +#define HUSTR_29 "level 29: the living end" +#define HUSTR_30 "level 30: icon of sin" + +#define HUSTR_31 "level 31: wolfenstein" +#define HUSTR_32 "level 32: grosse" + +#define PHUSTR_1 "level 1: congo" +#define PHUSTR_2 "level 2: well of souls" +#define PHUSTR_3 "level 3: aztec" +#define PHUSTR_4 "level 4: caged" +#define PHUSTR_5 "level 5: ghost town" +#define PHUSTR_6 "level 6: baron's lair" +#define PHUSTR_7 "level 7: caughtyard" +#define PHUSTR_8 "level 8: realm" +#define PHUSTR_9 "level 9: abattoire" +#define PHUSTR_10 "level 10: onslaught" +#define PHUSTR_11 "level 11: hunted" + +#define PHUSTR_12 "level 12: speed" +#define PHUSTR_13 "level 13: the crypt" +#define PHUSTR_14 "level 14: genesis" +#define PHUSTR_15 "level 15: the twilight" +#define PHUSTR_16 "level 16: the omen" +#define PHUSTR_17 "level 17: compound" +#define PHUSTR_18 "level 18: neurosphere" +#define PHUSTR_19 "level 19: nme" +#define PHUSTR_20 "level 20: the death domain" + +#define PHUSTR_21 "level 21: slayer" +#define PHUSTR_22 "level 22: impossible mission" +#define PHUSTR_23 "level 23: tombstone" +#define PHUSTR_24 "level 24: the final frontier" +#define PHUSTR_25 "level 25: the temple of darkness" +#define PHUSTR_26 "level 26: bunker" +#define PHUSTR_27 "level 27: anti-christ" +#define PHUSTR_28 "level 28: the sewers" +#define PHUSTR_29 "level 29: odyssey of noises" +#define PHUSTR_30 "level 30: the gateway of hell" + +#define PHUSTR_31 "level 31: cyberden" +#define PHUSTR_32 "level 32: go 2 it" + +#define THUSTR_1 "level 1: system control" +#define THUSTR_2 "level 2: human bbq" +#define THUSTR_3 "level 3: power control" +#define THUSTR_4 "level 4: wormhole" +#define THUSTR_5 "level 5: hanger" +#define THUSTR_6 "level 6: open season" +#define THUSTR_7 "level 7: prison" +#define THUSTR_8 "level 8: metal" +#define THUSTR_9 "level 9: stronghold" +#define THUSTR_10 "level 10: redemption" +#define THUSTR_11 "level 11: storage facility" + +#define THUSTR_12 "level 12: crater" +#define THUSTR_13 "level 13: nukage processing" +#define THUSTR_14 "level 14: steel works" +#define THUSTR_15 "level 15: dead zone" +#define THUSTR_16 "level 16: deepest reaches" +#define THUSTR_17 "level 17: processing area" +#define THUSTR_18 "level 18: mill" +#define THUSTR_19 "level 19: shipping/respawning" +#define THUSTR_20 "level 20: central processing" + +#define THUSTR_21 "level 21: administration center" +#define THUSTR_22 "level 22: habitat" +#define THUSTR_23 "level 23: lunar mining project" +#define THUSTR_24 "level 24: quarry" +#define THUSTR_25 "level 25: baron's den" +#define THUSTR_26 "level 26: ballistyx" +#define THUSTR_27 "level 27: mount pain" +#define THUSTR_28 "level 28: heck" +#define THUSTR_29 "level 29: river styx" +#define THUSTR_30 "level 30: last call" + +#define THUSTR_31 "level 31: pharaoh" +#define THUSTR_32 "level 32: caribbean" + +#define HUSTR_CHATMACRO1 "I'm ready to kick butt!" +#define HUSTR_CHATMACRO2 "I'm OK." +#define HUSTR_CHATMACRO3 "I'm not looking too good!" +#define HUSTR_CHATMACRO4 "Help!" +#define HUSTR_CHATMACRO5 "You suck!" +#define HUSTR_CHATMACRO6 "Next time, scumbag..." +#define HUSTR_CHATMACRO7 "Come here!" +#define HUSTR_CHATMACRO8 "I'll take care of it." +#define HUSTR_CHATMACRO9 "Yes" +#define HUSTR_CHATMACRO0 "No" + +#define HUSTR_TALKTOSELF1 "You mumble to yourself" +#define HUSTR_TALKTOSELF2 "Who's there?" +#define HUSTR_TALKTOSELF3 "You scare yourself" +#define HUSTR_TALKTOSELF4 "You start to rave" +#define HUSTR_TALKTOSELF5 "You've lost it..." + +#define HUSTR_MESSAGESENT "[Message Sent]" + +/* The following should NOT be changed unless it seems + * just AWFULLY necessary */ + +#define HUSTR_PLRGREEN "Player 1: " +#define HUSTR_PLRINDIGO "Player 2: " +#define HUSTR_PLRBROWN "Player 3: " +#define HUSTR_PLRRED "Player 4: " + +#define HUSTR_KEYGREEN 'g' +#define HUSTR_KEYINDIGO 'i' +#define HUSTR_KEYBROWN 'b' +#define HUSTR_KEYRED 'r' + +/* am_map.c */ + +#define AMSTR_FOLLOWON "Follow Mode ON" +#define AMSTR_FOLLOWOFF "Follow Mode OFF" + +#define AMSTR_GRIDON "Grid ON" +#define AMSTR_GRIDOFF "Grid OFF" + +#define AMSTR_MARKEDSPOT "Marked Spot" +#define AMSTR_MARKSCLEARED "All Marks Cleared" + +#define AMSTR_ROTATEON "Rotate Mode ON" +#define AMSTR_ROTATEOFF "Rotate Mode OFF" + +#define AMSTR_OVERLAYON "Overlay Mode ON" +#define AMSTR_OVERLAYOFF "Overlay Mode OFF" + +/* st_stuff.c */ + +#define STSTR_MUS "Music Change" +#define STSTR_NOMUS "IMPOSSIBLE SELECTION" +#define STSTR_DQDON "Degreelessness Mode On" +#define STSTR_DQDOFF "Degreelessness Mode Off" + +#define STSTR_KFAADDED "Very Happy Ammo Added" +#define STSTR_FAADDED "Ammo (no keys) Added" + +#define STSTR_NCON "No Clipping Mode ON" +#define STSTR_NCOFF "No Clipping Mode OFF" + +#define STSTR_BEHOLD "inVuln, Str, Inviso, Rad, Allmap, or Lite-amp" +#define STSTR_BEHOLDX "Power-up Toggled" + +#define STSTR_CHOPPERS "... doesn't suck - GM" +#define STSTR_CLEV "Changing Level..." + +#define STSTR_COMPON "Compatibility Mode On" /* phares */ +#define STSTR_COMPOFF "Compatibility Mode Off" /* phares */ + +/* f_finale.c */ + +#define E1TEXT \ + "Once you beat the big badasses and\n"\ + "clean out the moon base you're supposed\n"\ + "to win, aren't you? Aren't you? Where's\n"\ + "your fat reward and ticket home? What\n"\ + "the hell is this? It's not supposed to\n"\ + "end this way!\n"\ + "\n" \ + "It stinks like rotten meat, but looks\n"\ + "like the lost Deimos base. Looks like\n"\ + "you're stuck on The Shores of Hell.\n"\ + "The only way out is through.\n"\ + "\n"\ + "To continue the DOOM experience, play\n"\ + "The Shores of Hell and its amazing\n"\ + "sequel, Inferno!\n" + + +#define E2TEXT \ + "You've done it! The hideous cyber-\n"\ + "demon lord that ruled the lost Deimos\n"\ + "moon base has been slain and you\n"\ + "are triumphant! But ... where are\n"\ + "you? You clamber to the edge of the\n"\ + "moon and look down to see the awful\n"\ + "truth.\n" \ + "\n"\ + "Deimos floats above Hell itself!\n"\ + "You've never heard of anyone escaping\n"\ + "from Hell, but you'll make the bastards\n"\ + "sorry they ever heard of you! Quickly,\n"\ + "you rappel down to the surface of\n"\ + "Hell.\n"\ + "\n" \ + "Now, it's on to the final chapter of\n"\ + "DOOM! -- Inferno." + + +#define E3TEXT \ + "The loathsome spiderdemon that\n"\ + "masterminded the invasion of the moon\n"\ + "bases and caused so much death has had\n"\ + "its ass kicked for all time.\n"\ + "\n"\ + "A hidden doorway opens and you enter.\n"\ + "You've proven too tough for Hell to\n"\ + "contain, and now Hell at last plays\n"\ + "fair -- for you emerge from the door\n"\ + "to see the green fields of Earth!\n"\ + "Home at last.\n" \ + "\n"\ + "You wonder what's been happening on\n"\ + "Earth while you were battling evil\n"\ + "unleashed. It's good that no Hell-\n"\ + "spawn could have come through that\n"\ + "door with you ..." + + +#define E4TEXT \ + "the spider mastermind must have sent forth\n"\ + "its legions of hellspawn before your\n"\ + "final confrontation with that terrible\n"\ + "beast from hell. but you stepped forward\n"\ + "and brought forth eternal damnation and\n"\ + "suffering upon the horde as a true hero\n"\ + "would in the face of something so evil.\n"\ + "\n"\ + "besides, someone was gonna pay for what\n"\ + "happened to daisy, your pet rabbit.\n"\ + "\n"\ + "but now, you see spread before you more\n"\ + "potential pain and gibbitude as a nation\n"\ + "of demons run amok among our cities.\n"\ + "\n"\ + "next stop, hell on earth!" + + +/* after level 6, put this: */ + +#define C1TEXT \ + "YOU HAVE ENTERED DEEPLY INTO THE INFESTED\n" \ + "STARPORT. BUT SOMETHING IS WRONG. THE\n" \ + "MONSTERS HAVE BROUGHT THEIR OWN REALITY\n" \ + "WITH THEM, AND THE STARPORT'S TECHNOLOGY\n" \ + "IS BEING SUBVERTED BY THEIR PRESENCE.\n" \ + "\n"\ + "AHEAD, YOU SEE AN OUTPOST OF HELL, A\n" \ + "FORTIFIED ZONE. IF YOU CAN GET PAST IT,\n" \ + "YOU CAN PENETRATE INTO THE HAUNTED HEART\n" \ + "OF THE STARBASE AND FIND THE CONTROLLING\n" \ + "SWITCH WHICH HOLDS EARTH'S POPULATION\n" \ + "HOSTAGE." + +/* After level 11, put this: */ + +#define C2TEXT \ + "YOU HAVE WON! YOUR VICTORY HAS ENABLED\n" \ + "HUMANKIND TO EVACUATE EARTH AND ESCAPE\n"\ + "THE NIGHTMARE. NOW YOU ARE THE ONLY\n"\ + "HUMAN LEFT ON THE FACE OF THE PLANET.\n"\ + "CANNIBAL MUTATIONS, CARNIVOROUS ALIENS,\n"\ + "AND EVIL SPIRITS ARE YOUR ONLY NEIGHBORS.\n"\ + "YOU SIT BACK AND WAIT FOR DEATH, CONTENT\n"\ + "THAT YOU HAVE SAVED YOUR SPECIES.\n"\ + "\n"\ + "BUT THEN, EARTH CONTROL BEAMS DOWN A\n"\ + "MESSAGE FROM SPACE: \"SENSORS HAVE LOCATED\n"\ + "THE SOURCE OF THE ALIEN INVASION. IF YOU\n"\ + "GO THERE, YOU MAY BE ABLE TO BLOCK THEIR\n"\ + "ENTRY. THE ALIEN BASE IS IN THE HEART OF\n"\ + "YOUR OWN HOME CITY, NOT FAR FROM THE\n"\ + "STARPORT.\" SLOWLY AND PAINFULLY YOU GET\n"\ + "UP AND RETURN TO THE FRAY." + + +/* After level 20, put this: */ + +#define C3TEXT \ + "YOU ARE AT THE CORRUPT HEART OF THE CITY,\n"\ + "SURROUNDED BY THE CORPSES OF YOUR ENEMIES.\n"\ + "YOU SEE NO WAY TO DESTROY THE CREATURES'\n"\ + "ENTRYWAY ON THIS SIDE, SO YOU CLENCH YOUR\n"\ + "TEETH AND PLUNGE THROUGH IT.\n"\ + "\n"\ + "THERE MUST BE A WAY TO CLOSE IT ON THE\n"\ + "OTHER SIDE. WHAT DO YOU CARE IF YOU'VE\n"\ + "GOT TO GO THROUGH HELL TO GET TO IT?" + + +/* After level 29, put this: */ + +#define C4TEXT \ + "THE HORRENDOUS VISAGE OF THE BIGGEST\n"\ + "DEMON YOU'VE EVER SEEN CRUMBLES BEFORE\n"\ + "YOU, AFTER YOU PUMP YOUR ROCKETS INTO\n"\ + "HIS EXPOSED BRAIN. THE MONSTER SHRIVELS\n"\ + "UP AND DIES, ITS THRASHING LIMBS\n"\ + "DEVASTATING UNTOLD MILES OF HELL'S\n"\ + "SURFACE.\n"\ + "\n"\ + "YOU'VE DONE IT. THE INVASION IS OVER.\n"\ + "EARTH IS SAVED. HELL IS A WRECK. YOU\n"\ + "WONDER WHERE BAD FOLKS WILL GO WHEN THEY\n"\ + "DIE, NOW. WIPING THE SWEAT FROM YOUR\n"\ + "FOREHEAD YOU BEGIN THE LONG TREK BACK\n"\ + "HOME. REBUILDING EARTH OUGHT TO BE A\n"\ + "LOT MORE FUN THAN RUINING IT WAS.\n" + +/* Before level 31, put this: */ + +#define C5TEXT \ + "CONGRATULATIONS, YOU'VE FOUND THE SECRET\n"\ + "LEVEL! LOOKS LIKE IT'S BEEN BUILT BY\n"\ + "HUMANS, RATHER THAN DEMONS. YOU WONDER\n"\ + "WHO THE INMATES OF THIS CORNER OF HELL\n"\ + "WILL BE." + + +/* Before level 32, put this: */ + +#define C6TEXT \ + "CONGRATULATIONS, YOU'VE FOUND THE\n"\ + "SUPER SECRET LEVEL! YOU'D BETTER\n"\ + "BLAZE THROUGH THIS ONE!\n" + +/*** Plutonia ***/ +/* after map 06 */ + +#define P1TEXT \ + "You gloat over the steaming carcass of the\n"\ + "Guardian. With its death, you've wrested\n"\ + "the Accelerator from the stinking claws\n"\ + "of Hell. You relax and glance around the\n"\ + "room. Damn! There was supposed to be at\n"\ + "least one working prototype, but you can't\n"\ + "see it. The demons must have taken it.\n"\ + "\n"\ + "You must find the prototype, or all your\n"\ + "struggles will have been wasted. Keep\n"\ + "moving, keep fighting, keep killing.\n"\ + "Oh yes, keep living, too." + + +/* after map 11 */ + +#define P2TEXT \ + "Even the deadly Arch-Vile labyrinth could\n"\ + "not stop you, and you've gotten to the\n"\ + "prototype Accelerator which is soon\n"\ + "efficiently and permanently deactivated.\n"\ + "\n"\ + "You're good at that kind of thing." + + +/* after map 20 */ + +#define P3TEXT \ + "You've bashed and battered your way into\n"\ + "the heart of the devil-hive. Time for a\n"\ + "Search-and-Destroy mission, aimed at the\n"\ + "Gatekeeper, whose foul offspring is\n"\ + "cascading to Earth. Yeah, he's bad. But\n"\ + "you know who's worse!\n"\ + "\n"\ + "Grinning evilly, you check your gear, and\n"\ + "get ready to give the bastard a little Hell\n"\ + "of your own making!" + +/* after map 30 */ + +#define P4TEXT \ + "The Gatekeeper's evil face is splattered\n"\ + "all over the place. As its tattered corpse\n"\ + "collapses, an inverted Gate forms and\n"\ + "sucks down the shards of the last\n"\ + "prototype Accelerator, not to mention the\n"\ + "few remaining demons. You're done. Hell\n"\ + "has gone back to pounding bad dead folks \n"\ + "instead of good live ones. Remember to\n"\ + "tell your grandkids to put a rocket\n"\ + "launcher in your coffin. If you go to Hell\n"\ + "when you die, you'll need it for some\n"\ + "final cleaning-up ..." + +/* before map 31 */ + +#define P5TEXT \ + "You've found the second-hardest level we\n"\ + "got. Hope you have a saved game a level or\n"\ + "two previous. If not, be prepared to die\n"\ + "aplenty. For master marines only." + +/* before map 32 */ + +#define P6TEXT \ + "Betcha wondered just what WAS the hardest\n"\ + "level we had ready for ya? Now you know.\n"\ + "No one gets out alive." + +/*** TNT: Evilution ***/ + +#define T1TEXT \ + "You've fought your way out of the infested\n"\ + "experimental labs. It seems that UAC has\n"\ + "once again gulped it down. With their\n"\ + "high turnover, it must be hard for poor\n"\ + "old UAC to buy corporate health insurance\n"\ + "nowadays..\n"\ + "\n"\ + "Ahead lies the military complex, now\n"\ + "swarming with diseased horrors hot to get\n"\ + "their teeth into you. With luck, the\n"\ + "complex still has some warlike ordnance\n"\ + "laying around." + + +#define T2TEXT \ + "You hear the grinding of heavy machinery\n"\ + "ahead. You sure hope they're not stamping\n"\ + "out new hellspawn, but you're ready to\n"\ + "ream out a whole herd if you have to.\n"\ + "They might be planning a blood feast, but\n"\ + "you feel about as mean as two thousand\n"\ + "maniacs packed into one mad killer.\n"\ + "\n"\ + "You don't plan to go down easy." + + +#define T3TEXT \ + "The vista opening ahead looks real damn\n"\ + "familiar. Smells familiar, too -- like\n"\ + "fried excrement. You didn't like this\n"\ + "place before, and you sure as hell ain't\n"\ + "planning to like it now. The more you\n"\ + "brood on it, the madder you get.\n"\ + "Hefting your gun, an evil grin trickles\n"\ + "onto your face. Time to take some names." + +#define T4TEXT \ + "Suddenly, all is silent, from one horizon\n"\ + "to the other. The agonizing echo of Hell\n"\ + "fades away, the nightmare sky turns to\n"\ + "blue, the heaps of monster corpses start \n"\ + "to evaporate along with the evil stench \n"\ + "that filled the air. Jeeze, maybe you've\n"\ + "done it. Have you really won?\n"\ + "\n"\ + "Something rumbles in the distance.\n"\ + "A blue light begins to glow inside the\n"\ + "ruined skull of the demon-spitter." + + +#define T5TEXT \ + "What now? Looks totally different. Kind\n"\ + "of like King Tut's condo. Well,\n"\ + "whatever's here can't be any worse\n"\ + "than usual. Can it? Or maybe it's best\n"\ + "to let sleeping gods lie.." + + +#define T6TEXT \ + "Time for a vacation. You've burst the\n"\ + "bowels of hell and by golly you're ready\n"\ + "for a break. You mutter to yourself,\n"\ + "Maybe someone else can kick Hell's ass\n"\ + "next time around. Ahead lies a quiet town,\n"\ + "with peaceful flowing water, quaint\n"\ + "buildings, and presumably no Hellspawn.\n"\ + "\n"\ + "As you step off the transport, you hear\n"\ + "the stomp of a cyberdemon's iron shoe." + + + +/* + * Character cast strings F_FINALE.C + */ +#define CC_ZOMBIE "ZOMBIEMAN" +#define CC_SHOTGUN "SHOTGUN GUY" +#define CC_HEAVY "HEAVY WEAPON DUDE" +#define CC_IMP "IMP" +#define CC_DEMON "DEMON" +#define CC_LOST "LOST SOUL" +#define CC_CACO "CACODEMON" +#define CC_HELL "HELL KNIGHT" +#define CC_BARON "BARON OF HELL" +#define CC_ARACH "ARACHNOTRON" +#define CC_PAIN "PAIN ELEMENTAL" +#define CC_REVEN "REVENANT" +#define CC_MANCU "MANCUBUS" +#define CC_ARCH "ARCH-VILE" +#define CC_SPIDER "THE SPIDER MASTERMIND" +#define CC_CYBER "THE CYBERDEMON" +#define CC_HERO "OUR HERO" + + +#endif diff --git a/apps/plugins/doom/d_event.h b/apps/plugins/doom/d_event.h new file mode 100644 index 0000000000..6896fd5c37 --- /dev/null +++ b/apps/plugins/doom/d_event.h @@ -0,0 +1,128 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Event information structures. + * + *-----------------------------------------------------------------------------*/ + + +#ifndef __D_EVENT__ +#define __D_EVENT__ + + +#include "doomtype.h" + + +// +// Event handling. +// + +// Input event types. +typedef enum +{ + ev_keydown, + ev_keyup, + ev_mouse, + ev_joystick +} evtype_t; + +// Event structure. +typedef struct +{ + evtype_t type; + int data1; // keys / mouse/joystick buttons + int data2; // mouse/joystick x move + int data3; // mouse/joystick y move +} event_t; + + +typedef enum +{ + ga_nothing, + ga_loadlevel, + ga_newgame, + ga_loadgame, + ga_savegame, + ga_playdemo, + ga_completed, + ga_victory, + ga_worlddone, +} gameaction_t; + + + +// +// Button/action code definitions. +// +typedef enum +{ + // Press "Fire". + BT_ATTACK = 1, + + // Use button, to open doors, activate switches. + BT_USE = 2, + + // Flag: game events, not really buttons. + BT_SPECIAL = 128, + BT_SPECIALMASK = 3, + + // Flag, weapon change pending. + // If true, the next 4 bits hold weapon num. + BT_CHANGE = 4, + + // The 4bit weapon mask and shift, convenience. + //BT_WEAPONMASK = (8+16+32), + BT_WEAPONMASK = (8+16+32+64), // extended to pick up SSG // phares + BT_WEAPONSHIFT = 3, + + // Special events + BTS_LOADGAME = 0, // Loads a game + // Pause the game. + BTS_PAUSE = 1, + // Save the game at each console. + BTS_SAVEGAME = 2, + BTS_RESTARTLEVEL= 3, // Restarts the current level + + // Savegame slot numbers occupy the second byte of buttons. + BTS_SAVEMASK = (4+8+16), + BTS_SAVESHIFT = 2, + +} buttoncode_t; + + +// +// GLOBAL VARIABLES +// +#define MAXEVENTS 64 + +extern event_t events[MAXEVENTS]; +extern int eventhead; +extern int eventtail; + +extern gameaction_t gameaction; + +#endif diff --git a/apps/plugins/doom/d_french.h b/apps/plugins/doom/d_french.h new file mode 100644 index 0000000000..6910ad0094 --- /dev/null +++ b/apps/plugins/doom/d_french.h @@ -0,0 +1,437 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// $Id$ +// +// Copyright (C) 1993-1996 by id Software, Inc. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// Printed strings, french translation. +// +//----------------------------------------------------------------------------- + + +#ifndef __D_FRENCH__ +#define __D_FRENCH__ + +// +// D_Main.C +// +#define D_DEVSTR "MODE DEVELOPPEMENT ON.\n" +#define D_CDROM "VERSION CD-ROM: DEFAULT.CFG DANS C:\\DOOMDATA\n" + +// +// M_Menu.C +// +#define PRESSKEY "APPUYEZ SUR UNE TOUCHE." +#define PRESSYN "APPUYEZ SUR Y OU N" +#define QUITMSG "VOUS VOULEZ VRAIMENT\nQUITTER CE SUPER JEU?" +#define LOADNET "VOUS NE POUVEZ PAS CHARGER\nUN JEU EN RESEAU!\n\n"PRESSKEY +#define QLOADNET "CHARGEMENT RAPIDE INTERDIT EN RESEAU!\n\n"PRESSKEY +#define QSAVESPOT "VOUS N'AVEZ PAS CHOISI UN EMPLACEMENT!\n\n"PRESSKEY +#define SAVEDEAD "VOUS NE POUVEZ PAS SAUVER SI VOUS NE JOUEZ "\ +"PAS!\n\n"PRESSKEY +#define QSPROMPT "SAUVEGARDE RAPIDE DANS LE FICHIER \n\n'%s'?\n\n"PRESSYN +#define QLPROMPT "VOULEZ-VOUS CHARGER LA SAUVEGARDE"\ +"\n\n'%s'?\n\n"PRESSYN +#define NEWGAME "VOUS NE POUVEZ PAS LANCER\n"\ +"UN NOUVEAU JEU SUR RESEAU.\n\n"PRESSKEY +#define NIGHTMARE "VOUS CONFIRMEZ? CE NIVEAU EST\n"\ +"VRAIMENT IMPITOYABLE!n"PRESSYN +#define SWSTRING "CECI EST UNE VERSION SHAREWARE DE DOOM.\n\n"\ +"VOUS DEVRIEZ COMMANDER LA TRILOGIE COMPLETE.\n\n"PRESSKEY +#define MSGOFF "MESSAGES OFF" +#define MSGON "MESSAGES ON" +#define NETEND "VOUS NE POUVEZ PAS METTRE FIN A UN JEU SUR "\ +"RESEAU!\n\n"PRESSKEY +#define ENDGAME "VOUS VOULEZ VRAIMENT METTRE FIN AU JEU?\n\n"PRESSYN + +#define DOSY "(APPUYEZ SUR Y POUR REVENIR AU OS.)" + +#define DETAILHI "GRAPHISMES MAXIMUM " +#define DETAILLO "GRAPHISMES MINIMUM " +#define GAMMALVL0 "CORRECTION GAMMA OFF" +#define GAMMALVL1 "CORRECTION GAMMA NIVEAU 1" +#define GAMMALVL2 "CORRECTION GAMMA NIVEAU 2" +#define GAMMALVL3 "CORRECTION GAMMA NIVEAU 3" +#define GAMMALVL4 "CORRECTION GAMMA NIVEAU 4" +#define EMPTYSTRING "EMPLACEMENT VIDE" + +// +// P_inter.C +// +#define GOTARMOR "ARMURE RECUPEREE." +#define GOTMEGA "MEGA-ARMURE RECUPEREE!" +#define GOTHTHBONUS "BONUS DE SANTE RECUPERE." +#define GOTARMBONUS "BONUS D'ARMURE RECUPERE." +#define GOTSTIM "STIMPACK RECUPERE." +#define GOTMEDINEED "MEDIKIT RECUPERE. VOUS EN AVEZ VRAIMENT BESOIN!" +#define GOTMEDIKIT "MEDIKIT RECUPERE." +#define GOTSUPER "SUPERCHARGE!" + +#define GOTBLUECARD "CARTE MAGNETIQUE BLEUE RECUPEREE." +#define GOTYELWCARD "CARTE MAGNETIQUE JAUNE RECUPEREE." +#define GOTREDCARD "CARTE MAGNETIQUE ROUGE RECUPEREE." +#define GOTBLUESKUL "CLEF CRANE BLEUE RECUPEREE." +#define GOTYELWSKUL "CLEF CRANE JAUNE RECUPEREE." +#define GOTREDSKULL "CLEF CRANE ROUGE RECUPEREE." + +#define GOTINVUL "INVULNERABILITE!" +#define GOTBERSERK "BERSERK!" +#define GOTINVIS "INVISIBILITE PARTIELLE " +#define GOTSUIT "COMBINAISON ANTI-RADIATIONS " +#define GOTMAP "CARTE INFORMATIQUE " +#define GOTVISOR "VISEUR A AMPLIFICATION DE LUMIERE " +#define GOTMSPHERE "MEGASPHERE!" + +#define GOTCLIP "CHARGEUR RECUPERE." +#define GOTCLIPBOX "BOITE DE BALLES RECUPEREE." +#define GOTROCKET "ROQUETTE RECUPEREE." +#define GOTROCKBOX "CAISSE DE ROQUETTES RECUPEREE." +#define GOTCELL "CELLULE D'ENERGIE RECUPEREE." +#define GOTCELLBOX "PACK DE CELLULES D'ENERGIE RECUPERE." +#define GOTSHELLS "4 CARTOUCHES RECUPEREES." +#define GOTSHELLBOX "BOITE DE CARTOUCHES RECUPEREE." +#define GOTBACKPACK "SAC PLEIN DE MUNITIONS RECUPERE!" + +#define GOTBFG9000 "VOUS AVEZ UN BFG9000! OH, OUI!" +#define GOTCHAINGUN "VOUS AVEZ LA MITRAILLEUSE!" +#define GOTCHAINSAW "UNE TRONCONNEUSE!" +#define GOTLAUNCHER "VOUS AVEZ UN LANCE-ROQUETTES!" +#define GOTPLASMA "VOUS AVEZ UN FUSIL A PLASMA!" +#define GOTSHOTGUN "VOUS AVEZ UN FUSIL!" +#define GOTSHOTGUN2 "VOUS AVEZ UN SUPER FUSIL!" + +// +// P_Doors.C +// +#define PD_BLUEO "IL VOUS FAUT UNE CLEF BLEUE" +#define PD_REDO "IL VOUS FAUT UNE CLEF ROUGE" +#define PD_YELLOWO "IL VOUS FAUT UNE CLEF JAUNE" +#define PD_BLUEK PD_BLUEO +#define PD_REDK PD_REDO +#define PD_YELLOWK PD_YELLOWO + +// +// G_game.C +// +#define GGSAVED "JEU SAUVEGARDE." + +// +// HU_stuff.C +// +#define HUSTR_MSGU "[MESSAGE NON ENVOYE]" + +#define HUSTR_E1M1 "E1M1: HANGAR" +#define HUSTR_E1M2 "E1M2: USINE NUCLEAIRE " +#define HUSTR_E1M3 "E1M3: RAFFINERIE DE TOXINES " +#define HUSTR_E1M4 "E1M4: CENTRE DE CONTROLE " +#define HUSTR_E1M5 "E1M5: LABORATOIRE PHOBOS " +#define HUSTR_E1M6 "E1M6: TRAITEMENT CENTRAL " +#define HUSTR_E1M7 "E1M7: CENTRE INFORMATIQUE " +#define HUSTR_E1M8 "E1M8: ANOMALIE PHOBOS " +#define HUSTR_E1M9 "E1M9: BASE MILITAIRE " + +#define HUSTR_E2M1 "E2M1: ANOMALIE DEIMOS " +#define HUSTR_E2M2 "E2M2: ZONE DE CONFINEMENT " +#define HUSTR_E2M3 "E2M3: RAFFINERIE" +#define HUSTR_E2M4 "E2M4: LABORATOIRE DEIMOS " +#define HUSTR_E2M5 "E2M5: CENTRE DE CONTROLE " +#define HUSTR_E2M6 "E2M6: HALLS DES DAMNES " +#define HUSTR_E2M7 "E2M7: CUVES DE REPRODUCTION " +#define HUSTR_E2M8 "E2M8: TOUR DE BABEL " +#define HUSTR_E2M9 "E2M9: FORTERESSE DU MYSTERE " + +#define HUSTR_E3M1 "E3M1: DONJON DE L'ENFER " +#define HUSTR_E3M2 "E3M2: BOURBIER DU DESESPOIR " +#define HUSTR_E3M3 "E3M3: PANDEMONIUM" +#define HUSTR_E3M4 "E3M4: MAISON DE LA DOULEUR " +#define HUSTR_E3M5 "E3M5: CATHEDRALE PROFANE " +#define HUSTR_E3M6 "E3M6: MONT EREBUS" +#define HUSTR_E3M7 "E3M7: LIMBES" +#define HUSTR_E3M8 "E3M8: DIS" +#define HUSTR_E3M9 "E3M9: CLAPIERS" + +#define HUSTR_1 "NIVEAU 1: ENTREE " +#define HUSTR_2 "NIVEAU 2: HALLS SOUTERRAINS " +#define HUSTR_3 "NIVEAU 3: LE FEU NOURRI " +#define HUSTR_4 "NIVEAU 4: LE FOYER " +#define HUSTR_5 "NIVEAU 5: LES EGOUTS " +#define HUSTR_6 "NIVEAU 6: LE BROYEUR " +#define HUSTR_7 "NIVEAU 7: L'HERBE DE LA MORT" +#define HUSTR_8 "NIVEAU 8: RUSES ET PIEGES " +#define HUSTR_9 "NIVEAU 9: LE PUITS " +#define HUSTR_10 "NIVEAU 10: BASE DE RAVITAILLEMENT " +#define HUSTR_11 "NIVEAU 11: LE CERCLE DE LA MORT!" + +#define HUSTR_12 "NIVEAU 12: L'USINE " +#define HUSTR_13 "NIVEAU 13: LE CENTRE VILLE" +#define HUSTR_14 "NIVEAU 14: LES ANTRES PROFONDES " +#define HUSTR_15 "NIVEAU 15: LA ZONE INDUSTRIELLE " +#define HUSTR_16 "NIVEAU 16: LA BANLIEUE" +#define HUSTR_17 "NIVEAU 17: LES IMMEUBLES" +#define HUSTR_18 "NIVEAU 18: LA COUR " +#define HUSTR_19 "NIVEAU 19: LA CITADELLE " +#define HUSTR_20 "NIVEAU 20: JE T'AI EU!" + +#define HUSTR_21 "NIVEAU 21: LE NIRVANA" +#define HUSTR_22 "NIVEAU 22: LES CATACOMBES " +#define HUSTR_23 "NIVEAU 23: LA GRANDE FETE " +#define HUSTR_24 "NIVEAU 24: LE GOUFFRE " +#define HUSTR_25 "NIVEAU 25: LES CHUTES DE SANG" +#define HUSTR_26 "NIVEAU 26: LES MINES ABANDONNEES " +#define HUSTR_27 "NIVEAU 27: CHEZ LES MONSTRES " +#define HUSTR_28 "NIVEAU 28: LE MONDE DE L'ESPRIT " +#define HUSTR_29 "NIVEAU 29: LA LIMITE " +#define HUSTR_30 "NIVEAU 30: L'ICONE DU PECHE " + +#define HUSTR_31 "NIVEAU 31: WOLFENSTEIN" +#define HUSTR_32 "NIVEAU 32: LE MASSACRE" + + +#define HUSTR_CHATMACRO1 "JE SUIS PRET A LEUR EN FAIRE BAVER!" +#define HUSTR_CHATMACRO2 "JE VAIS BIEN." +#define HUSTR_CHATMACRO3 "JE N'AI PAS L'AIR EN FORME!" +#define HUSTR_CHATMACRO4 "AU SECOURS!" +#define HUSTR_CHATMACRO5 "TU CRAINS!" +#define HUSTR_CHATMACRO6 "LA PROCHAINE FOIS, MINABLE..." +#define HUSTR_CHATMACRO7 "VIENS ICI!" +#define HUSTR_CHATMACRO8 "JE VAIS M'EN OCCUPER." +#define HUSTR_CHATMACRO9 "OUI" +#define HUSTR_CHATMACRO0 "NON" + +#define HUSTR_TALKTOSELF1 "VOUS PARLEZ TOUT SEUL " +#define HUSTR_TALKTOSELF2 "QUI EST LA?" +#define HUSTR_TALKTOSELF3 "VOUS VOUS FAITES PEUR " +#define HUSTR_TALKTOSELF4 "VOUS COMMENCEZ A DELIRER " +#define HUSTR_TALKTOSELF5 "VOUS ETES LARGUE..." + +#define HUSTR_MESSAGESENT "[MESSAGE ENVOYE]" + +// The following should NOT be changed unless it seems +// just AWFULLY necessary + +#define HUSTR_PLRGREEN "VERT: " +#define HUSTR_PLRINDIGO "INDIGO: " +#define HUSTR_PLRBROWN "BRUN: " +#define HUSTR_PLRRED "ROUGE: " + +#define HUSTR_KEYGREEN 'g' // french key should be "V" +#define HUSTR_KEYINDIGO 'i' +#define HUSTR_KEYBROWN 'b' +#define HUSTR_KEYRED 'r' + +// +// AM_map.C +// + +#define AMSTR_FOLLOWON "MODE POURSUITE ON" +#define AMSTR_FOLLOWOFF "MODE POURSUITE OFF" + +#define AMSTR_GRIDON "GRILLE ON" +#define AMSTR_GRIDOFF "GRILLE OFF" + +#define AMSTR_MARKEDSPOT "REPERE MARQUE " +#define AMSTR_MARKSCLEARED "REPERES EFFACES " + +// +// ST_stuff.C +// + +#define STSTR_MUS "CHANGEMENT DE MUSIQUE " +#define STSTR_NOMUS "IMPOSSIBLE SELECTION" +#define STSTR_DQDON "INVULNERABILITE ON " +#define STSTR_DQDOFF "INVULNERABILITE OFF" + +#define STSTR_KFAADDED "ARMEMENT MAXIMUM! " +#define STSTR_FAADDED "ARMES (SAUF CLEFS) AJOUTEES" + +#define STSTR_NCON "BARRIERES ON" +#define STSTR_NCOFF "BARRIERES OFF" + +#define STSTR_BEHOLD " inVuln, Str, Inviso, Rad, Allmap, or Lite-amp" +#define STSTR_BEHOLDX "AMELIORATION ACTIVEE" + +#define STSTR_CHOPPERS "... DOESN'T SUCK - GM" +#define STSTR_CLEV "CHANGEMENT DE NIVEAU..." + +// +// F_Finale.C +// +#define E1TEXT "APRES AVOIR VAINCU LES GROS MECHANTS\n"\ +"ET NETTOYE LA BASE LUNAIRE, VOUS AVEZ\n"\ +"GAGNE, NON? PAS VRAI? OU EST DONC VOTRE\n"\ +" RECOMPENSE ET VOTRE BILLET DE\n"\ +"RETOUR? QU'EST-QUE CA VEUT DIRE?CE"\ +"N'EST PAS LA FIN ESPEREE!\n"\ +"\n" \ +"CA SENT LA VIANDE PUTREFIEE, MAIS\n"\ +"ON DIRAIT LA BASE DEIMOS. VOUS ETES\n"\ +"APPAREMMENT BLOQUE AUX PORTES DE L'ENFER.\n"\ +"LA SEULE ISSUE EST DE L'AUTRE COTE.\n"\ +"\n"\ +"POUR VIVRE LA SUITE DE DOOM, JOUEZ\n"\ +"A 'AUX PORTES DE L'ENFER' ET A\n"\ +"L'EPISODE SUIVANT, 'L'ENFER'!\n" + +#define E2TEXT "VOUS AVEZ REUSSI. L'INFAME DEMON\n"\ +"QUI CONTROLAIT LA BASE LUNAIRE DE\n"\ +"DEIMOS EST MORT, ET VOUS AVEZ\n"\ +"TRIOMPHE! MAIS... OU ETES-VOUS?\n"\ +"VOUS GRIMPEZ JUSQU'AU BORD DE LA\n"\ +"LUNE ET VOUS DECOUVREZ L'ATROCE\n"\ +"VERITE.\n" \ +"\n"\ +"DEIMOS EST AU-DESSUS DE L'ENFER!\n"\ +"VOUS SAVEZ QUE PERSONNE NE S'EN\n"\ +"EST JAMAIS ECHAPPE, MAIS CES FUMIERS\n"\ +"VONT REGRETTER DE VOUS AVOIR CONNU!\n"\ +"VOUS REDESCENDEZ RAPIDEMENT VERS\n"\ +"LA SURFACE DE L'ENFER.\n"\ +"\n" \ +"VOICI MAINTENANT LE CHAPITRE FINAL DE\n"\ +"DOOM! -- L'ENFER." + +#define E3TEXT "LE DEMON ARACHNEEN ET REPUGNANT\n"\ +"QUI A DIRIGE L'INVASION DES BASES\n"\ +"LUNAIRES ET SEME LA MORT VIENT DE SE\n"\ +"FAIRE PULVERISER UNE FOIS POUR TOUTES.\n"\ +"\n"\ +"UNE PORTE SECRETE S'OUVRE. VOUS ENTREZ.\n"\ +"VOUS AVEZ PROUVE QUE VOUS POUVIEZ\n"\ +"RESISTER AUX HORREURS DE L'ENFER.\n"\ +"IL SAIT ETRE BEAU JOUEUR, ET LORSQUE\n"\ +"VOUS SORTEZ, VOUS REVOYEZ LES VERTES\n"\ +"PRAIRIES DE LA TERRE, VOTRE PLANETE.\n"\ +"\n"\ +"VOUS VOUS DEMANDEZ CE QUI S'EST PASSE\n"\ +"SUR TERRE PENDANT QUE VOUS AVEZ\n"\ +"COMBATTU LE DEMON. HEUREUSEMENT,\n"\ +"AUCUN GERME DU MAL N'A FRANCHI\n"\ +"CETTE PORTE AVEC VOUS..." + + + +// after level 6, put this: + +#define C1TEXT "VOUS ETES AU PLUS PROFOND DE L'ASTROPORT\n" \ +"INFESTE DE MONSTRES, MAIS QUELQUE CHOSE\n" \ +"NE VA PAS. ILS ONT APPORTE LEUR PROPRE\n" \ +"REALITE, ET LA TECHNOLOGIE DE L'ASTROPORT\n" \ +"EST AFFECTEE PAR LEUR PRESENCE.\n" \ +"\n"\ +"DEVANT VOUS, VOUS VOYEZ UN POSTE AVANCE\n" \ +"DE L'ENFER, UNE ZONE FORTIFIEE. SI VOUS\n" \ +"POUVEZ PASSER, VOUS POURREZ PENETRER AU\n" \ +"COEUR DE LA BASE HANTEE ET TROUVER \n" \ +"L'INTERRUPTEUR DE CONTROLE QUI GARDE LA \n" \ +"POPULATION DE LA TERRE EN OTAGE." + +// After level 11, put this: + +#define C2TEXT "VOUS AVEZ GAGNE! VOTRE VICTOIRE A PERMIS\n" \ +"A L'HUMANITE D'EVACUER LA TERRE ET \n"\ +"D'ECHAPPER AU CAUCHEMAR. VOUS ETES \n"\ +"MAINTENANT LE DERNIER HUMAIN A LA SURFACE \n"\ +"DE LA PLANETE. VOUS ETES ENTOURE DE \n"\ +"MUTANTS CANNIBALES, D'EXTRATERRESTRES \n"\ +"CARNIVORES ET D'ESPRITS DU MAL. VOUS \n"\ +"ATTENDEZ CALMEMENT LA MORT, HEUREUX \n"\ +"D'AVOIR PU SAUVER VOTRE RACE.\n"\ +"MAIS UN MESSAGE VOUS PARVIENT SOUDAIN\n"\ +"DE L'ESPACE: \"NOS CAPTEURS ONT LOCALISE\n"\ +"LA SOURCE DE L'INVASION EXTRATERRESTRE.\n"\ +"SI VOUS Y ALLEZ, VOUS POURREZ PEUT-ETRE\n"\ +"LES ARRETER. LEUR BASE EST SITUEE AU COEUR\n"\ +"DE VOTRE VILLE NATALE, PRES DE L'ASTROPORT.\n"\ +"VOUS VOUS RELEVEZ LENTEMENT ET PENIBLEMENT\n"\ +"ET VOUS REPARTEZ POUR LE FRONT." + +// After level 20, put this: + +#define C3TEXT "VOUS ETES AU COEUR DE LA CITE CORROMPUE,\n"\ +"ENTOURE PAR LES CADAVRES DE VOS ENNEMIS.\n"\ +"VOUS NE VOYEZ PAS COMMENT DETRUIRE LA PORTE\n"\ +"DES CREATURES DE CE COTE. VOUS SERREZ\n"\ +"LES DENTS ET PLONGEZ DANS L'OUVERTURE.\n"\ +"\n"\ +"IL DOIT Y AVOIR UN MOYEN DE LA FERMER\n"\ +"DE L'AUTRE COTE. VOUS ACCEPTEZ DE\n"\ +"TRAVERSER L'ENFER POUR LE FAIRE?" + +// After level 29, put this: + +#define C4TEXT "LE VISAGE HORRIBLE D'UN DEMON D'UNE\n"\ +"TAILLE INCROYABLE S'EFFONDRE DEVANT\n"\ +"VOUS LORSQUE VOUS TIREZ UNE SALVE DE\n"\ +"ROQUETTES DANS SON CERVEAU. LE MONSTRE\n"\ +"SE RATATINE, SES MEMBRES DECHIQUETES\n"\ +"SE REPANDANT SUR DES CENTAINES DE\n"\ +"KILOMETRES A LA SURFACE DE L'ENFER.\n"\ +"\n"\ +"VOUS AVEZ REUSSI. L'INVASION N'AURA.\n"\ +"PAS LIEU. LA TERRE EST SAUVEE. L'ENFER\n"\ +"EST ANEANTI. EN VOUS DEMANDANT OU IRONT\n"\ +"MAINTENANT LES DAMNES, VOUS ESSUYEZ\n"\ +"VOTRE FRONT COUVERT DE SUEUR ET REPARTEZ\n"\ +"VERS LA TERRE. SA RECONSTRUCTION SERA\n"\ +"BEAUCOUP PLUS DROLE QUE SA DESTRUCTION.\n" + +// Before level 31, put this: + +#define C5TEXT "FELICITATIONS! VOUS AVEZ TROUVE LE\n"\ +"NIVEAU SECRET! IL SEMBLE AVOIR ETE\n"\ +"CONSTRUIT PAR LES HUMAINS. VOUS VOUS\n"\ +"DEMANDEZ QUELS PEUVENT ETRE LES\n"\ +"HABITANTS DE CE COIN PERDU DE L'ENFER." + +// Before level 32, put this: + +#define C6TEXT "FELICITATIONS! VOUS AVEZ DECOUVERT\n"\ +"LE NIVEAU SUPER SECRET! VOUS FERIEZ\n"\ +"MIEUX DE FONCER DANS CELUI-LA!\n" + +// +// Character cast strings F_FINALE.C +// +#define CC_ZOMBIE "ZOMBIE" +#define CC_SHOTGUN "TYPE AU FUSIL" +#define CC_HEAVY "MEC SUPER-ARME" +#define CC_IMP "DIABLOTIN" +#define CC_DEMON "DEMON" +#define CC_LOST "AME PERDUE" +#define CC_CACO "CACODEMON" +#define CC_HELL "CHEVALIER DE L'ENFER" +#define CC_BARON "BARON DE L'ENFER" +#define CC_ARACH "ARACHNOTRON" +#define CC_PAIN "ELEMENTAIRE DE LA DOULEUR" +#define CC_REVEN "REVENANT" +#define CC_MANCU "MANCUBUS" +#define CC_ARCH "ARCHI-INFAME" +#define CC_SPIDER "L'ARAIGNEE CERVEAU" +#define CC_CYBER "LE CYBERDEMON" +#define CC_HERO "NOTRE HEROS" + + + +#endif +//----------------------------------------------------------------------------- +// +// $Log$ +// Revision 1.1 2006/03/28 15:44:01 dave +// Patch #2969 - Doom! Currently only working on the H300. +// +// +//----------------------------------------------------------------------------- + + diff --git a/apps/plugins/doom/d_items.c b/apps/plugins/doom/d_items.c new file mode 100644 index 0000000000..de4cfaa8e2 --- /dev/null +++ b/apps/plugins/doom/d_items.c @@ -0,0 +1,138 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Something to do with weapon sprite frames. Don't ask me. + * + *----------------------------------------------------------------------------- + */ + +// We are referring to sprite numbers. +#include "doomtype.h" +#include "info.h" + +#ifdef __GNUG__ +#pragma implementation "d_items.h" +#endif +#include "d_items.h" + + +// +// PSPRITE ACTIONS for waepons. +// This struct controls the weapon animations. +// +// Each entry is: +// ammo/amunition type +// upstate +// downstate +// readystate +// atkstate, i.e. attack/fire/hit frame +// flashstate, muzzle flash +// +weaponinfo_t weaponinfo[NUMWEAPONS] = + { + { + // fist + am_noammo, + S_PUNCHUP, + S_PUNCHDOWN, + S_PUNCH, + S_PUNCH1, + S_NULL + }, + { + // pistol + am_clip, + S_PISTOLUP, + S_PISTOLDOWN, + S_PISTOL, + S_PISTOL1, + S_PISTOLFLASH + }, + { + // shotgun + am_shell, + S_SGUNUP, + S_SGUNDOWN, + S_SGUN, + S_SGUN1, + S_SGUNFLASH1 + }, + { + // chaingun + am_clip, + S_CHAINUP, + S_CHAINDOWN, + S_CHAIN, + S_CHAIN1, + S_CHAINFLASH1 + }, + { + // missile launcher + am_misl, + S_MISSILEUP, + S_MISSILEDOWN, + S_MISSILE, + S_MISSILE1, + S_MISSILEFLASH1 + }, + { + // plasma rifle + am_cell, + S_PLASMAUP, + S_PLASMADOWN, + S_PLASMA, + S_PLASMA1, + S_PLASMAFLASH1 + }, + { + // bfg 9000 + am_cell, + S_BFGUP, + S_BFGDOWN, + S_BFG, + S_BFG1, + S_BFGFLASH1 + }, + { + // chainsaw + am_noammo, + S_SAWUP, + S_SAWDOWN, + S_SAW, + S_SAW1, + S_NULL + }, + { + // super shotgun + am_shell, + S_DSGUNUP, + S_DSGUNDOWN, + S_DSGUN, + S_DSGUN1, + S_DSGUNFLASH1 + }, + }; diff --git a/apps/plugins/doom/d_items.h b/apps/plugins/doom/d_items.h new file mode 100644 index 0000000000..313fdb8649 --- /dev/null +++ b/apps/plugins/doom/d_items.h @@ -0,0 +1,57 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Items: key cards, artifacts, weapon, ammunition. + * + *-----------------------------------------------------------------------------*/ + + +#ifndef __D_ITEMS__ +#define __D_ITEMS__ + +#include "doomdef.h" + +#ifdef __GNUG__ +#pragma interface +#endif + + +/* Weapon info: sprite frames, ammunition use. */ +typedef struct +{ + ammotype_t ammo; + int upstate; + int downstate; + int readystate; + int atkstate; + int flashstate; + +} weaponinfo_t; + +extern weaponinfo_t weaponinfo[NUMWEAPONS]; + +#endif diff --git a/apps/plugins/doom/d_main.c b/apps/plugins/doom/d_main.c new file mode 100644 index 0000000000..d76779cb2b --- /dev/null +++ b/apps/plugins/doom/d_main.c @@ -0,0 +1,844 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * DOOM main program (D_DoomMain) and game loop (D_DoomLoop), + * plus functions to determine game mode (shareware, registered), + * parse command line parameters, configure game parameters (turbo), + * and call the startup functions. + * + *----------------------------------------------------------------------------- + */ + + +#include "rockmacros.h" + +#include "doomdef.h" +#include "doomtype.h" +#include "doomstat.h" +#include "dstrings.h" +#include "sounds.h" +#include "z_zone.h" +#include "w_wad.h" +#include "s_sound.h" +#include "v_video.h" +#include "f_finale.h" +#include "f_wipe.h" +#include "m_argv.h" +#include "m_misc.h" +#include "m_menu.h" +#include "i_system.h" +#include "i_sound.h" +#include "i_video.h" +#include "g_game.h" +#include "hu_stuff.h" +#include "wi_stuff.h" +#include "st_stuff.h" +#include "am_map.h" +#include "p_setup.h" +#include "r_draw.h" +#include "r_main.h" +#include "d_main.h" +#include "am_map.h" +#include "m_swap.h" + +// CPhipps - removed wadfiles[] stuff + +boolean devparm; // started game with -devparm + +// jff 1/24/98 add new versions of these variables to remember command line +boolean clnomonsters; // checkparm of -nomonsters +boolean clrespawnparm; // checkparm of -respawn +boolean clfastparm; // checkparm of -fast +// jff 1/24/98 end definition of command line version of play mode switches + +boolean nomonsters; // working -nomonsters +boolean respawnparm; // working -respawn +boolean fastparm; // working -fast + +boolean singletics = false; // debug flag to cancel adaptiveness + +boolean doomexit; + +//jff 1/22/98 parms for disabling music and sound +boolean nosfxparm; +boolean nomusicparm; + +//jff 4/18/98 +extern boolean inhelpscreens; + +skill_t startskill; +int startepisode; +int startmap; +boolean autostart; +int debugfile; +int ffmap; + +boolean advancedemo; + +extern boolean timingdemo, singledemo, demoplayback, fastdemo; // killough + +int basetic; + +void D_DoAdvanceDemo (void); + +/* + * D_PostEvent - Event handling + * + * Called by I/O functions when an event is received. + * Try event handlers for each code area in turn. + * cph - in the true spirit of the Boom source, let the + * short ciruit operator madness begin! + */ + +void D_PostEvent(event_t *ev) +{ + /* cph - suppress all input events at game start + * FIXME: This is a lousy kludge */ + if (gametic < 3) return; + M_Responder(ev) || + (gamestate == GS_LEVEL && ( + HU_Responder(ev) || + ST_Responder(ev) || + AM_Responder(ev) + ) + ) || + G_Responder(ev); +} + +// +// D_Wipe +// +// CPhipps - moved the screen wipe code from D_Display to here +// The screens to wipe between are already stored, this just does the timing +// and screen updating + +static void D_Wipe(void) +{ + boolean done; + int wipestart = I_GetTime () - 1; + + do + { + int nowtime, tics; + do + { + //I_uSleep(5000); // CPhipps - don't thrash cpu in this loop + nowtime = I_GetTime(); + tics = nowtime - wipestart; + } + while (!tics); + wipestart = nowtime; + + done = wipe_ScreenWipe(0,0,SCREENWIDTH,SCREENHEIGHT,tics); + I_UpdateNoBlit(); + M_Drawer(); // menu is drawn even on top of wipes + I_FinishUpdate(); // page flip or blit buffer + } + while (!done); +} + +// +// D_Display +// draw current display, possibly wiping it from the previous +// + +// wipegamestate can be set to -1 to force a wipe on the next draw +gamestate_t wipegamestate = GS_DEMOSCREEN; +extern boolean setsizeneeded; +extern int showMessages; + +void D_Display (void) +{ + static boolean isborderstate = false; + static boolean borderwillneedredraw = false; + static boolean inhelpscreensstate = false; + static gamestate_t oldgamestate = -1; + boolean wipe; + boolean viewactive = false, isborder = false; + + if (nodrawers) // for comparative timing / profiling + return; + + // save the current screen if about to wipe + if ((wipe = gamestate != wipegamestate)) + wipe_StartScreen(0, 0, SCREENWIDTH, SCREENHEIGHT); + + if (gamestate != GS_LEVEL) { // Not a level + switch (oldgamestate) { + case -1: + case GS_LEVEL: + V_SetPalette(0); // cph - use default (basic) palette + default: + break; + } + + switch (gamestate) { + case GS_INTERMISSION: + WI_Drawer(); + break; + case GS_FINALE: + F_Drawer(); + break; + case GS_DEMOSCREEN: + D_PageDrawer(); + break; + default: + break; + } + } else if (gametic != basetic) { // In a level + boolean redrawborderstuff; + + HU_Erase(); + + if (setsizeneeded) { // change the view size if needed + R_ExecuteSetViewSize(); + oldgamestate = -1; // force background redraw + } + + // Work out if the player view is visible, and if there is a border + viewactive = (!(automapmode & am_active) || (automapmode & am_overlay)) && !inhelpscreens; + isborder = viewactive ? (viewheight != SCREENHEIGHT) : (!inhelpscreens && (automapmode & am_active)); + + if (oldgamestate != GS_LEVEL) { + R_FillBackScreen (); // draw the pattern into the back screen + redrawborderstuff = isborder; + } else { + // CPhipps - + // If there is a border, and either there was no border last time, + // or the border might need refreshing, then redraw it. + redrawborderstuff = isborder && (!isborderstate || borderwillneedredraw); + // The border may need redrawing next time if the border surrounds the screen, + // and there is a menu being displayed + borderwillneedredraw = menuactive && isborder && viewactive && (viewwidth != SCREENWIDTH); + } + + if (redrawborderstuff) + R_DrawViewBorder(); + + // Now do the drawing + if (viewactive) + R_RenderPlayerView (&players[displayplayer]); + if (automapmode & am_active) + AM_Drawer(); + ST_Drawer((viewheight != SCREENHEIGHT) || ((automapmode & am_active) && !(automapmode & am_overlay)), redrawborderstuff); + R_DrawViewBorder(); + + HU_Drawer(); + } + + inhelpscreensstate = inhelpscreens; + isborderstate = isborder; + oldgamestate = wipegamestate = gamestate; + + // draw pause pic + if (paused) { + static int x; + + if (!x) { // Cache results of x pos calc + int lump = W_GetNumForName("M_PAUSE"); + const patch_t* p = W_CacheLumpNum(lump); + x = (320 - SHORT(p->width))/2; + W_UnlockLumpNum(lump); + } + + // CPhipps - updated for new patch drawing + V_DrawNamePatch(x, (!(automapmode & am_active) || (automapmode & am_overlay)) + ? 4+(viewwindowy*200/SCREENHEIGHT) : 4, // cph - Must un-stretch viewwindowy + 0, "M_PAUSE", CR_DEFAULT, VPT_STRETCH); + } + + // menus go directly to the screen + M_Drawer(); // menu is drawn even on top of everything + D_BuildNewTiccmds(); + + // normal update + if (!wipe) + I_FinishUpdate (); // page flip or blit buffer + else { + // wipe update + wipe_EndScreen(0, 0, SCREENWIDTH, SCREENHEIGHT); + D_Wipe(); + } +} + +// +// D_DoomLoop() +// +// Not a globally visible function, +// just included for source reference, +// called by D_DoomMain, never exits. +// Manages timing and IO, +// calls all ?_Responder, ?_Ticker, and ?_Drawer, +// calls I_GetTime, I_StartFrame, and I_StartTic +// + +extern boolean demorecording; + +static void D_DoomLoop (void) +{ + basetic = gametic; + + I_SubmitSound(); + + while (!doomexit) + { + // frame syncronous IO operations + //I_StartFrame (); + + // process one or more tics + if (singletics) + { + I_StartTic (); + G_BuildTiccmd (&netcmds[consoleplayer][maketic%BACKUPTICS]); + if (advancedemo) + D_DoAdvanceDemo (); + M_Ticker (); + G_Ticker (); + gametic++; + maketic++; + } + else + TryRunTics (); // will run at least one tic + + // killough 3/16/98: change consoleplayer to displayplayer + if (players[displayplayer].mo) // cph 2002/08/10 + S_UpdateSounds(players[displayplayer].mo);// move positional sounds + + // Update display, next frame, with current state. + D_Display(); + + // Sound mixing for the buffer is snychronous. +// I_UpdateSound(); + rb->yield(); + } +} + +// +// DEMO LOOP +// + +static int demosequence; // killough 5/2/98: made static +static int pagetic; +static const char *pagename; // CPhipps - const + +// +// D_PageTicker +// Handles timing for warped projection +// +void D_PageTicker(void) +{ + if (--pagetic < 0) + D_AdvanceDemo(); +} + +// +// D_PageDrawer +// +void D_PageDrawer(void) +{ + // CPhipps - updated for new patch drawing + V_DrawNamePatch(0, 0, 0, pagename, CR_DEFAULT, VPT_STRETCH); +} + +// +// D_AdvanceDemo +// Called after each demo or intro demosequence finishes +// +void D_AdvanceDemo (void) +{ + advancedemo = true; +} + +/* killough 11/98: functions to perform demo sequences + * cphipps 10/99: constness fixes + */ + +static void D_SetPageName(const char *name) +{ + pagename = name; +} + +static void D_DrawTitle1(const char *name) +{ + S_StartMusic(mus_intro); + pagetic = (TICRATE*170)/35; + D_SetPageName(name); +} + +static void D_DrawTitle2(const char *name) +{ + S_StartMusic(mus_dm2ttl); + D_SetPageName(name); +} + +/* killough 11/98: tabulate demo sequences + */ + +static struct +{ + void (*func)(const char *); + const char *name; +} const demostates[][4] = + { + { + {D_DrawTitle1, "TITLEPIC"}, + {D_DrawTitle1, "TITLEPIC"}, + {D_DrawTitle2, "TITLEPIC"}, + {D_DrawTitle1, "TITLEPIC"}, + }, + + { + {G_DeferedPlayDemo, "demo1"}, + {G_DeferedPlayDemo, "demo1"}, + {G_DeferedPlayDemo, "demo1"}, + {G_DeferedPlayDemo, "demo1"}, + }, + { + {D_SetPageName, "CREDIT"}, + {D_SetPageName, "CREDIT"}, + {D_SetPageName, "CREDIT"}, + {D_SetPageName, "CREDIT"}, + }, + + { + {G_DeferedPlayDemo, "demo2"}, + {G_DeferedPlayDemo, "demo2"}, + {G_DeferedPlayDemo, "demo2"}, + {G_DeferedPlayDemo, "demo2"}, + }, + + { + {D_SetPageName, "HELP2"}, + {D_SetPageName, "HELP2"}, + {D_SetPageName, "CREDIT"}, + {D_DrawTitle1, "TITLEPIC"}, + }, + + { + {G_DeferedPlayDemo, "demo3"}, + {G_DeferedPlayDemo, "demo3"}, + {G_DeferedPlayDemo, "demo3"}, + {G_DeferedPlayDemo, "demo3"}, + }, + + { + {NULL,0}, + {NULL,0}, + {NULL,0}, + {D_SetPageName, "CREDIT"}, + }, + + { + {NULL,0}, + {NULL,0}, + {NULL,0}, + {G_DeferedPlayDemo, "demo4"}, + }, + + { + {NULL,0}, + {NULL,0}, + {NULL,0}, + {NULL,0}, + } + }; + +/* + * This cycles through the demo sequences. + * killough 11/98: made table-driven + */ + +void D_DoAdvanceDemo(void) +{ + players[consoleplayer].playerstate = PST_LIVE; /* not reborn */ + advancedemo = usergame = paused = false; + gameaction = ga_nothing; + + pagetic = TICRATE * 11; /* killough 11/98: default behavior */ + gamestate = GS_DEMOSCREEN; + + if (netgame && !demoplayback) { + demosequence = 0; + } else + if (!demostates[++demosequence][gamemode].func) + demosequence = 0; + demostates[demosequence][gamemode].func(demostates[demosequence][gamemode].name); +} + +// +// D_StartTitle +// +void D_StartTitle (void) +{ + gameaction = ga_nothing; + demosequence = -1; + D_AdvanceDemo(); +} + +// +// D_AddFile +// +// Rewritten by Lee Killough +// +// Ty 08/29/98 - add source parm to indicate where this came from +// CPhipps - static, const char* parameter +// - source is an enum +// - modified to allocate & use new wadfiles array +void D_AddFile (const char *file, wad_source_t source) +{ + wadfiles = realloc(wadfiles, sizeof(*wadfiles)*(numwadfiles+1)); + wadfiles[numwadfiles].name = + AddDefaultExtension(strcpy(malloc(strlen(file)+5), file), ".wad"); + wadfiles[numwadfiles].src = source; // Ty 08/29/98 + numwadfiles++; +} + +// +// CheckIWAD +// +// Verify a file is indeed tagged as an IWAD +// Scan its lumps for levelnames and return gamemode as indicated +// Detect missing wolf levels in DOOM II +// +// The filename to check is passed in iwadname, the gamemode detected is +// returned in gmode, hassec returns the presence of secret levels +// +// jff 4/19/98 Add routine to test IWAD for validity and determine +// the gamemode from it. Also note if DOOM II, whether secret levels exist +// CPhipps - const char* for iwadname, made static +#if 0 +static void CheckIWAD(const char *iwadname,GameMode_t *gmode,boolean *hassec) +{ + if ( !fileexists (iwadname) ) + { + int ud=0,rg=0,sw=0,cm=0,sc=0; + int handle; + + // Identify IWAD correctly + if ( (handle = open (iwadname,O_RDONLY)) != -1) + { + wadinfo_t header; + + // read IWAD header + read (handle, &header, sizeof(header)); + if (!strncmp(header.identification,"IWAD",4)) + { + size_t length; + filelump_t *fileinfo; + + // read IWAD directory + header.numlumps = LONG(header.numlumps); + header.infotableofs = LONG(header.infotableofs); + length = header.numlumps; + fileinfo = malloc(length*sizeof(filelump_t)); + lseek (handle, header.infotableofs, SEEK_SET); + read (handle, fileinfo, length*sizeof(filelump_t)); + close(handle); + + // scan directory for levelname lumps + while (length--) + if (fileinfo[length].name[0] == 'E' && + fileinfo[length].name[2] == 'M' && + fileinfo[length].name[4] == 0) + { + if (fileinfo[length].name[1] == '4') + ++ud; + else if (fileinfo[length].name[1] == '3') + ++rg; + else if (fileinfo[length].name[1] == '2') + ++rg; + else if (fileinfo[length].name[1] == '1') + ++sw; + } + else if (fileinfo[length].name[0] == 'M' && + fileinfo[length].name[1] == 'A' && + fileinfo[length].name[2] == 'P' && + fileinfo[length].name[5] == 0) + { + ++cm; + if (fileinfo[length].name[3] == '3') + if (fileinfo[length].name[4] == '1' || + fileinfo[length].name[4] == '2') + ++sc; + } + + free(fileinfo); + } + else // missing IWAD tag in header + I_Error("CheckIWAD: IWAD tag %s not present", iwadname); + } + else // error from open call + I_Error("CheckIWAD: Can't open IWAD %s", iwadname); + + // Determine game mode from levels present + // Must be a full set for whichever mode is present + // Lack of wolf-3d levels also detected here + + *gmode = indetermined; + *hassec = false; + if (cm>=30) + { + *gmode = commercial; + *hassec = sc>=2; + } + else if (ud>=9) + *gmode = retail; + else if (rg>=18) + *gmode = registered; + else if (sw>=9) + *gmode = shareware; + } + else // error from access call + I_Error("CheckIWAD: IWAD %s not readable", iwadname); +} +#endif +void D_DoomMainSetup(void) +{ + int p; + + nomonsters = M_CheckParm ("-nomonsters"); + respawnparm = M_CheckParm ("-respawn"); + fastparm = M_CheckParm ("-fast"); + devparm = M_CheckParm ("-devparm"); + if (M_CheckParm ("-altdeath")) + deathmatch = 2; + else if (M_CheckParm ("-deathmatch")) + deathmatch = 1; + + printf("Welcome to Rockdoom"); + + switch ( gamemode ) + { + case retail: + printf ("The Ultimate DOOM Startup v%d.%d",DVERSION/100,DVERSION%100); + break; + case shareware: + printf ("DOOM Shareware Startup v%d.%d",DVERSION/100,DVERSION%100); + break; + case registered: + printf ("DOOM Registered Startup v%d.%d",DVERSION/100,DVERSION%100); + break; + case commercial: + switch (gamemission) + { + case pack_plut: + printf ("DOOM 2: Plutonia Experiment v%d.%d",DVERSION/100,DVERSION%100); + break; + case pack_tnt: + printf ("DOOM 2: TNT - Evilution v%d.%d",DVERSION/100,DVERSION%100); + break; + default: + printf ("DOOM 2: Hell on Earth v%d.%d",DVERSION/100,DVERSION%100); + break; + } + break; + default: + printf ("Public DOOM v%d.%d",DVERSION/100,DVERSION%100); + break; + } + + if (devparm) + printf(D_DEVSTR); + + // turbo option + if ((p=M_CheckParm ("-turbo"))) + { + int scale = 200; + extern int forwardmove[2]; + extern int sidemove[2]; + + if (p 400) + scale = 400; + printf ("turbo scale: %d%%\n",scale); + forwardmove[0] = forwardmove[0]*scale/100; + forwardmove[1] = forwardmove[1]*scale/100; + sidemove[0] = sidemove[0]*scale/100; + sidemove[1] = sidemove[1]*scale/100; + } + + // get skill / episode / map from parms + startskill = sk_medium; + startepisode = 1; + startmap = 1; + autostart = false; + + p = M_CheckParm ("-skill"); + if (p && p < myargc-1) + { + startskill = myargv[p+1][0]-'1'; + autostart = true; + } + + p = M_CheckParm ("-episode"); + if (p && p < myargc-1) + { + startepisode = myargv[p+1][0]-'0'; + startmap = 1; + autostart = true; + } + + p = M_CheckParm ("-warp"); + if (p && p < myargc-1) + { + if (gamemode == commercial) + startmap = atoi (myargv[p+1]); + else + { + startepisode = myargv[p+1][0]-'0'; + startmap = myargv[p+2][0]-'0'; + } + autostart = true; + } + + // CPhipps - move up netgame init + printf("D_InitNetGame: Checking for network game.\n"); + D_InitNetGame(); + + // init subsystems + printf ("V_Init: allocate screens.\n"); + V_Init (); + + printf ("W_Init: Init WADfiles.\n"); + W_Init(); + + V_InitColorTranslation(); //jff 4/24/98 load color translation lumps + + // Check for -file in shareware + if (modifiedgame) + { + // These are the lumps that will be checked in IWAD, + // if any one is not present, execution will be aborted. + char name[23][8]= + { + "e2m1","e2m2","e2m3","e2m4","e2m5","e2m6","e2m7","e2m8","e2m9", + "e3m1","e3m3","e3m3","e3m4","e3m5","e3m6","e3m7","e3m8","e3m9", + "dphoof","bfgga0","heada1","cybra1","spida1d1" + }; + int i; + + if ( gamemode == shareware) + I_Error("\nYou cannot -file with the shareware version. Register!"); + + // Check for fake IWAD with right name, + // but w/o all the lumps of the registered version. + if (gamemode == registered) + for (i = 0;i < 23; i++) + if (W_CheckNumForName(name[i])<0) + I_Error("\nThis is not the registered version."); + } + + // Iff additonal PWAD files are used, print modified banner + if (modifiedgame) + printf ("ATTENTION: This version of DOOM has been modified.\n"); + + // Check and print which version is executed. + switch ( gamemode ) + { + case shareware: + case indetermined: + printf ("Shareware!\n"); + break; + case registered: + case retail: + case commercial: + printf ("Commercial product - do not distribute!\n"); + break; + default: + // Ouch. + break; + } + + printf ("M_Init: Init miscellaneous info.\n"); + M_Init (); + + printf ("R_Init: Init DOOM refresh daemon - "); + R_Init (); + + printf ("P_Init: Init Playloop state.\n"); + P_Init (); + + printf ("I_Init: Setting up machine state.\n"); + I_Init (); + + printf ("S_Init: Setting up sound.\n"); + S_Init (snd_SfxVolume /* *8 */, snd_MusicVolume /* *8*/ ); + + printf ("HU_Init: Setting up heads up display.\n"); + HU_Init (); + + I_InitGraphics (); + + printf ("ST_Init: Init status bar.\n"); + ST_Init (); + + // check for a driver that wants intermission stats + p = M_CheckParm ("-statcopy"); + if (p && p gametic for all players +// + +static ticcmd_t* localcmds; + +ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS]; + +int maketic; +int ticdup=1; + +void G_BuildTiccmd (ticcmd_t *cmd); +void D_DoAdvanceDemo (void); + +void D_InitNetGame (void) +{ + int i; + + doomcom = Z_Malloc(sizeof *doomcom, PU_STATIC, NULL); + doomcom->consoleplayer = 0; + doomcom->numnodes = 0; doomcom->numplayers = 1; + localcmds = netcmds[consoleplayer]; + + for (i=0; inumplayers; i++) + playeringame[i] = true; + for (; iconsoleplayer; +} + +void D_BuildNewTiccmds() +{ + static int lastmadetic; + int newtics = I_GetTime() - lastmadetic; + lastmadetic += newtics; + while (newtics--) + { + I_StartTic(); + if (maketic - gametic > BACKUPTICS/2) break; + G_BuildTiccmd(&localcmds[maketic%BACKUPTICS]); + maketic++; + } +} + +// +// TryRunTics +// +extern boolean advancedemo; + +void TryRunTics (void) +{ + int runtics; + int entertime = I_GetTime(); + + // Wait for tics to run + while (1) { + D_BuildNewTiccmds(); + runtics = (server ? remotetic : maketic) - gametic; + if (!runtics) { +// if (server) I_WaitForPacket(ms_to_next_tick); +// else I_uSleep(ms_to_next_tick*1000); +// rb->sleep(ms_to_next_tick); + if (I_GetTime() - entertime > 10) { + remotesend--; +// { +// char buf[sizeof(packet_header_t)+1]; +// packet_set((packet_header_t *)buf, PKT_RETRANS, remotetic); +// buf[sizeof(buf)-1] = consoleplayer; +// I_SendPacket((packet_header_t *)buf, sizeof buf); +// } + M_Ticker(); return; + } + } else break; + } + + while (runtics--) { + if (advancedemo) + D_DoAdvanceDemo (); + M_Ticker (); + G_Ticker (); + gametic++; + } +} diff --git a/apps/plugins/doom/d_net.h b/apps/plugins/doom/d_net.h new file mode 100644 index 0000000000..6b586e3c96 --- /dev/null +++ b/apps/plugins/doom/d_net.h @@ -0,0 +1,213 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Networking stuff. + * + *-----------------------------------------------------------------------------*/ + + +#ifndef __D_NET__ +#define __D_NET__ + +#include "d_player.h" + + +#ifdef __GNUG__ +#pragma interface +#endif + + +// +// Network play related stuff. +// There is a data struct that stores network +// communication related stuff, and another +// one that defines the actual packets to +// be transmitted. +// + +#define DOOMCOM_ID 0x12345678l + +// Max computers/players in a game. +#define MAXNETNODES 8 + + +// Networking and tick handling related. +#define BACKUPTICS 12 + +typedef enum +{ + CMD_SEND = 1, + CMD_GET = 2 + +} command_t; + + +// +// Network packet data. +// +typedef struct +{ + // High bit is retransmit request. + unsigned checksum; + // Only valid if NCMD_RETRANSMIT. + byte retransmitfrom; + + byte starttic; + byte player; + byte numtics; + ticcmd_t cmds[BACKUPTICS]; + +} doomdata_t; + +// +// Startup packet difference +// SG: 4/12/98 +// Added so we can send more startup data to synch things like +// bobbing, recoil, etc. +// this is just mapped over the ticcmd_t array when setup packet is sent +// +// Note: the original code takes care of startskill, deathmatch, nomonsters +// respawn, startepisode, startmap +// Note: for phase 1 we need to add monsters_remember, variable_friction, +// weapon_recoil, allow_pushers, over_under, player_bobbing, +// fastparm, demo_insurance, and the rngseed +//Stick all options into bytes so we don't need to mess with bitfields +//WARNING: make sure this doesn't exceed the size of the ticcmds area! +//sizeof(ticcmd_t)*BACKUPTICS +//This is the current length of our extra stuff +// +//killough 5/2/98: this should all be replaced by calls to G_WriteOptions() +//and G_ReadOptions(), which were specifically designed to set up packets. +//By creating a separate struct and functions to read/write the options, +//you now have two functions and data to maintain instead of just one. +//If the array in g_game.c which G_WriteOptions()/G_ReadOptions() operates +//on, is too large (more than sizeof(ticcmd_t)*BACKUPTICS), it can +//either be shortened, or the net code needs to divide it up +//automatically into packets. The STARTUPLEN below is non-portable. +//There's a portable way to do it without having to know the sizes. + +#define STARTUPLEN 12 +typedef struct +{ + byte monsters_remember; + byte variable_friction; + byte weapon_recoil; + byte allow_pushers; + byte over_under; + byte player_bobbing; + byte fastparm; + byte demo_insurance; + unsigned long rngseed; + char filler[sizeof(ticcmd_t)*BACKUPTICS-STARTUPLEN]; +} startup_t; + +typedef enum { + // Leave space, so low values corresponding to normal netgame setup packets can be ignored + nm_plcolour = 3, + nm_savegamename = 4, +} netmisctype_t; + +typedef struct +{ + netmisctype_t type; + size_t len; + byte value[sizeof(ticcmd_t)*BACKUPTICS - sizeof(netmisctype_t) - sizeof(size_t)]; +} netmisc_t; + +typedef struct +{ + // Supposed to be DOOMCOM_ID? + long id; + + // DOOM executes an int to execute commands. + short intnum; + // Communication between DOOM and the driver. + // Is CMD_SEND or CMD_GET. + short command; + // Is dest for send, set by get (-1 = no packet). + short remotenode; + + // Number of bytes in doomdata to be sent + short datalength; + + // Info common to all nodes. + // Console is allways node 0. + short numnodes; + // Flag: 1 = no duplication, 2-5 = dup for slow nets. + short ticdup; + // Flag: 1 = send a backup tic in every packet. + short extratics; + // Flag: 1 = deathmatch. + short deathmatch; + // Flag: -1 = new game, 0-5 = load savegame + short savegame; + short episode; // 1-3 + short map; // 1-9 + short skill; // 1-5 + + // Info specific to this node. + short consoleplayer; + short numplayers; + + // These are related to the 3-display mode, + // in which two drones looking left and right + // were used to render two additional views + // on two additional computers. + // Probably not operational anymore. + // 1 = left, 0 = center, -1 = right + short angleoffset; + // 1 = drone + short drone; + + // The packet data to be sent. + doomdata_t data; + +} doomcom_t; + +// Create any new ticcmds and broadcast to other players. +void NetUpdate (void); +// Create any new ticcmds +void D_BuildNewTiccmds (void); + +// Broadcasts special packets to other players +// to notify of game exit +void D_QuitNetGame (void); + +//? how many ticks to run? +void TryRunTics (void); + +// CPhipps - move to header file +void D_InitNetGame (void); // This does the setup +void D_CheckNetGame(void); // This waits for game start + +// CPhipps - misc info broadcast +void D_NetSendMisc(netmisctype_t type, size_t len, void* data); + +// CPhipps - ask server for a wad file we need +boolean D_NetGetWad(const char* name); + +#endif diff --git a/apps/plugins/doom/d_player.h b/apps/plugins/doom/d_player.h new file mode 100644 index 0000000000..f86b68f9be --- /dev/null +++ b/apps/plugins/doom/d_player.h @@ -0,0 +1,232 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Player state structure. + * + *-----------------------------------------------------------------------------*/ + + +#ifndef __D_PLAYER__ +#define __D_PLAYER__ + + +// The player data structure depends on a number +// of other structs: items (internal inventory), +// animation states (closely tied to the sprites +// used to represent them, unfortunately). +#include "d_items.h" +#include "p_pspr.h" + +// In addition, the player is just a special +// case of the generic moving object/actor. +#include "p_mobj.h" + +// Finally, for odd reasons, the player input +// is buffered within the player data struct, +// as commands per game tick. +#include "d_ticcmd.h" + +#ifdef __GNUG__ +#pragma interface +#endif + + +// +// Player states. +// +typedef enum +{ + // Playing or camping. + PST_LIVE, + // Dead on the ground, view follows killer. + PST_DEAD, + // Ready to restart/respawn??? + PST_REBORN + +} playerstate_t; + + +// +// Player internal flags, for cheats and debug. +// +typedef enum +{ + // No clipping, walk through barriers. + CF_NOCLIP = 1, + // No damage, no health loss. + CF_GODMODE = 2, + // Not really a cheat, just a debug aid. + CF_NOMOMENTUM = 4 + +} cheat_t; + + +// +// Extended player object info: player_t +// +typedef struct player_s +{ + mobj_t* mo; + playerstate_t playerstate; + ticcmd_t cmd; + + // Determine POV, + // including viewpoint bobbing during movement. + // Focal origin above r.z + fixed_t viewz; + // Base height above floor for viewz. + fixed_t viewheight; + // Bob/squat speed. + fixed_t deltaviewheight; + // bounded/scaled total momentum. + fixed_t bob; + + /* killough 10/98: used for realistic bobbing (i.e. not simply overall speed) + * mo->momx and mo->momy represent true momenta experienced by player. + * This only represents the thrust that the player applies himself. + * This avoids anomolies with such things as Boom ice and conveyors. + */ + fixed_t momx, momy; // killough 10/98 + + // This is only used between levels, + // mo->health is used during levels. + int health; + int armorpoints; + // Armor type is 0-2. + int armortype; + + // Power ups. invinc and invis are tic counters. + int powers[NUMPOWERS]; + boolean cards[NUMCARDS]; + boolean backpack; + + // Frags, kills of other players. + int frags[MAXPLAYERS]; + weapontype_t readyweapon; + + // Is wp_nochange if not changing. + weapontype_t pendingweapon; + + boolean weaponowned[NUMWEAPONS]; + int ammo[NUMAMMO]; + int maxammo[NUMAMMO]; + + // True if button down last tic. + int attackdown; + int usedown; + + // Bit flags, for cheats and debug. + // See cheat_t, above. + int cheats; + + // Refired shots are less accurate. + int refire; + + // For intermission stats. + int killcount; + int itemcount; + int secretcount; + + // Hint messages. // CPhipps - const + const char* message; + + // For screen flashing (red or bright). + int damagecount; + int bonuscount; + + // Who did damage (NULL for floors/ceilings). + mobj_t* attacker; + + // So gun flashes light up areas. + int extralight; + + // Current PLAYPAL, ??? + // can be set to REDCOLORMAP for pain, etc. + int fixedcolormap; + + // Player skin colorshift, + // 0-3 for which color to draw player. + int colormap; + + // Overlay view sprites (gun, etc). + pspdef_t psprites[NUMPSPRITES]; + + // True if secret level has been done. + boolean didsecret; + +} player_t; + + +// +// INTERMISSION +// Structure passed e.g. to WI_Start(wb) +// +typedef struct +{ + boolean in; // whether the player is in game + + // Player stats, kills, collected items etc. + int skills; + int sitems; + int ssecret; + int stime; + int frags[4]; + int score; // current score on entry, modified on return + +} wbplayerstruct_t; + +typedef struct +{ + int epsd; // episode # (0-2) + + // if true, splash the secret level + boolean didsecret; + + // previous and next levels, origin 0 + int last; + int next; + + int maxkills; + int maxitems; + int maxsecret; + int maxfrags; + + // the par time + int partime; + + // index of this player in game + int pnum; + + wbplayerstruct_t plyr[MAXPLAYERS]; + + // CPhipps - total game time for completed levels so far + int totaltimes; + +} wbstartstruct_t; + + +#endif diff --git a/apps/plugins/doom/d_think.h b/apps/plugins/doom/d_think.h new file mode 100644 index 0000000000..55e9996e1b --- /dev/null +++ b/apps/plugins/doom/d_think.h @@ -0,0 +1,92 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * MapObj data. Map Objects or mobjs are actors, entities, + * thinker, take-your-pick... anything that moves, acts, or + * suffers state changes of more or less violent nature. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __D_THINK__ +#define __D_THINK__ + +#ifdef __GNUG__ +#pragma interface +#endif + +/* + * Experimental stuff. + * To compile this as "ANSI C with classes" + * we will need to handle the various + * action functions cleanly. + */ +// killough 11/98: convert back to C instead of C++ +typedef void (*actionf_t)(); +//typedef void (*actionf_v)(); +//typedef void (*actionf_p1)( void* ); +//typedef void (*actionf_p2)( void*, void* ); + +/* Note: In d_deh.c you will find references to these + * wherever code pointers and function handlers exist + */ +/* +typedef union +{ + actionf_p1 acp1; + actionf_v acv; + actionf_p2 acp2; + +} actionf_t; +*/ + +/* Historically, "think_t" is yet another + * function pointer to a routine to handle + * an actor. + */ +typedef actionf_t think_t; + + +/* Doubly linked list of actors. */ +typedef struct thinker_s +{ + struct thinker_s* prev; + struct thinker_s* next; + think_t function; + + /* killough 8/29/98: we maintain thinkers in several equivalence classes, + * according to various criteria, so as to allow quicker searches. + */ + + struct thinker_s *cnext, *cprev; /* Next, previous thinkers in same class */ + + /* killough 11/98: count of how many other objects reference + * this one using pointers. Used for garbage collection. + */ + unsigned references; +} thinker_t; + +#endif diff --git a/apps/plugins/doom/d_ticcmd.h b/apps/plugins/doom/d_ticcmd.h new file mode 100644 index 0000000000..1193a32df1 --- /dev/null +++ b/apps/plugins/doom/d_ticcmd.h @@ -0,0 +1,57 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * System specific interface stuff. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __D_TICCMD__ +#define __D_TICCMD__ + +#include "doomtype.h" + +#ifdef __GNUG__ +#pragma interface +#endif + +/* The data sampled per tick (single player) + * and transmitted to other peers (multiplayer). + * Mainly movements/button commands per game tick, + * plus a checksum for internal state consistency. + * CPhipps - explicitely signed the elements, since they have to be signed to work right + */ +typedef struct +{ + signed char forwardmove; /* *2048 for move */ + signed char sidemove; /* *2048 for move */ + signed short angleturn; /* <<16 for angle delta */ + short consistancy; /* checks for net game */ + byte chatchar; + byte buttons; +} ticcmd_t; + +#endif diff --git a/apps/plugins/doom/doomdata.h b/apps/plugins/doom/doomdata.h new file mode 100644 index 0000000000..f56524e6cd --- /dev/null +++ b/apps/plugins/doom/doomdata.h @@ -0,0 +1,187 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// $Id$ +// +// Copyright (C) 1993-1996 by id Software, Inc. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// all external data is defined here +// most of the data is loaded into different structures at run time +// some internal structures shared by many modules are here +// +//----------------------------------------------------------------------------- + +#ifndef __DOOMDATA__ +#define __DOOMDATA__ + +// The most basic types we use, portability. +#include "doomtype.h" + +// Some global defines, that configure the game. +#include "doomdef.h" + +#include "rockmacros.h" + +// +// Map level types. +// The following data structures define the persistent format +// used in the lumps of the WAD files. +// + +// Lump order in a map WAD: each map needs a couple of lumps +// to provide a complete scene geometry description. +enum { + ML_LABEL, // A separator, name, ExMx or MAPxx + ML_THINGS, // Monsters, items.. + ML_LINEDEFS, // LineDefs, from editing + ML_SIDEDEFS, // SideDefs, from editing + ML_VERTEXES, // Vertices, edited and BSP splits generated + ML_SEGS, // LineSegs, from LineDefs split by BSP + ML_SSECTORS, // SubSectors, list of LineSegs + ML_NODES, // BSP nodes + ML_SECTORS, // Sectors, from editing + ML_REJECT, // LUT, sector-sector visibility + ML_BLOCKMAP // LUT, motion clipping, walls/grid element +}; + +// A single Vertex. +typedef struct { + short x,y; +} PACKEDATTR mapvertex_t; + +// A SideDef, defining the visual appearance of a wall, +// by setting textures and offsets. +typedef struct { + short textureoffset; + short rowoffset; + char toptexture[8]; + char bottomtexture[8]; + char midtexture[8]; + short sector; // Front sector, towards viewer. +} PACKEDATTR mapsidedef_t; + +// A LineDef, as used for editing, and as input to the BSP builder. + +typedef struct { + short v1; + short v2; + short flags; + short special; + short tag; + short sidenum[2]; // sidenum[1] will be -1 if one sided +} PACKEDATTR maplinedef_t; + + +// +// LineDef attributes. +// + +// Solid, is an obstacle. +#define ML_BLOCKING 1 + +// Blocks monsters only. +#define ML_BLOCKMONSTERS 2 + +// Backside will not be present at all +// if not two sided. +#define ML_TWOSIDED 4 + +// If a texture is pegged, the texture will have +// the end exposed to air held constant at the +// top or bottom of the texture (stairs or pulled +// down things) and will move with a height change +// of one of the neighbor sectors. +// Unpegged textures allways have the first row of +// the texture at the top pixel of the line for both +// top and bottom textures (use next to windows). + +// upper texture unpegged +#define ML_DONTPEGTOP 8 + +// lower texture unpegged +#define ML_DONTPEGBOTTOM 16 + +// In AutoMap: don't map as two sided: IT'S A SECRET! +#define ML_SECRET 32 + +// Sound rendering: don't let sound cross two of these. +#define ML_SOUNDBLOCK 64 + +// Don't draw on the automap at all. +#define ML_DONTDRAW 128 + +// Set if already seen, thus drawn in automap. +#define ML_MAPPED 256 + +//jff 3/21/98 Set if line absorbs use by player +//allow multiple push/switch triggers to be used on one push +#define ML_PASSUSE 512 + +// Sector definition, from editing. +typedef struct { + short floorheight; + short ceilingheight; + char floorpic[8]; + char ceilingpic[8]; + short lightlevel; + short special; + short tag; +} PACKEDATTR mapsector_t; + +// SubSector, as generated by BSP. +typedef struct { + unsigned short numsegs; + unsigned short firstseg; // Index of first one; segs are stored sequentially. +} PACKEDATTR mapsubsector_t; + +// LineSeg, generated by splitting LineDefs +// using partition lines selected by BSP builder. +typedef struct { + short v1; + short v2; + short angle; + short linedef; + short side; + short offset; +} PACKEDATTR mapseg_t; + +// BSP node structure. + +// Indicate a leaf. +#define NF_SUBSECTOR 0x8000 + +typedef struct { + short x; // Partition line from (x,y) to x+dx,y+dy) + short y; + short dx; + short dy; + // Bounding box for each child, clip against view frustum. + short bbox[2][4]; + // If NF_SUBSECTOR its a subsector, else it's a node of another subtree. + unsigned short children[2]; +} PACKEDATTR mapnode_t; + +// Thing definition, position, orientation and type, +// plus skill/visibility flags and attributes. +typedef struct { + short x; + short y; + short angle; + short type; + short options; +} PACKEDATTR mapthing_t; + + + +#endif // __DOOMDATA__ diff --git a/apps/plugins/doom/doomdef.c b/apps/plugins/doom/doomdef.c new file mode 100644 index 0000000000..d4ad61e979 --- /dev/null +++ b/apps/plugins/doom/doomdef.c @@ -0,0 +1,39 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// $Id$ +// +// Copyright (C) 1993-1996 by id Software, Inc. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// $Log$ +// Revision 1.1 2006/03/28 15:44:01 dave +// Patch #2969 - Doom! Currently only working on the H300. +// +// +// DESCRIPTION: +// DoomDef - basic defines for DOOM, e.g. Version, game mode +// and skill level, and display parameters. +// +//----------------------------------------------------------------------------- + + +#ifdef __GNUG__ +#pragma implementation "doomdef.h" +#endif +#include "doomdef.h" + +// Location for any defines turned variables. + +// None. + + diff --git a/apps/plugins/doom/doomdef.h b/apps/plugins/doom/doomdef.h new file mode 100644 index 0000000000..f76b09263a --- /dev/null +++ b/apps/plugins/doom/doomdef.h @@ -0,0 +1,306 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Internally used data structures for virtually everything, + * key definitions, lots of other stuff. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __DOOMDEF__ +#define __DOOMDEF__ + +// killough 4/25/98: Make gcc extensions mean nothing on other compilers +#ifndef __GNUC__ +#define __attribute__(x) +#endif + +// +// Global parameters/defines. +// +// DOOM version +enum { DVERSION = 110 }; + +// Game mode handling - identify IWAD version +// to handle IWAD dependend animations etc. +typedef enum { + shareware, // DOOM 1 shareware, E1, M9 + registered, // DOOM 1 registered, E3, M27 + commercial, // DOOM 2 retail, E1 M34 (DOOM 2 german edition not handled) + retail, // DOOM 1 retail, E4, M36 + indetermined // Well, no IWAD found. +} GameMode_t; + +// Mission packs - might be useful for TC stuff? +typedef enum { + doom, // DOOM 1 + doom2, // DOOM 2 + pack_tnt, // TNT mission pack + pack_plut, // Plutonia pack + none +} GameMission_t; + +// Identify language to use, software localization. +typedef enum { + english, + french, + german, + unknown +} Language_t; + +// +// For resize of screen, at start of game. +// + +#define BASE_WIDTH 320 + +// It is educational but futile to change this +// scaling e.g. to 2. Drawing of status bar, +// menues etc. is tied to the scale implied +// by the graphics. + +#define INV_ASPECT_RATIO 0.625 // 0.75, ideally + +// killough 2/8/98: MAX versions for maximum screen sizes +// allows us to avoid the overhead of dynamic allocation +// when multiple screen sizes are supported + +// proff 08/17/98: Changed for high-res +#define MAX_SCREENWIDTH 1600 +#define MAX_SCREENHEIGHT 1200 + +#define SCREENWIDTH 320 +#define SCREENHEIGHT 200 + +// The maximum number of players, multiplayer/networking. +#define MAXPLAYERS 4 + +// phares 5/14/98: +// DOOM Editor Numbers (aka doomednum in mobj_t) + +#define DEN_PLAYER5 4001 +#define DEN_PLAYER6 4002 +#define DEN_PLAYER7 4003 +#define DEN_PLAYER8 4004 + +// State updates, number of tics / second. +#define TICRATE 35 + +// The current state of the game: whether we are playing, gazing +// at the intermission screen, the game final animation, or a demo. + +typedef enum { + GS_LEVEL, + GS_INTERMISSION, + GS_FINALE, + GS_DEMOSCREEN +} gamestate_t; + +// +// Difficulty/skill settings/filters. +// + +// Skill flags. +#define MTF_EASY 1 +#define MTF_NORMAL 2 +#define MTF_HARD 4 +// Deaf monsters/do not react to sound. +#define MTF_AMBUSH 8 + +/* killough 11/98 */ +#define MTF_NOTSINGLE 16 +#define MTF_NOTDM 32 +#define MTF_NOTCOOP 64 +#define MTF_FRIEND 128 +#define MTF_RESERVED 256 + +typedef enum { + sk_none=-1, //jff 3/24/98 create unpicked skill setting + sk_baby=0, + sk_easy, + sk_medium, + sk_hard, + sk_nightmare +} skill_t; + +// +// Key cards. +// + +typedef enum { + it_bluecard, + it_yellowcard, + it_redcard, + it_blueskull, + it_yellowskull, + it_redskull, + NUMCARDS +} card_t; + +// The defined weapons, including a marker +// indicating user has not changed weapon. +typedef enum { + wp_fist, + wp_pistol, + wp_shotgun, + wp_chaingun, + wp_missile, + wp_plasma, + wp_bfg, + wp_chainsaw, + wp_supershotgun, + + NUMWEAPONS, + wp_nochange // No pending weapon change. +} weapontype_t; + +// Ammunition types defined. +typedef enum { + am_clip, // Pistol / chaingun ammo. + am_shell, // Shotgun / double barreled shotgun. + am_cell, // Plasma rifle, BFG. + am_misl, // Missile launcher. + NUMAMMO, + am_noammo // Unlimited for chainsaw / fist. +} ammotype_t; + +// Power up artifacts. +typedef enum { + pw_invulnerability, + pw_strength, + pw_invisibility, + pw_ironfeet, + pw_allmap, + pw_infrared, + NUMPOWERS +} powertype_t; + +// Power up durations (how many seconds till expiration). +typedef enum { + INVULNTICS = (30*TICRATE), + INVISTICS = (60*TICRATE), + INFRATICS = (120*TICRATE), + IRONTICS = (60*TICRATE) +} powerduration_t; + +// +// DOOM keyboard definition. +// This is the stuff configured by Setup.Exe. +// Most key data are simple ascii (uppercased). +// +#define KEY_RIGHTARROW 0xae +#define KEY_LEFTARROW 0xac +#define KEY_UPARROW 0xad +#define KEY_DOWNARROW 0xaf +#define KEY_ESCAPE 0x1B +#define KEY_ENTER 0x0D +#define KEY_TAB 0x09 +#define KEY_F1 (0x80+0x3b) +#define KEY_F2 (0x80+0x3c) +#define KEY_F3 (0x80+0x3d) +#define KEY_F4 (0x80+0x3e) +#define KEY_F5 (0x80+0x3f) +#define KEY_F6 (0x80+0x40) +#define KEY_F7 (0x80+0x41) +#define KEY_F8 (0x80+0x42) +#define KEY_F9 (0x80+0x43) +#define KEY_F10 (0x80+0x44) +#define KEY_F11 (0x80+0x57) +#define KEY_F12 (0x80+0x58) +#define KEY_BACKSPACE 0x7F +#define KEY_PAUSE 0xff +#define KEY_EQUALS 0x3d +#define KEY_MINUS 0x2d +#define KEY_RSHIFT (0x80+0x36) +#define KEY_RCTRL (0x80+0x1d) +#define KEY_RALT (0x80+0x38) +#define KEY_LALT KEY_RALT +#define KEY_CAPSLOCK 0xba // phares + +// phares 3/2/98: +#define KEY_INSERT 0xd2 +#define KEY_HOME 0xc7 +#define KEY_PAGEUP 0xc9 +#define KEY_PAGEDOWN 0xd1 +#define KEY_DEL 0xc8 +#define KEY_END 0xcf +#define KEY_SCROLLLOCK 0xc6 +#define KEY_SPACEBAR 0x20 +// phares 3/2/98 + +#define KEY_NUMLOCK 0xC5 // killough 3/6/98 + +// cph - Add the numeric keypad keys, as suggested by krose 4/22/99: +// The way numbers are assigned to keys is a mess, but it's too late to +// change that easily. At least these additions are don neatly. +// Codes 0x100-0x200 are reserved for number pad + +#define KEY_KEYPAD0 (0x100 + '0') +#define KEY_KEYPAD1 (0x100 + '1') +#define KEY_KEYPAD2 (0x100 + '2') +#define KEY_KEYPAD3 (0x100 + '3') +#define KEY_KEYPAD4 (0x100 + '4') +#define KEY_KEYPAD5 (0x100 + '5') +#define KEY_KEYPAD6 (0x100 + '6') +#define KEY_KEYPAD7 (0x100 + '7') +#define KEY_KEYPAD8 (0x100 + '8') +#define KEY_KEYPAD9 (0x100 + '9') +#define KEY_KEYPADENTER (0x100 + KEY_ENTER) +#define KEY_KEYPADDIVIDE (0x100 + '/') +#define KEY_KEYPADMULTIPLY (0x100 + '*') +#define KEY_KEYPADMINUS (0x100 + '-') +#define KEY_KEYPADPLUS (0x100 + '+') +#define KEY_KEYPADPERIOD (0x100 + '.') + +// phares 4/19/98: +// Defines Setup Screen groups that config variables appear in. +// Used when resetting the defaults for every item in a Setup group. + +typedef enum { + ss_none, + ss_keys, + ss_weap, + ss_stat, + ss_auto, + ss_enem, + ss_mess, + ss_chat, + ss_gen, /* killough 10/98 */ + ss_comp, /* killough 10/98 */ + ss_max +} ss_types; + +// phares 3/20/98: +// +// Player friction is variable, based on controlling +// linedefs. More friction can create mud, sludge, +// magnetized floors, etc. Less friction can create ice. + +#define MORE_FRICTION_MOMENTUM 15000 // mud factor based on momentum +#define ORIG_FRICTION 0xE800 // original value +#define ORIG_FRICTION_FACTOR 2048 // original value + +#endif // __DOOMDEF__ diff --git a/apps/plugins/doom/doomstat.c b/apps/plugins/doom/doomstat.c new file mode 100644 index 0000000000..75cc209919 --- /dev/null +++ b/apps/plugins/doom/doomstat.c @@ -0,0 +1,104 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// $Id$ +// +// Copyright (C) 1993-1996 by id Software, Inc. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// $Log$ +// Revision 1.1 2006/03/28 15:44:01 dave +// Patch #2969 - Doom! Currently only working on the H300. +// +// +// DESCRIPTION: +// Put all global tate variables here. +// +//----------------------------------------------------------------------------- + +#ifdef __GNUG__ +#pragma implementation "doomstat.h" +#endif +#include "doomstat.h" + + +// Game Mode - identify IWAD as shareware, retail etc. +GameMode_t gamemode IDATA_ATTR= indetermined; +GameMission_t gamemission IDATA_ATTR = doom; + +// Language. +Language_t language = english; + +// Set if homebrew PWAD stuff has been added. +boolean modifiedgame; + +//----------------------------------------------------------------------------- + +// CPhipps - compatibility vars +complevel_t compatibility_level=prboom_3_compatibility, default_compatibility_level=prboom_3_compatibility; + +int comp[COMP_TOTAL] IBSS_ATTR, default_comp[COMP_TOTAL]; // killough 10/98 + +// v1.1-like pitched sounds +int pitched_sounds=0; // killough + +int default_translucency; // config file says // phares +boolean general_translucency IBSS_ATTR; // true if translucency is ok // phares + +int demo_insurance, default_demo_insurance; // killough 1/16/98 + +int allow_pushers IDATA_ATTR = 1; // MT_PUSH Things // phares 3/10/98 +int default_allow_pushers; // killough 3/1/98: make local to each game + +int variable_friction IDATA_ATTR = 1; // ice & mud // phares 3/10/98 +int default_variable_friction; // killough 3/1/98: make local to each game + +int weapon_recoil IBSS_ATTR; // weapon recoil // phares +int default_weapon_recoil; // killough 3/1/98: make local to each game + +int player_bobbing IBSS_ATTR; // whether player bobs or not // phares 2/25/98 +int default_player_bobbing; // killough 3/1/98: make local to each game + +int monsters_remember IBSS_ATTR; // killough 3/1/98 +int default_monsters_remember; + +int monster_infighting IDATA_ATTR=1; // killough 7/19/98: monster<=>monster attacks +int default_monster_infighting=1; + +int monster_friction IDATA_ATTR=1; // killough 10/98: monsters affected by friction +int default_monster_friction=1; + +#ifdef DOGS +int dogs, default_dogs; // killough 7/19/98: Marine's best friend :) +int dog_jumping, default_dog_jumping; // killough 10/98 +#endif + +// killough 8/8/98: distance friends tend to move towards players +int distfriend = 128, default_distfriend = 128; + +// killough 9/8/98: whether monsters are allowed to strafe or retreat +int monster_backing IBSS_ATTR, default_monster_backing; + +// killough 9/9/98: whether monsters are able to avoid hazards (e.g. crushers) +int monster_avoid_hazards IBSS_ATTR, default_monster_avoid_hazards; + +// killough 9/9/98: whether monsters help friends +int help_friends IBSS_ATTR, default_help_friends; + +int flashing_hom; // killough 10/98 + +int doom_weapon_toggles; // killough 10/98 + +int monkeys IBSS_ATTR, default_monkeys; + +boolean nosfxparm=0; +boolean rockblock=1; diff --git a/apps/plugins/doom/doomstat.h b/apps/plugins/doom/doomstat.h new file mode 100644 index 0000000000..42cd4f5716 --- /dev/null +++ b/apps/plugins/doom/doomstat.h @@ -0,0 +1,373 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// $Id$ +// +// Copyright (C) 1993-1996 by id Software, Inc. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// All the global variables that store the internal state. +// Theoretically speaking, the internal state of the engine +// should be found by looking at the variables collected +// here, and every relevant module will have to include +// this header file. +// In practice, things are a bit messy. +// +//----------------------------------------------------------------------------- + + +#ifndef __D_STATE__ +#define __D_STATE__ + +// We need globally shared data structures, +// for defining the global state variables. +#include "doomdata.h" +#include "d_net.h" + +// We need the playr data structure as well. +#include "d_player.h" + + +#ifdef __GNUG__ +#pragma interface +#endif + + +// ------------------------ +// Command line parameters. +// +extern boolean nomonsters; // checkparm of -nomonsters +extern boolean respawnparm; // checkparm of -respawn +extern boolean fastparm; // checkparm of -fast + +extern boolean devparm; // DEBUG: launched with -devparm + +enum automapmode_e { + am_active = 1, // currently shown + am_overlay= 2, // covers the screen, i.e. not overlay mode + am_rotate = 4, // rotates to the player facing direction + am_follow = 8, // keep the player centred + am_grid =16, // show grid +}; +extern enum automapmode_e automapmode; // Mode that the automap is in + +// ----------------------------------------------------- +// Game Mode - identify IWAD as shareware, retail etc. +// +extern GameMode_t gamemode; +extern GameMission_t gamemission; + +// Set if homebrew PWAD stuff has been added. +extern boolean modifiedgame; + +// CPhipps - new compatibility handling +extern complevel_t compatibility_level, default_compatibility_level; + +// CPhipps - old compatibility testing flags aliased to new handling +#define compatibility (compatibility_level<=boom_compatibility_compatibility) +#define demo_compatibility (compatibility_level <= doom_demo_compatibility) +#define mbf_features (compatibility_level>=mbf_compatibility) + +extern int default_translucency; +extern boolean general_translucency; // true if translucency is ok // phares + +extern int demo_insurance, default_demo_insurance; // killough 4/5/98 + +// ------------------------------------------- +// killough 10/98: compatibility vector + +enum { + comp_telefrag, + comp_dropoff, + comp_vile, + comp_pain, + comp_skull, + comp_blazing, + comp_doorlight, + comp_model, + comp_god, + comp_falloff, + comp_floors, + comp_skymap, + comp_pursuit, + comp_doorstuck, + comp_staylift, + comp_zombie, + comp_stairs, + comp_infcheat, + comp_zerotags, + comp_moveblock, + comp_respawn, /* cph - this is the inverse of comp_respawnfix from eternity */ + comp_sound, + COMP_NUM, /* cph - should be last in sequence */ + COMP_TOTAL=32 // Some extra room for additional variables +}; + +extern int comp[COMP_TOTAL], default_comp[COMP_TOTAL]; + +extern boolean nosfxparm; +extern boolean rockblock; + +// ------------------------------------------- +// Language. +extern Language_t language; + + +// ------------------------------------------- +// Selected skill type, map etc. +// + +// Defaults for menu, methinks. +extern skill_t startskill; +extern int startepisode; +extern int startmap; + +extern boolean autostart; + +// Selected by user. +extern skill_t gameskill; +extern int gameepisode; +extern int gamemap; + +// Nightmare mode flag, single player. +extern boolean respawnmonsters; + +// Netgame? Only true if >1 player. +extern boolean netgame; + +// Flag: true only if started as net deathmatch. +// An enum might handle altdeath/cooperative better. +extern boolean deathmatch; + +// ------------------------- +// Internal parameters for sound rendering. +// These have been taken from the DOS version, +// but are not (yet) supported with Linux +// (e.g. no sound volume adjustment with menu. + +// These are not used, but should be (menu). +// From m_menu.c: +// Sound FX volume has default, 0 - 15 +// Music volume has default, 0 - 15 +// These are multiplied by 8. +extern int snd_SfxVolume; // maximum volume for sound +extern int snd_MusicVolume; // maximum volume for music + +// Current music/sfx card - index useless +// w/o a reference LUT in a sound module. +// Ideally, this would use indices found +// in: /usr/include/linux/soundcard.h +extern int snd_MusicDevice; +extern int snd_SfxDevice; +// Config file? Same disclaimer as above. +extern int snd_DesiredMusicDevice; +extern int snd_DesiredSfxDevice; + + +// ------------------------- +// Status flags for refresh. +// + +// Depending on view size - no status bar? +// Note that there is no way to disable the +// status bar explicitely. +extern boolean statusbaractive; + +extern boolean automapactive; // In AutoMap mode? +extern boolean menuactive; // Menu overlayed? +extern boolean paused; // Game Pause? + + +extern boolean viewactive; + +extern boolean nodrawers; +extern boolean noblit; + +extern int viewwindowx; +extern int viewwindowy; +extern int viewheight; +extern int viewwidth; +extern int scaledviewwidth; + +// This one is related to the 3-screen display mode. +// ANG90 = left side, ANG270 = right +extern int viewangleoffset; + +// Player taking events, and displaying. +extern int consoleplayer; +extern int displayplayer; + + +// ------------------------------------- +// Scores, rating. +// Statistics on a given map, for intermission. +// +extern int totalkills, totallive; +extern int totalitems; +extern int totalsecret; + +// Timer, for scores. +extern int levelstarttic; // gametic at level start +extern int basetic; /* killough 9/29/98: levelstarttic, adjusted */ +extern int leveltime; // tics in game play for par + + + +// -------------------------------------- +// DEMO playback/recording related stuff. +// No demo, there is a human player in charge? +// Disable save/end game? +extern boolean usergame; + +//? +extern boolean demoplayback; +extern boolean demorecording; + +// Quit after playing a demo from cmdline. +extern boolean singledemo; + + + + +//? +extern gamestate_t gamestate; + +//----------------------------- +// Internal parameters, fixed. +// These are set by the engine, and not changed +// according to user inputs. Partly load from +// WAD, partly set at startup time. + +extern int gametic; + +// Bookkeeping on players - state. +extern player_t players[MAXPLAYERS]; + +// Alive? Disconnected? +extern boolean playeringame[MAXPLAYERS]; + + +// Player spawn spots for deathmatch. +#define MAX_DM_STARTS 10 +//extern mapthing_t deathmatchstarts[MAX_DM_STARTS]; +extern mapthing_t *deathmatchstarts; // killough +extern size_t num_deathmatchstarts; // killough +extern mapthing_t* deathmatch_p; + +// Player spawn spots. +extern mapthing_t playerstarts[MAXPLAYERS]; + +// Intermission stats. +// Parameters for world map / intermission. +extern wbstartstruct_t wminfo; + + +// LUT of ammunition limits for each kind. +// This doubles with BackPack powerup item. +extern int maxammo[NUMAMMO]; + +//----------------------------------------- +// Internal parameters, used for engine. +// + +// File handling stuff. +extern char basedefault[]; +extern int debugfile; + +// if true, load all graphics at level load +extern boolean precache; + + +// wipegamestate can be set to -1 +// to force a wipe on the next draw +extern gamestate_t wipegamestate; + +extern int mouseSensitivity; +//? +// debug flag to cancel adaptiveness +extern boolean singletics; + +extern int bodyqueslot; + + + +// Needed to store the number of the dummy sky flat. +// Used for rendering, +// as well as tracking projectiles etc. +extern int skyflatnum; + +// Netgame stuff (buffers and pointers, i.e. indices). +extern doomcom_t* doomcom; +extern doomdata_t* netbuffer; // This points inside doomcom. + +extern int rndindex; + +extern int maketic; + +extern ticcmd_t netcmds[][BACKUPTICS]; + +extern int ticdup; + +extern int nettics[MAXNETNODES]; + +//----------------------------------------------------------------------------- + +// v1.1-like pitched sounds +extern int pitched_sounds; // killough 2/21/98 + +extern int allow_pushers; // MT_PUSH Things // phares 3/10/98 +extern int default_allow_pushers; + +extern int variable_friction; // ice & mud // phares 3/10/98 +extern int default_variable_friction; + +extern int monsters_remember; // killough 3/1/98 +extern int default_monsters_remember; + +extern int weapon_recoil; // weapon recoil // phares +extern int default_weapon_recoil; + +extern int player_bobbing; // whether player bobs or not // phares 2/25/98 +extern int default_player_bobbing; // killough 3/1/98: make local to each game + +#ifdef DOGS +extern int dogs, default_dogs; // killough 7/19/98: Marine's best friend :) +extern int dog_jumping, default_dog_jumping; // killough 10/98 +#endif + +/* killough 8/8/98: distance friendly monsters tend to stay from player */ +extern int distfriend, default_distfriend; + +/* killough 9/8/98: whether monsters are allowed to strafe or retreat */ +extern int monster_backing, default_monster_backing; + +/* killough 9/9/98: whether monsters intelligently avoid hazards */ +extern int monster_avoid_hazards, default_monster_avoid_hazards; + +/* killough 10/98: whether monsters are affected by friction */ +extern int monster_friction, default_monster_friction; + +/* killough 9/9/98: whether monsters help friends */ +extern int help_friends, default_help_friends; + +extern int flashing_hom; // killough 10/98 + +extern int doom_weapon_toggles; // killough 10/98 + +/* killough 7/19/98: whether monsters should fight against each other */ +extern int monster_infighting, default_monster_infighting; + +extern int monkeys, default_monkeys; + + +#endif diff --git a/apps/plugins/doom/doomtype.h b/apps/plugins/doom/doomtype.h new file mode 100644 index 0000000000..59b33758da --- /dev/null +++ b/apps/plugins/doom/doomtype.h @@ -0,0 +1,85 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Simple basic typedefs, isolated here to make it easier + * separating modules. + * + *-----------------------------------------------------------------------------*/ +#ifndef __DOOMTYPE__ +#define __DOOMTYPE__ +#include "rockmacros.h" + +#ifndef __BYTEBOOL__ +#define __BYTEBOOL__ +// Fixed to use builtin bool type with C++. +#ifdef __cplusplus +typedef bool boolean; +#else +//typedef enum {false, true} boolean; +//#define boolean bool +typedef enum _boolean { FALSE, TRUE } boolean; +#endif +typedef unsigned char byte; +#endif + +typedef signed long long int_64_t; +typedef unsigned long long uint_64_t; + +#define MAXCHAR ((char)0x7f) +#define MAXSHORT ((short)0x7fff) + +// Max pos 32-bit int. +#define MAXINT ((int)0x7fffffff) +#define MAXLONG ((long)0x7fffffff) +#define MINCHAR ((char)0x80) +#define MINSHORT ((short)0x8000) + +// Max negative 32-bit integer. +#define MININT ((int)0x80000000) +#define MINLONG ((long)0x80000000) + +/* cph - move compatibility levels here so we can use them in d_server.c */ +typedef enum { + doom_12_compatibility, /* Behave like early doom versions */ + doom_demo_compatibility, /* As compatible as possible for + * playing original Doom demos */ + doom_compatibility, /* Compatible with original Doom levels */ + boom_compatibility_compatibility, /* Boom's compatibility mode */ + boom_201_compatibility, /* Compatible with Boom v2.01 */ + boom_202_compatibility, /* Compatible with Boom v2.01 */ + lxdoom_1_compatibility, /* LxDoom v1.3.2+ */ + mbf_compatibility, /* MBF */ + prboom_1_compatibility, /* PrBoom 2.03beta? */ + prboom_2_compatibility, /* PrBoom 2.1.0-2.1.1 */ + prboom_3_compatibility, /* Latest PrBoom */ + MAX_COMPATIBILITY_LEVEL, /* Must be last entry */ + /* Aliases follow */ + boom_compatibility = boom_201_compatibility, /* Alias used by G_Compatibility */ + best_compatibility = prboom_3_compatibility, +} complevel_t; + +#endif diff --git a/apps/plugins/doom/dstrings.c b/apps/plugins/doom/dstrings.c new file mode 100644 index 0000000000..104e99c479 --- /dev/null +++ b/apps/plugins/doom/dstrings.c @@ -0,0 +1,83 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Globally defined strings. + * + *----------------------------------------------------------------------------- + */ + +#ifdef __GNUG__ +#pragma implementation "dstrings.h" +#endif +#include "dstrings.h" + + +// killough 1/18/98: remove hardcoded limit, add const: +const char *const endmsg[]= + { + // DOOM1 + QUITMSG, + "please don't leave, there's more\ndemons to toast!", + "let's beat it -- this is turning\ninto a bloodbath!", + "i wouldn't leave if i were you.\ndos is much worse.", + "you're trying to say you like dos\nbetter than me, right?", + "don't leave yet -- there's a\ndemon around that corner!", + "ya know, next time you come in here\ni'm gonna toast ya.", + "go ahead and leave. see if i care.", // 1/15/98 killough + + // QuitDOOM II messages + "you want to quit?\nthen, thou hast lost an eighth!", + "don't go now, there's a \ndimensional shambler waiting\nat the dos prompt!", + "get outta here and go back\nto your boring programs.", + "if i were your boss, i'd \n deathmatch ya in a minute!", + "look, bud. you leave now\nand you forfeit your body count!", + "just leave. when you come\nback, i'll be waiting with a bat.", + "you're lucky i don't smack\nyou for thinking about leaving.", // 1/15/98 killough + + // FinalDOOM? + + // Note that these ending "bad taste" strings were commented out + // in the original id code as the #else case of an #if 1 + // Obviously they were internal playthings before the release of + // DOOM2 and were not intended for public use. + // + // Following messages commented out for now. Bad taste. // phares + + // "fuck you, pussy!\nget the fuck out!", + // "you quit and i'll jizz\nin your cystholes!", + // "if you leave, i'll make\nthe lord drink my jizz.", + // "hey, ron! can we say\n'fuck' in the game?", + // "i'd leave: this is just\nmore monsters and levels.\nwhat a load.", + // "suck it down, asshole!\nyou're a fucking wimp!", + // "don't quit now! we're \nstill spending your money!", + + // Internal debug. Different style, too. + "THIS IS NO MESSAGE!\nPage intentionally left blank.", // 1/15/98 killough + }; + +// killough 1/18/98: remove hardcoded limit and replace with var (silly hack): +const size_t NUM_QUITMESSAGES = sizeof(endmsg)/sizeof(*endmsg) - 1; diff --git a/apps/plugins/doom/dstrings.h b/apps/plugins/doom/dstrings.h new file mode 100644 index 0000000000..4402c21f1f --- /dev/null +++ b/apps/plugins/doom/dstrings.h @@ -0,0 +1,73 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * DOOM strings, by language. + * Note: In BOOM, some new strings hav ebeen defined that are + * not found in the French version. A better approach is + * to create a BEX text-replacement file for other + * languages since any language can be supported that way + * without recompiling the program. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __DSTRINGS__ +#define __DSTRINGS__ + +#include "d_englsh.h" +#include "rockmacros.h" + +/* Note this is not externally modifiable through DEH/BEX + * Misc. other strings. + * #define SAVEGAMENAME "boomsav" * killough 3/22/98 * + * Ty 05/04/98 - replaced with a modifiable string, see d_deh.c + */ + +// Misc. other strings. +#define SAVEGAMENAME GAMEBASE"doomsav" + +/* + * File locations, + * relative to current position. + * Path names are OS-sensitive. + */ +#define DEVMAPS "devmaps" +#define DEVDATA "devdata" + + +/* Not done in french? + * QuitDOOM messages * + * killough 1/18/98: + * replace hardcoded limit with extern var (silly hack, I know) + */ + +#include + +extern const size_t NUM_QUITMESSAGES; /* Calculated in dstrings.c */ + +extern const char* const endmsg[]; /* killough 1/18/98 const added */ + +#endif diff --git a/apps/plugins/doom/f_finale.c b/apps/plugins/doom/f_finale.c new file mode 100644 index 0000000000..4deb3df689 --- /dev/null +++ b/apps/plugins/doom/f_finale.c @@ -0,0 +1,682 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Game completion, final screen animation. + * + *----------------------------------------------------------------------------- + */ + +#include "doomstat.h" +#include "d_event.h" +#include "d_englsh.h" +#include "m_swap.h" +#include "v_video.h" +#include "w_wad.h" +#include "s_sound.h" +#include "sounds.h" +//#include "d_deh.h" // Ty 03/22/98 - externalizations +#include "f_finale.h" // CPhipps - hmm... +#include "rockmacros.h" + +// Stage of animation: +// 0 = text, 1 = art screen, 2 = character cast +static int finalestage; // cph - +static int finalecount; // made static +static const char* finaletext; // cph - +static const char* finaleflat; // made static const + +// defines for the end mission display text // phares + +#define TEXTSPEED 3 // original value // phares +#define TEXTWAIT 250 // original value // phares +#define NEWTEXTSPEED 0.01f // new value // phares +#define NEWTEXTWAIT 1000 // new value // phares + +// CPhipps - removed the old finale screen text message strings; +// they were commented out for ages already +// Ty 03/22/98 - ... the new s_WHATEVER extern variables are used +// in the code below instead. + +void F_StartCast (void); +void F_CastTicker (void); +boolean F_CastResponder (event_t *ev); +void F_CastDrawer (void); + +void WI_checkForAccelerate(void); // killough 3/28/98: used to +extern int acceleratestage; // accelerate intermission screens +static int midstage; // whether we're in "mid-stage" + +// +// F_StartFinale +// +void F_StartFinale (void) +{ + gameaction = ga_nothing; + gamestate = GS_FINALE; + automapmode &= ~am_active; + + // killough 3/28/98: clear accelerative text flags + acceleratestage = midstage = 0; + + // Okay - IWAD dependend stuff. + // This has been changed severly, and + // some stuff might have changed in the process. + switch ( gamemode ) + { + + // DOOM 1 - E1, E3 or E4, but each nine missions + case shareware: + case registered: + case retail: + { + S_ChangeMusic(mus_victor, true); + + switch (gameepisode) + { + case 1: + finaleflat = "FLOOR4_8"; + finaletext = E1TEXT; + break; + case 2: + finaleflat = "SFLR6_1"; + finaletext = E2TEXT; + break; + case 3: + finaleflat = "MFLR8_4"; + finaletext = E3TEXT; + break; + case 4: + finaleflat = "MFLR8_3"; + finaletext = E4TEXT; + break; + default: + // Ouch. + break; + } + break; + } + + // DOOM II and missions packs with E1, M34 + case commercial: + { + S_ChangeMusic(mus_read_m, true); + + // Ty 08/27/98 - added the gamemission logic + switch (gamemap) + { + case 6: + finaleflat = "SLIME16"; + finaletext = (gamemission==pack_tnt) ? T1TEXT : + (gamemission==pack_plut) ? P1TEXT : C1TEXT; + break; + case 11: + finaleflat = "RROCK14"; + finaletext = (gamemission==pack_tnt) ? T2TEXT : + (gamemission==pack_plut) ? P2TEXT : C2TEXT; + break; + case 20: + finaleflat = "RROCK07"; + finaletext = (gamemission==pack_tnt) ? T3TEXT : + (gamemission==pack_plut) ? P3TEXT : C3TEXT; + break; + case 30: + finaleflat = "RROCK17"; + finaletext = (gamemission==pack_tnt) ? T4TEXT : + (gamemission==pack_plut) ? P4TEXT : C4TEXT; + break; + case 15: + finaleflat = "RROCK13"; + finaletext = (gamemission==pack_tnt) ? T5TEXT : + (gamemission==pack_plut) ? P5TEXT : C5TEXT; + break; + case 31: + finaleflat = "RROCK19"; + finaletext = (gamemission==pack_tnt) ? T6TEXT : + (gamemission==pack_plut) ? P6TEXT : C6TEXT; + break; + default: + // Ouch. + break; + } + break; + } + + + // Indeterminate. + default: + S_ChangeMusic(mus_read_m, true); + finaleflat = "F_SKY1"; // Not used anywhere else. + finaletext = C1TEXT; // FIXME - other text, music? + break; + } + + finalestage = 0; + finalecount = 0; + +} + + + +boolean F_Responder (event_t *event) +{ + if (finalestage == 2) + return F_CastResponder (event); + + return false; +} + +// Get_TextSpeed() returns the value of the text display speed // phares +// Rewritten to allow user-directed acceleration -- killough 3/28/98 + +static float Get_TextSpeed(void) +{ + return midstage ? NEWTEXTSPEED : (midstage=acceleratestage) ? + acceleratestage=0, NEWTEXTSPEED : TEXTSPEED; +} + +// +// F_Ticker +// +// killough 3/28/98: almost totally rewritten, to use +// player-directed acceleration instead of constant delays. +// Now the player can accelerate the text display by using +// the fire/use keys while it is being printed. The delay +// automatically responds to the user, and gives enough +// time to read. +// +// killough 5/10/98: add back v1.9 demo compatibility +// + +void F_Ticker(void) +{ + int i; + if (!demo_compatibility) + WI_checkForAccelerate(); // killough 3/28/98: check for acceleration + else + if (gamemode == commercial && finalecount > 50) // check for skipping + for (i=0; i strlen(finaletext)*speed + + (midstage ? NEWTEXTWAIT : TEXTWAIT) || + (midstage && acceleratestage)) { + if (gamemode != commercial) // Doom 1 / Ultimate Doom episode end + { // with enough time, it's automatic + finalecount = 0; + finalestage = 1; + wipegamestate = -1; // force a wipe + if (gameepisode == 3) + S_StartMusic(mus_bunny); + } + else // you must press a button to continue in Doom 2 + if (!demo_compatibility && midstage) + { +next_level: + if (gamemap == 30) + F_StartCast(); // cast of Doom 2 characters + else + gameaction = ga_worlddone; // next level, e.g. MAP07 + } + } + } +} + + +// +// F_TextWrite +// +// This program displays the background and text at end-mission // phares +// text time. It draws both repeatedly so that other displays, // | +// like the main menu, can be drawn over it dynamically and // V +// erased dynamically. The TEXTSPEED constant is changed into +// the Get_TextSpeed function so that the speed of writing the // ^ +// text can be increased, and there's still time to read what's // | +// written. // phares +// CPhipps - reformatted + +#include "hu_stuff.h" +extern patchnum_t hu_font[HU_FONTSIZE]; + + +void F_TextWrite (void) +{ + V_DrawBackground(finaleflat, 0); + { // draw some of the text onto the screen + int cx = 10; + int cy = 10; + const char* ch = finaletext; // CPhipps - const + int count = (int)((float)(finalecount - 10)/Get_TextSpeed()); // phares + int w; + + if (count < 0) + count = 0; + + for ( ; count ; count-- ) { + int c = *ch++; + + if (!c) + break; + if (c == '\n') { + cx = 10; + cy += 11; + continue; + } + + c = toupper(c) - HU_FONTSTART; + if (c < 0 || c> HU_FONTSIZE) { + cx += 4; + continue; + } + + w = SHORT (hu_font[c].width); + if (cx+w > SCREENWIDTH) + break; + // CPhipps - patch drawing updated + V_DrawNumPatch(cx, cy, 0, hu_font[c].lumpnum, CR_DEFAULT, VPT_STRETCH); + cx+=w; + } + } +} + +// +// Final DOOM 2 animation +// Casting by id Software. +// in order of appearance +// +typedef struct +{ + const char *name; // CPhipps - const** + mobjtype_t type; +} castinfo_t; + +#define MAX_CASTORDER 18 /* Ty - hard coded for now */ +static const castinfo_t castorder[] = { // CPhipps - static const, initialised here + { CC_ZOMBIE, MT_POSSESSED }, + { CC_SHOTGUN, MT_SHOTGUY }, + { CC_HEAVY, MT_CHAINGUY }, + { CC_IMP, MT_TROOP }, + { CC_DEMON, MT_SERGEANT }, + { CC_LOST, MT_SKULL }, + { CC_CACO, MT_HEAD }, + { CC_HELL, MT_KNIGHT }, + { CC_BARON, MT_BRUISER }, + { CC_ARACH, MT_BABY }, + { CC_PAIN, MT_PAIN }, + { CC_REVEN, MT_UNDEAD }, + { CC_MANCU, MT_FATSO }, + { CC_ARCH, MT_VILE }, + { CC_SPIDER, MT_SPIDER }, + { CC_CYBER, MT_CYBORG }, + { CC_HERO, MT_PLAYER }, + { NULL, 0} + }; + +int castnum; +int casttics; +state_t* caststate; +boolean castdeath; +int castframes; +int castonmelee; +boolean castattacking; + + +// +// F_StartCast +// +extern gamestate_t wipegamestate; + +void F_StartCast (void) +{ + wipegamestate = -1; // force a screen wipe + castnum = 0; + caststate = &states[mobjinfo[castorder[castnum].type].seestate]; + casttics = caststate->tics; + castdeath = false; + finalestage = 2; + castframes = 0; + castonmelee = 0; + castattacking = false; + S_ChangeMusic(mus_evil, true); +} + + +// +// F_CastTicker +// +void F_CastTicker (void) +{ + int st; + int sfx; + + if (--casttics > 0) + return; // not time to change state yet + + if (caststate->tics == -1 || caststate->nextstate == S_NULL) + { + // switch from deathstate to next monster + castnum++; + castdeath = false; + if (castorder[castnum].name == NULL) + castnum = 0; + if (mobjinfo[castorder[castnum].type].seesound) + S_StartSound (NULL, mobjinfo[castorder[castnum].type].seesound); + caststate = &states[mobjinfo[castorder[castnum].type].seestate]; + castframes = 0; + } + else + { + // just advance to next state in animation + if (caststate == &states[S_PLAY_ATK1]) + goto stopattack; // Oh, gross hack! + st = caststate->nextstate; + caststate = &states[st]; + castframes++; + + // sound hacks.... + switch (st) + { + case S_PLAY_ATK1: sfx = sfx_dshtgn; break; + case S_POSS_ATK2: sfx = sfx_pistol; break; + case S_SPOS_ATK2: sfx = sfx_shotgn; break; + case S_VILE_ATK2: sfx = sfx_vilatk; break; + case S_SKEL_FIST2: sfx = sfx_skeswg; break; + case S_SKEL_FIST4: sfx = sfx_skepch; break; + case S_SKEL_MISS2: sfx = sfx_skeatk; break; + case S_FATT_ATK8: + case S_FATT_ATK5: + case S_FATT_ATK2: sfx = sfx_firsht; break; + case S_CPOS_ATK2: + case S_CPOS_ATK3: + case S_CPOS_ATK4: sfx = sfx_shotgn; break; + case S_TROO_ATK3: sfx = sfx_claw; break; + case S_SARG_ATK2: sfx = sfx_sgtatk; break; + case S_BOSS_ATK2: + case S_BOS2_ATK2: + case S_HEAD_ATK2: sfx = sfx_firsht; break; + case S_SKULL_ATK2: sfx = sfx_sklatk; break; + case S_SPID_ATK2: + case S_SPID_ATK3: sfx = sfx_shotgn; break; + case S_BSPI_ATK2: sfx = sfx_plasma; break; + case S_CYBER_ATK2: + case S_CYBER_ATK4: + case S_CYBER_ATK6: sfx = sfx_rlaunc; break; + case S_PAIN_ATK3: sfx = sfx_sklatk; break; + default: sfx = 0; break; + } + + if (sfx) + S_StartSound (NULL, sfx); + } + + if (castframes == 12) + { + // go into attack frame + castattacking = true; + if (castonmelee) + caststate=&states[mobjinfo[castorder[castnum].type].meleestate]; + else + caststate=&states[mobjinfo[castorder[castnum].type].missilestate]; + castonmelee ^= 1; + if (caststate == &states[S_NULL]) + { + if (castonmelee) + caststate= + &states[mobjinfo[castorder[castnum].type].meleestate]; + else + caststate= + &states[mobjinfo[castorder[castnum].type].missilestate]; + } + } + + if (castattacking) + { + if (castframes == 24 + || caststate == &states[mobjinfo[castorder[castnum].type].seestate] ) + { +stopattack: + castattacking = false; + castframes = 0; + caststate = &states[mobjinfo[castorder[castnum].type].seestate]; + } + } + + casttics = caststate->tics; + if (casttics == -1) + casttics = 15; +} + + +// +// F_CastResponder +// + +boolean F_CastResponder (event_t* ev) +{ + if (ev->type != ev_keydown) + return false; + + if (castdeath) + return true; // already in dying frames + + // go into death frame + castdeath = true; + caststate = &states[mobjinfo[castorder[castnum].type].deathstate]; + casttics = caststate->tics; + castframes = 0; + castattacking = false; + if (mobjinfo[castorder[castnum].type].deathsound) + S_StartSound (NULL, mobjinfo[castorder[castnum].type].deathsound); + + return true; +} + + +static void F_CastPrint (const char* text) // CPhipps - static, const char* +{ + const char* ch; // CPhipps - const + int c; + int cx; + int w; + int width; + + // find width + ch = text; + width = 0; + + while (ch) + { + c = *ch++; + if (!c) + break; + c = toupper(c) - HU_FONTSTART; + if (c < 0 || c> HU_FONTSIZE) + { + width += 4; + continue; + } + + w = SHORT (hu_font[c].width); + width += w; + } + + // draw it + cx = 160-width/2; + ch = text; + while (ch) + { + c = *ch++; + if (!c) + break; + c = toupper(c) - HU_FONTSTART; + if (c < 0 || c> HU_FONTSIZE) + { + cx += 4; + continue; + } + + w = SHORT (hu_font[c].width); + // CPhipps - patch drawing updated + V_DrawNumPatch(cx, 180, 0, hu_font[c].lumpnum, CR_DEFAULT, VPT_STRETCH); + cx+=w; + } +} + + +// +// F_CastDrawer +// +void V_DrawPatchFlipped (int x, int y, int scrn, patch_t *patch); + +void F_CastDrawer (void) +{ + spritedef_t* sprdef; + spriteframe_t* sprframe; + int lump; + boolean flip; + + // erase the entire screen to a background + V_DrawNamePatch(0,0,0, "BOSSBACK", CR_DEFAULT, VPT_STRETCH); // Ty 03/30/98 bg texture extern + + F_CastPrint (castorder[castnum].name); + + // draw the current frame in the middle of the screen + sprdef = &sprites[caststate->sprite]; + sprframe = &sprdef->spriteframes[ caststate->frame & FF_FRAMEMASK]; + lump = sprframe->lump[0]; + flip = (boolean)sprframe->flip[0]; + + // CPhipps - patch drawing updated + V_DrawNumPatch(160, 170, 0, lump+firstspritelump, CR_DEFAULT, + VPT_STRETCH | (flip ? VPT_FLIP : 0)); +} + + +// +// F_BunnyScroll +// +static const char pfub2[] = { "PFUB2" }; +static const char pfub1[] = { "PFUB1" }; + +static void F_BunnyScroll (void) +{ + char name[10]; + int stage; + static int laststage; + + V_MarkRect (0, 0, SCREENWIDTH, SCREENHEIGHT); + { + int scrolled = 320 - (finalecount-230)/2; + if (scrolled <= 0) { + V_DrawNamePatch(0, 0, 0, pfub2, CR_DEFAULT, VPT_STRETCH); + } else if (scrolled >= 320) { + V_DrawNamePatch(0, 0, 0, pfub1, CR_DEFAULT, VPT_STRETCH); + } else { +#define SCRN 2 + + int realscrolled = (SCREENWIDTH * scrolled) / 320; + + V_AllocScreen(SCRN); + V_DrawNamePatch(0, 0, SCRN, pfub2, CR_DEFAULT, VPT_STRETCH); + V_CopyRect(realscrolled, 0, SCRN, SCREENWIDTH-realscrolled, SCREENHEIGHT, 0, 0, 0, VPT_NONE); + V_DrawNamePatch(0, 0, SCRN, pfub1, CR_DEFAULT, VPT_STRETCH); + V_CopyRect(0, 0, SCRN, realscrolled, SCREENHEIGHT, SCREENWIDTH-realscrolled, 0, 0, VPT_NONE); + V_FreeScreen(SCRN); + } + } + + if (finalecount < 1130) + return; + if (finalecount < 1180) + { + // CPhipps - patch drawing updated + V_DrawNamePatch((320-13*8)/2, (200-8*8)/2,0, "END0", CR_DEFAULT, VPT_STRETCH); + laststage = 0; + return; + } + + stage = (finalecount-1180) / 5; + if (stage > 6) + stage = 6; + if (stage > laststage) + { + S_StartSound (NULL, sfx_pistol); + laststage = stage; + } + + snprintf (name,sizeof(name), "END%i",stage); + // CPhipps - patch drawing updated + V_DrawNamePatch((320-13*8)/2, (200-8*8)/2, 0, name, CR_DEFAULT, VPT_STRETCH); +} + + +// +// F_Drawer +// +void F_Drawer (void) +{ + if (finalestage == 2) + { + F_CastDrawer (); + return; + } + + if (!finalestage) + F_TextWrite (); + else + { + switch (gameepisode) + { + // CPhipps - patch drawing updated + case 1: + if ( gamemode == retail ) + V_DrawNamePatch(0, 0, 0, "CREDIT", CR_DEFAULT, VPT_STRETCH); + else + V_DrawNamePatch(0, 0, 0, "HELP2", CR_DEFAULT, VPT_STRETCH); + break; + case 2: + V_DrawNamePatch(0, 0, 0, "VICTORY2", CR_DEFAULT, VPT_STRETCH); + break; + case 3: + F_BunnyScroll (); + break; + case 4: + V_DrawNamePatch(0, 0, 0, "ENDPIC", CR_DEFAULT, VPT_STRETCH); + break; + } + } +} diff --git a/apps/plugins/doom/f_finale.h b/apps/plugins/doom/f_finale.h new file mode 100644 index 0000000000..63e2fbd3e4 --- /dev/null +++ b/apps/plugins/doom/f_finale.h @@ -0,0 +1,54 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Related to f_finale.c, which is called at the end of a level + * + *-----------------------------------------------------------------------------*/ + + +#ifndef __F_FINALE__ +#define __F_FINALE__ + +#include "doomtype.h" +#include "d_event.h" + +/* + * FINALE + */ + +/* Called by main loop. */ +boolean F_Responder (event_t* ev); + +/* Called by main loop. */ +void F_Ticker (void); + +/* Called by main loop. */ +void F_Drawer (void); + +void F_StartFinale (void); + +#endif diff --git a/apps/plugins/doom/f_wipe.c b/apps/plugins/doom/f_wipe.c new file mode 100644 index 0000000000..a6251f295e --- /dev/null +++ b/apps/plugins/doom/f_wipe.c @@ -0,0 +1,193 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Mission begin melt/wipe screen special effect. + * + *----------------------------------------------------------------------------- + */ + +#include "rockmacros.h" +#include "z_zone.h" +#include "doomdef.h" +#include "i_video.h" +#include "v_video.h" +#include "m_random.h" +#include "f_wipe.h" + + + +// +// SCREEN WIPE PACKAGE +// + +// CPhipps - macros for the source and destination screens +#define SRC_SCR 2 +#define DEST_SCR 3 + +static byte *wipe_scr_start; +static byte *wipe_scr_end; +static byte *wipe_scr; + +static void wipe_shittyColMajorXform(short *array, int width, int height) +{ + short *dest = Z_Malloc(width*height*sizeof(short), PU_STATIC, 0); + int x, y; + + for(y=0;y not ready to scroll yet) + y = (int *) malloc(width*sizeof(int)); + y[0] = -(M_Random()%16); + for (i=1;i 0) + y[i] = 0; + else + if (y[i] == -16) + y[i] = -15; + } + return 0; +} + +static int wipe_doMelt(int width, int height, int ticks) +{ + boolean done = true; + int i; + + width /= 2; + + while (ticks--) + for (i=0;i= height) + dy = height - y[i]; + s = &((short *)wipe_scr_end)[i*height+y[i]]; + d = &((short *)wipe_scr)[y[i]*width+i]; + idx = 0; + for (j=dy;j;j--) + { + d[idx] = *(s++); + idx += width; + } + y[i] += dy; + s = &((short *)wipe_scr_start)[i*height]; + d = &((short *)wipe_scr)[y[i]*width+i]; + idx = 0; + for (j=height-y[i];j;j--) + { + d[idx] = *(s++); + idx += width; + } + done = false; + } + return done; +} + +// CPhipps - modified to allocate and deallocate screens[2 to 3] as needed, saving memory + +static int wipe_exitMelt(int width, int height, int ticks) +{ + (void)width; + (void)height; + (void)ticks; + free(y); + free(wipe_scr_start); + free(wipe_scr_end); + // Paranoia + y = NULL; + wipe_scr_start = wipe_scr_end = screens[SRC_SCR] = screens[DEST_SCR] = NULL; + return 0; +} + +int wipe_StartScreen(int x, int y, int width, int height) +{ + wipe_scr_start = screens[SRC_SCR] = malloc(SCREENWIDTH * SCREENHEIGHT); + V_CopyRect(x, y, 0, width, height, x, y, SRC_SCR, VPT_NONE ); // Copy start screen to buffer + return 0; +} + +int wipe_EndScreen(int x, int y, int width, int height) +{ + wipe_scr_end = screens[DEST_SCR] = malloc(SCREENWIDTH * SCREENHEIGHT); + V_CopyRect(x, y, 0, width, height, x, y, DEST_SCR, VPT_NONE); // Copy end screen to buffer + V_CopyRect(x, y, SRC_SCR, width, height, x, y, 0 , VPT_NONE); // restore start screen + return 0; +} + +// killough 3/5/98: reformatted and cleaned up +int wipe_ScreenWipe(int x, int y, int width, int height, int ticks) +{ + (void)x; + (void)y; + static boolean go; // when zero, stop the wipe + if (!go) // initial stuff + { + go = 1; + wipe_scr = screens[0]; + wipe_initMelt(width, height, ticks); + } + V_MarkRect(0, 0, width, height); // do a piece of wipe-in + if (wipe_doMelt(width, height, ticks)) // final stuff + { + wipe_exitMelt(width, height, ticks); + go = 0; + } + return !go; +} diff --git a/apps/plugins/doom/f_wipe.h b/apps/plugins/doom/f_wipe.h new file mode 100644 index 0000000000..ec19a812ef --- /dev/null +++ b/apps/plugins/doom/f_wipe.h @@ -0,0 +1,43 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Mission start screen wipe/melt, special effects. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __F_WIPE_H__ +#define __F_WIPE_H__ + +/* + * SCREEN WIPE PACKAGE + */ + +int wipe_ScreenWipe (int x, int y, int width, int height, int ticks); +int wipe_StartScreen(int x, int y, int width, int height); +int wipe_EndScreen (int x, int y, int width, int height); + +#endif diff --git a/apps/plugins/doom/g_game.c b/apps/plugins/doom/g_game.c new file mode 100644 index 0000000000..426ab1ca13 --- /dev/null +++ b/apps/plugins/doom/g_game.c @@ -0,0 +1,2818 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: none + * The original Doom description was none, basically because this file + * has everything. This ties up the game logic, linking the menu and + * input code to the underlying game by creating & respawning players, + * building game tics, calling the underlying thing logic. + * + *----------------------------------------------------------------------------- + */ + +#include "doomdef.h" +#include "doomstat.h" +#include "z_zone.h" +#include "f_finale.h" +#include "m_argv.h" +#include "m_misc.h" +#include "m_menu.h" +#include "m_random.h" +#include "i_system.h" +#include "p_map.h" +#include "p_setup.h" +#include "p_saveg.h" +#include "p_tick.h" + +#include "d_main.h" + +#include "wi_stuff.h" +#include "hu_stuff.h" +#include "st_stuff.h" +#include "am_map.h" + +// Needs access to LFB. +#include "v_video.h" + +#include "w_wad.h" +#include "r_main.h" +#include "s_sound.h" + +// Data. +#include "dstrings.h" +#include "sounds.h" + +// SKY handling - still the wrong place. +#include "r_data.h" +#include "r_sky.h" +#include "p_inter.h" +#include "g_game.h" + +#include "rockmacros.h" + +#define SAVEGAMESIZE 0x20000 +#define SAVESTRINGSIZE 24 + +static size_t savegamesize = SAVEGAMESIZE; // killough +static boolean netdemo; +static const byte *demobuffer; /* cph - only used for playback */ +static int demofd; /* cph - record straight to file */ +static const byte *demo_p; +static short consistancy[MAXPLAYERS][BACKUPTICS]; + +gameaction_t gameaction; +gamestate_t gamestate; +skill_t gameskill; +boolean respawnmonsters; +int gameepisode; +int gamemap; +boolean paused; +// CPhipps - moved *_loadgame vars here +static boolean forced_loadgame = false; +static boolean command_loadgame = false; + +boolean usergame; // ok to save / end game +boolean timingdemo; // if true, exit with report on completion +boolean fastdemo; // if true, run at full speed -- killough +boolean nodrawers; // for comparative timing purposes +boolean noblit; // for comparative timing purposes +int starttime; // for comparative timing purposes +boolean deathmatch; // only if started as net death +boolean netgame; // only true if packets are broadcast +boolean playeringame[MAXPLAYERS]; +player_t players[MAXPLAYERS]; +int consoleplayer; // player taking events and displaying +int displayplayer; // view being displayed +int gametic; +int levelstarttic; // gametic at level start +int basetic; /* killough 9/29/98: for demo sync */ +int totalkills, totallive, totalitems, totalsecret; // for intermission +boolean demorecording; +boolean demoplayback; +boolean singledemo; // quit after playing a demo from cmdline +wbstartstruct_t wminfo; // parms for world map / intermission +boolean haswolflevels = false;// jff 4/18/98 wolf levels present +static byte *savebuffer; // CPhipps - static +int autorun = false; // always running? // phares +int totalleveltimes; // CPhipps - total time for all completed levels +int longtics; + +// +// controls (have defaults) +// +int key_right; +int key_left; +int key_up; +int key_down; +int key_menu_right; // phares 3/7/98 +int key_menu_left; // | +int key_menu_up; // V +int key_menu_down; +int key_menu_backspace; // ^ +int key_menu_escape; // | +int key_menu_enter; // phares 3/7/98 +int key_strafeleft; +int key_straferight; +int key_fire; +int key_use; +int key_strafe; +int key_speed; +int key_escape = KEY_ESCAPE; // phares 4/13/98 +int key_weapon; + +int key_savegame; // phares +int key_loadgame; // | +int key_autorun; // V +int key_reverse; +int key_zoomin; +int key_zoomout; + +int key_reverse; + +int key_chat; +int key_backspace; +int key_enter; +int key_map_right; +int key_map_left; +int key_map_up; +int key_map_down; +int key_map_zoomin; +int key_map_zoomout; +int key_map; +int key_map_gobig; +int key_map_follow; +int key_map_mark; +int key_map_clear; +int key_map_grid; +int key_map_overlay; // cph - map overlay +int key_map_rotate; // cph - map rotation +int key_help = KEY_F1; // phares 4/13/98 +int key_soundvolume; +int key_hud; +int key_quicksave; +int key_endgame; +int key_messages; +int key_quickload; +int key_quit; +int key_gamma; +int key_spy; +int key_pause; +int key_setup; +int destination_keys[MAXPLAYERS]; +int key_weapontoggle; +int key_weapon1; +int key_weapon2; +int key_weapon3; +int key_weapon4; +int key_weapon5; +int key_weapon6; +int key_weapon7; // ^ +int key_weapon8; // | +int key_weapon9; // phares + +int key_screenshot; // killough 2/22/98: screenshot key +int mousebfire; +int mousebstrafe; +int mousebforward; +int joybfire; +int joybstrafe; +int joybuse; +int joybspeed; + +#define MAXPLMOVE (forwardmove[1]) +#define TURBOTHRESHOLD 0x32 +#define SLOWTURNTICS 6 +#define QUICKREVERSE (short)32768 // 180 degree reverse // phares +#define NUMKEYS 512 + +fixed_t forwardmove[2] = {0x19, 0x32}; +fixed_t sidemove[2] = {0x18, 0x28}; +fixed_t angleturn[3] = {640, 1280, 320}; // + slow turn + +// CPhipps - made lots of key/button state vars static +static boolean gamekeydown[NUMKEYS]; +static int turnheld; // for accelerative turning + +static boolean mousearray[4]; +static boolean *mousebuttons = &mousearray[1]; // allow [-1] + +// mouse values are used once +static int mousex; +static int mousey; +static unsigned int dclicktime; +static unsigned int dclickstate; +static unsigned int dclicks; +static unsigned int dclicktime2; +static unsigned int dclickstate2; +static unsigned int dclicks2; + +// joystick values are repeated +static int joyxmove; +static int joyymove; +static boolean joyarray[5]; +static boolean *joybuttons = &joyarray[1]; // allow [-1] + +// Game events info +static buttoncode_t special_event; // Event triggered by local player, to send +static byte savegameslot; // Slot to load if gameaction == ga_loadgame +char savedescription[SAVEDESCLEN]; // Description to save in savegame if gameaction == ga_savegame + +//jff 3/24/98 declare startskill external, define defaultskill here +extern skill_t startskill; //note 0-based +int defaultskill; //note 1-based + +// killough 2/8/98: make corpse queue variable in size +int bodyqueslot, bodyquesize; // killough 2/8/98 +mobj_t **bodyque = 0; // phares 8/10/98 + +void* statcopy; // for statistics driver + +static void G_DoSaveGame (boolean menu); +static const byte* G_ReadDemoHeader(const byte* demo_p); + +// +// G_BuildTiccmd +// Builds a ticcmd from all of the available inputs +// or reads it from the demo buffer. +// If recording a demo, write it out +// +static inline signed char fudgef(signed char b) +{ + static int c; + if (!b || !demo_compatibility || longtics) return b; + if (++c & 0x1f) return b; + b |= 1; if (b>2) b-=2; + return b; +} + +static inline signed short fudgea(signed short b) +{ + if (!b || !demo_compatibility || !longtics) return b; + b |= 1; if (b>2) b-=2; + return b; +} + +void G_BuildTiccmd(ticcmd_t* cmd) +{ + boolean strafe; + boolean bstrafe; + int speed; + int tspeed; + int forward; + int side; + int newweapon=0; // phares + /* cphipps - remove needless I_BaseTiccmd call, just set the ticcmd to zero */ + memset(cmd,0,sizeof*cmd); + cmd->consistancy = consistancy[consoleplayer][maketic%BACKUPTICS]; + + strafe = gamekeydown[key_strafe] || mousebuttons[mousebstrafe] + || joybuttons[joybstrafe]; + speed = autorun || gamekeydown[key_speed] || joybuttons[joybspeed]; // phares + + forward = side = 0; + + // use two stage accelerative turning + // on the keyboard and joystick + if (joyxmove < 0 || joyxmove > 0 || + gamekeydown[key_right] || gamekeydown[key_left]) + turnheld += ticdup; + else + turnheld = 0; + + if (turnheld < SLOWTURNTICS) + tspeed = 2; // slow turn + else + tspeed = speed; + + // turn 180 degrees in one keystroke? // phares + // | + if (gamekeydown[key_reverse]) // V + { + cmd->angleturn += QUICKREVERSE; // ^ + gamekeydown[key_reverse] = false; // | + } // phares + + // let movement keys cancel each other out + + if (strafe) + { + if (gamekeydown[key_right]) + side += sidemove[speed]; + if (gamekeydown[key_left]) + side -= sidemove[speed]; + if (joyxmove > 0) + side += sidemove[speed]; + if (joyxmove < 0) + side -= sidemove[speed]; + } + else + { + if (gamekeydown[key_right]) + cmd->angleturn -= angleturn[tspeed]; + if (gamekeydown[key_left]) + cmd->angleturn += angleturn[tspeed]; + if (joyxmove > 0) + cmd->angleturn -= angleturn[tspeed]; + if (joyxmove < 0) + cmd->angleturn += angleturn[tspeed]; + } + + if (gamekeydown[key_up]) + forward += forwardmove[speed]; + if (gamekeydown[key_down]) + forward -= forwardmove[speed]; + if (joyymove < 0) + forward += forwardmove[speed]; + if (joyymove > 0) + forward -= forwardmove[speed]; + if (gamekeydown[key_straferight]) + side += sidemove[speed]; + if (gamekeydown[key_strafeleft]) + side -= sidemove[speed]; + + // buttons + cmd->chatchar = HU_dequeueChatChar(); + + if (gamekeydown[key_fire] || mousebuttons[mousebfire] || + joybuttons[joybfire]) + cmd->buttons |= BT_ATTACK; + + if (gamekeydown[key_use] || joybuttons[joybuse]) + { + cmd->buttons |= BT_USE; + // clear double clicks if hit use button + dclicks = 0; + } + + // Toggle between the top 2 favorite weapons. // phares + // If not currently aiming one of these, switch to // phares + // the favorite. Only switch if you possess the weapon. // phares + + // killough 3/22/98: + // + // Perform automatic weapons switch here rather than in p_pspr.c, + // except in demo_compatibility mode. + // + // killough 3/26/98, 4/2/98: fix autoswitch when no weapons are left + + if ((!demo_compatibility && players[consoleplayer].attackdown && // killough + !P_CheckAmmo(&players[consoleplayer])) || gamekeydown[key_weapontoggle]) + newweapon = P_SwitchWeapon(&players[consoleplayer]); // phares + else + { // phares 02/26/98: Added gamemode checks + if(gamekeydown[key_weapon]) + { + volatile unsigned int wpcheck; // I don't know why this is needed, but it is + for(wpcheck=0; wpcheck<9; wpcheck++) + if(players[consoleplayer].weaponowned[wpcheck] && wpcheck>players[consoleplayer].readyweapon ) + { + newweapon=wpcheck; + break; + } + if(players[consoleplayer].weaponowned[wp_chainsaw]&&newweapon==0) + newweapon=1; + } + else + { + newweapon = + gamekeydown[key_weapon1] ? wp_fist : // killough 5/2/98: reformatted + gamekeydown[key_weapon2] ? wp_pistol : + gamekeydown[key_weapon3] ? wp_shotgun : + gamekeydown[key_weapon4] ? wp_chaingun : + gamekeydown[key_weapon5] ? wp_missile : + gamekeydown[key_weapon6] && gamemode != shareware ? wp_plasma : + gamekeydown[key_weapon7] && gamemode != shareware ? wp_bfg : + gamekeydown[key_weapon8] ? wp_chainsaw : + gamekeydown[key_weapon9] && gamemode == commercial ? wp_supershotgun : + wp_nochange; + } + + // killough 3/22/98: For network and demo consistency with the + // new weapons preferences, we must do the weapons switches here + // instead of in p_user.c. But for old demos we must do it in + // p_user.c according to the old rules. Therefore demo_compatibility + // determines where the weapons switch is made. + + // killough 2/8/98: + // Allow user to switch to fist even if they have chainsaw. + // Switch to fist or chainsaw based on preferences. + // Switch to shotgun or SSG based on preferences. + + if (!demo_compatibility) + { + const player_t *player = &players[consoleplayer]; + + // only select chainsaw from '1' if it's owned, it's + // not already in use, and the player prefers it or + // the fist is already in use, or the player does not + // have the berserker strength. + + if (newweapon==wp_fist && player->weaponowned[wp_chainsaw] && + player->readyweapon!=wp_chainsaw && + (player->readyweapon==wp_fist || + !player->powers[pw_strength] || + P_WeaponPreferred(wp_chainsaw, wp_fist))) + newweapon = wp_chainsaw; + + // Select SSG from '3' only if it's owned and the player + // does not have a shotgun, or if the shotgun is already + // in use, or if the SSG is not already in use and the + // player prefers it. + if(!gamekeydown[key_weapon]) + if (newweapon == wp_shotgun && gamemode == commercial && + player->weaponowned[wp_supershotgun] && + (!player->weaponowned[wp_shotgun] || + player->readyweapon == wp_shotgun || + (player->readyweapon != wp_supershotgun && + P_WeaponPreferred(wp_supershotgun, wp_shotgun)))) + newweapon = wp_supershotgun; + + } + // killough 2/8/98, 3/22/98 -- end of weapon selection changes + } + + if(newweapon >wp_nochange) // something is messed up with the weapon switching code above allowing it to give values greater + { // then wp_nochange which really screws the game up + newweapon=0; + } + if (newweapon != wp_nochange) + { + cmd->buttons |= BT_CHANGE; + cmd->buttons |= newweapon< 1 ) + { + dclickstate = mousebuttons[mousebforward]; + if (dclickstate) + dclicks++; + if (dclicks == 2) + { + cmd->buttons |= BT_USE; + dclicks = 0; + } + else + dclicktime = 0; + } + else + if ((dclicktime += ticdup) > 20) + { + dclicks = 0; + dclickstate = 0; + } + + // strafe double click + + bstrafe = mousebuttons[mousebstrafe] || joybuttons[joybstrafe]; + if (bstrafe != dclickstate2 && dclicktime2 > 1 ) + { + dclickstate2 = bstrafe; + if (dclickstate2) + dclicks2++; + if (dclicks2 == 2) + { + cmd->buttons |= BT_USE; + dclicks2 = 0; + } + else + dclicktime2 = 0; + } + else + if ((dclicktime2 += ticdup) > 20) + { + dclicks2 = 0; + dclickstate2 = 0; + } + forward += mousey; + if (strafe) + side += mousex / 4; /* mead Don't want to strafe as fast as turns.*/ + else + cmd->angleturn -= mousex; /* mead now have enough dynamic range 2-10-00 */ + + mousex = mousey = 0; + + if (forward > MAXPLMOVE) + forward = MAXPLMOVE; + else if (forward < -MAXPLMOVE) + forward = -MAXPLMOVE; + if (side > MAXPLMOVE) + side = MAXPLMOVE; + else if (side < -MAXPLMOVE) + side = -MAXPLMOVE; + + cmd->forwardmove += fudgef(forward); + cmd->sidemove += side; + cmd->angleturn = fudgea(cmd->angleturn); + + // CPhipps - special events (game new/load/save/pause) + if (special_event & BT_SPECIAL) { + cmd->buttons = special_event; + special_event = 0; + } +} + +// +// G_RestartLevel +// + +void G_RestartLevel(void) +{ + special_event = BT_SPECIAL | (BTS_RESTARTLEVEL & BT_SPECIALMASK); +} + +#include "z_bmalloc.h" +// +// G_DoLoadLevel +// +extern gamestate_t wipegamestate; + +static void G_DoLoadLevel (void) +{ + int i; + + // Set the sky map. + // First thing, we have a dummy sky texture name, + // a flat. The data is in the WAD only because + // we look for an actual index, instead of simply + // setting one. + + skyflatnum = R_FlatNumForName ( SKYFLATNAME ); + + // DOOM determines the sky texture to be used + // depending on the current episode, and the game version. + if (gamemode == commercial) + // || gamemode == pack_tnt //jff 3/27/98 sorry guys pack_tnt,pack_plut + // || gamemode == pack_plut) //aren't gamemodes, this was matching retail + { + skytexture = R_TextureNumForName ("SKY3"); + if (gamemap < 12) + skytexture = R_TextureNumForName ("SKY1"); + else + if (gamemap < 21) + skytexture = R_TextureNumForName ("SKY2"); + } + else //jff 3/27/98 and lets not forget about DOOM and Ultimate DOOM huh? + switch (gameepisode) + { + case 1: + skytexture = R_TextureNumForName ("SKY1"); + break; + case 2: + skytexture = R_TextureNumForName ("SKY2"); + break; + case 3: + skytexture = R_TextureNumForName ("SKY3"); + break; + case 4: // Special Edition sky + skytexture = R_TextureNumForName ("SKY4"); + break; + }//jff 3/27/98 end sky setting fix + + levelstarttic = gametic; // for time calculation + + if (!demo_compatibility && !mbf_features) // killough 9/29/98 + basetic = gametic; + + if (wipegamestate == GS_LEVEL) + wipegamestate = -1; // force a wipe + + gamestate = GS_LEVEL; + + for (i=0 ; idata1 == key_spy && netgame && (demoplayback || !deathmatch) && + gamestate == GS_LEVEL) + { + if (ev->type == ev_keyup) + gamekeydown[key_spy] = false; + if (ev->type == ev_keydown && !gamekeydown[key_spy]) + { + gamekeydown[key_spy] = true; + do // spy mode + if (++displayplayer >= MAXPLAYERS) + displayplayer = 0; + while (!playeringame[displayplayer] && displayplayer!=consoleplayer); + + ST_Start(); // killough 3/7/98: switch status bar views too + HU_Start(); + S_UpdateSounds(players[displayplayer].mo); + } + return true; + } + + // any other key pops up menu if in demos + // + // killough 8/2/98: enable automap in -timedemo demos + // + // killough 9/29/98: make any key pop up menu regardless of + // which kind of demo, and allow other events during playback + + if (gameaction == ga_nothing && (demoplayback || gamestate == GS_DEMOSCREEN)) + { + // killough 9/29/98: allow user to pause demos during playback + if (ev->type == ev_keydown && ev->data1 == key_pause) + { + if (paused ^= 2) + S_PauseSound(); + else + S_ResumeSound(); + return true; + } + // killough 10/98: + // Don't pop up menu, if paused in middle + // of demo playback, or if automap active. + // Don't suck up keys, which may be cheats + + return gamestate == GS_DEMOSCREEN && + !(paused & 2) && !(automapmode & am_active) && + ((ev->type == ev_keydown) || + (ev->type == ev_mouse && ev->data1) || + (ev->type == ev_joystick && ev->data1)) ? + M_StartControlPanel(), true : false; + } + + if (gamestate == GS_FINALE && F_Responder(ev)) + return true; // finale ate the event + + switch (ev->type) + { + case ev_keydown: + if (ev->data1 == key_pause) // phares + { + special_event = BT_SPECIAL | (BTS_PAUSE & BT_SPECIALMASK); + return true; + } + if (ev->data1 data1] = true; + return true; // eat key down events + + case ev_keyup: + if (ev->data1 data1] = false; + return false; // always let key up events filter down + + case ev_mouse: + mousebuttons[0] = ev->data1 & 1; + mousebuttons[1] = ev->data1 & 2; + mousebuttons[2] = ev->data1 & 4; +// mousex = ev->data2*(mouseSensitivity+5)/10; +// mousey = ev->data3*(mouseSensitivity+5)/10; + return true; // eat events + + case ev_joystick: + joybuttons[0] = ev->data1 & 1; + joybuttons[1] = ev->data1 & 2; + joybuttons[2] = ev->data1 & 4; + joybuttons[3] = ev->data1 & 8; + joyxmove = ev->data2; + joyymove = ev->data3; + return true; // eat events + + default: + break; + } + return false; +} + +// +// G_Ticker +// Make ticcmd_ts for the players. +// +extern int mapcolor_me; + +void G_Ticker (void) +{ + int i; + static gamestate_t prevgamestate; + + P_MapStart(); + // do player reborns if needed + for (i=0 ; iforwardmove > TURBOTHRESHOLD && + !(gametic&31) && ((gametic>>5)&3) == i ) + { + extern char *player_names[]; + /* cph - don't use sprintf, use doom_printf */ + doom_printf ("%s is turbo!", player_names[i]); + } + + if (netgame && !netdemo && !(gametic%ticdup) ) + { + if (gametic > BACKUPTICS + && consistancy[i][buf] != cmd->consistancy) + I_Error("G_Ticker: Consistency failure (%i should be %i)", + cmd->consistancy, consistancy[i][buf]); + if (players[i].mo) + consistancy[i][buf] = players[i].mo->x; + else + consistancy[i][buf] = 0; // killough 2/14/98 + } + } + } + + // check for special buttons + for (i=0 ; i>BTS_SAVESHIFT; + gameaction = ga_savegame; + break; + + // CPhipps - remote loadgame request + case BTS_LOADGAME: + savegameslot = + (players[i].cmd.buttons & BTS_SAVEMASK)>>BTS_SAVESHIFT; + gameaction = ga_loadgame; + forced_loadgame = netgame; // Force if a netgame + command_loadgame = false; + break; + + // CPhipps - Restart the level + case BTS_RESTARTLEVEL: + if (demoplayback || (compatibility_level < lxdoom_1_compatibility)) + break; // CPhipps - Ignore in demos or old games + gameaction = ga_loadlevel; + break; + } + players[i].cmd.buttons = 0; + } + } + } + } + + // cph - if the gamestate changed, we may need to clean up the old gamestate + if (gamestate != prevgamestate) { + switch (prevgamestate) { + case GS_INTERMISSION: + WI_End(); + default: + break; + } + prevgamestate = gamestate; + } + + // do main actions + switch (gamestate) + { + case GS_LEVEL: + P_Ticker (); + ST_Ticker (); + AM_Ticker (); + HU_Ticker (); + break; + + case GS_INTERMISSION: + WI_Ticker (); + break; + + case GS_FINALE: + F_Ticker (); + break; + + case GS_DEMOSCREEN: + D_PageTicker (); + break; + } +} + + +// +// PLAYER STRUCTURE FUNCTIONS +// also see P_SpawnPlayer in P_Things +// + +// +// G_PlayerFinishLevel +// Can when a player completes a level. +// +void G_PlayerFinishLevel(int player) +{ + player_t *p = &players[player]; + memset(p->powers, 0, sizeof (p->powers)); + memset(p->cards, 0, sizeof (p->cards)); + p->mo->flags &= ~MF_SHADOW; // cancel invisibility + p->extralight = 0; // cancel gun flashes + p->fixedcolormap = 0; // cancel ir gogles + p->damagecount = 0; // no palette changes + p->bonuscount = 0; +} + +// CPhipps - G_SetPlayerColour +// Player colours stuff +// +// G_SetPlayerColour + +#include "r_draw.h" +extern byte playernumtotrans[MAXPLAYERS]; + +void G_ChangedPlayerColour(int pn, int cl) +{ + int i; + + if (!netgame) return; + + mapcolor_plyr[pn] = cl; + + // Rebuild colour translation tables accordingly + R_InitTranslationTables(); + // Change translations on existing player mobj's + for (i=0; iflags &= ~MF_TRANSLATION; + players[i].mo->flags |= playernumtotrans[i] << MF_TRANSSHIFT; + } + } +} + +// +// G_PlayerReborn +// Called after a player dies +// almost everything is cleared and initialized +// +void G_PlayerReborn (int player) +{ + player_t *p; + int i; + int frags[MAXPLAYERS]; + int killcount; + int itemcount; + int secretcount; + + memcpy (frags, players[player].frags, sizeof frags); + killcount = players[player].killcount; + itemcount = players[player].itemcount; + secretcount = players[player].secretcount; + + p = &players[player]; + + // killough 3/10/98,3/21/98: preserve cheats across idclev + { + int cheats = p->cheats; + memset (p, 0, sizeof(*p)); + p->cheats = cheats; + } + + memcpy(players[player].frags, frags, sizeof(players[player].frags)); + players[player].killcount = killcount; + players[player].itemcount = itemcount; + players[player].secretcount = secretcount; + + p->usedown = p->attackdown = true; // don't do anything immediately + p->playerstate = PST_LIVE; + p->health = MAXHEALTH; + p->readyweapon = p->pendingweapon = wp_pistol; + p->weaponowned[wp_fist] = true; + p->weaponowned[wp_pistol] = true; + p->ammo[am_clip] = 50; + + for (i=0 ; imaxammo[i] = maxammo[i]; + +} + +// +// G_CheckSpot +// Returns false if the player cannot be respawned +// at the given mapthing_t spot +// because something is occupying it +// + +void P_SpawnPlayer(mapthing_t *mthing); + +boolean G_CheckSpot(int playernum, mapthing_t *mthing) +{ + fixed_t x,y; + subsector_t *ss; + int i; + + if (!players[playernum].mo) + { + // first spawn of level, before corpses + for (i=0 ; ix == mthing->x << FRACBITS + && players[i].mo->y == mthing->y << FRACBITS) + return false; + return true; + } + + x = mthing->x << FRACBITS; + y = mthing->y << FRACBITS; + + // killough 4/2/98: fix bug where P_CheckPosition() uses a non-solid + // corpse to detect collisions with other players in DM starts + // + // Old code: + // if (!P_CheckPosition (players[playernum].mo, x, y)) + // return false; + + players[playernum].mo->flags |= MF_SOLID; + i = P_CheckPosition(players[playernum].mo, x, y); + players[playernum].mo->flags &= ~MF_SOLID; + if (!i) + return false; + + // flush an old corpse if needed + // killough 2/8/98: make corpse queue have an adjustable limit + // killough 8/1/98: Fix bugs causing strange crashes + + if (bodyquesize > 0) + { + static mobj_t **bodyque; + static int queuesize; + if (queuesize < bodyquesize) + { + bodyque = realloc(bodyque, bodyquesize*sizeof*bodyque); + memset(bodyque+queuesize, 0, + (bodyquesize-queuesize)*sizeof*bodyque); + queuesize = bodyquesize; + } + if (bodyqueslot >= bodyquesize) + P_RemoveMobj(bodyque[bodyqueslot % bodyquesize]); + bodyque[bodyqueslot++ % bodyquesize] = players[playernum].mo; + } + else + if (!bodyquesize) + P_RemoveMobj(players[playernum].mo); + + // spawn a teleport fog + ss = R_PointInSubsector (x,y); + { // Teleport fog at respawn point + fixed_t xa=0,ya=0; + int an; + mobj_t *mo; + + /* BUG: an can end up negative, because mthing->angle is (signed) short. + * We have to emulate original Doom's behaviour, deferencing past the start + * of the array, into the previous array (finetangent) */ + an = ( ANG45 * ((signed)mthing->angle/45) ) >> ANGLETOFINESHIFT; + switch (an) { + case -4096: xa = finetangent[2048]; // finecosine[-4096] + ya = finetangent[0]; // finesine[-4096] + break; + case -3072: xa = finetangent[3072]; // finecosine[-3072] + ya = finetangent[1024]; // finesine[-3072] + break; + case -2048: xa = finesine[0]; // finecosine[-2048] + ya = finetangent[2048]; // finesine[-2048] + break; + case -1024: xa = finesine[1024]; // finecosine[-1024] + ya = finetangent[3072]; // finesine[-1024] + break; + case 1024: + case 2048: + case 3072: + case 4096: + case 0: xa = finecosine[an]; + ya = finesine[an]; + break; + default: I_Error("G_CheckSpot: unexpected angle %d\n",an); + } + + + mo = P_SpawnMobj(x+20*xa, y+20*ya, ss->sector->floorheight, MT_TFOG); + + if (players[consoleplayer].viewz != 1) + S_StartSound(mo, sfx_telept); // don't start sound on first frame + } + + return true; +} + + +// +// G_DeathMatchSpawnPlayer +// Spawns a player at one of the random death match spots +// called at level load and each death +// +void G_DeathMatchSpawnPlayer (int playernum) +{ + int j, selections = deathmatch_p - deathmatchstarts; + + if (selections < MAXPLAYERS) + I_Error("G_DeathMatchSpawnPlayer: Only %i deathmatch spots, %d required", + selections, MAXPLAYERS); + + for (j=0 ; j<20 ; j++) + { + int i = P_Random(pr_dmspawn) % selections; + if (G_CheckSpot (playernum, &deathmatchstarts[i]) ) + { + deathmatchstarts[i].type = playernum+1; + P_SpawnPlayer (&deathmatchstarts[i]); + return; + } + } + + // no good spot, so the player will probably get stuck + P_SpawnPlayer (&playerstarts[playernum]); +} + +// +// G_DoReborn +// + +void G_DoReborn (int playernum) +{ + if (!netgame) + gameaction = ga_loadlevel; // reload the level from scratch + else + { // respawn at the start + int i; + + // first dissasociate the corpse + players[playernum].mo->player = NULL; + + // spawn at random spot if in death match + if (deathmatch) + { + G_DeathMatchSpawnPlayer (playernum); + return; + } + + if (G_CheckSpot (playernum, &playerstarts[playernum]) ) + { + P_SpawnPlayer (&playerstarts[playernum]); + return; + } + + // try to spawn at one of the other players spots + for (i=0 ; i lump); + return s; +} + +static uint_64_t G_Signature(void) +{ + static uint_64_t s = 0; + static boolean computed = false; + char name[9]; + int episode, map; + + if (!computed) { + computed = true; + if (gamemode == commercial) + for (map = haswolflevels ? 32 : 30; map; map--) + snprintf(name, sizeof(name), "map%02d", map), s = G_UpdateSignature(s, name); + else + for (episode = gamemode==retail ? 4 : + gamemode==shareware ? 1 : 3; episode; episode--) + for (map = 9; map; map--) + snprintf(name, sizeof(name), "E%dM%d", episode, map), s = G_UpdateSignature(s, name); + } + return s; +} + +// +// killough 5/15/98: add forced loadgames, which allow user to override checks +// + +void G_ForcedLoadGame(void) +{ + // CPhipps - net loadgames are always forced, so we only reach here + // in single player + gameaction = ga_loadgame; + forced_loadgame = true; +} + +// killough 3/16/98: add slot info +// killough 5/15/98: add command-line +void G_LoadGame(int slot, boolean command) +{ + if (!demoplayback && !command) { + // CPhipps - handle savegame filename in G_DoLoadGame + // - Delay load so it can be communicated in net game + // - store info in special_event + special_event = BT_SPECIAL | (BTS_LOADGAME & BT_SPECIALMASK) | + ((slot << BTS_SAVESHIFT) & BTS_SAVEMASK); + forced_loadgame = netgame; // CPhipps - always force load netgames + } else { + // Do the old thing, immediate load + gameaction = ga_loadgame; + forced_loadgame = false; + savegameslot = slot; + demoplayback = false; + } + command_loadgame = command; +} + +// killough 5/15/98: +// Consistency Error when attempting to load savegame. + +static void G_LoadGameErr(const char *msg) +{ + (void) msg; // Need to fix, but right now we're ignoring a forced load + Z_Free(savebuffer); // Free the savegame buffer +// M_ForcedLoadGame(msg); // Print message asking for 'Y' to force + if (command_loadgame) // If this was a command-line -loadgame + { + D_StartTitle(); // Start the title screen + gamestate = GS_DEMOSCREEN; // And set the game state accordingly + } +} + +// CPhipps - size of version header +#define VERSIONSIZE 16 + +const char * comp_lev_str[MAX_COMPATIBILITY_LEVEL] = + { "doom v1.2", "demo", "doom", "\"boom compatibility\"", "boom v2.01", "boom v2.02", "lxdoom v1.3.2+", + "MBF", "PrBoom 2.03beta", "PrBoom v2.1.0-2.1.1", + "Current PrBoom" }; + +static const struct { + unsigned int comp_level; + const char* ver_printf; + int version; +} version_headers[] = { + { prboom_1_compatibility, "PrBoom %d", 260}, + /* cph - we don't need a new version_header for prboom_3_comp/v2.1.1, since + * the file format is unchanged. */ + { prboom_3_compatibility, "PrBoom %d", 210} + }; + +static const size_t num_version_headers = sizeof(version_headers) / sizeof(version_headers[0]); + +void G_DoLoadGame(void) +{ + int length, i; + // CPhipps - do savegame filename stuff here + char name[100+1]; // killough 3/22/98 + int savegame_compatibility = -1; + + G_SaveGameName(name,sizeof(name),savegameslot, demoplayback); + + gameaction = ga_nothing; + + length = M_ReadFile(name, &savebuffer); + save_p = savebuffer + SAVESTRINGSIZE; + + // CPhipps - read the description field, compare with supported ones + for (i=0; (size_t)i= prboom_2_compatibility) { + memcpy(&totalleveltimes, save_p, sizeof totalleveltimes); + save_p += sizeof totalleveltimes; + } + else totalleveltimes = 0; + + // killough 11/98: load revenant tracer state + basetic = gametic - *save_p++; + + // dearchive all the modifications + P_UnArchivePlayers (); + P_UnArchiveWorld (); + P_UnArchiveThinkers (); + P_UnArchiveSpecials (); + P_UnArchiveRNG (); // killough 1/18/98: load RNG information + P_UnArchiveMap (); // killough 1/22/98: load automap information + + if (*save_p != 0xe6) + I_Error ("G_DoLoadGame: Bad savegame"); + + // done + Z_Free (savebuffer); + + if (setsizeneeded) + R_ExecuteSetViewSize (); + + // draw the pattern into the back screen + R_FillBackScreen (); + + /* killough 12/98: support -recordfrom and -loadgame -playdemo */ + if (!command_loadgame) + singledemo = false; /* Clear singledemo flag if loading from menu */ + else + if (singledemo) { + gameaction = ga_loadgame; /* Mark that we're loading a game before demo */ + G_DoPlayDemo(); /* This will detect it and won't reinit level */ + } else /* Command line + record means it's a recordfrom */ + if (demorecording) + G_BeginRecording(); +} + +// +// G_SaveGame +// Called by the menu task. +// Description is a 24 byte text string +// + +void G_SaveGame(int slot, char *description) +{ + strcpy(savedescription, description); + if (demoplayback) { + /* cph - We're doing a user-initiated save game while a demo is + * running so, go outside normal mechanisms + */ + savegameslot = slot; + G_DoSaveGame(true); + } + // CPhipps - store info in special_event + special_event = BT_SPECIAL | (BTS_SAVEGAME & BT_SPECIALMASK) | + ((slot << BTS_SAVESHIFT) & BTS_SAVEMASK); +#ifdef HAVE_NET + D_NetSendMisc(nm_savegamename, strlen(savedescription)+1, savedescription); +#endif +} + +// Check for overrun and realloc if necessary -- Lee Killough 1/22/98 +void CheckSaveGame(size_t size) +{ + size_t pos = save_p - savebuffer; + size += 1024; // breathing room + if (pos+size > savegamesize) + save_p = (savebuffer = realloc(savebuffer, + savegamesize += (size+1023) & ~1023)) + pos; +} + +/* killough 3/22/98: form savegame name in one location + * (previously code was scattered around in multiple places) + * cph - Avoid possible buffer overflow problems by passing + * size to this function and using snprintf */ + +void G_SaveGameName(char *name, size_t size, int slot, boolean demoplayback) +{ + const char* sgn = demoplayback ? "demosav" : SAVEGAMENAME; + snprintf (name, size, "%s%d.dsg", sgn, slot); +} + +static void G_DoSaveGame (boolean menu) +{ + char name[100+1]; + char name2[VERSIONSIZE]; + char *description; + int length, i; + + gameaction = ga_nothing; // cph - cancel savegame at top of this function, + // in case later problems cause a premature exit + + G_SaveGameName(name,sizeof(name),savegameslot, demoplayback && !menu); + + description = savedescription; + + save_p = savebuffer = malloc(savegamesize); + + CheckSaveGame(SAVESTRINGSIZE+VERSIONSIZE+sizeof(unsigned long)); + memcpy (save_p, description, SAVESTRINGSIZE); + save_p += SAVESTRINGSIZE; + memset (name2,0,sizeof(name2)); + + // CPhipps - scan for the version header + for (i=0; (size_t)i= prboom_2_compatibility) { + memcpy(save_p, &totalleveltimes, sizeof totalleveltimes); + save_p += sizeof totalleveltimes; + } + else totalleveltimes = 0; + + // killough 11/98: save revenant tracer state + *save_p++ = (gametic-basetic) & 255; + + // killough 3/22/98: add Z_CheckHeap after each call to ensure consistency + Z_CheckHeap(); + P_ArchivePlayers(); + Z_CheckHeap(); + + // phares 9/13/98: Move mobj_t->index out of P_ArchiveThinkers so the + // indices can be used by P_ArchiveWorld when the sectors are saved. + // This is so we can save the index of the mobj_t of the thinker that + // caused a sound, referenced by sector_t->soundtarget. + P_ThinkerToIndex(); + + P_ArchiveWorld(); + Z_CheckHeap(); + P_ArchiveThinkers(); + + // phares 9/13/98: Move index->mobj_t out of P_ArchiveThinkers, simply + // for symmetry with the P_ThinkerToIndex call above. + + P_IndexToThinker(); + + Z_CheckHeap(); + P_ArchiveSpecials(); + P_ArchiveRNG(); // killough 1/18/98: save RNG information + Z_CheckHeap(); + P_ArchiveMap(); // killough 1/22/98: save automap information + + *save_p++ = 0xe6; // consistancy marker + + length = save_p - savebuffer; + + Z_CheckHeap(); + doom_printf( "%s", M_WriteFile(name, savebuffer, length) + ? GGSAVED /* Ty - externalised */ + : "Game save failed!"); // CPhipps - not externalised + + free(savebuffer); // killough + savebuffer = save_p = NULL; + + savedescription[0] = 0; +} + +static skill_t d_skill; +static int d_episode; +static int d_map; + +void G_DeferedInitNew(skill_t skill, int episode, int map) +{ + d_skill = skill; + d_episode = episode; + d_map = map; + gameaction = ga_newgame; +} + +extern int variable_friction; +extern int default_variable_friction; // ice & mud + +extern int weapon_recoil, default_weapon_recoil; // weapon recoil + +extern int allow_pushers; +extern int default_allow_pushers; // MT_PUSH Things + +extern int player_bobbing; +extern int default_player_bobbing; // whether player bobs or not + +extern int monsters_remember, default_monsters_remember; + +/* cph - + * G_Compatibility + * + * Initialises the comp[] array based on the compatibility_level + * For reference, MBF did: + * for (i=0; i < COMP_TOTAL; i++) + * comp[i] = compatibility; + * + * Instead, we have a lookup table showing at what version a fix was + * introduced. + */ + +void G_Compatibility(void) +{ + static const complevel_t fix_levels[COMP_NUM] = { + mbf_compatibility, /* comp_telefrag - monsters used to telefrag only + * on MAP30, now they do it for spawners only */ + mbf_compatibility, /* comp_dropoff - MBF encourages things to drop + * off of overhangs */ + boom_compatibility,/* comp_vile - original Doom archville bugs like + * ghosts */ + boom_compatibility,/* comp_pain - original Doom limits Pain Elements + * from spawning too many skulls */ + boom_compatibility,/* comp_skull - original Doom let skulls be spit + * through walls by Pain Elementals */ + boom_compatibility,/* comp_blazing - original Doom duplicated + * blazing door sound */ + mbf_compatibility, /* comp_doorlight - MBF made door lighting changes + * more gradual */ + boom_compatibility,/* comp_model - improvements to the game physics */ + boom_compatibility,/* comp_god - fixes to God mode */ + mbf_compatibility, /* comp_falloff - MBF encourages things to drop + * off of overhangs */ + boom_compatibility_compatibility, + /* comp_floors - fixes for moving floors bugs */ + boom_compatibility,/* comp_skymap */ + mbf_compatibility, /* comp_pursuit - MBF AI change, limited pursuit? */ + boom_compatibility,/* comp_doorstuck - monsters stuck in doors fix */ + mbf_compatibility, /* comp_staylift - MBF AI change, monsters try + * to stay on lifts */ + lxdoom_1_compatibility, /* comp_zombie - prevent dead players + * triggering stuff */ + boom_compatibility_compatibility, /* comp_stairs - see p_floor.c */ + mbf_compatibility, /* comp_infcheat - FIXME */ + boom_compatibility,/* comp_zerotags - allow zero tags in wads */ + lxdoom_1_compatibility, /* comp_moveblock - enables keygrab and + * mancubi shots going thru walls */ + prboom_2_compatibility, /* comp_respawn - objects which aren't on the map + * at game start respawn at (0,0) */ + boom_compatibility_compatibility, /* comp_sound - see s_sound.c */ + }; + int i; + for (i=0; i>= 1; // don't change 1->0 since it causes cycles + mobjinfo[MT_BRUISERSHOT].speed = 20*FRACUNIT; + mobjinfo[MT_HEADSHOT].speed = 20*FRACUNIT; + mobjinfo[MT_TROOPSHOT].speed = 20*FRACUNIT; + } + else + { + for (i=S_SARG_RUN1; i<=S_SARG_PAIN2; i++) + states[i].tics <<= 1; + mobjinfo[MT_BRUISERSHOT].speed = 15*FRACUNIT; + mobjinfo[MT_HEADSHOT].speed = 10*FRACUNIT; + mobjinfo[MT_TROOPSHOT].speed = 10*FRACUNIT; + } + } +} + +// The sky texture to be used instead of the F_SKY1 dummy. +extern int skytexture; + +// +// G_InitNew +// Can be called by the startup code or the menu task, +// consoleplayer, displayplayer, playeringame[] should be set. +// + +void G_InitNew(skill_t skill, int episode, int map) +{ + int i; + + if (paused) + { + paused = false; + S_ResumeSound(); + } + + if (skill > sk_nightmare) + skill = sk_nightmare; + + if (episode < 1) + episode = 1; + + if (gamemode == retail) + { + if (episode > 4) + episode = 4; + } + else + if (gamemode == shareware) + { + if (episode > 1) + episode = 1; // only start episode 1 on shareware + } + else + if (episode > 3) + episode = 3; + + if (map < 1) + map = 1; + if (map > 9 && gamemode != commercial) + map = 9; + + G_SetFastParms(fastparm || skill == sk_nightmare); // killough 4/10/98 + + M_ClearRandom(); + + respawnmonsters = skill == sk_nightmare || respawnparm; + + // force players to be initialized upon first level load + for (i=0 ; iforwardmove = ((signed char)*demo_p++); + cmd->sidemove = ((signed char)*demo_p++); + if (!longtics) { + cmd->angleturn = ((unsigned char)*demo_p++)<<8; + } else { + unsigned int lowbyte = (unsigned char)*demo_p++; + cmd->angleturn = (((signed int)(*demo_p++))<<8) + lowbyte; + } + cmd->buttons = (unsigned char)*demo_p++; + } +} + +/* Demo limits removed -- killough + * cph - record straight to file + */ +void G_WriteDemoTiccmd (ticcmd_t* cmd) +{ + char buf[5]; + char *p = buf; + + *p++ = cmd->forwardmove; + *p++ = cmd->sidemove; + if (!longtics) { + *p++ = (cmd->angleturn+128)>>8; + } else { + signed short a = cmd->angleturn; + *p++ = a & 0xff; + *p++ = (a >> 8) & 0xff; + } + *p++ = cmd->buttons; + if (write(demofd, buf, p-buf) != p-buf) + I_Error("G_WriteDemoTiccmd: error writing demo"); + + /* cph - alias demo_p to it so we can read it back */ + demo_p = buf; + G_ReadDemoTiccmd (cmd); // make SURE it is exactly the same +} + +// +// G_RecordDemo +// + +void G_RecordDemo (const char* name) +{ + char demoname[100]; + usergame = false; + AddDefaultExtension(strcpy(demoname, name), ".lmp"); // 1/18/98 killough + demorecording = true; + /* cph - Record demos straight to file + * If file already exists, try to continue existing demo + */ + if (fileexists(demoname)) { + demofd = open(demoname, O_WRONLY | O_APPEND); + } else { + demofd = open(demoname, O_WRONLY | O_RDONLY); + if (demofd) { + int slot = -1; + int rc; + { + byte buf[200]; + size_t len; + read(demofd, buf, sizeof(buf)); + + len = G_ReadDemoHeader(buf) - buf; + lseek(demofd, len, SEEK_SET); + } + do { + byte buf[4]; + rc = read(demofd, buf, sizeof(buf)); + if (buf[0] == DEMOMARKER) break; + if (buf[3] & BT_SPECIAL) + if ((buf[3] & BT_SPECIALMASK) == BTS_SAVEGAME) + slot = (buf[3] & BTS_SAVEMASK)>>BTS_SAVESHIFT; + } while (rc == /* sizeof(buf) is out of scope here */ 4 ); + if (slot == -1) I_Error("G_RecordDemo: No save in demo, can't continue"); + lseek(demofd, -rc, SEEK_CUR); + G_LoadGame(slot, false); + autostart = false; + } + } + if (!demofd) I_Error("G_RecordDemo: failed to open %s", name); +} + +// These functions are used to read and write game-specific options in demos +// and savegames so that demo sync is preserved and savegame restoration is +// complete. Not all options (for example "compatibility"), however, should +// be loaded and saved here. It is extremely important to use the same +// positions as before for the variables, so if one becomes obsolete, the +// byte(s) should still be skipped over or padded with 0's. +// Lee Killough 3/1/98 + +extern int forceOldBsp; + +byte *G_WriteOptions(byte *demo_p) +{ + byte *target = demo_p + GAME_OPTION_SIZE; + + *demo_p++ = monsters_remember; // part of monster AI + + *demo_p++ = variable_friction; // ice & mud + + *demo_p++ = weapon_recoil; // weapon recoil + + *demo_p++ = allow_pushers; // MT_PUSH Things + + *demo_p++ = 0; + + *demo_p++ = player_bobbing; // whether player bobs or not + + // killough 3/6/98: add parameters to savegame, move around some in demos + *demo_p++ = respawnparm; + *demo_p++ = fastparm; + *demo_p++ = nomonsters; + + *demo_p++ = demo_insurance; // killough 3/31/98 + + // killough 3/26/98: Added rngseed. 3/31/98: moved here + *demo_p++ = (byte)((rngseed >> 24) & 0xff); + *demo_p++ = (byte)((rngseed >> 16) & 0xff); + *demo_p++ = (byte)((rngseed >> 8) & 0xff); + *demo_p++ = (byte)( rngseed & 0xff); + + // Options new to v2.03 begin here + + *demo_p++ = monster_infighting; // killough 7/19/98 + +#ifdef DOGS + *demo_p++ = dogs; // killough 7/19/98 +#else + *demo_p++ = 0; +#endif + + *demo_p++ = 0; + *demo_p++ = 0; + + *demo_p++ = (distfriend >> 8) & 0xff; // killough 8/8/98 + *demo_p++ = distfriend & 0xff; // killough 8/8/98 + + *demo_p++ = monster_backing; // killough 9/8/98 + + *demo_p++ = monster_avoid_hazards; // killough 9/9/98 + + *demo_p++ = monster_friction; // killough 10/98 + + *demo_p++ = help_friends; // killough 9/9/98 + +#ifdef DOGS + *demo_p++ = dog_jumping; +#else + *demo_p++ = 0; +#endif + + *demo_p++ = monkeys; + + { // killough 10/98: a compatibility vector now + int i; + for (i=0; i < COMP_TOTAL; i++) + *demo_p++ = comp[i] != 0; + } + + *demo_p++ = (compatibility_level >= prboom_2_compatibility) && forceOldBsp; // cph 2002/07/20 + + //---------------- + // Padding at end + //---------------- + while (demo_p < target) + *demo_p++ = 0; + + if (demo_p != target) + I_Error("G_WriteOptions: GAME_OPTION_SIZE is too small"); + + return target; +} + +/* Same, but read instead of write + * cph - const byte*'s + */ + +const byte *G_ReadOptions(const byte *demo_p) +{ + const byte *target = demo_p + GAME_OPTION_SIZE; + + monsters_remember = *demo_p++; + + variable_friction = *demo_p; // ice & mud + demo_p++; + + weapon_recoil = *demo_p; // weapon recoil + demo_p++; + + allow_pushers = *demo_p; // MT_PUSH Things + demo_p++; + + demo_p++; + + player_bobbing = *demo_p; // whether player bobs or not + demo_p++; + + // killough 3/6/98: add parameters to savegame, move from demo + respawnparm = *demo_p++; + fastparm = *demo_p++; + nomonsters = *demo_p++; + + demo_insurance = *demo_p++; // killough 3/31/98 + + // killough 3/26/98: Added rngseed to demos; 3/31/98: moved here + + rngseed = *demo_p++ & 0xff; + rngseed <<= 8; + rngseed += *demo_p++ & 0xff; + rngseed <<= 8; + rngseed += *demo_p++ & 0xff; + rngseed <<= 8; + rngseed += *demo_p++ & 0xff; + + // Options new to v2.03 + if (mbf_features) + { + monster_infighting = *demo_p++; // killough 7/19/98 + +#ifdef DOGS + dogs = *demo_p++; // killough 7/19/98 +#else + demo_p++; +#endif + + demo_p += 2; + + distfriend = *demo_p++ << 8; // killough 8/8/98 + distfriend+= *demo_p++; + + monster_backing = *demo_p++; // killough 9/8/98 + + monster_avoid_hazards = *demo_p++; // killough 9/9/98 + + monster_friction = *demo_p++; // killough 10/98 + + help_friends = *demo_p++; // killough 9/9/98 + +#ifdef DOGS + dog_jumping = *demo_p++; // killough 10/98 +#else + demo_p++; +#endif + + monkeys = *demo_p++; + + { // killough 10/98: a compatibility vector now + int i; + for (i=0; i < COMP_TOTAL; i++) + comp[i] = *demo_p++; + } + + forceOldBsp = *demo_p++; // cph 2002/07/20 + } + else /* defaults for versions <= 2.02 */ + { + /* cph - comp[] has already been set up right by G_Compatibility */ + + monster_infighting = 1; // killough 7/19/98 + + monster_backing = 0; // killough 9/8/98 + + monster_avoid_hazards = 0; // killough 9/9/98 + + monster_friction = 0; // killough 10/98 + + help_friends = 0; // killough 9/9/98 + +#ifdef DOGS + dogs = 0; // killough 7/19/98 + dog_jumping = 0; // killough 10/98 +#endif + + monkeys = 0; + } + + return target; +} + +void G_BeginRecording (void) +{ + int i; + byte *demostart, *demo_p; + demostart = demo_p = malloc(1000); + + /* cph - 3 demo record formats supported: MBF+, BOOM, and Doom v1.9 */ + if (mbf_features) { + { /* Write version code into demo */ + unsigned char v=0; + switch(compatibility_level) { + case doom_12_compatibility: + case doom_demo_compatibility: + case doom_compatibility: + case boom_compatibility_compatibility: + case boom_201_compatibility: + case boom_202_compatibility: + case lxdoom_1_compatibility: + case prboom_1_compatibility: + case MAX_COMPATIBILITY_LEVEL: + case mbf_compatibility: v = 204; break; + case prboom_2_compatibility: v = 210; break; + case prboom_3_compatibility: v = 211; break; + } + *demo_p++ = v; + } + + // signature + *demo_p++ = 0x1d; + *demo_p++ = 'M'; + *demo_p++ = 'B'; + *demo_p++ = 'F'; + *demo_p++ = 0xe6; + *demo_p++ = '\0'; + + /* killough 2/22/98: save compatibility flag in new demos + * cph - FIXME? MBF demos will always be not in compat. mode */ + *demo_p++ = 0; + + *demo_p++ = gameskill; + *demo_p++ = gameepisode; + *demo_p++ = gamemap; + *demo_p++ = deathmatch; + *demo_p++ = consoleplayer; + + demo_p = G_WriteOptions(demo_p); // killough 3/1/98: Save game options + + for (i=0 ; i doom_compatibility) { + byte v=0, c=0; /* Nominally, version and compatibility bits */ + switch (compatibility_level) { + case boom_compatibility_compatibility: v = 202, c = 1; break; + case boom_201_compatibility: v = 201; c = 0; break; + case boom_202_compatibility: v = 202, c = 0; break; + default: I_Error("G_BeginRecording: Boom compatibility level unrecognised?"); + } + *demo_p++ = v; + + // signature + *demo_p++ = 0x1d; + *demo_p++ = 'B'; + *demo_p++ = 'o'; + *demo_p++ = 'o'; + *demo_p++ = 'm'; + *demo_p++ = 0xe6; + + /* CPhipps - save compatibility level in demos */ + *demo_p++ = c; + + *demo_p++ = gameskill; + *demo_p++ = gameepisode; + *demo_p++ = gamemap; + *demo_p++ = deathmatch; + *demo_p++ = consoleplayer; + + demo_p = G_WriteOptions(demo_p); // killough 3/1/98: Save game options + + for (i=0 ; i compatibility; new demos load + // compatibility flag, and other flags as well, as a part of the demo. + + demover = *demo_p++; + + if (demover < 200) // Autodetect old demos + { + compatibility_level = doom_demo_compatibility; + if (demover >= 111) longtics = 1; + + G_Compatibility(); + + // killough 3/2/98: force these variables to be 0 in demo_compatibility + + variable_friction = 0; + + weapon_recoil = 0; + + allow_pushers = 0; + + monster_infighting = 1; // killough 7/19/98 + +#ifdef DOGS + dogs = 0; // killough 7/19/98 + dog_jumping = 0; // killough 10/98 +#endif + + monster_backing = 0; // killough 9/8/98 + + monster_avoid_hazards = 0; // killough 9/9/98 + + monster_friction = 0; // killough 10/98 + help_friends = 0; // killough 9/9/98 + monkeys = 0; + + // killough 3/6/98: rearrange to fix savegame bugs (moved fastparm, + // respawnparm, nomonsters flags to G_LoadOptions()/G_SaveOptions()) + + if ((skill=demover) >= 100) // For demos from versions >= 1.4 + { + skill = *demo_p++; + episode = *demo_p++; + map = *demo_p++; + deathmatch = *demo_p++; + respawnparm = *demo_p++; + fastparm = *demo_p++; + nomonsters = *demo_p++; + consoleplayer = *demo_p++; + } + else + { + episode = *demo_p++; + map = *demo_p++; + deathmatch = respawnparm = fastparm = + nomonsters = consoleplayer = 0; + } + } + else // new versions of demos + { + demo_p += 6; // skip signature; + switch (demover) { + case 200: /* BOOM */ + case 201: + if (!*demo_p++) + compatibility_level = boom_201_compatibility; + else + compatibility_level = boom_compatibility_compatibility; + break; + case 202: + if (!*demo_p++) + compatibility_level = boom_202_compatibility; + else + compatibility_level = boom_compatibility_compatibility; + break; + case 203: + /* LxDoom or MBF - determine from signature + * cph - load compatibility level */ + switch (demobuffer[2]) { + case 'B': /* LxDoom */ + /* cph - DEMOSYNC - LxDoom demos recorded in compatibility modes support dropped */ + compatibility_level = lxdoom_1_compatibility; + break; + case 'M': + compatibility_level = mbf_compatibility; + demo_p++; + break; + } + break; + case 210: + compatibility_level = prboom_2_compatibility; + demo_p++; + break; + case 211: + compatibility_level = prboom_3_compatibility; + demo_p++; + break; + } + G_Compatibility(); + skill = *demo_p++; + episode = *demo_p++; + map = *demo_p++; + deathmatch = *demo_p++; + consoleplayer = *demo_p++; + + /* killough 11/98: save option pointer for below */ + if (mbf_features) + option_p = demo_p; + + demo_p = G_ReadOptions(demo_p); // killough 3/1/98: Read game options + + if (demover == 200) // killough 6/3/98: partially fix v2.00 demos + demo_p += 128-GAME_OPTION_SIZE; + } + +// printf( "G_DoPlayDemo: playing demo with %s compatibility\n", +// comp_lev_str[compatibility_level]); + + if (demo_compatibility) // only 4 players can exist in old demos + { + for (i=0; i<4; i++) // intentionally hard-coded 4 -- killough + playeringame[i] = *demo_p++; + for (;i < MAXPLAYERS; i++) + playeringame[i] = 0; + } + else + { + for (i=0 ; i < MAXPLAYERS; i++) + playeringame[i] = *demo_p++; + demo_p += MIN_MAXPLAYERS - MAXPLAYERS; + } + + if (playeringame[1]) + { + netgame = true; + netdemo = true; + } + + if (gameaction != ga_loadgame) { /* killough 12/98: support -loadgame */ + G_InitNew(skill, episode, map); + } + + for (i=0; imessage=... and so I've added this dprintf. +// +// killough 3/6/98: Made limit static to allow z_zone functions to call +// this function, without calling realloc(), which seems to cause problems. + +#define MAX_MESSAGE_SIZE 1024 +static char msg[MAX_MESSAGE_SIZE]; + +// CPhipps - renamed to doom_printf to avoid name collision with glibc +void doom_printf(const char *s, ...) +{ + va_list v; + va_start(v,s); + vsnprintf(msg,sizeof(msg),s,v); /* print message in buffer */ + va_end(v); + players[consoleplayer].message = msg; // set new message +} + diff --git a/apps/plugins/doom/g_game.h b/apps/plugins/doom/g_game.h new file mode 100644 index 0000000000..6a2d3dcd97 --- /dev/null +++ b/apps/plugins/doom/g_game.h @@ -0,0 +1,192 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: Main game control interface. + *-----------------------------------------------------------------------------*/ + +#ifndef __G_GAME__ +#define __G_GAME__ + +#include "doomdef.h" +#include "d_event.h" +#include "d_ticcmd.h" + +// +// GAME +// + +// killough 5/2/98: number of bytes reserved for saving options +#define GAME_OPTION_SIZE 64 + +boolean G_Responder(event_t *ev); +boolean G_CheckDemoStatus(void); +boolean G_CheckDemoStatus(void); +void G_DeathMatchSpawnPlayer(int playernum); +void G_InitNew(skill_t skill, int episode, int map); +void G_DeferedInitNew(skill_t skill, int episode, int map); +void G_DeferedPlayDemo(const char *demo); // CPhipps - const +void G_LoadGame(int slot, boolean is_command); // killough 5/15/98 +void G_ForcedLoadGame(void); // killough 5/15/98: forced loadgames +void G_DoLoadGame(void); +void G_SaveGame(int slot, char *description); // Called by M_Responder. +void G_BeginRecording(void); +// CPhipps - const on these string params +void G_RecordDemo(const char *name); // Only called by startup code. +void G_PlayDemo(const char *name); +void G_TimeDemo(const char *name); +void G_ExitLevel(void); +void G_SecretExitLevel(void); +void G_WorldDone(void); +void G_EndGame(void); /* cph - make m_menu.c call a G_* function for this */ +void G_Ticker(void); +void G_ReloadDefaults(void); // killough 3/1/98: loads game defaults +void G_SaveGameName(char *, size_t, int, boolean); /* killough 3/22/98: sets savegame filename */ +void G_SetFastParms(int); // killough 4/10/98: sets -fast parameters +void G_DoNewGame(void); +void G_DoReborn(int playernum); +void G_DoPlayDemo(void); +void G_DoCompleted(void); +void G_ReadDemoTiccmd(ticcmd_t *cmd); +void G_WriteDemoTiccmd(ticcmd_t *cmd); +void G_DoWorldDone(void); +void G_Compatibility(void); +const byte *G_ReadOptions(const byte *demo_p); /* killough 3/1/98 - cph: const byte* */ +byte *G_WriteOptions(byte *demo_p); // killough 3/1/98 +void G_PlayerReborn(int player); +void G_InitNew(skill_t skill, int episode, int map); +void G_RestartLevel(void); // CPhipps - menu involked level restart +void G_DoLoadGame(void); +void G_DoVictory(void); +void G_BuildTiccmd (ticcmd_t* cmd); // CPhipps - move decl to header +void G_ChangedPlayerColour(int pn, int cl); // CPhipps - On-the-fly player colour changing +void G_MakeSpecialEvent(buttoncode_t bc, ...); /* cph - new event stuff */ + +// killough 1/18/98: Doom-style printf; killough 4/25/98: add gcc attributes +// CPhipps - renames to doom_printf to avoid name collision with glibc +void doom_printf(const char *, ...) __attribute__((format(printf,1,2))); + +// killough 5/2/98: moved from m_misc.c: + +extern int key_right; +extern int key_left; +extern int key_up; +extern int key_down; +extern int key_menu_right; // phares 3/7/98 +extern int key_menu_left; // | +extern int key_menu_up; // V +extern int key_menu_down; +extern int key_menu_backspace; // ^ +extern int key_menu_escape; // | +extern int key_menu_enter; // phares 3/7/98 +extern int key_strafeleft; +extern int key_straferight; + +extern int key_fire; +extern int key_use; +extern int key_strafe; +extern int key_speed; +extern int key_escape; // phares +extern int key_savegame; // | +extern int key_loadgame; // V +extern int key_autorun; +extern int key_reverse; +extern int key_zoomin; +extern int key_zoomout; +extern int key_chat; +extern int key_backspace; +extern int key_enter; +extern int key_help; +extern int key_soundvolume; +extern int key_hud; +extern int key_quicksave; +extern int key_endgame; +extern int key_messages; +extern int key_quickload; +extern int key_quit; +extern int key_gamma; +extern int key_spy; +extern int key_pause; +extern int key_setup; +extern int key_forward; +extern int key_leftturn; +extern int key_rightturn; +extern int key_backward; +extern int key_weapon; +extern int key_weapontoggle; +extern int key_weapon1; +extern int key_weapon2; +extern int key_weapon3; +extern int key_weapon4; +extern int key_weapon5; +extern int key_weapon6; +extern int key_weapon7; +extern int key_weapon8; +extern int key_weapon9; +extern int destination_keys[MAXPLAYERS]; +extern int key_map_right; +extern int key_map_left; +extern int key_map_up; +extern int key_map_down; +extern int key_map_zoomin; +extern int key_map_zoomout; +extern int key_map; +extern int key_map_gobig; +extern int key_map_follow; +extern int key_map_mark; // ^ +extern int key_map_clear; // | +extern int key_map_grid; // phares +extern int key_map_rotate; // cph - map rotation +extern int key_map_overlay;// cph - map overlay +extern int key_screenshot; // killough 2/22/98 -- add key for screenshot +extern int autorun; // always running? // phares + +extern int joybfire; +extern int joybuse; +extern int joybstrafe; +extern int joybspeed; + +extern int mousebfire; +extern int mousebstrafe; +extern int mousebforward; + + +extern int defaultskill; //jff 3/24/98 default skill +extern boolean haswolflevels; //jff 4/18/98 wolf levels present + +extern int bodyquesize; // killough 2/8/98: adustable corpse limit + +// killough 5/2/98: moved from d_deh.c: +// Par times (new item with BOOM) - from g_game.c +extern int pars[4][10]; // hardcoded array size +extern int cpars[32]; // hardcoded array size +// CPhipps - Make savedesciption visible in wider scope +#define SAVEDESCLEN 32 +extern char savedescription[SAVEDESCLEN]; // Description to save in savegame + +/* cph - compatibility level strings */ +extern const char * comp_lev_str[]; + +#endif diff --git a/apps/plugins/doom/hu_lib.c b/apps/plugins/doom/hu_lib.c new file mode 100644 index 0000000000..2ac3d35dde --- /dev/null +++ b/apps/plugins/doom/hu_lib.c @@ -0,0 +1,770 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: heads-up text and input code + * + *----------------------------------------------------------------------------- + */ + +#include "doomdef.h" +#include "doomstat.h" +#include "v_video.h" +#include "m_swap.h" +#include "hu_lib.h" +#include "hu_stuff.h" +#include "r_main.h" +#include "r_draw.h" + +#include "rockmacros.h" + +// boolean : whether the screen is always erased +#define noterased viewwindowx + +extern int key_backspace; // phares +extern int key_enter; // phares + +// +// not used currently +// code to initialize HUlib would go here if needed +// +void HUlib_init(void) +{ +} + +//////////////////////////////////////////////////////// +// +// Basic text line widget +// +//////////////////////////////////////////////////////// + +// +// HUlib_clearTextLine() +// +// Blank the internal text line in a hu_textline_t widget +// +// Passed a hu_textline_t, returns nothing +// +void HUlib_clearTextLine(hu_textline_t* t) +{ + t->linelen = // killough 1/23 98: support multiple lines + t->len = 0; + t->l[0] = 0; + t->needsupdate = true; +} + +// +// HUlib_initTextLine() +// +// Initialize a hu_textline_t widget. Set the position, font, start char +// of the font, and color range to be used. +// +// Passed a hu_textline_t, and the values used to initialize +// Returns nothing +// +void HUlib_initTextLine(hu_textline_t* t, int x, int y, + const patchnum_t* f, int sc, int cm ) +//jff 2/16/98 add color range parameter +{ + t->x = x; + t->y = y; + t->f = f; + t->sc = sc; + t->cm = cm; + HUlib_clearTextLine(t); +} + +// +// HUlib_addCharToTextLine() +// +// Adds a character at the end of the text line in a hu_textline_t widget +// +// Passed the hu_textline_t and the char to add +// Returns false if already at length limit, true if the character added +// +boolean HUlib_addCharToTextLine +( hu_textline_t* t, + char ch ) +{ + // killough 1/23/98 -- support multiple lines + if (t->linelen == HU_MAXLINELENGTH) + return false; + else + { + t->linelen++; + if (ch == '\n') + t->linelen=0; + + t->l[t->len++] = ch; + t->l[t->len] = 0; + t->needsupdate = 4; + return true; + } + +} + +// +// HUlib_delCharFromTextLine() +// +// Deletes a character at the end of the text line in a hu_textline_t widget +// +// Passed the hu_textline_t +// Returns false if already empty, true if the character deleted +// +boolean HUlib_delCharFromTextLine(hu_textline_t* t) +{ + if (!t->len) return false; + else + { + t->l[--t->len] = 0; + t->needsupdate = 4; + return true; + } +} + +// +// HUlib_drawTextLine() +// +// Draws a hu_textline_t widget +// +// Passed the hu_textline_t and flag whether to draw a cursor +// Returns nothing +// +void HUlib_drawTextLine +( hu_textline_t* l, + boolean drawcursor ) +{ + + int i; + int w; + int x; + unsigned char c; + int oc = l->cm; //jff 2/17/98 remember default color + int y = l->y; // killough 1/18/98 -- support multiple lines + + // draw the new stuff + x = l->x; + for (i=0;ilen;i++) + { + c = toupper(l->l[i]); //jff insure were not getting a cheap toupper conv. + + if (c=='\n') // killough 1/18/98 -- support multiple lines + x=0,y+=8; + else if (c=='\t') // killough 1/23/98 -- support tab stops + x=x-x%80+80; + else if (c=='\x1b') //jff 2/17/98 escape code for color change + { //jff 3/26/98 changed to actual escape char + if (++ilen) + if (l->l[i]>='0' && l->l[i]<='9') + l->cm = l->l[i]-'0'; + } + else if (c != ' ' && c >= l->sc && c <= 127) + { + w = SHORT(l->f[c - l->sc].width); + if (x+w > BASE_WIDTH) + break; + // killough 1/18/98 -- support multiple lines: + // CPhipps - patch drawing updated + V_DrawNumPatch(x, y, FG, l->f[c - l->sc].lumpnum, l->cm, VPT_TRANS | VPT_STRETCH); + x += w; + } + else + { + x += 4; + if (x >= BASE_WIDTH) + break; + } + } + l->cm = oc; //jff 2/17/98 restore original color + + // draw the cursor if requested + if (drawcursor && x + SHORT(l->f['_' - l->sc].width) <= BASE_WIDTH) + { + // killough 1/18/98 -- support multiple lines + // CPhipps - patch drawing updated + V_DrawNumPatch(x, y, FG, l->f['_' - l->sc].lumpnum, CR_DEFAULT, VPT_NONE | VPT_STRETCH); + } +} + +// +// HUlib_eraseTextLine() +// +// Erases a hu_textline_t widget when screen border is behind text +// Sorta called by HU_Erase and just better darn get things straight +// +// Passed the hu_textline_t +// Returns nothing +// +void HUlib_eraseTextLine(hu_textline_t* l) +{ + int lh; + int y; + int yoffset; + + // Only erases when NOT in automap and the screen is reduced, + // and the text must either need updating or refreshing + // (because of a recent change back from the automap) + + if (!(automapmode & am_active) && viewwindowx && l->needsupdate) + { + lh = SHORT(l->f[0].height) + 1; + for (y=l->y,yoffset=y*SCREENWIDTH ; yy+lh ; y++,yoffset+=SCREENWIDTH) + { + if (y < viewwindowy || y >= viewwindowy + viewheight) + R_VideoErase(yoffset, SCREENWIDTH); // erase entire line + else + { + // erase left border + R_VideoErase(yoffset, viewwindowx); + // erase right border + R_VideoErase(yoffset + viewwindowx + viewwidth, viewwindowx); + } + } + } + + if (l->needsupdate) l->needsupdate--; +} + +//////////////////////////////////////////////////////// +// +// Player message widget (up to 4 lines of text) +// +//////////////////////////////////////////////////////// + +// +// HUlib_initSText() +// +// Initialize a hu_stext_t widget. Set the position, number of lines, font, +// start char of the font, and color range to be used, and whether enabled. +// +// Passed a hu_stext_t, and the values used to initialize +// Returns nothing +// +void HUlib_initSText +( hu_stext_t* s, + int x, + int y, + int h, + const patchnum_t* font, + int startchar, + int cm, //jff 2/16/98 add color range parameter + boolean* on ) +{ + + int i; + + s->h = h; + s->on = on; + s->laston = true; + s->cl = 0; + for (i=0;il[i], + x, + y - i*(SHORT(font[0].height)+1), + font, + startchar, + cm + ); +} + +// +// HUlib_addLineToSText() +// +// Adds a blank line to a hu_stext_t widget +// +// Passed a hu_stext_t +// Returns nothing +// +void HUlib_addLineToSText(hu_stext_t* s) +{ + + int i; + + // add a clear line + if (++s->cl == s->h) + s->cl = 0; + HUlib_clearTextLine(&s->l[s->cl]); + + // everything needs updating + for (i=0 ; ih ; i++) + s->l[i].needsupdate = 4; + +} + +// +// HUlib_addMessageToSText() +// +// Adds a message line with prefix to a hu_stext_t widget +// +// Passed a hu_stext_t, the prefix string, and a message string +// Returns nothing +// +void HUlib_addMessageToSText(hu_stext_t* s, const char* prefix, const char* msg) +{ + HUlib_addLineToSText(s); + if (prefix) + while (*prefix) + HUlib_addCharToTextLine(&s->l[s->cl], *(prefix++)); + + while (*msg) + HUlib_addCharToTextLine(&s->l[s->cl], *(msg++)); +} + +// +// HUlib_drawSText() +// +// Displays a hu_stext_t widget +// +// Passed a hu_stext_t +// Returns nothing +// +void HUlib_drawSText(hu_stext_t* s) +{ + int i, idx; + hu_textline_t *l; + + if (!*s->on) + return; // if not on, don't draw + + // draw everything + for (i=0 ; ih ; i++) + { + idx = s->cl - i; + if (idx < 0) + idx += s->h; // handle queue of lines + + l = &s->l[idx]; + + // need a decision made here on whether to skip the draw + HUlib_drawTextLine(l, false); // no cursor, please + } +} + +// +// HUlib_eraseSText() +// +// Erases a hu_stext_t widget, when the screen is not fullsize +// +// Passed a hu_stext_t +// Returns nothing +// +void HUlib_eraseSText(hu_stext_t* s) +{ + int i; + + for (i=0 ; ih ; i++) + { + if (s->laston && !*s->on) + s->l[i].needsupdate = 4; + HUlib_eraseTextLine(&s->l[i]); + } + s->laston = *s->on; +} + +//////////////////////////////////////////////////////// +// +// Scrolling message review widget +// +// jff added 2/26/98 +// +//////////////////////////////////////////////////////// + +// +// HUlib_initMText() +// +// Initialize a hu_mtext_t widget. Set the position, width, number of lines, +// font, start char of the font, color range, background font, and whether +// enabled. +// +// Passed a hu_mtext_t, and the values used to initialize +// Returns nothing +// +void HUlib_initMText(hu_mtext_t *m, int x, int y, int w, int h, + const patchnum_t* font, int startchar, int cm, + const patchnum_t* bgfont, boolean *on) +{ + int i; + + m->nl = 0; + m->nr = 0; + m->cl = -1; //jff 4/28/98 prepare for pre-increment + m->x = x; + m->y = y; + m->w = w; + m->h = h; + m->bg = bgfont; + m->on = on; + for (i=0;il[i], + x, + y + (hud_list_bgon? i+1 : i)*HU_REFRESHSPACING, + font, + startchar, + cm + ); + } +} + +// +// HUlib_addLineToMText() +// +// Adds a blank line to a hu_mtext_t widget +// +// Passed a hu_mtext_t +// Returns nothing +// +void HUlib_addLineToMText(hu_mtext_t* m) +{ + // add a clear line + if (++m->cl == hud_msg_lines) + m->cl = 0; + HUlib_clearTextLine(&m->l[m->cl]); + + if (m->nlnl++; + + // needs updating + m->l[m->cl].needsupdate = 4; +} + +// +// HUlib_addMessageToMText() +// +// Adds a message line with prefix to a hu_mtext_t widget +// +// Passed a hu_mtext_t, the prefix string, and a message string +// Returns nothing +// +void HUlib_addMessageToMText(hu_mtext_t* m, const char* prefix, const char* msg) +{ + HUlib_addLineToMText(m); + if (prefix) + while (*prefix) + HUlib_addCharToTextLine(&m->l[m->cl], *(prefix++)); + + while (*msg) + HUlib_addCharToTextLine(&m->l[m->cl], *(msg++)); +} + +// +// HUlib_drawMBg() +// +// Draws a background box which the message display review widget can +// display over +// +// Passed position, width, height, and the background patches +// Returns nothing +// +void HUlib_drawMBg +( int x, + int y, + int w, + int h, + const patchnum_t* bgp +) +{ + int xs = bgp[0].width; + int ys = bgp[0].height; + int i,j; + + // CPhipps - patch drawing updated + // top rows + V_DrawNumPatch(x, y, FG, bgp[0].lumpnum, CR_DEFAULT, VPT_STRETCH); // ul + for (j=x+xs;jon) + return; // if not on, don't draw + + // draw everything + if (hud_list_bgon) + HUlib_drawMBg(m->x,m->y,m->w,m->h,m->bg); + y = m->y + HU_REFRESHSPACING; + for (i=0 ; inl ; i++) + { + idx = m->cl - i; + if (idx < 0) + idx += m->nl; // handle queue of lines + + l = &m->l[idx]; + if (hud_list_bgon) + { + l->x = m->x + 4; + l->y = m->y + (i+1)*HU_REFRESHSPACING; + } + else + { + l->x = m->x; + l->y = m->y + i*HU_REFRESHSPACING; + } + + // need a decision made here on whether to skip the draw + HUlib_drawTextLine(l, false); // no cursor, please + } +} + +// +// HUlib_eraseMBg() +// +// Erases background behind hu_mtext_t widget, when the screen is not fullsize +// +// Passed a hu_mtext_t +// Returns nothing +// +static void HUlib_eraseMBg(hu_mtext_t* m) +{ + int lh; + int y; + int yoffset; + + // Only erases when NOT in automap and the screen is reduced, + // and the text must either need updating or refreshing + // (because of a recent change back from the automap) + + if (!(automapmode & am_active) && viewwindowx) + { + lh = SHORT(m->l[0].f[0].height) + 1; + for (y=m->y,yoffset=y*SCREENWIDTH ; yy+lh*(hud_msg_lines+2) ; y++,yoffset+=SCREENWIDTH) + { + if (y < viewwindowy || y >= viewwindowy + viewheight) + R_VideoErase(yoffset, SCREENWIDTH); // erase entire line + else + { + // erase left border + R_VideoErase(yoffset, viewwindowx); + // erase right border + R_VideoErase(yoffset + viewwindowx + viewwidth, viewwindowx); + + } + } + } +} + +// +// HUlib_eraseMText() +// +// Erases a hu_mtext_t widget, when the screen is not fullsize +// +// Passed a hu_mtext_t +// Returns nothing +// +void HUlib_eraseMText(hu_mtext_t* m) +{ + int i; + + if (hud_list_bgon) + HUlib_eraseMBg(m); + + for (i=0 ; i< m->nl ; i++) + { + m->l[i].needsupdate = 4; + HUlib_eraseTextLine(&m->l[i]); + } +} + +//////////////////////////////////////////////////////// +// +// Interactive text entry widget +// +//////////////////////////////////////////////////////// + +// +// HUlib_initIText() +// +// Initialize a hu_itext_t widget. Set the position, font, +// start char of the font, color range, and whether enabled. +// +// Passed a hu_itext_t, and the values used to initialize +// Returns nothing +// +void HUlib_initIText +( hu_itext_t* it, + int x, + int y, + const patchnum_t* font, + int startchar, + int cm, //jff 2/16/98 add color range parameter + boolean* on ) +{ + it->lm = 0; // default left margin is start of text + it->on = on; + it->laston = true; + HUlib_initTextLine(&it->l, x, y, font, startchar, cm); +} + +// The following deletion routines adhere to the left margin restriction + +// +// HUlib_delCharFromIText() +// +// Deletes a character at the end of the text line in a hu_itext_t widget +// +// Passed the hu_itext_t +// Returns nothing +// +void HUlib_delCharFromIText(hu_itext_t* it) +{ + if (it->l.len != it->lm) + HUlib_delCharFromTextLine(&it->l); +} + +// +// HUlib_eraseLineFromIText() +// +// Deletes all characters from a hu_itext_t widget +// +// Passed the hu_itext_t +// Returns nothing +// +void HUlib_eraseLineFromIText(hu_itext_t* it) +{ + while (it->lm != it->l.len) + HUlib_delCharFromTextLine(&it->l); +} + +// +// HUlib_resetIText() +// +// Deletes all characters from a hu_itext_t widget +// Resets left margin as well +// +// Passed the hu_itext_t +// Returns nothing +// +void HUlib_resetIText(hu_itext_t* it) +{ + it->lm = 0; + HUlib_clearTextLine(&it->l); +} + +// +// HUlib_addPrefixToIText() +// +// Adds a prefix string passed to a hu_itext_t widget +// Sets left margin to length of string added +// +// Passed the hu_itext_t and the prefix string +// Returns nothing +// +void HUlib_addPrefixToIText +( hu_itext_t* it, + char* str ) +{ + while (*str) + HUlib_addCharToTextLine(&it->l, *(str++)); + it->lm = it->l.len; +} + +// +// HUlib_keyInIText() +// +// Wrapper function for handling general keyed input. +// +// Passed the hu_itext_t and the char input +// Returns true if it ate the key +// +boolean HUlib_keyInIText +( hu_itext_t* it, + unsigned char ch ) +{ + + if (ch >= ' ' && ch <= '_') + HUlib_addCharToTextLine(&it->l, (char) ch); + else if (ch == key_backspace) // phares + HUlib_delCharFromIText(it); + else if (ch != key_enter) // phares + return false; // did not eat key + + return true; // ate the key +} + +// +// HUlib_drawIText() +// +// Displays a hu_itext_t widget +// +// Passed the hu_itext_t +// Returns nothing +// +void HUlib_drawIText(hu_itext_t* it) +{ + hu_textline_t *l = &it->l; + + if (!*it->on) + return; + HUlib_drawTextLine(l, true); // draw the line w/ cursor +} + +// +// HUlib_eraseIText() +// +// Erases a hu_itext_t widget when the screen is not fullsize +// +// Passed the hu_itext_t +// Returns nothing +// +void HUlib_eraseIText(hu_itext_t* it) +{ + if (it->laston && !*it->on) + it->l.needsupdate = 4; + HUlib_eraseTextLine(&it->l); + it->laston = *it->on; +} + diff --git a/apps/plugins/doom/hu_lib.h b/apps/plugins/doom/hu_lib.h new file mode 100644 index 0000000000..76d26bbb0f --- /dev/null +++ b/apps/plugins/doom/hu_lib.h @@ -0,0 +1,264 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: none + * + *-----------------------------------------------------------------------------*/ + +#ifndef __HULIB__ +#define __HULIB__ + +// We are referring to patches. +#include "r_defs.h" +#include "v_video.h" //jff 2/16/52 include color range defs + + +/* background and foreground screen numbers + * different from other modules. */ +#define BG 1 +#define FG 0 + +/* font stuff + * #define HU_CHARERASE KEYD_BACKSPACE / not used / phares + */ + +#define HU_MAXLINES 4 +#define HU_MAXLINELENGTH 80 +#define HU_REFRESHSPACING 8 /*jff 2/26/98 space lines in text refresh widget*/ +/*jff 2/26/98 maximum number of messages allowed in refresh list */ +#define HU_MAXMESSAGES 16 + +/* + * Typedefs of widgets + */ + +/* Text Line widget + * (parent of Scrolling Text and Input Text widgets) */ +typedef struct +{ + // left-justified position of scrolling text window + int x; + int y; + + const patchnum_t* f; // font + int sc; // start character + //const char *cr; //jff 2/16/52 output color range + // Proff - Made this an int again. Needed for OpenGL + int cm; //jff 2/16/52 output color range + + // killough 1/23/98: Support multiple lines: + #define MAXLINES 25 + + int linelen; + char l[HU_MAXLINELENGTH*MAXLINES+1]; // line of text + int len; // current line length + + // whether this line needs to be udpated + int needsupdate; + +} hu_textline_t; + + + +// Scrolling Text window widget +// (child of Text Line widget) +typedef struct +{ + hu_textline_t l[HU_MAXLINES]; // text lines to draw + int h; // height in lines + int cl; // current line number + + // pointer to boolean stating whether to update window + boolean* on; + boolean laston; // last value of *->on. + +} hu_stext_t; + +//jff 2/26/98 new widget to display last hud_msg_lines of messages +// Message refresh window widget +typedef struct +{ + hu_textline_t l[HU_MAXMESSAGES]; // text lines to draw + int nl; // height in lines + int nr; // total height in rows + int cl; // current line number + + int x,y,w,h; // window position and size + const patchnum_t *bg; // patches for background + + // pointer to boolean stating whether to update window + boolean* on; + boolean laston; // last value of *->on. + +} hu_mtext_t; + + + +// Input Text Line widget +// (child of Text Line widget) +typedef struct +{ + hu_textline_t l; // text line to input on + + // left margin past which I am not to delete characters + int lm; + + // pointer to boolean stating whether to update window + boolean* on; + boolean laston; // last value of *->on; + +} hu_itext_t; + + +// +// Widget creation, access, and update routines +// + +// initializes heads-up widget library +void HUlib_init(void); + +// +// textline code +// + +// clear a line of text +void HUlib_clearTextLine(hu_textline_t *t); + +void HUlib_initTextLine +( + hu_textline_t *t, + int x, + int y, + const patchnum_t *f, + int sc, + int cm //jff 2/16/98 add color range parameter +); + +// returns success +boolean HUlib_addCharToTextLine(hu_textline_t *t, char ch); + +// returns success +boolean HUlib_delCharFromTextLine(hu_textline_t *t); + +// draws tline +void HUlib_drawTextLine(hu_textline_t *l, boolean drawcursor); + +// erases text line +void HUlib_eraseTextLine(hu_textline_t *l); + + +// +// Scrolling Text window widget routines +// + +// initialize an stext widget +void HUlib_initSText +( hu_stext_t* s, + int x, + int y, + int h, + const patchnum_t* font, + int startchar, + int cm, //jff 2/16/98 add color range parameter + boolean* on ); + +// add a new line +void HUlib_addLineToSText(hu_stext_t* s); + +// add a text message to an stext widget +void HUlib_addMessageToSText(hu_stext_t* s, const char* prefix, const char* msg); + +// draws stext +void HUlib_drawSText(hu_stext_t* s); + +// erases all stext lines +void HUlib_eraseSText(hu_stext_t* s); + +//jff 2/26/98 message refresh widget +// initialize refresh text widget +void HUlib_initMText(hu_mtext_t *m, int x, int y, int w, int h, const patchnum_t* font, + int startchar, int cm, const patchnum_t* bgfont, boolean *on); + +//jff 2/26/98 message refresh widget +// add a text line to refresh text widget +void HUlib_addLineToMText( hu_mtext_t* m ); + +//jff 2/26/98 message refresh widget +// add a text message to refresh text widget +void HUlib_addMessageToMText(hu_mtext_t* m, const char* prefix, const char* msg); + +//jff 2/26/98 new routine to display a background on which +// the list of last hud_msg_lines are displayed +void HUlib_drawMBg +( int x, + int y, + int w, + int h, + const patchnum_t* bgp +); + +//jff 2/26/98 message refresh widget +// draws mtext +void HUlib_drawMText(hu_mtext_t* m); + +//jff 4/28/98 erases behind message list +void HUlib_eraseMText(hu_mtext_t* m); + +// Input Text Line widget routines +void HUlib_initIText +( hu_itext_t* it, + int x, + int y, + const patchnum_t* font, + int startchar, + int cm, //jff 2/16/98 add color range parameter + boolean* on ); + +// enforces left margin +void HUlib_delCharFromIText(hu_itext_t* it); + +// enforces left margin +void HUlib_eraseLineFromIText(hu_itext_t* it); + +// resets line and left margin +void HUlib_resetIText(hu_itext_t* it); + +// left of left-margin +void HUlib_addPrefixToIText +( hu_itext_t* it, + char* str ); + +// whether eaten +boolean HUlib_keyInIText +( hu_itext_t* it, + unsigned char ch ); + +void HUlib_drawIText(hu_itext_t* it); + +// erases all itext lines +void HUlib_eraseIText(hu_itext_t* it); + +#endif diff --git a/apps/plugins/doom/hu_stuff.c b/apps/plugins/doom/hu_stuff.c new file mode 100644 index 0000000000..fd7bd0d4f4 --- /dev/null +++ b/apps/plugins/doom/hu_stuff.c @@ -0,0 +1,1753 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: Heads-up displays + * + *----------------------------------------------------------------------------- + */ + +// killough 5/3/98: remove unnecessary headers + +#include "doomstat.h" +#include "hu_stuff.h" +#include "hu_lib.h" +#include "st_stuff.h" /* jff 2/16/98 need loc of status bar */ +#include "w_wad.h" +#include "s_sound.h" +#include "dstrings.h" +#include "sounds.h" +//#include "d_deh.h" /* Ty 03/27/98 - externalization of mapnamesx arrays */ +#include "g_game.h" +#include "m_swap.h" + +// global heads up display controls + +int hud_active; //jff 2/17/98 controls heads-up display mode +int hud_displayed; //jff 2/23/98 turns heads-up display on/off +int hud_nosecrets; //jff 2/18/98 allows secrets line to be disabled in HUD +int hud_distributed; //jff 3/4/98 display HUD in different places on screen +int hud_graph_keys=1; //jff 3/7/98 display HUD keys as graphics + +// +// Locally used constants, shortcuts. +// +// Ty 03/28/98 - +// These four shortcuts modifed to reflect char ** of mapnamesx[] +#define HU_TITLE (mapnames[(gameepisode-1)*9+gamemap-1]) +#define HU_TITLE2 (mapnames2[gamemap-1]) +#define HU_TITLEP (mapnamesp[gamemap-1]) +#define HU_TITLET (mapnamest[gamemap-1]) +#define HU_TITLEHEIGHT 1 +#define HU_TITLEX 0 +//jff 2/16/98 change 167 to ST_Y-1 +// CPhipps - changed to ST_TY +// proff - changed to 200-ST_HEIGHT for stretching +#define HU_TITLEY ((200-ST_HEIGHT) - 1 - SHORT(hu_font[0].height)) + +//jff 2/16/98 add coord text widget coordinates +// proff - changed to SCREENWIDTH to 320 for stretching +#define HU_COORDX (320 - 13*SHORT(hu_font2['A'-HU_FONTSTART].width)) +//jff 3/3/98 split coord widget into three lines in upper right of screen +#define HU_COORDX_Y (1 + 0*SHORT(hu_font['A'-HU_FONTSTART].height)) +#define HU_COORDY_Y (2 + 1*SHORT(hu_font['A'-HU_FONTSTART].height)) +#define HU_COORDZ_Y (3 + 2*SHORT(hu_font['A'-HU_FONTSTART].height)) + +//jff 2/16/98 add ammo, health, armor widgets, 2/22/98 less gap +#define HU_GAPY 8 +#define HU_HUDHEIGHT (6*HU_GAPY) +#define HU_HUDX 2 +#define HU_HUDY (200-HU_HUDHEIGHT-1) +#define HU_MONSECX (HU_HUDX) +#define HU_MONSECY (HU_HUDY+0*HU_GAPY) +#define HU_KEYSX (HU_HUDX) +//jff 3/7/98 add offset for graphic key widget +#define HU_KEYSGX (HU_HUDX+4*SHORT(hu_font2['A'-HU_FONTSTART].width)) +#define HU_KEYSY (HU_HUDY+1*HU_GAPY) +#define HU_WEAPX (HU_HUDX) +#define HU_WEAPY (HU_HUDY+2*HU_GAPY) +#define HU_AMMOX (HU_HUDX) +#define HU_AMMOY (HU_HUDY+3*HU_GAPY) +#define HU_HEALTHX (HU_HUDX) +#define HU_HEALTHY (HU_HUDY+4*HU_GAPY) +#define HU_ARMORX (HU_HUDX) +#define HU_ARMORY (HU_HUDY+5*HU_GAPY) + +//jff 3/4/98 distributed HUD positions +#define HU_HUDX_LL 2 +#define HU_HUDY_LL (200-2*HU_GAPY-1) +// proff/nicolas 09/20/98: Changed for high-res +#define HU_HUDX_LR (320-120) +#define HU_HUDY_LR (200-2*HU_GAPY-1) +// proff/nicolas 09/20/98: Changed for high-res +#define HU_HUDX_UR (320-96) +#define HU_HUDY_UR 2 +#define HU_MONSECX_D (HU_HUDX_LL) +#define HU_MONSECY_D (HU_HUDY_LL+0*HU_GAPY) +#define HU_KEYSX_D (HU_HUDX_LL) +#define HU_KEYSGX_D (HU_HUDX_LL+4*SHORT(hu_font2['A'-HU_FONTSTART].width)) +#define HU_KEYSY_D (HU_HUDY_LL+1*HU_GAPY) +#define HU_WEAPX_D (HU_HUDX_LR) +#define HU_WEAPY_D (HU_HUDY_LR+0*HU_GAPY) +#define HU_AMMOX_D (HU_HUDX_LR) +#define HU_AMMOY_D (HU_HUDY_LR+1*HU_GAPY) +#define HU_HEALTHX_D (HU_HUDX_UR) +#define HU_HEALTHY_D (HU_HUDY_UR+0*HU_GAPY) +#define HU_ARMORX_D (HU_HUDX_UR) +#define HU_ARMORY_D (HU_HUDY_UR+1*HU_GAPY) + +//#define HU_INPUTTOGGLE 't' // not used // phares +#define HU_INPUTX HU_MSGX +#define HU_INPUTY (HU_MSGY + HU_MSGHEIGHT*(SHORT(hu_font[0].height) +1)) +#define HU_INPUTWIDTH 64 +#define HU_INPUTHEIGHT 1 + +#define key_alt KEY_RALT +#define key_shift KEY_RSHIFT + +const char* chat_macros[] = + // Ty 03/27/98 - *not* externalized + // CPhipps - const char* + { + HUSTR_CHATMACRO0, + HUSTR_CHATMACRO1, + HUSTR_CHATMACRO2, + HUSTR_CHATMACRO3, + HUSTR_CHATMACRO4, + HUSTR_CHATMACRO5, + HUSTR_CHATMACRO6, + HUSTR_CHATMACRO7, + HUSTR_CHATMACRO8, + HUSTR_CHATMACRO9 + }; + +const char* player_names[] = + // Ty 03/27/98 - *not* externalized + // CPhipps - const char* + { + HUSTR_PLRGREEN, + HUSTR_PLRINDIGO, + HUSTR_PLRBROWN, + HUSTR_PLRRED + }; + +//jff 3/17/98 translate player colmap to text color ranges +int plyrcoltran[MAXPLAYERS]={CR_GREEN,CR_GRAY,CR_BROWN,CR_RED}; + +char chat_char; // remove later. +static player_t* plr; + +// font sets +patchnum_t hu_font[HU_FONTSIZE]; +patchnum_t hu_font2[HU_FONTSIZE]; +patchnum_t hu_fontk[HU_FONTSIZE];//jff 3/7/98 added for graphic key indicators +patchnum_t hu_msgbg[9]; //jff 2/26/98 add patches for message background + +// widgets +static hu_textline_t w_title; +static hu_stext_t w_message; +static hu_itext_t w_chat; +static hu_itext_t w_inputbuffer[MAXPLAYERS]; +static hu_textline_t w_coordx; //jff 2/16/98 new coord widget for automap +static hu_textline_t w_coordy; //jff 3/3/98 split coord widgets automap +static hu_textline_t w_coordz; //jff 3/3/98 split coord widgets automap +static hu_textline_t w_ammo; //jff 2/16/98 new ammo widget for hud +static hu_textline_t w_health; //jff 2/16/98 new health widget for hud +static hu_textline_t w_armor; //jff 2/16/98 new armor widget for hud +static hu_textline_t w_weapon; //jff 2/16/98 new weapon widget for hud +static hu_textline_t w_keys; //jff 2/16/98 new keys widget for hud +static hu_textline_t w_gkeys; //jff 3/7/98 graphic keys widget for hud +static hu_textline_t w_monsec; //jff 2/16/98 new kill/secret widget for hud +static hu_mtext_t w_rtext; //jff 2/26/98 text message refresh widget + +static boolean always_off = false; +static char chat_dest[MAXPLAYERS]; +boolean chat_on; +static boolean message_on; +static boolean message_list; //2/26/98 enable showing list of messages +boolean message_dontfuckwithme; +static boolean message_nottobefuckedwith; +static int message_counter; +extern int showMessages; +extern boolean automapactive; +static boolean headsupactive = false; + +//jff 2/16/98 hud supported automap colors added +int hudcolor_titl; // color range of automap level title +int hudcolor_xyco; // color range of new coords on automap +//jff 2/16/98 hud text colors, controls added +int hudcolor_mesg; // color range of scrolling messages +int hudcolor_chat; // color range of chat lines +int hud_msg_lines; // number of message lines in window +//jff 2/26/98 hud text colors, controls added +int hudcolor_list; // list of messages color +int hud_list_bgon; // enable for solid window background for message list + +//jff 2/16/98 initialization strings for ammo, health, armor widgets +static char hud_coordstrx[32]; +static char hud_coordstry[32]; +static char hud_coordstrz[32]; +static char hud_ammostr[80]; +static char hud_healthstr[80]; +static char hud_armorstr[80]; +static char hud_weapstr[80]; +static char hud_keysstr[80]; +static char hud_gkeysstr[80]; //jff 3/7/98 add support for graphic key display +static char hud_monsecstr[80]; + +//jff 2/16/98 declaration of color switch points +extern int ammo_red; +extern int ammo_yellow; +extern int health_red; +extern int health_yellow; +extern int health_green; +extern int armor_red; +extern int armor_yellow; +extern int armor_green; + +// +// Builtin map names. +// The actual names can be found in DStrings.h. +// +// Ty 03/27/98 - externalized map name arrays - now in d_deh.c +// and converted to arrays of pointers to char * +// See modified HUTITLEx macros +char* mapnames[] = // DOOM shareware/registered/retail (Ultimate) names. + { + + HUSTR_E1M1, + HUSTR_E1M2, + HUSTR_E1M3, + HUSTR_E1M4, + HUSTR_E1M5, + HUSTR_E1M6, + HUSTR_E1M7, + HUSTR_E1M8, + HUSTR_E1M9, + + HUSTR_E2M1, + HUSTR_E2M2, + HUSTR_E2M3, + HUSTR_E2M4, + HUSTR_E2M5, + HUSTR_E2M6, + HUSTR_E2M7, + HUSTR_E2M8, + HUSTR_E2M9, + + HUSTR_E3M1, + HUSTR_E3M2, + HUSTR_E3M3, + HUSTR_E3M4, + HUSTR_E3M5, + HUSTR_E3M6, + HUSTR_E3M7, + HUSTR_E3M8, + HUSTR_E3M9, + + HUSTR_E4M1, + HUSTR_E4M2, + HUSTR_E4M3, + HUSTR_E4M4, + HUSTR_E4M5, + HUSTR_E4M6, + HUSTR_E4M7, + HUSTR_E4M8, + HUSTR_E4M9, + + "NEWLEVEL", + "NEWLEVEL", + "NEWLEVEL", + "NEWLEVEL", + "NEWLEVEL", + "NEWLEVEL", + "NEWLEVEL", + "NEWLEVEL", + "NEWLEVEL" + }; + +char* mapnames2[] = // DOOM 2 map names. + { + HUSTR_1, + HUSTR_2, + HUSTR_3, + HUSTR_4, + HUSTR_5, + HUSTR_6, + HUSTR_7, + HUSTR_8, + HUSTR_9, + HUSTR_10, + HUSTR_11, + + HUSTR_12, + HUSTR_13, + HUSTR_14, + HUSTR_15, + HUSTR_16, + HUSTR_17, + HUSTR_18, + HUSTR_19, + HUSTR_20, + + HUSTR_21, + HUSTR_22, + HUSTR_23, + HUSTR_24, + HUSTR_25, + HUSTR_26, + HUSTR_27, + HUSTR_28, + HUSTR_29, + HUSTR_30, + HUSTR_31, + HUSTR_32 + }; + + +char* mapnamesp[] = // Plutonia WAD map names. + { + PHUSTR_1, + PHUSTR_2, + PHUSTR_3, + PHUSTR_4, + PHUSTR_5, + PHUSTR_6, + PHUSTR_7, + PHUSTR_8, + PHUSTR_9, + PHUSTR_10, + PHUSTR_11, + + PHUSTR_12, + PHUSTR_13, + PHUSTR_14, + PHUSTR_15, + PHUSTR_16, + PHUSTR_17, + PHUSTR_18, + PHUSTR_19, + PHUSTR_20, + + PHUSTR_21, + PHUSTR_22, + PHUSTR_23, + PHUSTR_24, + PHUSTR_25, + PHUSTR_26, + PHUSTR_27, + PHUSTR_28, + PHUSTR_29, + PHUSTR_30, + PHUSTR_31, + PHUSTR_32 + }; + + +char *mapnamest[] = // TNT WAD map names. + { + THUSTR_1, + THUSTR_2, + THUSTR_3, + THUSTR_4, + THUSTR_5, + THUSTR_6, + THUSTR_7, + THUSTR_8, + THUSTR_9, + THUSTR_10, + THUSTR_11, + + THUSTR_12, + THUSTR_13, + THUSTR_14, + THUSTR_15, + THUSTR_16, + THUSTR_17, + THUSTR_18, + THUSTR_19, + THUSTR_20, + + THUSTR_21, + THUSTR_22, + THUSTR_23, + THUSTR_24, + THUSTR_25, + THUSTR_26, + THUSTR_27, + THUSTR_28, + THUSTR_29, + THUSTR_30, + THUSTR_31, + THUSTR_32 + }; + +// key tables +// jff 5/10/98 french support removed, +// as it was not being used and couldn't be easily tested +// +const char* shiftxform; + +const char english_shiftxform[] = + { + 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, + ' ', '!', '"', '#', '$', '%', '&', + '"', // shift-' + '(', ')', '*', '+', + '<', // shift-, + '_', // shift-- + '>', // shift-. + '?', // shift-/ + ')', // shift-0 + '!', // shift-1 + '@', // shift-2 + '#', // shift-3 + '$', // shift-4 + '%', // shift-5 + '^', // shift-6 + '&', // shift-7 + '*', // shift-8 + '(', // shift-9 + ':', + ':', // shift-; + '<', + '+', // shift-= + '>', '?', '@', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', + 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + '[', // shift-[ + '!', // shift-backslash - OH MY GOD DOES WATCOM SUCK + ']', // shift-] + '"', '_', + '\'', // shift-` + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', + 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + '{', '|', '}', '~', 127 + }; + +// +// HU_Init() +// +// Initialize the heads-up display, text that overwrites the primary display +// +// Passed nothing, returns nothing +// +void HU_Init(void) +{ + int i; + int j; + char buffer[9]; + + shiftxform = english_shiftxform; + + // load the heads-up font + j = HU_FONTSTART; + for (i=0;i0?"0":"00"), j); //NOTE ROCKHACK: "STCFN%.3d" + R_SetPatchNum(&hu_font[i], buffer); + } + else if ('A'<=j && j<='Z') + { + snprintf(buffer, sizeof(buffer), "DIG%c",j); + R_SetPatchNum(&hu_font2[i], buffer); + snprintf(buffer, sizeof(buffer), "STCFN%s%d", (j/10>0?"0":"00"), j); //NOTE ROCKHACK: "STCFN%.3d" + R_SetPatchNum(&hu_font[i], buffer); + } + else if (j=='-') + { + R_SetPatchNum(&hu_font2[i], "DIG45"); + R_SetPatchNum(&hu_font[i], "STCFN045"); + } + else if (j=='/') + { + R_SetPatchNum(&hu_font2[i], "DIG47"); + R_SetPatchNum(&hu_font[i], "STCFN047"); + } + else if (j==':') + { + R_SetPatchNum(&hu_font2[i], "DIG58"); + R_SetPatchNum(&hu_font[i], "STCFN058"); + } + else if (j=='[') + { + R_SetPatchNum(&hu_font2[i], "DIG91"); + R_SetPatchNum(&hu_font[i], "STCFN091"); + } + else if (j==']') + { + R_SetPatchNum(&hu_font2[i], "DIG93"); + R_SetPatchNum(&hu_font[i], "STCFN093"); + } + else if (j<97) + { + snprintf(buffer, sizeof(buffer), "STCFN%s%d", (j/10>0?"0":"00"), j); //NOTE ROCKHACK: "STCFN%.3d" + R_SetPatchNum(&hu_font2[i], buffer); + R_SetPatchNum(&hu_font[i], buffer); + //jff 2/23/98 make all font chars defined, useful or not + } + else if (j>122) + { + snprintf(buffer, sizeof(buffer), "STBR%d", j); //NOTE: "STBR%.3d" + R_SetPatchNum(&hu_font2[i], buffer); + R_SetPatchNum(&hu_font[i], buffer); + } + else + hu_font[i] = hu_font[0]; //jff 2/16/98 account for gap + } + + // CPhipps - load patches for message background + for (i=0; i<9; i++) { + snprintf(buffer, sizeof(buffer), "BOX%c%c", "UCL"[i/3], "LCR"[i%3]); + R_SetPatchNum(&hu_msgbg[i], buffer); + } + + // CPhipps - load patches for keys and double keys + for (i=0; i<6; i++) { + snprintf(buffer, sizeof(buffer), "STKEYS%d", i); + R_SetPatchNum(&hu_fontk[i], buffer); + } +} + +// +// HU_Stop() +// +// Make the heads-up displays inactive +// +// Passed nothing, returns nothing +// +void HU_Stop(void) +{ + headsupactive = false; +} + +// +// HU_Start(void) +// +// Create and initialize the heads-up widgets, software machines to +// maintain, update, and display information over the primary display +// +// This routine must be called after any change to the heads up configuration +// in order for the changes to take effect in the actual displays +// +// Passed nothing, returns nothing +// +void HU_Start(void) +{ + + int i; + const char* s; /* cph - const */ + + if (headsupactive) // stop before starting + HU_Stop(); + + plr = &players[displayplayer]; // killough 3/7/98 + message_on = false; + message_dontfuckwithme = false; + message_nottobefuckedwith = false; + chat_on = false; + + // create the message widget + // messages to player in upper-left of screen + HUlib_initSText + ( + &w_message, + HU_MSGX, + HU_MSGY, + HU_MSGHEIGHT, + hu_font, + HU_FONTSTART, + hudcolor_mesg, + &message_on + ); + + //jff 2/16/98 added some HUD widgets + // create the map title widget - map title display in lower left of automap + HUlib_initTextLine + ( + &w_title, + HU_TITLEX, + HU_TITLEY, + hu_font, + HU_FONTSTART, + hudcolor_titl + ); + + // create the hud health widget + // bargraph and number for amount of health, + // lower left or upper right of screen + HUlib_initTextLine + ( + &w_health, + hud_distributed? HU_HEALTHX_D : HU_HEALTHX, //3/4/98 distribute + hud_distributed? HU_HEALTHY_D : HU_HEALTHY, + hu_font2, + HU_FONTSTART, + CR_GREEN + ); + + // create the hud armor widget + // bargraph and number for amount of armor, + // lower left or upper right of screen + HUlib_initTextLine + ( + &w_armor, + hud_distributed? HU_ARMORX_D : HU_ARMORX, //3/4/98 distribute + hud_distributed? HU_ARMORY_D : HU_ARMORY, + hu_font2, + HU_FONTSTART, + CR_GREEN + ); + + // create the hud ammo widget + // bargraph and number for amount of ammo for current weapon, + // lower left or lower right of screen + HUlib_initTextLine + ( + &w_ammo, + hud_distributed? HU_AMMOX_D : HU_AMMOX, //3/4/98 distribute + hud_distributed? HU_AMMOY_D : HU_AMMOY, + hu_font2, + HU_FONTSTART, + CR_GOLD + ); + + // create the hud weapons widget + // list of numbers of weapons possessed + // lower left or lower right of screen + HUlib_initTextLine + ( + &w_weapon, + hud_distributed? HU_WEAPX_D : HU_WEAPX, //3/4/98 distribute + hud_distributed? HU_WEAPY_D : HU_WEAPY, + hu_font2, + HU_FONTSTART, + CR_GRAY + ); + + // create the hud keys widget + // display of key letters possessed + // lower left of screen + HUlib_initTextLine + ( + &w_keys, + hud_distributed? HU_KEYSX_D : HU_KEYSX, //3/4/98 distribute + hud_distributed? HU_KEYSY_D : HU_KEYSY, + hu_font2, + HU_FONTSTART, + CR_GRAY + ); + + // create the hud graphic keys widget + // display of key graphics possessed + // lower left of screen + HUlib_initTextLine + ( + &w_gkeys, + hud_distributed? HU_KEYSGX_D : HU_KEYSGX, //3/4/98 distribute + hud_distributed? HU_KEYSY_D : HU_KEYSY, + hu_fontk, + HU_FONTSTART, + CR_RED + ); + + // create the hud monster/secret widget + // totals and current values for kills, items, secrets + // lower left of screen + HUlib_initTextLine + ( + &w_monsec, + hud_distributed? HU_MONSECX_D : HU_MONSECX, //3/4/98 distribute + hud_distributed? HU_MONSECY_D : HU_MONSECY, + hu_font2, + HU_FONTSTART, + CR_GRAY + ); + + // create the hud text refresh widget + // scrolling display of last hud_msg_lines messages received + if (hud_msg_lines>HU_MAXMESSAGES) + hud_msg_lines=HU_MAXMESSAGES; + //jff 4/21/98 if setup has disabled message list while active, turn it off + message_list = hud_msg_lines > 1; //jff 8/8/98 initialize both ways + //jff 2/26/98 add the text refresh widget initialization + HUlib_initMText + ( + &w_rtext, + 0, + 0, + 320, + // SCREENWIDTH, + (hud_msg_lines+2)*HU_REFRESHSPACING, + hu_font, + HU_FONTSTART, + hudcolor_list, + hu_msgbg, + &message_list + ); + + // initialize the automap's level title widget + if (gamestate == GS_LEVEL) /* cph - stop SEGV here when not in level */ + switch (gamemode) + { + case shareware: + case registered: + case retail: + s = HU_TITLE; + break; + + case commercial: + default: // Ty 08/27/98 - modified to check mission for TNT/Plutonia + s = (gamemission==pack_tnt) ? HU_TITLET : + (gamemission==pack_plut) ? HU_TITLEP : HU_TITLE2; + break; + } else s = ""; + while (*s) + HUlib_addCharToTextLine(&w_title, *(s++)); + + // create the automaps coordinate widget + // jff 3/3/98 split coord widget into three lines: x,y,z + // jff 2/16/98 added + HUlib_initTextLine + ( + &w_coordx, + HU_COORDX, + HU_COORDX_Y, + hu_font, + HU_FONTSTART, + hudcolor_xyco + ); + HUlib_initTextLine + ( + &w_coordy, + HU_COORDX, + HU_COORDY_Y, + hu_font, + HU_FONTSTART, + hudcolor_xyco + ); + HUlib_initTextLine + ( + &w_coordz, + HU_COORDX, + HU_COORDZ_Y, + hu_font, + HU_FONTSTART, + hudcolor_xyco + ); + + // initialize the automaps coordinate widget + //jff 3/3/98 split coordstr widget into 3 parts + snprintf(hud_coordstrx,sizeof(hud_coordstrx),"X: %-5d",0); //jff 2/22/98 added z + s = hud_coordstrx; + while (*s) + HUlib_addCharToTextLine(&w_coordx, *(s++)); + snprintf(hud_coordstry,sizeof(hud_coordstry),"Y: %-5d",0); //jff 3/3/98 split x,y,z + s = hud_coordstry; + while (*s) + HUlib_addCharToTextLine(&w_coordy, *(s++)); + snprintf(hud_coordstrz,sizeof(hud_coordstrz),"Z: %-5d",0); //jff 3/3/98 split x,y,z + s = hud_coordstrz; + while (*s) + HUlib_addCharToTextLine(&w_coordz, *(s++)); + + //jff 2/16/98 initialize ammo widget + strcpy(hud_ammostr,"AMM "); + s = hud_ammostr; + while (*s) + HUlib_addCharToTextLine(&w_ammo, *(s++)); + + //jff 2/16/98 initialize health widget + strcpy(hud_healthstr,"HEL "); + s = hud_healthstr; + while (*s) + HUlib_addCharToTextLine(&w_health, *(s++)); + + //jff 2/16/98 initialize armor widget + strcpy(hud_armorstr,"ARM "); + s = hud_armorstr; + while (*s) + HUlib_addCharToTextLine(&w_armor, *(s++)); + + //jff 2/17/98 initialize weapons widget + strcpy(hud_weapstr,"WEA "); + s = hud_weapstr; + while (*s) + HUlib_addCharToTextLine(&w_weapon, *(s++)); + + //jff 2/17/98 initialize keys widget + if (!deathmatch) //jff 3/17/98 show frags in deathmatch mode + strcpy(hud_keysstr,"KEY "); + else + strcpy(hud_keysstr,"FRG "); + s = hud_keysstr; + while (*s) + HUlib_addCharToTextLine(&w_keys, *(s++)); + + //jff 2/17/98 initialize graphic keys widget + strcpy(hud_gkeysstr," "); + s = hud_gkeysstr; + while (*s) + HUlib_addCharToTextLine(&w_gkeys, *(s++)); + + //jff 2/17/98 initialize kills/items/secret widget + strcpy(hud_monsecstr,"STS "); + s = hud_monsecstr; + while (*s) + HUlib_addCharToTextLine(&w_monsec, *(s++)); + + // create the chat widget + HUlib_initIText + ( + &w_chat, + HU_INPUTX, + HU_INPUTY, + hu_font, + HU_FONTSTART, + hudcolor_chat, + &chat_on + ); + + // create the inputbuffer widgets, one per player + for (i=0 ; imo->x)>>FRACBITS); + HUlib_clearTextLine(&w_coordx); + s = hud_coordstrx; + while (*s) + HUlib_addCharToTextLine(&w_coordx, *(s++)); + HUlib_drawTextLine(&w_coordx, false); + + //jff 3/3/98 split coord display into x,y,z lines + // y-coord + snprintf(hud_coordstry,sizeof(hud_coordstry),"Y: %-5d", (plr->mo->y)>>FRACBITS); + HUlib_clearTextLine(&w_coordy); + s = hud_coordstry; + while (*s) + HUlib_addCharToTextLine(&w_coordy, *(s++)); + HUlib_drawTextLine(&w_coordy, false); + + //jff 3/3/98 split coord display into x,y,z lines + //jff 2/22/98 added z + // z-coord + snprintf(hud_coordstrz,sizeof(hud_coordstrz),"Z: %-5d", (plr->mo->z)>>FRACBITS); + HUlib_clearTextLine(&w_coordz); + s = hud_coordstrz; + while (*s) + HUlib_addCharToTextLine(&w_coordz, *(s++)); + HUlib_drawTextLine(&w_coordz, false); + } + + // draw the weapon/health/ammo/armor/kills/keys displays if optioned + //jff 2/17/98 allow new hud stuff to be turned off + // killough 2/21/98: really allow new hud stuff to be turned off COMPLETELY + if + ( + hud_active>0 && // hud optioned on + hud_displayed && // hud on from fullscreen key + viewheight==SCREENHEIGHT && // fullscreen mode is active + !(automapmode & am_active) // automap is not active + ) + { + doit = !(gametic&1); //jff 3/4/98 speed update up for slow systems + if (doit) //jff 8/7/98 update every time, avoid lag in update + { + HU_MoveHud(); // insure HUD display coords are correct + + // do the hud ammo display + // clear the widgets internal line + HUlib_clearTextLine(&w_ammo); + strcpy(hud_ammostr,"AMM "); + if (weaponinfo[plr->readyweapon].ammo == am_noammo) + { // special case for weapon with no ammo selected - blank bargraph + N/A + strcat(hud_ammostr,"\x7f\x7f\x7f\x7f\x7f\x7f\x7f N/A"); + w_ammo.cm = CR_GRAY; + } + else + { + int ammo = plr->ammo[weaponinfo[plr->readyweapon].ammo]; + int fullammo = plr->maxammo[weaponinfo[plr->readyweapon].ammo]; + int ammopct = (100*ammo)/fullammo; + int ammobars = ammopct/4; + + // build the numeric amount init string + snprintf(ammostr,sizeof(ammostr),"%d/%d",ammo,fullammo); + // build the bargraph string + // full bargraph chars + for (i=4;i<4+ammobars/4;) + hud_ammostr[i++] = 123; + // plus one last character with 0,1,2,3 bars + switch(ammobars%4) + { + case 0: + break; + case 1: + hud_ammostr[i++] = 126; + break; + case 2: + hud_ammostr[i++] = 125; + break; + case 3: + hud_ammostr[i++] = 124; + break; + } + // pad string with blank bar characters + while(i<4+7) + hud_ammostr[i++] = 127; + hud_ammostr[i] = '\0'; + strcat(hud_ammostr,ammostr); + + // set the display color from the percentage of total ammo held + if (ammopcthealth; + int healthbars = health>100? 25 : health/4; + + // clear the widgets internal line + HUlib_clearTextLine(&w_health); + + // build the numeric amount init string + snprintf(healthstr,sizeof(healthstr),"%3d",health); + // build the bargraph string + // full bargraph chars + for (i=4;i<4+healthbars/4;) + hud_healthstr[i++] = 123; + // plus one last character with 0,1,2,3 bars + switch(healthbars%4) + { + case 0: + break; + case 1: + hud_healthstr[i++] = 126; + break; + case 2: + hud_healthstr[i++] = 125; + break; + case 3: + hud_healthstr[i++] = 124; + break; + } + // pad string with blank bar characters + while(i<4+7) + hud_healthstr[i++] = 127; + hud_healthstr[i] = '\0'; + strcat(hud_healthstr,healthstr); + + // set the display color from the amount of health posessed + if (healtharmorpoints; + int armorbars = armor>100? 25 : armor/4; + + // clear the widgets internal line + HUlib_clearTextLine(&w_armor); + // build the numeric amount init string + snprintf(armorstr,sizeof(armorstr),"%3d",armor); + // build the bargraph string + // full bargraph chars + for (i=4;i<4+armorbars/4;) + hud_armorstr[i++] = 123; + // plus one last character with 0,1,2,3 bars + switch(armorbars%4) + { + case 0: + break; + case 1: + hud_armorstr[i++] = 126; + break; + case 2: + hud_armorstr[i++] = 125; + break; + case 3: + hud_armorstr[i++] = 124; + break; + } + // pad string with blank bar characters + while(i<4+7) + hud_armorstr[i++] = 127; + hud_armorstr[i] = '\0'; + strcat(hud_armorstr,armorstr); + + // set the display color from the amount of armor posessed + if (armor=wp_plasma && w!=wp_chainsaw) + ok=0; + break; + case retail: + case registered: + if (w>=wp_supershotgun) + ok=0; + break; + default: + case commercial: + break; + } + if (!ok) continue; + + ammo = plr->ammo[weaponinfo[w].ammo]; + fullammo = plr->maxammo[weaponinfo[w].ammo]; + ammopct=0; + + // skip weapons not currently posessed + if (!plr->weaponowned[w]) + continue; + + ammopct = fullammo? (100*ammo)/fullammo : 100; + + // display each weapon number in a color related to the ammo for it + hud_weapstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths + if (weaponinfo[w].ammo==am_noammo) //jff 3/14/98 show berserk on HUD + hud_weapstr[i++] = plr->powers[pw_strength]? '0'+CR_GREEN : '0'+CR_GRAY; + else if (ammopct1) + { + int k; + + hud_keysstr[4] = '\0'; //jff 3/7/98 make sure deleted keys go away + //jff add case for graphic key display + if (!deathmatch && hud_graph_keys) + { + i=0; + hud_gkeysstr[i] = '\0'; //jff 3/7/98 init graphic keys widget string + // build text string whose characters call out graphic keys from fontk + for (k=0;k<6;k++) + { + // skip keys not possessed + if (!plr->cards[k]) + continue; + + hud_gkeysstr[i++] = '!'+k; // key number plus '!' is char for key + hud_gkeysstr[i++] = ' '; // spacing + hud_gkeysstr[i++] = ' '; + } + hud_gkeysstr[i]='\0'; + } + else // not possible in current code, unless deathmatching, + { + i=4; + hud_keysstr[i] = '\0'; //jff 3/7/98 make sure deleted keys go away + + // if deathmatch, build string showing top four frag counts + if (deathmatch) //jff 3/17/98 show frags, not keys, in deathmatch + { + int top1=-999,top2=-999,top3=-999,top4=-999; + int idx1=-1,idx2=-1,idx3=-1,idx4=-1; + int fragcount,m; + char numbuf[32]; + + // scan thru players + for (k=0;ktop1) + { + top4=top3; top3=top2; top2 = top1; top1=fragcount; + idx4=idx3; idx3=idx2; idx2 = idx1; idx1=k; + } + else if (fragcount>top2) + { + top4=top3; top3=top2; top2=fragcount; + idx4=idx3; idx3=idx2; idx2=k; + } + else if (fragcount>top3) + { + top4=top3; top3=fragcount; + idx4=idx3; idx3=k; + } + else if (fragcount>top4) + { + top4=fragcount; + idx4=k; + } + } + // if the biggest number exists, put it in the init string + if (idx1>-1) + { + snprintf(numbuf,sizeof(numbuf),"%5d",top1); + // make frag count in player's color via escape code + hud_keysstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths + hud_keysstr[i++] = '0'+plyrcoltran[idx1&3]; + s = numbuf; + while (*s) + hud_keysstr[i++] = *(s++); + } + // if the second biggest number exists, put it in the init string + if (idx2>-1) + { + snprintf(numbuf,sizeof(numbuf),"%5d",top2); + // make frag count in player's color via escape code + hud_keysstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths + hud_keysstr[i++] = '0'+plyrcoltran[idx2&3]; + s = numbuf; + while (*s) + hud_keysstr[i++] = *(s++); + } + // if the third biggest number exists, put it in the init string + if (idx3>-1) + { + snprintf(numbuf,sizeof(numbuf),"%5d",top3); + // make frag count in player's color via escape code + hud_keysstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths + hud_keysstr[i++] = '0'+plyrcoltran[idx3&3]; + s = numbuf; + while (*s) + hud_keysstr[i++] = *(s++); + } + // if the fourth biggest number exists, put it in the init string + if (idx4>-1) + { + snprintf(numbuf,sizeof(numbuf),"%5d",top4); + // make frag count in player's color via escape code + hud_keysstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths + hud_keysstr[i++] = '0'+plyrcoltran[idx4&3]; + s = numbuf; + while (*s) + hud_keysstr[i++] = *(s++); + } + hud_keysstr[i] = '\0'; + } //jff 3/17/98 end of deathmatch clause + else // build alphabetical key display (not used currently) + { + // scan the keys + for (k=0;k<6;k++) + { + // skip any not possessed by the displayed player's stats + if (!plr->cards[k]) + continue; + + // use color escapes to make text in key's color + hud_keysstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths + switch(k) + { + case 0: + hud_keysstr[i++] = '0'+CR_BLUE; + hud_keysstr[i++] = 'B'; + hud_keysstr[i++] = 'C'; + hud_keysstr[i++] = ' '; + break; + case 1: + hud_keysstr[i++] = '0'+CR_GOLD; + hud_keysstr[i++] = 'Y'; + hud_keysstr[i++] = 'C'; + hud_keysstr[i++] = ' '; + break; + case 2: + hud_keysstr[i++] = '0'+CR_RED; + hud_keysstr[i++] = 'R'; + hud_keysstr[i++] = 'C'; + hud_keysstr[i++] = ' '; + break; + case 3: + hud_keysstr[i++] = '0'+CR_BLUE; + hud_keysstr[i++] = 'B'; + hud_keysstr[i++] = 'S'; + hud_keysstr[i++] = ' '; + break; + case 4: + hud_keysstr[i++] = '0'+CR_GOLD; + hud_keysstr[i++] = 'Y'; + hud_keysstr[i++] = 'S'; + hud_keysstr[i++] = ' '; + break; + case 5: + hud_keysstr[i++] = '0'+CR_RED; + hud_keysstr[i++] = 'R'; + hud_keysstr[i++] = 'S'; + hud_keysstr[i++] = ' '; + break; + } + hud_keysstr[i]='\0'; + } + } + } + } + // display the keys/frags line each frame + if (hud_active>1) + { + HUlib_clearTextLine(&w_keys); // clear the widget strings + HUlib_clearTextLine(&w_gkeys); + + // transfer the built string (frags or key title) to the widget + s = hud_keysstr; //jff 3/7/98 display key titles/key text or frags + while (*s) + HUlib_addCharToTextLine(&w_keys, *(s++)); + HUlib_drawTextLine(&w_keys, false); + + //jff 3/17/98 show graphic keys in non-DM only + if (!deathmatch) //jff 3/7/98 display graphic keys + { + // transfer the graphic key text to the widget + s = hud_gkeysstr; + while (*s) + HUlib_addCharToTextLine(&w_gkeys, *(s++)); + // display the widget + HUlib_drawTextLine(&w_gkeys, false); + } + } + + // display the hud kills/items/secret display if optioned + if (!hud_nosecrets) + { + if (hud_active>1 && doit) + { + // clear the internal widget text buffer + HUlib_clearTextLine(&w_monsec); + //jff 3/26/98 use ESC not '\' for paths + // build the init string with fixed colors + snprintf + ( + hud_monsecstr,sizeof(hud_monsecstr), + "STS \x1b\x36K \x1b\x33%d \x1b\x36M \x1b\x33%d \x1b\x37I \x1b\x33%d/%d \x1b\x35S \x1b\x33%d/%d", + plr->killcount,totallive, + plr->itemcount,totalitems, + plr->secretcount,totalsecret + ); + // transfer the init string to the widget + s = hud_monsecstr; + while (*s) + HUlib_addCharToTextLine(&w_monsec, *(s++)); + } + // display the kills/items/secrets each frame, if optioned + if (hud_active>1) + HUlib_drawTextLine(&w_monsec, false); + } + } + + //jff 3/4/98 display last to give priority + HU_Erase(); // jff 4/24/98 Erase current lines before drawing current + // needed when screen not fullsize + + //jff 4/21/98 if setup has disabled message list while active, turn it off + if (hud_msg_lines<=1) + message_list = false; + + // if the message review not enabled, show the standard message widget + if (!message_list) + HUlib_drawSText(&w_message); + + // if the message review is enabled show the scrolling message review + if (hud_msg_lines>1 && message_list) + HUlib_drawMText(&w_rtext); + + // display the interactive buffer for chat entry + HUlib_drawIText(&w_chat); +} + +// +// HU_Erase() +// +// Erase hud display lines that can be trashed by small screen display +// +// Passed nothing, returns nothing +// +void HU_Erase(void) +{ + // erase the message display or the message review display + if (!message_list) + HUlib_eraseSText(&w_message); + else + HUlib_eraseMText(&w_rtext); + + // erase the interactive text buffer for chat entry + HUlib_eraseIText(&w_chat); + + // erase the automap title + HUlib_eraseTextLine(&w_title); +} + +// +// HU_Ticker() +// +// Update the hud displays once per frame +// +// Passed nothing, returns nothing +// +static boolean bsdown; // Is backspace down? +static int bscounter; + +void HU_Ticker(void) +{ + int i, rc; + char c; + + // tick down message counter if message is up + if (message_counter && !--message_counter) + { + message_on = false; + message_nottobefuckedwith = false; + } + if (bsdown && bscounter++ > 9) { + HUlib_keyInIText(&w_chat, (unsigned char)key_backspace); + bscounter = 8; + } + + // if messages on, or "Messages Off" is being displayed + // this allows the notification of turning messages off to be seen + if (showMessages || message_dontfuckwithme) + { + // display message if necessary + if ((plr->message && !message_nottobefuckedwith) + || (plr->message && message_dontfuckwithme)) + { + //post the message to the message widget + HUlib_addMessageToSText(&w_message, 0, plr->message); + //jff 2/26/98 add message to refresh text widget too + HUlib_addMessageToMText(&w_rtext, 0, plr->message); + + // clear the message to avoid posting multiple times + plr->message = 0; + // note a message is displayed + message_on = true; + // start the message persistence counter + message_counter = HU_MSGTIMEOUT; + // transfer "Messages Off" exception to the "being displayed" variable + message_nottobefuckedwith = message_dontfuckwithme; + // clear the flag that "Messages Off" is being posted + message_dontfuckwithme = 0; + } + } + + // check for incoming chat characters + if (netgame) + { + for (i=0; i= 'a' && c <= 'z') + c = (char) shiftxform[(unsigned char) c]; + rc = HUlib_keyInIText(&w_inputbuffer[i], c); + if (rc && c == KEY_ENTER) + { + if (w_inputbuffer[i].l.len + && (chat_dest[i] == consoleplayer+1 + || chat_dest[i] == HU_BROADCAST)) + { + HUlib_addMessageToSText(&w_message, + player_names[i], + w_inputbuffer[i].l.l); + + message_nottobefuckedwith = true; + message_on = true; + message_counter = HU_MSGTIMEOUT; + if ( gamemode == commercial ) + S_StartSound(0, sfx_radio); + else + S_StartSound(0, sfx_tink); + } + HUlib_resetIText(&w_inputbuffer[i]); + } + } + players[i].cmd.chatchar = 0; + } + } + } +} + +#define QUEUESIZE 128 + +static char chatchars[QUEUESIZE]; +static int head = 0; +static int tail = 0; + +// +// HU_queueChatChar() +// +// Add an incoming character to the circular chat queue +// +// Passed the character to queue, returns nothing +// +void HU_queueChatChar(char c) +{ + if (((head + 1) & (QUEUESIZE-1)) == tail) + { + plr->message = HUSTR_MSGU; + } + else + { + chatchars[head] = c; + head = (head + 1) & (QUEUESIZE-1); + } +} + +// +// HU_dequeueChatChar() +// +// Remove the earliest added character from the circular chat queue +// +// Passed nothing, returns the character dequeued +// +char HU_dequeueChatChar(void) +{ + char c; + + if (head != tail) + { + c = chatchars[tail]; + tail = (tail + 1) & (QUEUESIZE-1); + } + else + { + c = 0; + } + return c; +} + +// +// HU_Responder() +// +// Responds to input events that affect the heads up displays +// +// Passed the event to respond to, returns true if the event was handled +// +boolean HU_Responder(event_t *ev) +{ + + static char lastmessage[HU_MAXLINELENGTH+1]; + const char* macromessage; // CPhipps - const char* + boolean eatkey = false; + static boolean shiftdown = false; + static boolean altdown = false; + unsigned char c; + int i; + int numplayers; + + static int num_nobrainers = 0; + + numplayers = 0; + for (i=0 ; idata1 == key_shift) + { + shiftdown = ev->type == ev_keydown; + return false; + } + else if (ev->data1 == key_alt) + { + altdown = ev->type == ev_keydown; + return false; + } + else if (ev->data1 == key_backspace) + { + bsdown = ev->type == ev_keydown; + bscounter = 0; + } + + if (ev->type != ev_keydown) + return false; + + if (!chat_on) + { + if (ev->data1 == key_enter) // phares + { +#ifndef INSTRUMENTED // never turn on message review if INSTRUMENTED defined + if (hud_msg_lines>1) // it posts multi-line messages that will trash + { + if (message_list) HU_Erase(); //jff 4/28/98 erase behind messages + message_list = !message_list; //jff 2/26/98 toggle list of messages + } +#endif + if (!message_list) // if not message list, refresh message + { + message_on = true; + message_counter = HU_MSGTIMEOUT; + } + eatkey = true; + }//jff 2/26/98 no chat if message review is displayed + else if (!message_list && netgame && ev->data1 == key_chat) + { + eatkey = chat_on = true; + HUlib_resetIText(&w_chat); + HU_queueChatChar(HU_BROADCAST); + }//jff 2/26/98 no chat if message review is displayed + // killough 10/02/98: no chat if demo playback + else if (!demoplayback && !message_list && netgame && numplayers > 2) + { + for (i=0; idata1 == destination_keys[i]) + { + if (playeringame[i] && i!=consoleplayer) + { + eatkey = chat_on = true; + HUlib_resetIText(&w_chat); + HU_queueChatChar((char)(i+1)); + break; + } + else if (i == consoleplayer) + { + num_nobrainers++; + if (num_nobrainers < 3) + plr->message = HUSTR_TALKTOSELF1; + else if (num_nobrainers < 6) + plr->message = HUSTR_TALKTOSELF2; + else if (num_nobrainers < 9) + plr->message = HUSTR_TALKTOSELF3; + else if (num_nobrainers < 32) + plr->message = HUSTR_TALKTOSELF4; + else + plr->message = HUSTR_TALKTOSELF5; + } + } + } + } + }//jff 2/26/98 no chat functions if message review is displayed + else if (!message_list) + { + c = ev->data1; + // send a macro + if (altdown) + { + c = c - '0'; + if (c > 9) + return false; + macromessage = chat_macros[c]; + + // kill last message with a '\n' + HU_queueChatChar((char)key_enter); // DEBUG!!! // phares + + // send the macro message + while (*macromessage) + HU_queueChatChar(*macromessage++); + HU_queueChatChar((char)key_enter); // phares + + // leave chat mode and notify that it was sent + chat_on = false; + strcpy(lastmessage, chat_macros[c]); + plr->message = lastmessage; + eatkey = true; + } + else + { + if (shiftdown || (c >= 'a' && c <= 'z')) + c = shiftxform[c]; + eatkey = HUlib_keyInIText(&w_chat, c); + if (eatkey) + HU_queueChatChar(c); + + if (c == key_enter) // phares + { + chat_on = false; + if (w_chat.l.len) + { + strcpy(lastmessage, w_chat.l.l); + plr->message = lastmessage; + } + } + else if (c == key_escape) // phares + chat_on = false; + } + } + return eatkey; +} diff --git a/apps/plugins/doom/hu_stuff.h b/apps/plugins/doom/hu_stuff.h new file mode 100644 index 0000000000..76c6a90313 --- /dev/null +++ b/apps/plugins/doom/hu_stuff.h @@ -0,0 +1,92 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: Head up display + * + *-----------------------------------------------------------------------------*/ + +#ifndef __HU_STUFF_H__ +#define __HU_STUFF_H__ + +#include "d_event.h" + +/* + * Globally visible constants. + */ +#define HU_FONTSTART '!' /* the first font characters */ +#define HU_FONTEND (0x7f) /*jff 2/16/98 '_' the last font characters */ + +/* Calculate # of glyphs in font. */ +#define HU_FONTSIZE (HU_FONTEND - HU_FONTSTART + 1) + +#define HU_BROADCAST 5 + +/*#define HU_MSGREFRESH KEYD_ENTER phares */ +#define HU_MSGX 0 +#define HU_MSGY 0 +#define HU_MSGWIDTH 64 /* in characters */ +#define HU_MSGHEIGHT 1 /* in lines */ + +#define HU_MSGTIMEOUT (4*TICRATE) + +/* + * Heads up text + */ +void HU_Init(void); +void HU_Start(void); + +boolean HU_Responder(event_t* ev); + +void HU_Ticker(void); +void HU_Drawer(void); +char HU_dequeueChatChar(void); +void HU_Erase(void); + +/* killough 5/2/98: moved from m_misc.c: */ + +/* jff 2/16/98 hud supported automap colors added */ +extern int hudcolor_titl; /* color range of automap level title */ +extern int hudcolor_xyco; /* color range of new coords on automap */ +/* jff 2/16/98 hud text colors, controls added */ +extern int hudcolor_mesg; /* color range of scrolling messages */ +extern int hudcolor_chat; /* color range of chat lines */ +/* jff 2/26/98 hud message list color and background enable */ +extern int hudcolor_list; /* color of list of past messages */ +extern int hud_list_bgon; /* solid window background for list of messages */ +extern int hud_msg_lines; /* number of message lines in window up to 16 */ +extern int hud_distributed; /* whether hud is all in lower left or distributed */ +/* jff 2/23/98 hud is currently displayed */ +extern int hud_displayed; /* hud is displayed */ +/* jff 2/18/98 hud/status control */ +extern int hud_active; /* hud mode 0=off, 1=small, 2=full */ +extern int hud_nosecrets; /* status does not list secrets/items/kills */ + +extern char* mapnames[]; +extern char* mapnames2[]; +extern char* mapnamesp[]; +extern char* mapnamest[]; + +#endif diff --git a/apps/plugins/doom/i_sound.c b/apps/plugins/doom/i_sound.c new file mode 100644 index 0000000000..471b0ee193 --- /dev/null +++ b/apps/plugins/doom/i_sound.c @@ -0,0 +1,607 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * System interface for sound. + * + *----------------------------------------------------------------------------- + */ + +#include "z_zone.h" + +#include "i_system.h" +#include "i_sound.h" +#include "m_argv.h" +#include "m_misc.h" +#include "w_wad.h" +#include "m_swap.h" +#include "d_main.h" +#include "doomdef.h" +#include "rockmacros.h" + +// The number of internal mixing channels, +// the samples calculated for each mixing step, +// the size of the 16bit, 2 hardware channel (stereo) +// mixing buffer, and the samplerate of the raw data. + +// Needed for calling the actual sound output. +#define SAMPLECOUNT 512 + +#define NUM_CHANNELS 16 +// It is 2 for 16bit, and 2 for two channels. +#define BUFMUL 4 +#define MIXBUFFERSIZE (SAMPLECOUNT*BUFMUL) + +#define SAMPLERATE 11025 // 44100 22050 11025 +#define SAMPLESIZE 2 // 16bit + +// The global mixing buffer. +// Basically, samples from all active internal channels +// are modifed and added, and stored in the buffer +// that is submitted to the audio device. +signed short mixbuffer[MIXBUFFERSIZE]; + +typedef struct { + // SFX id of the playing sound effect. + // Used to catch duplicates (like chainsaw). + int id; + // The channel step amount... + unsigned int step; + // ... and a 0.16 bit remainder of last step. + unsigned int stepremainder; + unsigned int samplerate; + // The channel data pointers, start and end. + const unsigned char* data; + const unsigned char* enddata; + // Time/gametic that the channel started playing, + // used to determine oldest, which automatically + // has lowest priority. + // In case number of active sounds exceeds + // available channels. + int starttime; + // Hardware left and right channel volume lookup. + int *leftvol_lookup; + int *rightvol_lookup; +} channel_info_t; + +channel_info_t channelinfo[NUM_CHANNELS]; + +int *vol_lookup; // Volume lookups. + +int steptable[256]; // Pitch to stepping lookup. (Not setup properly right now) + +// +// This function loads the sound data from the WAD lump for single sound. +// It is used to cache all the sounddata at startup. +// +void* getsfx( const char* sfxname ) +{ + unsigned char* sfx; + unsigned char* paddedsfx; + int size; + char name[20]; + int sfxlump; + + // Get the sound data from the WAD, allocate lump + // in zone memory. + snprintf(name, sizeof(name), "ds%s", sfxname); + + // Now, there is a severe problem with the sound handling, in it is not + // (yet/anymore) gamemode aware. That means, sounds from DOOM II will be + // requested even with DOOM shareware. + // The sound list is wired into sounds.c, which sets the external variable. + // I do not do runtime patches to that variable. Instead, we will use a + // default sound for replacement. + if ( W_CheckNumForName(name) == -1 ) + sfxlump = W_GetNumForName("dspistol"); + else + sfxlump = W_GetNumForName(name); + + size = W_LumpLength( sfxlump ); + + sfx = (unsigned char*)W_CacheLumpNum( sfxlump); + + paddedsfx = (unsigned char*)malloc( size ); // Allocate from memory. + memcpy(paddedsfx, sfx, size ); // Now copy and pad. + W_UnlockLumpNum(sfxlump); // Remove the cached lump. + + return (void *) (paddedsfx); // Return allocated data. +} + +/* cph + * stopchan + * Stops a sound + */ +static void stopchan(int i) +{ + channelinfo[i].data=NULL; +} + +// +// This function adds a sound to the +// list of currently active sounds, +// which is maintained as a given number +// (eight, usually) of internal channels. +// Returns a handle. +// +int addsfx( int sfxid, int channel) +{ + stopchan(channel); + + // We will handle the new SFX. + // Set pointer to raw data. + { + int lump = S_sfx[sfxid].lumpnum; + size_t len = W_LumpLength(lump); + + /* Find padded length */ + len -= 8; + channelinfo[channel].data = S_sfx[sfxid].data; + + /* Set pointer to end of raw data. */ + channelinfo[channel].enddata = channelinfo[channel].data + len - 1; + channelinfo[channel].samplerate = (channelinfo[channel].data[3]<<8)+channelinfo[channel].data[2]; + channelinfo[channel].data += 8; /* Skip header */ + } + + channelinfo[channel].stepremainder = 0; + // Should be gametic, I presume. + channelinfo[channel].starttime = gametic; + + // Preserve sound SFX id, + // e.g. for avoiding duplicates of chainsaw. + channelinfo[channel].id = sfxid; + + return channel; +} + +static void updateSoundParams(int handle, int volume, int seperation, int pitch) +{ + int rightvol; + int leftvol; + int slot = handle; + int step = steptable[pitch]; +#ifdef RANGECHECK + if (handle>=NUM_CHANNELS) + I_Error("I_UpdateSoundParams: handle out of range"); +#endif + // Set stepping + // MWM 2000-12-24: Calculates proportion of channel samplerate + // to global samplerate for mixing purposes. + // Patched to shift left *then* divide, to minimize roundoff errors + // as well as to use SAMPLERATE as defined above, not to assume 11025 Hz + if (pitched_sounds) + channelinfo[slot].step = step + (((channelinfo[slot].samplerate<<16)/SAMPLERATE)-65536); + else + channelinfo[slot].step = ((channelinfo[slot].samplerate<<16)/SAMPLERATE); + + // Separation, that is, orientation/stereo. + // range is: 1 - 256 + seperation += 1; + + // Per left/right channel. + // x^2 seperation, + // adjust volume properly. + leftvol = volume - ((volume*seperation*seperation) >> 16); + seperation = seperation - 257; + rightvol= volume - ((volume*seperation*seperation) >> 16); + + // Sanity check, clamp volume. + if (rightvol < 0 || rightvol > 127) + I_Error("rightvol out of bounds"); + + if (leftvol < 0 || leftvol > 127) + I_Error("leftvol out of bounds"); + + // Get the proper lookup table piece + // for this volume level??? + channelinfo[slot].leftvol_lookup = &vol_lookup[leftvol*256]; + channelinfo[slot].rightvol_lookup = &vol_lookup[rightvol*256]; +} + +void I_UpdateSoundParams(int handle, int volume, int seperation, int pitch) +{ + updateSoundParams(handle, volume, seperation, pitch); +} + +// +// SFX API +// Note: this was called by S_Init. +// However, whatever they did in the +// old DPMS based DOS version, this +// were simply dummies in the Linux +// version. +// See soundserver initdata(). +// +void I_SetChannels() +{ + // Init internal lookups (raw data, mixing buffer, channels). + // This function sets up internal lookups used during + // the mixing process. + int i; + int j; + int* steptablemid = steptable + 128; + + // Okay, reset internal mixing channels to zero. + for (i=0; iname); + return W_GetNumForName(namebuf); +} + +// +// Starting a sound means adding it +// to the current list of active sounds +// in the internal channels. +// As the SFX info struct contains +// e.g. a pointer to the raw data, +// it is ignored. +// As our sound handling does not handle +// priority, it is ignored. +// Pitching (that is, increased speed of playback) +// is set, but currently not used by mixing. +// +int I_StartSound(int id, int channel, int vol, int sep, int pitch, int priority) +{ + (void)priority; + int handle; + + // Returns a handle (not used). + handle = addsfx(id,channel); + +#ifdef RANGECHECK + if (handle>=NUM_CHANNELS) + I_Error("I_StartSound: handle out of range"); +#endif + updateSoundParams(handle, vol, sep, pitch); + + return handle; +} + +void I_StopSound (int handle) +{ +#ifdef RANGECHECK + if (handle>=NUM_CHANNELS) + I_Error("I_StopSound: handle out of range"); +#endif + stopchan(handle); +} + +int I_SoundIsPlaying(int handle) +{ +#ifdef RANGECHECK + if (handle>=NUM_CHANNELS) + I_Error("I_SoundIsPlaying: handle out of range"); +#endif + return channelinfo[handle].data != NULL; +} + +// +// This function loops all active (internal) sound +// channels, retrieves a given number of samples +// from the raw sound data, modifies it according +// to the current (internal) channel parameters, +// mixes the per channel samples into the given +// mixing buffer, and clamping it to the allowed +// range. +// +// This function currently supports only 16bit. +// + +bool swap=0; +bool lastswap=1; + // Pointers in global mixbuffer, left, right, end. + signed short* leftout; + signed short* rightout; + signed short* leftend; + +void I_UpdateSound( void ) +{ + // Mix current sound data. + // Data, from raw sound, for right and left. + register unsigned char sample; + register int dl; + register int dr; + + // Step in mixbuffer, left and right, thus two. + int step; + + // Mixing channel index. + int chan; + + if(lastswap==swap) + return; + lastswap=swap; + + // Left and right channel + // are in global mixbuffer, alternating. + leftout = (swap ? mixbuffer : mixbuffer + SAMPLECOUNT*2); + rightout = (swap ? mixbuffer : mixbuffer + SAMPLECOUNT*2)+1; + step = 2; + + // Determine end, for left channel only + // (right channel is implicit). + leftend = (swap ? mixbuffer : mixbuffer + SAMPLECOUNT*2) + SAMPLECOUNT*step; + + // Mix sounds into the mixing buffer. + // Loop over step*SAMPLECOUNT, + // that is 512 values for two channels. + while (leftout != leftend) + { + // Reset left/right value. + dl = 0; + dr = 0; + + // Love thy L2 chache - made this a loop. + // Now more channels could be set at compile time + // as well. Thus loop those channels. + for ( chan = 0; chan < NUM_CHANNELS; chan++ ) + { + // Check channel, if active. + if (channelinfo[chan].data) + { + // Get the raw data from the channel. + sample = (((unsigned int)channelinfo[chan].data[0] * (0x10000 - channelinfo[chan].stepremainder)) + + ((unsigned int)channelinfo[chan].data[1] * (channelinfo[chan].stepremainder))) >> 16; + // Add left and right part + // for this channel (sound) + // to the current data. + // Adjust volume accordingly. + dl += channelinfo[chan].leftvol_lookup[sample]; + dr += channelinfo[chan].rightvol_lookup[sample]; + // Increment index ??? + channelinfo[chan].stepremainder += channelinfo[chan].step; + // MSB is next sample??? + channelinfo[chan].data += channelinfo[chan].stepremainder >> 16; + // Limit to LSB??? + channelinfo[chan].stepremainder &= 0xffff; + + // Check whether we are done. + if (channelinfo[chan].data >= channelinfo[chan].enddata) + stopchan(chan); + } + } + + // Clamp to range. Left hardware channel. + // Has been char instead of short. + // if (dl > 127) *leftout = 127; + // else if (dl < -128) *leftout = -128; + // else *leftout = dl; + + if (dl > 0x7fff) + *leftout = 0x7fff; + else if (dl < -0x8000) + *leftout = -0x8000; + else + *leftout = (signed short)dl; + + // Same for right hardware channel. + if (dr > 0x7fff) + *rightout = 0x7fff; + else if (dr < -0x8000) + *rightout = -0x8000; + else + *rightout = (signed short)dr; + + // Increment current pointers in mixbuffer. + leftout += step; + rightout += step; + } +} + +// +// This would be used to write out the mixbuffer +// during each game loop update. +// Updates sound buffer and audio device at runtime. +// It is called during Timer interrupt with SNDINTR. +// Mixing now done synchronous, and +// only output be done asynchronous? +// + +void get_more(unsigned char** start, size_t* size) +{ + // This code works fine, the only problem is that doom runs slower then the sound + // updates (sometimes). This code forces the update if the sound hasn't been + // remixed. + if(lastswap!=swap) + I_UpdateSound(); // Force sound update (We don't want stutters) + + *start = (unsigned char*)((swap ? mixbuffer : mixbuffer + SAMPLECOUNT*2)); + *size = SAMPLECOUNT*2*sizeof(short); + swap=!swap; +} + + +void I_SubmitSound(void) +{ + if (nosfxparm) + return; + +#if !defined(SIMULATOR) + rb->pcm_play_data(&get_more, NULL, 0); +#endif +} + +void I_ShutdownSound(void) +{ +#if !defined(SIMULATOR) + rb->pcm_play_stop(); + rb->pcm_set_frequency(44100); // 44100 +#endif +} + +void I_InitSound() +{ + int i; + + // Initialize external data (all sounds) at start, keep static. + printf( "I_InitSound: "); +#if !defined(SIMULATOR) + rb->pcm_play_stop(); + rb->pcm_set_frequency(SAMPLERATE); +#endif + + vol_lookup=malloc(128*256*sizeof(int)); + + for (i=1 ; idata; // Previously loaded already? + } + + printf( " pre-cached all sound data\n"); + + // Now initialize mixbuffer with zero. + for ( i = 0; i< MIXBUFFERSIZE; i++ ) + mixbuffer[i] = 0; + + // Finished initialization. + printf("I_InitSound: sound module ready\n"); +} + +// +// MUSIC API. +// Still no music done. +// Remains. Dummies. +// +void I_InitMusic(void) { +} +void I_ShutdownMusic(void) { +} + +static int looping=0; +static int musicdies=-1; + +void I_PlaySong(int handle, int looping) +{ + // UNUSED. + handle = looping = 0; + musicdies = gametic + TICRATE*30; +} + +void I_PauseSong (int handle) +{ + // UNUSED. + handle = 0; +} + +void I_ResumeSong (int handle) +{ + // UNUSED. + handle = 0; +} + +void I_StopSong(int handle) +{ + // UNUSED. + handle = 0; + + looping = 0; + musicdies = 0; +} + +void I_UnRegisterSong(int handle) +{ + // UNUSED. + handle = 0; +} + +int I_RegisterSong(const void *data) +{ + // UNUSED. + data = NULL; + + return 1; +} + +// Is the song playing? +int I_QrySongPlaying(int handle) +{ + // UNUSED. + handle = 0; + return looping || musicdies > gametic; +} + +// Interrupt handler. +void I_HandleSoundTimer( int ignore ) +{ + (void)ignore; +} + +// Get the interrupt. Set duration in millisecs. +int I_SoundSetTimer( int duration_of_tick ) +{ + (void)duration_of_tick; + // Error is -1. + return 0; +} + +// Remove the interrupt. Set duration to zero. +void I_SoundDelTimer(void) +{ +} diff --git a/apps/plugins/doom/i_sound.h b/apps/plugins/doom/i_sound.h new file mode 100644 index 0000000000..2e733b1c62 --- /dev/null +++ b/apps/plugins/doom/i_sound.h @@ -0,0 +1,126 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// $Id$ +// +// Copyright (C) 1993-1996 by id Software, Inc. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// +// DESCRIPTION: +// System interface, sound. +// +//----------------------------------------------------------------------------- + +#ifndef __I_SOUND__ +#define __I_SOUND__ + +#include "doomdef.h" + +// UNIX hack, to be removed. +#ifdef SNDSERV +extern FILE* sndserver; +extern char* sndserver_filename; +#endif + +#include "doomstat.h" +#include "sounds.h" + + + +// Init at program start... +void I_InitSound(void); + +// ... update sound buffer and audio device at runtime... +void I_UpdateSound(void); +void I_SubmitSound(void); + +// ... shut down and relase at program termination. +void I_ShutdownSound(void); + + +// +// SFX I/O +// + +// Initialize channels? +void I_SetChannels(void); + +// Get raw data lump index for sound descriptor. +int I_GetSfxLumpNum (sfxinfo_t* sfxinfo ); + + +// Starts a sound in a particular sound channel. +int +I_StartSound +( int id, + int vol, + int cnum, + int sep, + int pitch, + int priority ); + + +// Stops a sound channel. +void I_StopSound(int handle); + +// Called by S_*() functions +// to see if a channel is still playing. +// Returns 0 if no longer playing, 1 if playing. +int I_SoundIsPlaying(int handle); + +// Updates the volume, separation, +// and pitch of a sound channel. +void +I_UpdateSoundParams +( int handle, + int vol, + int sep, + int pitch ); + + +// +// MUSIC I/O +// +void I_InitMusic(void); +void I_ShutdownMusic(void); +// Volume. +void I_SetMusicVolume(int volume); +// PAUSE game handling. +void I_PauseSong(int handle); +void I_ResumeSong(int handle); +// Registers a song handle to song data. +int I_RegisterSong(const void *data); +// Called by anything that wishes to start music. +// plays a song, and when the song is done, +// starts playing it again in an endless loop. +// Horrible thing to do, considering. +void +I_PlaySong +( int handle, + int looping ); +// Stops a song over 3 seconds. +void I_StopSong(int handle); +// See above (register), then think backwards +void I_UnRegisterSong(int handle); + + + +#endif +//----------------------------------------------------------------------------- +// +// $Log$ +// Revision 1.1 2006/03/28 15:44:01 dave +// Patch #2969 - Doom! Currently only working on the H300. +// +// +//----------------------------------------------------------------------------- diff --git a/apps/plugins/doom/i_system.c b/apps/plugins/doom/i_system.c new file mode 100644 index 0000000000..1e564054f8 --- /dev/null +++ b/apps/plugins/doom/i_system.c @@ -0,0 +1,134 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// $Id$ +// +// Copyright (C) 1993-1996 by id Software, Inc. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// $Log$ +// Revision 1.1 2006/03/28 15:44:01 dave +// Patch #2969 - Doom! Currently only working on the H300. +// +// +// DESCRIPTION: +// +//----------------------------------------------------------------------------- + +#include "doomdef.h" +#include "m_misc.h" +#include "i_video.h" +#include "i_sound.h" + +#include "d_net.h" +#include "g_game.h" +#include "z_zone.h" + +#ifdef __GNUG__ +#pragma implementation "i_system.h" +#endif +#include "i_system.h" + +#include "rockmacros.h" + +// +// I_GetTime +// returns time in 1/35th second tics +// +#if (CONFIG_CPU != PP5020) +volatile unsigned int doomtimer=0; + +void doomtime(void) +{ + doomtimer++; +} +#endif + +int I_GetTime (void) +{ +#ifdef SIMULATOR +#if HZ==100 + return ((7*(*rb->current_tick))/20); +#else + #error FIX - I assumed HZ was 100 +#endif +#else +#if (CONFIG_CPU == PP5020) + return (USEC_TIMER * 7)/200000; +#else + return doomtimer; +#endif +#endif +} + +// +// I_Init +// + +// I was looking into this and comparing the speed versus Prboom +// Turns out they are running the game much slower then I thought the game was +// played. This explains why run was unusable other then through straight stretches +// The game is much slower now (in terms of game speed). +void I_Init (void) +{ +#if (CONFIG_CPU != PP5020) && !defined(SIMULATOR) + rb->timer_register(1, NULL, CPU_FREQ/TICRATE, 1, doomtime); +#endif + I_InitSound(); +} + +// +// I_Quit +// +extern boolean doomexit; +void I_Quit (void) +{ + I_ShutdownSound(); + I_ShutdownMusic(); + I_ShutdownGraphics(); +#if (CONFIG_CPU != PP5020) && !defined(SIMULATOR) + rb->timer_unregister(); +#endif + doomexit=1; +} + +void I_WaitVBL(int count) +{ + rb->sleep(count); +} + +// +// I_Error +// +extern boolean demorecording; + +void I_Error (char *error, ...) +{ + char p_buf[50]; + va_list ap; + + va_start(ap, error); + vsnprintf(p_buf,sizeof(p_buf), error, ap); + va_end(ap); + + printf("%s",p_buf); + + // Shutdown. Here might be other errors. + if (demorecording) + G_CheckDemoStatus(); +/* + I_ShutdownGraphics(); +*/ + + I_Quit(); + rb->sleep(HZ*2); +} diff --git a/apps/plugins/doom/i_system.h b/apps/plugins/doom/i_system.h new file mode 100644 index 0000000000..e594cb24ab --- /dev/null +++ b/apps/plugins/doom/i_system.h @@ -0,0 +1,65 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// $Id$ +// +// Copyright (C) 1993-1996 by id Software, Inc. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// System specific interface stuff. +// +//----------------------------------------------------------------------------- + + +#ifndef __I_SYSTEM__ +#define __I_SYSTEM__ + +#include "d_ticcmd.h" +#include "d_event.h" + +#ifdef __GNUG__ +#pragma interface +#endif + + +// Called by DoomMain. +void I_Init (void); + +// Called by D_DoomLoop, +// returns current time in tics. +int I_GetTime (void); + +// +// Called by D_DoomLoop, +// called before processing any tics in a frame +// (just after displaying a frame). +// Time consuming syncronous operations +// are performed here (joystick reading). +// Can call D_PostEvent. +// +void I_StartFrame (void); + +// +// Called by D_DoomLoop, +// called before processing each tic in a frame. +// Quick syncronous operations are performed here. +// Can call D_PostEvent. +void I_StartTic (void); + +// Called by M_Responder when quit is selected. +// Clean exit, displays sell blurb. +void I_Quit (void); + +void I_Error (char *error, ...); + +#endif diff --git a/apps/plugins/doom/i_video.c b/apps/plugins/doom/i_video.c new file mode 100644 index 0000000000..b77205ff84 --- /dev/null +++ b/apps/plugins/doom/i_video.c @@ -0,0 +1,454 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * $Id$ + * + * Copyright (C) 1993-1996 by id Software, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * $Log$ + * Revision 1.1 2006/03/28 15:44:01 dave + * Patch #2969 - Doom! Currently only working on the H300. + * + * + * DESCRIPTION: + * DOOM graphics and buttons. H300 Port by Karl Kurbjun + * IPOD port by Dave Chapman and Paul Louden + * Additional work by Thom Johansen + * + *----------------------------------------------------------------------------- + */ + +#include "doomstat.h" +#include "i_system.h" +#include "v_video.h" +#include "m_argv.h" +#include "d_main.h" + +#include "doomdef.h" + +#include "rockmacros.h" + +static fb_data palette[256] IBSS_ATTR; +static fb_data *paldata=NULL; + +#if !defined(CPU_COLDFIRE) || defined(SIMULATOR) +/* + This code is credit to the IDOOM port. It is not used for the H300, but + serves as a good reference point for other targets. +*/ +static fb_data * xtable = 0; +static fb_data * ytable1 = 0; +static fb_data * ytable2 = 0; + +#define FLOOR4(a) \ + (( a >> 2) << 2) + +static int video_w, video_h; + +static void genscalexytable(void) +{ + // shall we use uint8_t intead of ints? + int y = video_h-1; + int x = video_w-1; + int i = 1 + (x>y?x:y); + xtable = malloc(sizeof(int)*video_w ); + ytable1 = malloc(sizeof(int)*video_h ); + ytable2 = malloc(sizeof(int)*video_h ); + + while(i--) + { + if(y>=0) + { + ytable1[y] = ((y*SCREENHEIGHT) / video_h) * SCREENWIDTH; + ytable2[y] = y*video_w; + y--; + } + if(x>=0) + { + xtable[x] = (x*SCREENWIDTH) / video_w; + x--; + } + } +} +#endif + +// +// I_ShutdownGraphics (NOT USED) +// +void I_ShutdownGraphics(void) +{ +} + +// +// I_StartFrame (NOT USED) +// +void I_StartFrame (void) +{ +} + +// +// I_GetEvent (NOT USED) +// +void I_GetEvent(void) +{ +} + +// +// I_StartTic +// + +#if CONFIG_KEYPAD == IPOD_4G_PAD +//#define DOOMBUTTON_SCROLLWHEEL +#define DOOMBUTTON_UP BUTTON_MENU +#define DOOMBUTTON_WEAPON BUTTON_SELECT +#define DOOMBUTTON_LEFT BUTTON_LEFT +#define DOOMBUTTON_RIGHT BUTTON_RIGHT +#define DOOMBUTTON_SHOOT BUTTON_PLAY +#define DOOMBUTTON_ENTER BUTTON_SELECT +#define DOOMBUTTON_OPEN BUTTON_MENU +#else +#define DOOMBUTTON_UP BUTTON_UP +#define DOOMBUTTON_DOWN BUTTON_DOWN +#define DOOMBUTTON_LEFT BUTTON_LEFT +#define DOOMBUTTON_RIGHT BUTTON_RIGHT +#define DOOMBUTTON_SHOOT BUTTON_REC +#define DOOMBUTTON_OPEN BUTTON_MODE +#define DOOMBUTTON_ESC BUTTON_OFF +#define DOOMBUTTON_ENTER BUTTON_SELECT +#define DOOMBUTTON_WEAPON BUTTON_ON +#endif + +int getkey(event_t * event) +{ + // Same button handling as rockboy + static unsigned int oldbuttonstate = 0, newbuttonstate=0; + + static int released, pressed; + +#if CONFIG_KEYPAD == IRIVER_H300_PAD + static unsigned int holdbutton=0; + static int hswitch=0; + if (rb->button_hold()&~holdbutton) + { + if(hswitch==0) + { + event->type = ev_keydown; + hswitch=1; + } + else + { + event->type = ev_keyup; + hswitch=0; + } + event->data1=KEY_RSHIFT; + D_PostEvent(event); + } + holdbutton=rb->button_hold(); +#endif + + newbuttonstate = rb->button_status(); + released = ~newbuttonstate & oldbuttonstate; + pressed = newbuttonstate & ~oldbuttonstate; + oldbuttonstate = newbuttonstate; + if(released) + { + event->type = ev_keyup; + if(released & DOOMBUTTON_LEFT) + { + event->data1=KEY_LEFTARROW; + D_PostEvent(event); + } + if(released & DOOMBUTTON_RIGHT) + { + event->data1=KEY_RIGHTARROW; + D_PostEvent(event); + } +#ifdef DOOMBUTTON_DOWN + if(released & DOOMBUTTON_DOWN) + { + event->data1=KEY_DOWNARROW; + D_PostEvent(event); + } +#endif + if(released & DOOMBUTTON_UP) + { + event->data1=KEY_UPARROW; + D_PostEvent(event); + } + if(released & DOOMBUTTON_SHOOT) + { + event->data1=KEY_RCTRL; + D_PostEvent(event); + } + if(released & DOOMBUTTON_OPEN) + { + event->data1=' '; + D_PostEvent(event); + } +#ifdef DOOMBUTTON_ESC + if(released & DOOMBUTTON_ESC) + { + event->data1=KEY_ESCAPE; + D_PostEvent(event); + } +#endif +#ifdef DOOMBUTTON_ENTER + if(released & DOOMBUTTON_ENTER) + { + event->data1=KEY_ENTER; + D_PostEvent(event); + } +#endif +#ifdef DOOMBUTTON_WEAPON + if(released & DOOMBUTTON_WEAPON) + { + event->data1 ='w'; + D_PostEvent(event); + } +#endif + } + if(pressed) + { + event->type = ev_keydown; + if(pressed & DOOMBUTTON_LEFT) + { + event->data1=KEY_LEFTARROW; + D_PostEvent(event); + } + if(pressed & DOOMBUTTON_RIGHT) + { + event->data1=KEY_RIGHTARROW; + D_PostEvent(event); + } +#ifdef DOOMBUTTON_DOWN + if(pressed & DOOMBUTTON_DOWN) + { + event->data1=KEY_DOWNARROW; + D_PostEvent(event); + } +#endif + if(pressed & DOOMBUTTON_UP) + { + event->data1=KEY_UPARROW; + D_PostEvent(event); + } + if(pressed & DOOMBUTTON_SHOOT) + { + event->data1=KEY_RCTRL; + D_PostEvent(event); + } + if(pressed & DOOMBUTTON_OPEN) + { + event->data1=' '; + D_PostEvent(event); + } +#ifdef DOOMBUTTON_ESC + if(pressed & DOOMBUTTON_ESC) + { + event->data1=KEY_ESCAPE; + D_PostEvent(event); + } +#endif +#ifdef DOOMBUTTON_ENTER + if(pressed & DOOMBUTTON_ENTER) + { + event->data1=KEY_ENTER; + D_PostEvent(event); + } +#endif +#ifdef DOOMBUTTON_WEAPON + if(pressed & DOOMBUTTON_WEAPON) + { + event->data1='w'; + D_PostEvent(event); + } +#endif + } + if(pressed || released) + return 1; + else + return 0; +} + +event_t event; +void I_StartTic (void) +{ + getkey(&event); +} + + +/////////////////////////////////////////////////////////// +// Palette stuff. +// +static void I_UploadNewPalette(int pal) +{ + // This is used to replace the current 256 colour cmap with a new one + // Used by 256 colour PseudoColor modes + static int cachedgamma; + static size_t num_pals; + + if ((paldata == NULL) || (cachedgamma != usegamma)) { + int lump = W_GetNumForName("PLAYPAL"); + const byte *pall = W_CacheLumpNum(lump); + register const byte *const gtable = gammatable[cachedgamma = usegamma]; + register int i; + + num_pals = W_LumpLength(lump) / (3*256); + num_pals *= 256; + + if (!paldata) { + // First call - allocate and prepare colour array + paldata = malloc(sizeof(*paldata)*num_pals); + } + + // set the colormap entries + for (i=0 ; (size_t)i= num_pals) + I_Error("I_UploadNewPalette: Palette number out of range (%d>=%d)", + pal, num_pals); +#endif + memcpy(palette,paldata+256*pal,256*sizeof(fb_data)); +} + +// +// I_UpdateNoBlit +// +void I_UpdateNoBlit (void) +{ +} + +// +// I_FinishUpdate +// + +void I_FinishUpdate (void) +{ +#if defined(CPU_COLDFIRE) && !defined(SIMULATOR) + /* + Faster screen update than the lookuptables -> I'm wasting 7 pixels of width + though. This code also doesn't use the framebuffer so rockbox's drawing + functions will not work on top of the doom drawing. + */ + + // Start the write + *(volatile unsigned short *) 0xf0000000 = 0x21; // register + *(volatile unsigned short *) 0xf0000002 = 0; // value + *(volatile unsigned short *) 0xf0000000 = 0x22; // GRAM + + unsigned char *screenptr=screens[0]; + int wcnt=0, hcnt=0; + + *(volatile unsigned short *) 0xf0000002 = 0; + *(volatile unsigned short *) 0xf0000002 = 0; + *(volatile unsigned short *) 0xf0000002 = 0; + + while(hcnt= SCREENHEIGHT + paletteIndex = screens[0][((y*SCREENHEIGHT) / video_h) + * SCREENWIDTH + x]; + rb->lcd_framebuffer[y * video_w + x] = palette[paletteIndex]; +#else + paletteIndex = screens[0][ytable1[y] +xtable[x]]; + rb->lcd_framebuffer[x + ytable2[y]] = palette[paletteIndex]; +#endif + } + } + rb->lcd_update(); +#endif +} + +// +// I_ReadScreen +// +void I_ReadScreen (byte* scr) +{ + memcpy (scr, screens[0], SCREENWIDTH*SCREENHEIGHT); +} + +// +// I_SetPalette +// +void I_SetPalette (int pal) +{ + I_UploadNewPalette(pal); +} + +// +// I_InitGraphics +// +void I_InitGraphics(void) +{ + static int firsttime=1; + + if (!firsttime) + return; + firsttime = 0; + + printf("Starting Graphics engine\n"); + + /* Note: The other screens are initialized later */ + screens[0] = malloc (SCREENWIDTH * SCREENHEIGHT * sizeof(unsigned char)); + +#if defined(CPU_COLDFIRE) && !defined(SIMULATOR) + coldfire_set_macsr(EMAC_FRACTIONAL | EMAC_SATURATE); +#else + + video_h = LCD_HEIGHT; + video_w = FLOOR4(LCD_WIDTH); // From IDOOM, the width has to be a multiple of 4 + genscalexytable(); +#endif +} diff --git a/apps/plugins/doom/i_video.h b/apps/plugins/doom/i_video.h new file mode 100644 index 0000000000..fd8f269d6b --- /dev/null +++ b/apps/plugins/doom/i_video.h @@ -0,0 +1,56 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// $Id$ +// +// Copyright (C) 1993-1996 by id Software, Inc. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// System specific interface stuff. +// +//----------------------------------------------------------------------------- + + +#ifndef __I_VIDEO__ +#define __I_VIDEO__ + + +#include "doomtype.h" +#include "rockmacros.h" + +#ifdef __GNUG__ +#pragma interface +#endif + + +// Called by D_DoomMain, +// determines the hardware configuration +// and sets up the video mode +void I_InitGraphics (void); + +void I_ShutdownGraphics(void); + +// Takes full 8 bit values. +void I_SetPalette (int pal); + +void I_UpdateNoBlit (void); +void I_FinishUpdate (void) ICODE_ATTR; + +// Wait for vertical retrace or pause a bit. +void I_WaitVBL(int count); + +void I_ReadScreen (byte* scr); + + + +#endif diff --git a/apps/plugins/doom/info.c b/apps/plugins/doom/info.c new file mode 100644 index 0000000000..015270f0f5 --- /dev/null +++ b/apps/plugins/doom/info.c @@ -0,0 +1,5185 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Thing frame/state LUT, + * generated by multigen utilitiy. + * This one is the original DOOM version, preserved. + * BOOM changes include commenting and addition of predefined lumps + * for providing things that aren't in the IWAD without sending a + * separate must-use wad file around with the EXE. + * + *----------------------------------------------------------------------------- + */ + +// Data. +#include "sounds.h" +#include "m_fixed.h" + +#ifdef __GNUG__ +#pragma implementation "info.h" +#endif +#include "info.h" + +#include "p_mobj.h" + +#include "rockmacros.h" + +// ******************************************************************** +// Sprite names +// ******************************************************************** +// This is the list of sprite 4-character prefixes. They are searched +// through, with a NULL entry terminating the list. In DOOM originally +// this NULL entry was missing, and coincidentally the next thing in +// memory was the dummy state_t[] entry that started with zero bytes. +// killough 1/17/98: add an explicit NULL entry. +// NUMSPRITES is an enum from info.h where all these are listed +// as SPR_xxxx + +const char *sprnames[NUMSPRITES+1] = { + "TROO","SHTG","PUNG","PISG","PISF","SHTF","SHT2","CHGG","CHGF","MISG", + "MISF","SAWG","PLSG","PLSF","BFGG","BFGF","BLUD","PUFF","BAL1","BAL2", + "PLSS","PLSE","MISL","BFS1","BFE1","BFE2","TFOG","IFOG","PLAY","POSS", + "SPOS","VILE","FIRE","FATB","FBXP","SKEL","MANF","FATT","CPOS","SARG", + "HEAD","BAL7","BOSS","BOS2","SKUL","SPID","BSPI","APLS","APBX","CYBR", + "PAIN","SSWV","KEEN","BBRN","BOSF","ARM1","ARM2","BAR1","BEXP","FCAN", + "BON1","BON2","BKEY","RKEY","YKEY","BSKU","RSKU","YSKU","STIM","MEDI", + "SOUL","PINV","PSTR","PINS","MEGA","SUIT","PMAP","PVIS","CLIP","AMMO", + "ROCK","BROK","CELL","CELP","SHEL","SBOX","BPAK","BFUG","MGUN","CSAW", + "LAUN","PLAS","SHOT","SGN2","COLU","SMT2","GOR1","POL2","POL5","POL4", + "POL3","POL1","POL6","GOR2","GOR3","GOR4","GOR5","SMIT","COL1","COL2", + "COL3","COL4","CAND","CBRA","COL6","TRE1","TRE2","ELEC","CEYE","FSKU", + "COL5","TBLU","TGRN","TRED","SMBT","SMGT","SMRT","HDB1","HDB2","HDB3", + "HDB4","HDB5","HDB6","POB1","POB2","BRS1","TLMP","TLP2",NULL + }; + +// ******************************************************************** +// Function addresses or Code Pointers +// ******************************************************************** +// These function addresses are the Code Pointers that have been +// modified for years by Dehacked enthusiasts. The new BEX format +// allows more extensive changes (see d_deh.c) + +// Doesn't work with g++, needs actionf_p1 +void A_Light0(); +void A_WeaponReady(); +void A_Lower(); +void A_Raise(); +void A_Punch(); +void A_ReFire(); +void A_FirePistol(); +void A_Light1(); +void A_FireShotgun(); +void A_Light2(); +void A_FireShotgun2(); +void A_CheckReload(); +void A_OpenShotgun2(); +void A_LoadShotgun2(); +void A_CloseShotgun2(); +void A_FireCGun(); +void A_GunFlash(); +void A_FireMissile(); +void A_Saw(); +void A_FirePlasma(); +void A_BFGsound(); +void A_FireBFG(); +void A_BFGSpray(); +void A_Explode(); +void A_Pain(); +void A_PlayerScream(); +void A_Fall(); +void A_XScream(); +void A_Look(); +void A_Chase(); +void A_FaceTarget(); +void A_PosAttack(); +void A_Scream(); +void A_SPosAttack(); +void A_VileChase(); +void A_VileStart(); +void A_VileTarget(); +void A_VileAttack(); +void A_StartFire(); +void A_Fire(); +void A_FireCrackle(); +void A_Tracer(); +void A_SkelWhoosh(); +void A_SkelFist(); +void A_SkelMissile(); +void A_FatRaise(); +void A_FatAttack1(); +void A_FatAttack2(); +void A_FatAttack3(); +void A_BossDeath(); +void A_CPosAttack(); +void A_CPosRefire(); +void A_TroopAttack(); +void A_SargAttack(); +void A_HeadAttack(); +void A_BruisAttack(); +void A_SkullAttack(); +void A_Metal(); +void A_SpidRefire(); +void A_BabyMetal(); +void A_BspiAttack(); +void A_Hoof(); +void A_CyberAttack(); +void A_PainAttack(); +void A_PainDie(); +void A_KeenDie(); +void A_BrainPain(); +void A_BrainScream(); +void A_BrainDie(); +void A_BrainAwake(); +void A_BrainSpit(); +void A_SpawnSound(); +void A_SpawnFly(); +void A_BrainExplode(); +void A_Die(); +void A_Stop(); +void A_Detonate(); /* killough 8/9/98: detonate a bomb or other device */ +void A_Mushroom(); /* killough 10/98: mushroom effect */ + +// ******************************************************************** +// State or "frame" information +// ******************************************************************** +// Each of the states, otherwise known as "frames", is outlined +// here. The data in each element of the array is the way it is +// initialized, with sprite names identified by their enumerator +// value such as SPR_SHTG. These correlate to the above sprite +// array so don't change them around unless you understand what +// you're doing. +// +// The commented name beginning with S_ at the end of each line +// is there to help figure out where the next-frame pointer is +// pointing. These are also additionally identified in info.h +// as enumerated values. From a change-and-recompile point of +// view this is fairly workable, but it adds a lot to the effort +// when trying to change things externally. See also the d_deh.c +// parts where frame rewiring is done for more details and the +// extended way a BEX file can handle this. + +state_t states[NUMSTATES] = { + {SPR_TROO,0,-1,NULL,S_NULL,0,0}, // S_NULL + {SPR_SHTG,4,0,A_Light0,S_NULL,0,0}, // S_LIGHTDONE + {SPR_PUNG,0,1,A_WeaponReady,S_PUNCH,0,0}, // S_PUNCH + {SPR_PUNG,0,1,A_Lower,S_PUNCHDOWN,0,0}, // S_PUNCHDOWN + {SPR_PUNG,0,1,A_Raise,S_PUNCHUP,0,0}, // S_PUNCHUP + {SPR_PUNG,1,4,NULL,S_PUNCH2,0,0}, // S_PUNCH1 + {SPR_PUNG,2,4,A_Punch,S_PUNCH3,0,0}, // S_PUNCH2 + {SPR_PUNG,3,5,NULL,S_PUNCH4,0,0}, // S_PUNCH3 + {SPR_PUNG,2,4,NULL,S_PUNCH5,0,0}, // S_PUNCH4 + {SPR_PUNG,1,5,A_ReFire,S_PUNCH,0,0}, // S_PUNCH5 + {SPR_PISG,0,1,A_WeaponReady,S_PISTOL,0,0},// S_PISTOL + {SPR_PISG,0,1,A_Lower,S_PISTOLDOWN,0,0}, // S_PISTOLDOWN + {SPR_PISG,0,1,A_Raise,S_PISTOLUP,0,0}, // S_PISTOLUP + {SPR_PISG,0,4,NULL,S_PISTOL2,0,0}, // S_PISTOL1 + {SPR_PISG,1,6,A_FirePistol,S_PISTOL3,0,0},// S_PISTOL2 + {SPR_PISG,2,4,NULL,S_PISTOL4,0,0}, // S_PISTOL3 + {SPR_PISG,1,5,A_ReFire,S_PISTOL,0,0}, // S_PISTOL4 + {SPR_PISF,32768,7,A_Light1,S_LIGHTDONE,0,0}, // S_PISTOLFLASH + {SPR_SHTG,0,1,A_WeaponReady,S_SGUN,0,0}, // S_SGUN + {SPR_SHTG,0,1,A_Lower,S_SGUNDOWN,0,0}, // S_SGUNDOWN + {SPR_SHTG,0,1,A_Raise,S_SGUNUP,0,0}, // S_SGUNUP + {SPR_SHTG,0,3,NULL,S_SGUN2,0,0}, // S_SGUN1 + {SPR_SHTG,0,7,A_FireShotgun,S_SGUN3,0,0}, // S_SGUN2 + {SPR_SHTG,1,5,NULL,S_SGUN4,0,0}, // S_SGUN3 + {SPR_SHTG,2,5,NULL,S_SGUN5,0,0}, // S_SGUN4 + {SPR_SHTG,3,4,NULL,S_SGUN6,0,0}, // S_SGUN5 + {SPR_SHTG,2,5,NULL,S_SGUN7,0,0}, // S_SGUN6 + {SPR_SHTG,1,5,NULL,S_SGUN8,0,0}, // S_SGUN7 + {SPR_SHTG,0,3,NULL,S_SGUN9,0,0}, // S_SGUN8 + {SPR_SHTG,0,7,A_ReFire,S_SGUN,0,0}, // S_SGUN9 + {SPR_SHTF,32768,4,A_Light1,S_SGUNFLASH2,0,0}, // S_SGUNFLASH1 + {SPR_SHTF,32769,3,A_Light2,S_LIGHTDONE,0,0}, // S_SGUNFLASH2 + {SPR_SHT2,0,1,A_WeaponReady,S_DSGUN,0,0}, // S_DSGUN + {SPR_SHT2,0,1,A_Lower,S_DSGUNDOWN,0,0}, // S_DSGUNDOWN + {SPR_SHT2,0,1,A_Raise,S_DSGUNUP,0,0}, // S_DSGUNUP + {SPR_SHT2,0,3,NULL,S_DSGUN2,0,0}, // S_DSGUN1 + {SPR_SHT2,0,7,A_FireShotgun2,S_DSGUN3,0,0}, // S_DSGUN2 + {SPR_SHT2,1,7,NULL,S_DSGUN4,0,0}, // S_DSGUN3 + {SPR_SHT2,2,7,A_CheckReload,S_DSGUN5,0,0}, // S_DSGUN4 + {SPR_SHT2,3,7,A_OpenShotgun2,S_DSGUN6,0,0}, // S_DSGUN5 + {SPR_SHT2,4,7,NULL,S_DSGUN7,0,0}, // S_DSGUN6 + {SPR_SHT2,5,7,A_LoadShotgun2,S_DSGUN8,0,0}, // S_DSGUN7 + {SPR_SHT2,6,6,NULL,S_DSGUN9,0,0}, // S_DSGUN8 + {SPR_SHT2,7,6,A_CloseShotgun2,S_DSGUN10,0,0}, // S_DSGUN9 + {SPR_SHT2,0,5,A_ReFire,S_DSGUN,0,0}, // S_DSGUN10 + {SPR_SHT2,1,7,NULL,S_DSNR2,0,0}, // S_DSNR1 + {SPR_SHT2,0,3,NULL,S_DSGUNDOWN,0,0}, // S_DSNR2 + {SPR_SHT2,32776,5,A_Light1,S_DSGUNFLASH2,0,0}, // S_DSGUNFLASH1 + {SPR_SHT2,32777,4,A_Light2,S_LIGHTDONE,0,0}, // S_DSGUNFLASH2 + {SPR_CHGG,0,1,A_WeaponReady,S_CHAIN,0,0}, // S_CHAIN + {SPR_CHGG,0,1,A_Lower,S_CHAINDOWN,0,0}, // S_CHAINDOWN + {SPR_CHGG,0,1,A_Raise,S_CHAINUP,0,0}, // S_CHAINUP + {SPR_CHGG,0,4,A_FireCGun,S_CHAIN2,0,0}, // S_CHAIN1 + {SPR_CHGG,1,4,A_FireCGun,S_CHAIN3,0,0}, // S_CHAIN2 + {SPR_CHGG,1,0,A_ReFire,S_CHAIN,0,0}, // S_CHAIN3 + {SPR_CHGF,32768,5,A_Light1,S_LIGHTDONE,0,0}, // S_CHAINFLASH1 + {SPR_CHGF,32769,5,A_Light2,S_LIGHTDONE,0,0}, // S_CHAINFLASH2 + {SPR_MISG,0,1,A_WeaponReady,S_MISSILE,0,0}, // S_MISSILE + {SPR_MISG,0,1,A_Lower,S_MISSILEDOWN,0,0}, // S_MISSILEDOWN + {SPR_MISG,0,1,A_Raise,S_MISSILEUP,0,0}, // S_MISSILEUP + {SPR_MISG,1,8,A_GunFlash,S_MISSILE2,0,0}, // S_MISSILE1 + {SPR_MISG,1,12,A_FireMissile,S_MISSILE3,0,0}, // S_MISSILE2 + {SPR_MISG,1,0,A_ReFire,S_MISSILE,0,0}, // S_MISSILE3 + {SPR_MISF,32768,3,A_Light1,S_MISSILEFLASH2,0,0}, // S_MISSILEFLASH1 + {SPR_MISF,32769,4,NULL,S_MISSILEFLASH3,0,0}, // S_MISSILEFLASH2 + {SPR_MISF,32770,4,A_Light2,S_MISSILEFLASH4,0,0}, // S_MISSILEFLASH3 + {SPR_MISF,32771,4,A_Light2,S_LIGHTDONE,0,0}, // S_MISSILEFLASH4 + {SPR_SAWG,2,4,A_WeaponReady,S_SAWB,0,0}, // S_SAW + {SPR_SAWG,3,4,A_WeaponReady,S_SAW,0,0}, // S_SAWB + {SPR_SAWG,2,1,A_Lower,S_SAWDOWN,0,0}, // S_SAWDOWN + {SPR_SAWG,2,1,A_Raise,S_SAWUP,0,0}, // S_SAWUP + {SPR_SAWG,0,4,A_Saw,S_SAW2,0,0}, // S_SAW1 + {SPR_SAWG,1,4,A_Saw,S_SAW3,0,0}, // S_SAW2 + {SPR_SAWG,1,0,A_ReFire,S_SAW,0,0}, // S_SAW3 + {SPR_PLSG,0,1,A_WeaponReady,S_PLASMA,0,0}, // S_PLASMA + {SPR_PLSG,0,1,A_Lower,S_PLASMADOWN,0,0}, // S_PLASMADOWN + {SPR_PLSG,0,1,A_Raise,S_PLASMAUP,0,0}, // S_PLASMAUP + {SPR_PLSG,0,3,A_FirePlasma,S_PLASMA2,0,0}, // S_PLASMA1 + {SPR_PLSG,1,20,A_ReFire,S_PLASMA,0,0}, // S_PLASMA2 + {SPR_PLSF,32768,4,A_Light1,S_LIGHTDONE,0,0}, // S_PLASMAFLASH1 + {SPR_PLSF,32769,4,A_Light1,S_LIGHTDONE,0,0}, // S_PLASMAFLASH2 + {SPR_BFGG,0,1,A_WeaponReady,S_BFG,0,0}, // S_BFG + {SPR_BFGG,0,1,A_Lower,S_BFGDOWN,0,0}, // S_BFGDOWN + {SPR_BFGG,0,1,A_Raise,S_BFGUP,0,0}, // S_BFGUP + {SPR_BFGG,0,20,A_BFGsound,S_BFG2,0,0}, // S_BFG1 + {SPR_BFGG,1,10,A_GunFlash,S_BFG3,0,0}, // S_BFG2 + {SPR_BFGG,1,10,A_FireBFG,S_BFG4,0,0}, // S_BFG3 + {SPR_BFGG,1,20,A_ReFire,S_BFG,0,0}, // S_BFG4 + {SPR_BFGF,32768,11,A_Light1,S_BFGFLASH2,0,0}, // S_BFGFLASH1 + {SPR_BFGF,32769,6,A_Light2,S_LIGHTDONE,0,0}, // S_BFGFLASH2 + {SPR_BLUD,2,8,NULL,S_BLOOD2,0,0}, // S_BLOOD1 + {SPR_BLUD,1,8,NULL,S_BLOOD3,0,0}, // S_BLOOD2 + {SPR_BLUD,0,8,NULL,S_NULL,0,0}, // S_BLOOD3 + {SPR_PUFF,32768,4,NULL,S_PUFF2,0,0}, // S_PUFF1 + {SPR_PUFF,1,4,NULL,S_PUFF3,0,0}, // S_PUFF2 + {SPR_PUFF,2,4,NULL,S_PUFF4,0,0}, // S_PUFF3 + {SPR_PUFF,3,4,NULL,S_NULL,0,0}, // S_PUFF4 + {SPR_BAL1,32768,4,NULL,S_TBALL2,0,0}, // S_TBALL1 + {SPR_BAL1,32769,4,NULL,S_TBALL1,0,0}, // S_TBALL2 + {SPR_BAL1,32770,6,NULL,S_TBALLX2,0,0}, // S_TBALLX1 + {SPR_BAL1,32771,6,NULL,S_TBALLX3,0,0}, // S_TBALLX2 + {SPR_BAL1,32772,6,NULL,S_NULL,0,0}, // S_TBALLX3 + {SPR_BAL2,32768,4,NULL,S_RBALL2,0,0}, // S_RBALL1 + {SPR_BAL2,32769,4,NULL,S_RBALL1,0,0}, // S_RBALL2 + {SPR_BAL2,32770,6,NULL,S_RBALLX2,0,0}, // S_RBALLX1 + {SPR_BAL2,32771,6,NULL,S_RBALLX3,0,0}, // S_RBALLX2 + {SPR_BAL2,32772,6,NULL,S_NULL,0,0}, // S_RBALLX3 + {SPR_PLSS,32768,6,NULL,S_PLASBALL2,0,0}, // S_PLASBALL + {SPR_PLSS,32769,6,NULL,S_PLASBALL,0,0}, // S_PLASBALL2 + {SPR_PLSE,32768,4,NULL,S_PLASEXP2,0,0}, // S_PLASEXP + {SPR_PLSE,32769,4,NULL,S_PLASEXP3,0,0}, // S_PLASEXP2 + {SPR_PLSE,32770,4,NULL,S_PLASEXP4,0,0}, // S_PLASEXP3 + {SPR_PLSE,32771,4,NULL,S_PLASEXP5,0,0}, // S_PLASEXP4 + {SPR_PLSE,32772,4,NULL,S_NULL,0,0}, // S_PLASEXP5 + {SPR_MISL,32768,1,NULL,S_ROCKET,0,0}, // S_ROCKET + {SPR_BFS1,32768,4,NULL,S_BFGSHOT2,0,0}, // S_BFGSHOT + {SPR_BFS1,32769,4,NULL,S_BFGSHOT,0,0}, // S_BFGSHOT2 + {SPR_BFE1,32768,8,NULL,S_BFGLAND2,0,0}, // S_BFGLAND + {SPR_BFE1,32769,8,NULL,S_BFGLAND3,0,0}, // S_BFGLAND2 + {SPR_BFE1,32770,8,A_BFGSpray,S_BFGLAND4,0,0}, // S_BFGLAND3 + {SPR_BFE1,32771,8,NULL,S_BFGLAND5,0,0}, // S_BFGLAND4 + {SPR_BFE1,32772,8,NULL,S_BFGLAND6,0,0}, // S_BFGLAND5 + {SPR_BFE1,32773,8,NULL,S_NULL,0,0}, // S_BFGLAND6 + {SPR_BFE2,32768,8,NULL,S_BFGEXP2,0,0}, // S_BFGEXP + {SPR_BFE2,32769,8,NULL,S_BFGEXP3,0,0}, // S_BFGEXP2 + {SPR_BFE2,32770,8,NULL,S_BFGEXP4,0,0}, // S_BFGEXP3 + {SPR_BFE2,32771,8,NULL,S_NULL,0,0}, // S_BFGEXP4 + {SPR_MISL,32769,8,A_Explode,S_EXPLODE2,0,0}, // S_EXPLODE1 + {SPR_MISL,32770,6,NULL,S_EXPLODE3,0,0}, // S_EXPLODE2 + {SPR_MISL,32771,4,NULL,S_NULL,0,0}, // S_EXPLODE3 + {SPR_TFOG,32768,6,NULL,S_TFOG01,0,0}, // S_TFOG + {SPR_TFOG,32769,6,NULL,S_TFOG02,0,0}, // S_TFOG01 + {SPR_TFOG,32768,6,NULL,S_TFOG2,0,0}, // S_TFOG02 + {SPR_TFOG,32769,6,NULL,S_TFOG3,0,0}, // S_TFOG2 + {SPR_TFOG,32770,6,NULL,S_TFOG4,0,0}, // S_TFOG3 + {SPR_TFOG,32771,6,NULL,S_TFOG5,0,0}, // S_TFOG4 + {SPR_TFOG,32772,6,NULL,S_TFOG6,0,0}, // S_TFOG5 + {SPR_TFOG,32773,6,NULL,S_TFOG7,0,0}, // S_TFOG6 + {SPR_TFOG,32774,6,NULL,S_TFOG8,0,0}, // S_TFOG7 + {SPR_TFOG,32775,6,NULL,S_TFOG9,0,0}, // S_TFOG8 + {SPR_TFOG,32776,6,NULL,S_TFOG10,0,0}, // S_TFOG9 + {SPR_TFOG,32777,6,NULL,S_NULL,0,0}, // S_TFOG10 + {SPR_IFOG,32768,6,NULL,S_IFOG01,0,0}, // S_IFOG + {SPR_IFOG,32769,6,NULL,S_IFOG02,0,0}, // S_IFOG01 + {SPR_IFOG,32768,6,NULL,S_IFOG2,0,0}, // S_IFOG02 + {SPR_IFOG,32769,6,NULL,S_IFOG3,0,0}, // S_IFOG2 + {SPR_IFOG,32770,6,NULL,S_IFOG4,0,0}, // S_IFOG3 + {SPR_IFOG,32771,6,NULL,S_IFOG5,0,0}, // S_IFOG4 + {SPR_IFOG,32772,6,NULL,S_NULL,0,0}, // S_IFOG5 + {SPR_PLAY,0,-1,NULL,S_NULL,0,0}, // S_PLAY + {SPR_PLAY,0,4,NULL,S_PLAY_RUN2,0,0}, // S_PLAY_RUN1 + {SPR_PLAY,1,4,NULL,S_PLAY_RUN3,0,0}, // S_PLAY_RUN2 + {SPR_PLAY,2,4,NULL,S_PLAY_RUN4,0,0}, // S_PLAY_RUN3 + {SPR_PLAY,3,4,NULL,S_PLAY_RUN1,0,0}, // S_PLAY_RUN4 + {SPR_PLAY,4,12,NULL,S_PLAY,0,0}, // S_PLAY_ATK1 + {SPR_PLAY,32773,6,NULL,S_PLAY_ATK1,0,0}, // S_PLAY_ATK2 + {SPR_PLAY,6,4,NULL,S_PLAY_PAIN2,0,0}, // S_PLAY_PAIN + {SPR_PLAY,6,4,A_Pain,S_PLAY,0,0}, // S_PLAY_PAIN2 + {SPR_PLAY,7,10,NULL,S_PLAY_DIE2,0,0}, // S_PLAY_DIE1 + {SPR_PLAY,8,10,A_PlayerScream,S_PLAY_DIE3,0,0}, // S_PLAY_DIE2 + {SPR_PLAY,9,10,A_Fall,S_PLAY_DIE4,0,0}, // S_PLAY_DIE3 + {SPR_PLAY,10,10,NULL,S_PLAY_DIE5,0,0}, // S_PLAY_DIE4 + {SPR_PLAY,11,10,NULL,S_PLAY_DIE6,0,0}, // S_PLAY_DIE5 + {SPR_PLAY,12,10,NULL,S_PLAY_DIE7,0,0}, // S_PLAY_DIE6 + {SPR_PLAY,13,-1,NULL,S_NULL,0,0}, // S_PLAY_DIE7 + {SPR_PLAY,14,5,NULL,S_PLAY_XDIE2,0,0}, // S_PLAY_XDIE1 + {SPR_PLAY,15,5,A_XScream,S_PLAY_XDIE3,0,0}, // S_PLAY_XDIE2 + {SPR_PLAY,16,5,A_Fall,S_PLAY_XDIE4,0,0}, // S_PLAY_XDIE3 + {SPR_PLAY,17,5,NULL,S_PLAY_XDIE5,0,0}, // S_PLAY_XDIE4 + {SPR_PLAY,18,5,NULL,S_PLAY_XDIE6,0,0}, // S_PLAY_XDIE5 + {SPR_PLAY,19,5,NULL,S_PLAY_XDIE7,0,0}, // S_PLAY_XDIE6 + {SPR_PLAY,20,5,NULL,S_PLAY_XDIE8,0,0}, // S_PLAY_XDIE7 + {SPR_PLAY,21,5,NULL,S_PLAY_XDIE9,0,0}, // S_PLAY_XDIE8 + {SPR_PLAY,22,-1,NULL,S_NULL,0,0}, // S_PLAY_XDIE9 + {SPR_POSS,0,10,A_Look,S_POSS_STND2,0,0}, // S_POSS_STND + {SPR_POSS,1,10,A_Look,S_POSS_STND,0,0}, // S_POSS_STND2 + {SPR_POSS,0,4,A_Chase,S_POSS_RUN2,0,0}, // S_POSS_RUN1 + {SPR_POSS,0,4,A_Chase,S_POSS_RUN3,0,0}, // S_POSS_RUN2 + {SPR_POSS,1,4,A_Chase,S_POSS_RUN4,0,0}, // S_POSS_RUN3 + {SPR_POSS,1,4,A_Chase,S_POSS_RUN5,0,0}, // S_POSS_RUN4 + {SPR_POSS,2,4,A_Chase,S_POSS_RUN6,0,0}, // S_POSS_RUN5 + {SPR_POSS,2,4,A_Chase,S_POSS_RUN7,0,0}, // S_POSS_RUN6 + {SPR_POSS,3,4,A_Chase,S_POSS_RUN8,0,0}, // S_POSS_RUN7 + {SPR_POSS,3,4,A_Chase,S_POSS_RUN1,0,0}, // S_POSS_RUN8 + {SPR_POSS,4,10,A_FaceTarget,S_POSS_ATK2,0,0}, // S_POSS_ATK1 + {SPR_POSS,5,8,A_PosAttack,S_POSS_ATK3,0,0}, // S_POSS_ATK2 + {SPR_POSS,4,8,NULL,S_POSS_RUN1,0,0}, // S_POSS_ATK3 + {SPR_POSS,6,3,NULL,S_POSS_PAIN2,0,0}, // S_POSS_PAIN + {SPR_POSS,6,3,A_Pain,S_POSS_RUN1,0,0}, // S_POSS_PAIN2 + {SPR_POSS,7,5,NULL,S_POSS_DIE2,0,0}, // S_POSS_DIE1 + {SPR_POSS,8,5,A_Scream,S_POSS_DIE3,0,0}, // S_POSS_DIE2 + {SPR_POSS,9,5,A_Fall,S_POSS_DIE4,0,0}, // S_POSS_DIE3 + {SPR_POSS,10,5,NULL,S_POSS_DIE5,0,0}, // S_POSS_DIE4 + {SPR_POSS,11,-1,NULL,S_NULL,0,0}, // S_POSS_DIE5 + {SPR_POSS,12,5,NULL,S_POSS_XDIE2,0,0}, // S_POSS_XDIE1 + {SPR_POSS,13,5,A_XScream,S_POSS_XDIE3,0,0}, // S_POSS_XDIE2 + {SPR_POSS,14,5,A_Fall,S_POSS_XDIE4,0,0}, // S_POSS_XDIE3 + {SPR_POSS,15,5,NULL,S_POSS_XDIE5,0,0}, // S_POSS_XDIE4 + {SPR_POSS,16,5,NULL,S_POSS_XDIE6,0,0}, // S_POSS_XDIE5 + {SPR_POSS,17,5,NULL,S_POSS_XDIE7,0,0}, // S_POSS_XDIE6 + {SPR_POSS,18,5,NULL,S_POSS_XDIE8,0,0}, // S_POSS_XDIE7 + {SPR_POSS,19,5,NULL,S_POSS_XDIE9,0,0}, // S_POSS_XDIE8 + {SPR_POSS,20,-1,NULL,S_NULL,0,0}, // S_POSS_XDIE9 + {SPR_POSS,10,5,NULL,S_POSS_RAISE2,0,0}, // S_POSS_RAISE1 + {SPR_POSS,9,5,NULL,S_POSS_RAISE3,0,0}, // S_POSS_RAISE2 + {SPR_POSS,8,5,NULL,S_POSS_RAISE4,0,0}, // S_POSS_RAISE3 + {SPR_POSS,7,5,NULL,S_POSS_RUN1,0,0}, // S_POSS_RAISE4 + {SPR_SPOS,0,10,A_Look,S_SPOS_STND2,0,0}, // S_SPOS_STND + {SPR_SPOS,1,10,A_Look,S_SPOS_STND,0,0}, // S_SPOS_STND2 + {SPR_SPOS,0,3,A_Chase,S_SPOS_RUN2,0,0}, // S_SPOS_RUN1 + {SPR_SPOS,0,3,A_Chase,S_SPOS_RUN3,0,0}, // S_SPOS_RUN2 + {SPR_SPOS,1,3,A_Chase,S_SPOS_RUN4,0,0}, // S_SPOS_RUN3 + {SPR_SPOS,1,3,A_Chase,S_SPOS_RUN5,0,0}, // S_SPOS_RUN4 + {SPR_SPOS,2,3,A_Chase,S_SPOS_RUN6,0,0}, // S_SPOS_RUN5 + {SPR_SPOS,2,3,A_Chase,S_SPOS_RUN7,0,0}, // S_SPOS_RUN6 + {SPR_SPOS,3,3,A_Chase,S_SPOS_RUN8,0,0}, // S_SPOS_RUN7 + {SPR_SPOS,3,3,A_Chase,S_SPOS_RUN1,0,0}, // S_SPOS_RUN8 + {SPR_SPOS,4,10,A_FaceTarget,S_SPOS_ATK2,0,0}, // S_SPOS_ATK1 + {SPR_SPOS,32773,10,A_SPosAttack,S_SPOS_ATK3,0,0}, // S_SPOS_ATK2 + {SPR_SPOS,4,10,NULL,S_SPOS_RUN1,0,0}, // S_SPOS_ATK3 + {SPR_SPOS,6,3,NULL,S_SPOS_PAIN2,0,0}, // S_SPOS_PAIN + {SPR_SPOS,6,3,A_Pain,S_SPOS_RUN1,0,0}, // S_SPOS_PAIN2 + {SPR_SPOS,7,5,NULL,S_SPOS_DIE2,0,0}, // S_SPOS_DIE1 + {SPR_SPOS,8,5,A_Scream,S_SPOS_DIE3,0,0}, // S_SPOS_DIE2 + {SPR_SPOS,9,5,A_Fall,S_SPOS_DIE4,0,0}, // S_SPOS_DIE3 + {SPR_SPOS,10,5,NULL,S_SPOS_DIE5,0,0}, // S_SPOS_DIE4 + {SPR_SPOS,11,-1,NULL,S_NULL,0,0}, // S_SPOS_DIE5 + {SPR_SPOS,12,5,NULL,S_SPOS_XDIE2,0,0}, // S_SPOS_XDIE1 + {SPR_SPOS,13,5,A_XScream,S_SPOS_XDIE3,0,0}, // S_SPOS_XDIE2 + {SPR_SPOS,14,5,A_Fall,S_SPOS_XDIE4,0,0}, // S_SPOS_XDIE3 + {SPR_SPOS,15,5,NULL,S_SPOS_XDIE5,0,0}, // S_SPOS_XDIE4 + {SPR_SPOS,16,5,NULL,S_SPOS_XDIE6,0,0}, // S_SPOS_XDIE5 + {SPR_SPOS,17,5,NULL,S_SPOS_XDIE7,0,0}, // S_SPOS_XDIE6 + {SPR_SPOS,18,5,NULL,S_SPOS_XDIE8,0,0}, // S_SPOS_XDIE7 + {SPR_SPOS,19,5,NULL,S_SPOS_XDIE9,0,0}, // S_SPOS_XDIE8 + {SPR_SPOS,20,-1,NULL,S_NULL,0,0}, // S_SPOS_XDIE9 + {SPR_SPOS,11,5,NULL,S_SPOS_RAISE2,0,0}, // S_SPOS_RAISE1 + {SPR_SPOS,10,5,NULL,S_SPOS_RAISE3,0,0}, // S_SPOS_RAISE2 + {SPR_SPOS,9,5,NULL,S_SPOS_RAISE4,0,0}, // S_SPOS_RAISE3 + {SPR_SPOS,8,5,NULL,S_SPOS_RAISE5,0,0}, // S_SPOS_RAISE4 + {SPR_SPOS,7,5,NULL,S_SPOS_RUN1,0,0}, // S_SPOS_RAISE5 + {SPR_VILE,0,10,A_Look,S_VILE_STND2,0,0}, // S_VILE_STND + {SPR_VILE,1,10,A_Look,S_VILE_STND,0,0}, // S_VILE_STND2 + {SPR_VILE,0,2,A_VileChase,S_VILE_RUN2,0,0}, // S_VILE_RUN1 + {SPR_VILE,0,2,A_VileChase,S_VILE_RUN3,0,0}, // S_VILE_RUN2 + {SPR_VILE,1,2,A_VileChase,S_VILE_RUN4,0,0}, // S_VILE_RUN3 + {SPR_VILE,1,2,A_VileChase,S_VILE_RUN5,0,0}, // S_VILE_RUN4 + {SPR_VILE,2,2,A_VileChase,S_VILE_RUN6,0,0}, // S_VILE_RUN5 + {SPR_VILE,2,2,A_VileChase,S_VILE_RUN7,0,0}, // S_VILE_RUN6 + {SPR_VILE,3,2,A_VileChase,S_VILE_RUN8,0,0}, // S_VILE_RUN7 + {SPR_VILE,3,2,A_VileChase,S_VILE_RUN9,0,0}, // S_VILE_RUN8 + {SPR_VILE,4,2,A_VileChase,S_VILE_RUN10,0,0}, // S_VILE_RUN9 + {SPR_VILE,4,2,A_VileChase,S_VILE_RUN11,0,0}, // S_VILE_RUN10 + {SPR_VILE,5,2,A_VileChase,S_VILE_RUN12,0,0}, // S_VILE_RUN11 + {SPR_VILE,5,2,A_VileChase,S_VILE_RUN1,0,0}, // S_VILE_RUN12 + {SPR_VILE,32774,0,A_VileStart,S_VILE_ATK2,0,0}, // S_VILE_ATK1 + {SPR_VILE,32774,10,A_FaceTarget,S_VILE_ATK3,0,0}, // S_VILE_ATK2 + {SPR_VILE,32775,8,A_VileTarget,S_VILE_ATK4,0,0}, // S_VILE_ATK3 + {SPR_VILE,32776,8,A_FaceTarget,S_VILE_ATK5,0,0}, // S_VILE_ATK4 + {SPR_VILE,32777,8,A_FaceTarget,S_VILE_ATK6,0,0}, // S_VILE_ATK5 + {SPR_VILE,32778,8,A_FaceTarget,S_VILE_ATK7,0,0}, // S_VILE_ATK6 + {SPR_VILE,32779,8,A_FaceTarget,S_VILE_ATK8,0,0}, // S_VILE_ATK7 + {SPR_VILE,32780,8,A_FaceTarget,S_VILE_ATK9,0,0}, // S_VILE_ATK8 + {SPR_VILE,32781,8,A_FaceTarget,S_VILE_ATK10,0,0}, // S_VILE_ATK9 + {SPR_VILE,32782,8,A_VileAttack,S_VILE_ATK11,0,0}, // S_VILE_ATK10 + {SPR_VILE,32783,20,NULL,S_VILE_RUN1,0,0}, // S_VILE_ATK11 + {SPR_VILE,32794,10,NULL,S_VILE_HEAL2,0,0}, // S_VILE_HEAL1 + {SPR_VILE,32795,10,NULL,S_VILE_HEAL3,0,0}, // S_VILE_HEAL2 + {SPR_VILE,32796,10,NULL,S_VILE_RUN1,0,0}, // S_VILE_HEAL3 + {SPR_VILE,16,5,NULL,S_VILE_PAIN2,0,0}, // S_VILE_PAIN + {SPR_VILE,16,5,A_Pain,S_VILE_RUN1,0,0}, // S_VILE_PAIN2 + {SPR_VILE,16,7,NULL,S_VILE_DIE2,0,0}, // S_VILE_DIE1 + {SPR_VILE,17,7,A_Scream,S_VILE_DIE3,0,0}, // S_VILE_DIE2 + {SPR_VILE,18,7,A_Fall,S_VILE_DIE4,0,0}, // S_VILE_DIE3 + {SPR_VILE,19,7,NULL,S_VILE_DIE5,0,0}, // S_VILE_DIE4 + {SPR_VILE,20,7,NULL,S_VILE_DIE6,0,0}, // S_VILE_DIE5 + {SPR_VILE,21,7,NULL,S_VILE_DIE7,0,0}, // S_VILE_DIE6 + {SPR_VILE,22,7,NULL,S_VILE_DIE8,0,0}, // S_VILE_DIE7 + {SPR_VILE,23,5,NULL,S_VILE_DIE9,0,0}, // S_VILE_DIE8 + {SPR_VILE,24,5,NULL,S_VILE_DIE10,0,0}, // S_VILE_DIE9 + {SPR_VILE,25,-1,NULL,S_NULL,0,0}, // S_VILE_DIE10 + {SPR_FIRE,32768,2,A_StartFire,S_FIRE2,0,0}, // S_FIRE1 + {SPR_FIRE,32769,2,A_Fire,S_FIRE3,0,0}, // S_FIRE2 + {SPR_FIRE,32768,2,A_Fire,S_FIRE4,0,0}, // S_FIRE3 + {SPR_FIRE,32769,2,A_Fire,S_FIRE5,0,0}, // S_FIRE4 + {SPR_FIRE,32770,2,A_FireCrackle,S_FIRE6,0,0}, // S_FIRE5 + {SPR_FIRE,32769,2,A_Fire,S_FIRE7,0,0}, // S_FIRE6 + {SPR_FIRE,32770,2,A_Fire,S_FIRE8,0,0}, // S_FIRE7 + {SPR_FIRE,32769,2,A_Fire,S_FIRE9,0,0}, // S_FIRE8 + {SPR_FIRE,32770,2,A_Fire,S_FIRE10,0,0}, // S_FIRE9 + {SPR_FIRE,32771,2,A_Fire,S_FIRE11,0,0}, // S_FIRE10 + {SPR_FIRE,32770,2,A_Fire,S_FIRE12,0,0}, // S_FIRE11 + {SPR_FIRE,32771,2,A_Fire,S_FIRE13,0,0}, // S_FIRE12 + {SPR_FIRE,32770,2,A_Fire,S_FIRE14,0,0}, // S_FIRE13 + {SPR_FIRE,32771,2,A_Fire,S_FIRE15,0,0}, // S_FIRE14 + {SPR_FIRE,32772,2,A_Fire,S_FIRE16,0,0}, // S_FIRE15 + {SPR_FIRE,32771,2,A_Fire,S_FIRE17,0,0}, // S_FIRE16 + {SPR_FIRE,32772,2,A_Fire,S_FIRE18,0,0}, // S_FIRE17 + {SPR_FIRE,32771,2,A_Fire,S_FIRE19,0,0}, // S_FIRE18 + {SPR_FIRE,32772,2,A_FireCrackle,S_FIRE20,0,0}, // S_FIRE19 + {SPR_FIRE,32773,2,A_Fire,S_FIRE21,0,0}, // S_FIRE20 + {SPR_FIRE,32772,2,A_Fire,S_FIRE22,0,0}, // S_FIRE21 + {SPR_FIRE,32773,2,A_Fire,S_FIRE23,0,0}, // S_FIRE22 + {SPR_FIRE,32772,2,A_Fire,S_FIRE24,0,0}, // S_FIRE23 + {SPR_FIRE,32773,2,A_Fire,S_FIRE25,0,0}, // S_FIRE24 + {SPR_FIRE,32774,2,A_Fire,S_FIRE26,0,0}, // S_FIRE25 + {SPR_FIRE,32775,2,A_Fire,S_FIRE27,0,0}, // S_FIRE26 + {SPR_FIRE,32774,2,A_Fire,S_FIRE28,0,0}, // S_FIRE27 + {SPR_FIRE,32775,2,A_Fire,S_FIRE29,0,0}, // S_FIRE28 + {SPR_FIRE,32774,2,A_Fire,S_FIRE30,0,0}, // S_FIRE29 + {SPR_FIRE,32775,2,A_Fire,S_NULL,0,0}, // S_FIRE30 + {SPR_PUFF,1,4,NULL,S_SMOKE2,0,0}, // S_SMOKE1 + {SPR_PUFF,2,4,NULL,S_SMOKE3,0,0}, // S_SMOKE2 + {SPR_PUFF,1,4,NULL,S_SMOKE4,0,0}, // S_SMOKE3 + {SPR_PUFF,2,4,NULL,S_SMOKE5,0,0}, // S_SMOKE4 + {SPR_PUFF,3,4,NULL,S_NULL,0,0}, // S_SMOKE5 + {SPR_FATB,32768,2,A_Tracer,S_TRACER2,0,0}, // S_TRACER + {SPR_FATB,32769,2,A_Tracer,S_TRACER,0,0}, // S_TRACER2 + {SPR_FBXP,32768,8,NULL,S_TRACEEXP2,0,0}, // S_TRACEEXP1 + {SPR_FBXP,32769,6,NULL,S_TRACEEXP3,0,0}, // S_TRACEEXP2 + {SPR_FBXP,32770,4,NULL,S_NULL,0,0}, // S_TRACEEXP3 + {SPR_SKEL,0,10,A_Look,S_SKEL_STND2,0,0}, // S_SKEL_STND + {SPR_SKEL,1,10,A_Look,S_SKEL_STND,0,0}, // S_SKEL_STND2 + {SPR_SKEL,0,2,A_Chase,S_SKEL_RUN2,0,0}, // S_SKEL_RUN1 + {SPR_SKEL,0,2,A_Chase,S_SKEL_RUN3,0,0}, // S_SKEL_RUN2 + {SPR_SKEL,1,2,A_Chase,S_SKEL_RUN4,0,0}, // S_SKEL_RUN3 + {SPR_SKEL,1,2,A_Chase,S_SKEL_RUN5,0,0}, // S_SKEL_RUN4 + {SPR_SKEL,2,2,A_Chase,S_SKEL_RUN6,0,0}, // S_SKEL_RUN5 + {SPR_SKEL,2,2,A_Chase,S_SKEL_RUN7,0,0}, // S_SKEL_RUN6 + {SPR_SKEL,3,2,A_Chase,S_SKEL_RUN8,0,0}, // S_SKEL_RUN7 + {SPR_SKEL,3,2,A_Chase,S_SKEL_RUN9,0,0}, // S_SKEL_RUN8 + {SPR_SKEL,4,2,A_Chase,S_SKEL_RUN10,0,0}, // S_SKEL_RUN9 + {SPR_SKEL,4,2,A_Chase,S_SKEL_RUN11,0,0}, // S_SKEL_RUN10 + {SPR_SKEL,5,2,A_Chase,S_SKEL_RUN12,0,0}, // S_SKEL_RUN11 + {SPR_SKEL,5,2,A_Chase,S_SKEL_RUN1,0,0}, // S_SKEL_RUN12 + {SPR_SKEL,6,0,A_FaceTarget,S_SKEL_FIST2,0,0}, // S_SKEL_FIST1 + {SPR_SKEL,6,6,A_SkelWhoosh,S_SKEL_FIST3,0,0}, // S_SKEL_FIST2 + {SPR_SKEL,7,6,A_FaceTarget,S_SKEL_FIST4,0,0}, // S_SKEL_FIST3 + {SPR_SKEL,8,6,A_SkelFist,S_SKEL_RUN1,0,0}, // S_SKEL_FIST4 + {SPR_SKEL,32777,0,A_FaceTarget,S_SKEL_MISS2,0,0}, // S_SKEL_MISS1 + {SPR_SKEL,32777,10,A_FaceTarget,S_SKEL_MISS3,0,0}, // S_SKEL_MISS2 + {SPR_SKEL,10,10,A_SkelMissile,S_SKEL_MISS4,0,0}, // S_SKEL_MISS3 + {SPR_SKEL,10,10,A_FaceTarget,S_SKEL_RUN1,0,0}, // S_SKEL_MISS4 + {SPR_SKEL,11,5,NULL,S_SKEL_PAIN2,0,0}, // S_SKEL_PAIN + {SPR_SKEL,11,5,A_Pain,S_SKEL_RUN1,0,0}, // S_SKEL_PAIN2 + {SPR_SKEL,11,7,NULL,S_SKEL_DIE2,0,0}, // S_SKEL_DIE1 + {SPR_SKEL,12,7,NULL,S_SKEL_DIE3,0,0}, // S_SKEL_DIE2 + {SPR_SKEL,13,7,A_Scream,S_SKEL_DIE4,0,0}, // S_SKEL_DIE3 + {SPR_SKEL,14,7,A_Fall,S_SKEL_DIE5,0,0}, // S_SKEL_DIE4 + {SPR_SKEL,15,7,NULL,S_SKEL_DIE6,0,0}, // S_SKEL_DIE5 + {SPR_SKEL,16,-1,NULL,S_NULL,0,0}, // S_SKEL_DIE6 + {SPR_SKEL,16,5,NULL,S_SKEL_RAISE2,0,0}, // S_SKEL_RAISE1 + {SPR_SKEL,15,5,NULL,S_SKEL_RAISE3,0,0}, // S_SKEL_RAISE2 + {SPR_SKEL,14,5,NULL,S_SKEL_RAISE4,0,0}, // S_SKEL_RAISE3 + {SPR_SKEL,13,5,NULL,S_SKEL_RAISE5,0,0}, // S_SKEL_RAISE4 + {SPR_SKEL,12,5,NULL,S_SKEL_RAISE6,0,0}, // S_SKEL_RAISE5 + {SPR_SKEL,11,5,NULL,S_SKEL_RUN1,0,0}, // S_SKEL_RAISE6 + {SPR_MANF,32768,4,NULL,S_FATSHOT2,0,0}, // S_FATSHOT1 + {SPR_MANF,32769,4,NULL,S_FATSHOT1,0,0}, // S_FATSHOT2 + {SPR_MISL,32769,8,NULL,S_FATSHOTX2,0,0}, // S_FATSHOTX1 + {SPR_MISL,32770,6,NULL,S_FATSHOTX3,0,0}, // S_FATSHOTX2 + {SPR_MISL,32771,4,NULL,S_NULL,0,0}, // S_FATSHOTX3 + {SPR_FATT,0,15,A_Look,S_FATT_STND2,0,0}, // S_FATT_STND + {SPR_FATT,1,15,A_Look,S_FATT_STND,0,0}, // S_FATT_STND2 + {SPR_FATT,0,4,A_Chase,S_FATT_RUN2,0,0}, // S_FATT_RUN1 + {SPR_FATT,0,4,A_Chase,S_FATT_RUN3,0,0}, // S_FATT_RUN2 + {SPR_FATT,1,4,A_Chase,S_FATT_RUN4,0,0}, // S_FATT_RUN3 + {SPR_FATT,1,4,A_Chase,S_FATT_RUN5,0,0}, // S_FATT_RUN4 + {SPR_FATT,2,4,A_Chase,S_FATT_RUN6,0,0}, // S_FATT_RUN5 + {SPR_FATT,2,4,A_Chase,S_FATT_RUN7,0,0}, // S_FATT_RUN6 + {SPR_FATT,3,4,A_Chase,S_FATT_RUN8,0,0}, // S_FATT_RUN7 + {SPR_FATT,3,4,A_Chase,S_FATT_RUN9,0,0}, // S_FATT_RUN8 + {SPR_FATT,4,4,A_Chase,S_FATT_RUN10,0,0}, // S_FATT_RUN9 + {SPR_FATT,4,4,A_Chase,S_FATT_RUN11,0,0}, // S_FATT_RUN10 + {SPR_FATT,5,4,A_Chase,S_FATT_RUN12,0,0}, // S_FATT_RUN11 + {SPR_FATT,5,4,A_Chase,S_FATT_RUN1,0,0}, // S_FATT_RUN12 + {SPR_FATT,6,20,A_FatRaise,S_FATT_ATK2,0,0}, // S_FATT_ATK1 + {SPR_FATT,32775,10,A_FatAttack1,S_FATT_ATK3,0,0}, // S_FATT_ATK2 + {SPR_FATT,8,5,A_FaceTarget,S_FATT_ATK4,0,0}, // S_FATT_ATK3 + {SPR_FATT,6,5,A_FaceTarget,S_FATT_ATK5,0,0}, // S_FATT_ATK4 + {SPR_FATT,32775,10,A_FatAttack2,S_FATT_ATK6,0,0}, // S_FATT_ATK5 + {SPR_FATT,8,5,A_FaceTarget,S_FATT_ATK7,0,0}, // S_FATT_ATK6 + {SPR_FATT,6,5,A_FaceTarget,S_FATT_ATK8,0,0}, // S_FATT_ATK7 + {SPR_FATT,32775,10,A_FatAttack3,S_FATT_ATK9,0,0}, // S_FATT_ATK8 + {SPR_FATT,8,5,A_FaceTarget,S_FATT_ATK10,0,0}, // S_FATT_ATK9 + {SPR_FATT,6,5,A_FaceTarget,S_FATT_RUN1,0,0}, // S_FATT_ATK10 + {SPR_FATT,9,3,NULL,S_FATT_PAIN2,0,0}, // S_FATT_PAIN + {SPR_FATT,9,3,A_Pain,S_FATT_RUN1,0,0}, // S_FATT_PAIN2 + {SPR_FATT,10,6,NULL,S_FATT_DIE2,0,0}, // S_FATT_DIE1 + {SPR_FATT,11,6,A_Scream,S_FATT_DIE3,0,0}, // S_FATT_DIE2 + {SPR_FATT,12,6,A_Fall,S_FATT_DIE4,0,0}, // S_FATT_DIE3 + {SPR_FATT,13,6,NULL,S_FATT_DIE5,0,0}, // S_FATT_DIE4 + {SPR_FATT,14,6,NULL,S_FATT_DIE6,0,0}, // S_FATT_DIE5 + {SPR_FATT,15,6,NULL,S_FATT_DIE7,0,0}, // S_FATT_DIE6 + {SPR_FATT,16,6,NULL,S_FATT_DIE8,0,0}, // S_FATT_DIE7 + {SPR_FATT,17,6,NULL,S_FATT_DIE9,0,0}, // S_FATT_DIE8 + {SPR_FATT,18,6,NULL,S_FATT_DIE10,0,0}, // S_FATT_DIE9 + {SPR_FATT,19,-1,A_BossDeath,S_NULL,0,0}, // S_FATT_DIE10 + {SPR_FATT,17,5,NULL,S_FATT_RAISE2,0,0}, // S_FATT_RAISE1 + {SPR_FATT,16,5,NULL,S_FATT_RAISE3,0,0}, // S_FATT_RAISE2 + {SPR_FATT,15,5,NULL,S_FATT_RAISE4,0,0}, // S_FATT_RAISE3 + {SPR_FATT,14,5,NULL,S_FATT_RAISE5,0,0}, // S_FATT_RAISE4 + {SPR_FATT,13,5,NULL,S_FATT_RAISE6,0,0}, // S_FATT_RAISE5 + {SPR_FATT,12,5,NULL,S_FATT_RAISE7,0,0}, // S_FATT_RAISE6 + {SPR_FATT,11,5,NULL,S_FATT_RAISE8,0,0}, // S_FATT_RAISE7 + {SPR_FATT,10,5,NULL,S_FATT_RUN1,0,0}, // S_FATT_RAISE8 + {SPR_CPOS,0,10,A_Look,S_CPOS_STND2,0,0}, // S_CPOS_STND + {SPR_CPOS,1,10,A_Look,S_CPOS_STND,0,0}, // S_CPOS_STND2 + {SPR_CPOS,0,3,A_Chase,S_CPOS_RUN2,0,0}, // S_CPOS_RUN1 + {SPR_CPOS,0,3,A_Chase,S_CPOS_RUN3,0,0}, // S_CPOS_RUN2 + {SPR_CPOS,1,3,A_Chase,S_CPOS_RUN4,0,0}, // S_CPOS_RUN3 + {SPR_CPOS,1,3,A_Chase,S_CPOS_RUN5,0,0}, // S_CPOS_RUN4 + {SPR_CPOS,2,3,A_Chase,S_CPOS_RUN6,0,0}, // S_CPOS_RUN5 + {SPR_CPOS,2,3,A_Chase,S_CPOS_RUN7,0,0}, // S_CPOS_RUN6 + {SPR_CPOS,3,3,A_Chase,S_CPOS_RUN8,0,0}, // S_CPOS_RUN7 + {SPR_CPOS,3,3,A_Chase,S_CPOS_RUN1,0,0}, // S_CPOS_RUN8 + {SPR_CPOS,4,10,A_FaceTarget,S_CPOS_ATK2,0,0}, // S_CPOS_ATK1 + {SPR_CPOS,32773,4,A_CPosAttack,S_CPOS_ATK3,0,0}, // S_CPOS_ATK2 + {SPR_CPOS,32772,4,A_CPosAttack,S_CPOS_ATK4,0,0}, // S_CPOS_ATK3 + {SPR_CPOS,5,1,A_CPosRefire,S_CPOS_ATK2,0,0}, // S_CPOS_ATK4 + {SPR_CPOS,6,3,NULL,S_CPOS_PAIN2,0,0}, // S_CPOS_PAIN + {SPR_CPOS,6,3,A_Pain,S_CPOS_RUN1,0,0}, // S_CPOS_PAIN2 + {SPR_CPOS,7,5,NULL,S_CPOS_DIE2,0,0}, // S_CPOS_DIE1 + {SPR_CPOS,8,5,A_Scream,S_CPOS_DIE3,0,0}, // S_CPOS_DIE2 + {SPR_CPOS,9,5,A_Fall,S_CPOS_DIE4,0,0}, // S_CPOS_DIE3 + {SPR_CPOS,10,5,NULL,S_CPOS_DIE5,0,0}, // S_CPOS_DIE4 + {SPR_CPOS,11,5,NULL,S_CPOS_DIE6,0,0}, // S_CPOS_DIE5 + {SPR_CPOS,12,5,NULL,S_CPOS_DIE7,0,0}, // S_CPOS_DIE6 + {SPR_CPOS,13,-1,NULL,S_NULL,0,0}, // S_CPOS_DIE7 + {SPR_CPOS,14,5,NULL,S_CPOS_XDIE2,0,0}, // S_CPOS_XDIE1 + {SPR_CPOS,15,5,A_XScream,S_CPOS_XDIE3,0,0}, // S_CPOS_XDIE2 + {SPR_CPOS,16,5,A_Fall,S_CPOS_XDIE4,0,0}, // S_CPOS_XDIE3 + {SPR_CPOS,17,5,NULL,S_CPOS_XDIE5,0,0}, // S_CPOS_XDIE4 + {SPR_CPOS,18,5,NULL,S_CPOS_XDIE6,0,0}, // S_CPOS_XDIE5 + {SPR_CPOS,19,-1,NULL,S_NULL,0,0}, // S_CPOS_XDIE6 + {SPR_CPOS,13,5,NULL,S_CPOS_RAISE2,0,0}, // S_CPOS_RAISE1 + {SPR_CPOS,12,5,NULL,S_CPOS_RAISE3,0,0}, // S_CPOS_RAISE2 + {SPR_CPOS,11,5,NULL,S_CPOS_RAISE4,0,0}, // S_CPOS_RAISE3 + {SPR_CPOS,10,5,NULL,S_CPOS_RAISE5,0,0}, // S_CPOS_RAISE4 + {SPR_CPOS,9,5,NULL,S_CPOS_RAISE6,0,0}, // S_CPOS_RAISE5 + {SPR_CPOS,8,5,NULL,S_CPOS_RAISE7,0,0}, // S_CPOS_RAISE6 + {SPR_CPOS,7,5,NULL,S_CPOS_RUN1,0,0}, // S_CPOS_RAISE7 + {SPR_TROO,0,10,A_Look,S_TROO_STND2,0,0}, // S_TROO_STND + {SPR_TROO,1,10,A_Look,S_TROO_STND,0,0}, // S_TROO_STND2 + {SPR_TROO,0,3,A_Chase,S_TROO_RUN2,0,0}, // S_TROO_RUN1 + {SPR_TROO,0,3,A_Chase,S_TROO_RUN3,0,0}, // S_TROO_RUN2 + {SPR_TROO,1,3,A_Chase,S_TROO_RUN4,0,0}, // S_TROO_RUN3 + {SPR_TROO,1,3,A_Chase,S_TROO_RUN5,0,0}, // S_TROO_RUN4 + {SPR_TROO,2,3,A_Chase,S_TROO_RUN6,0,0}, // S_TROO_RUN5 + {SPR_TROO,2,3,A_Chase,S_TROO_RUN7,0,0}, // S_TROO_RUN6 + {SPR_TROO,3,3,A_Chase,S_TROO_RUN8,0,0}, // S_TROO_RUN7 + {SPR_TROO,3,3,A_Chase,S_TROO_RUN1,0,0}, // S_TROO_RUN8 + {SPR_TROO,4,8,A_FaceTarget,S_TROO_ATK2,0,0}, // S_TROO_ATK1 + {SPR_TROO,5,8,A_FaceTarget,S_TROO_ATK3,0,0}, // S_TROO_ATK2 + {SPR_TROO,6,6,A_TroopAttack,S_TROO_RUN1,0,0}, // S_TROO_ATK3 + {SPR_TROO,7,2,NULL,S_TROO_PAIN2,0,0}, // S_TROO_PAIN + {SPR_TROO,7,2,A_Pain,S_TROO_RUN1,0,0}, // S_TROO_PAIN2 + {SPR_TROO,8,8,NULL,S_TROO_DIE2,0,0}, // S_TROO_DIE1 + {SPR_TROO,9,8,A_Scream,S_TROO_DIE3,0,0}, // S_TROO_DIE2 + {SPR_TROO,10,6,NULL,S_TROO_DIE4,0,0}, // S_TROO_DIE3 + {SPR_TROO,11,6,A_Fall,S_TROO_DIE5,0,0}, // S_TROO_DIE4 + {SPR_TROO,12,-1,NULL,S_NULL,0,0}, // S_TROO_DIE5 + {SPR_TROO,13,5,NULL,S_TROO_XDIE2,0,0}, // S_TROO_XDIE1 + {SPR_TROO,14,5,A_XScream,S_TROO_XDIE3,0,0}, // S_TROO_XDIE2 + {SPR_TROO,15,5,NULL,S_TROO_XDIE4,0,0}, // S_TROO_XDIE3 + {SPR_TROO,16,5,A_Fall,S_TROO_XDIE5,0,0}, // S_TROO_XDIE4 + {SPR_TROO,17,5,NULL,S_TROO_XDIE6,0,0}, // S_TROO_XDIE5 + {SPR_TROO,18,5,NULL,S_TROO_XDIE7,0,0}, // S_TROO_XDIE6 + {SPR_TROO,19,5,NULL,S_TROO_XDIE8,0,0}, // S_TROO_XDIE7 + {SPR_TROO,20,-1,NULL,S_NULL,0,0}, // S_TROO_XDIE8 + {SPR_TROO,12,8,NULL,S_TROO_RAISE2,0,0}, // S_TROO_RAISE1 + {SPR_TROO,11,8,NULL,S_TROO_RAISE3,0,0}, // S_TROO_RAISE2 + {SPR_TROO,10,6,NULL,S_TROO_RAISE4,0,0}, // S_TROO_RAISE3 + {SPR_TROO,9,6,NULL,S_TROO_RAISE5,0,0}, // S_TROO_RAISE4 + {SPR_TROO,8,6,NULL,S_TROO_RUN1,0,0}, // S_TROO_RAISE5 + {SPR_SARG,0,10,A_Look,S_SARG_STND2,0,0}, // S_SARG_STND + {SPR_SARG,1,10,A_Look,S_SARG_STND,0,0}, // S_SARG_STND2 + {SPR_SARG,0,2,A_Chase,S_SARG_RUN2,0,0}, // S_SARG_RUN1 + {SPR_SARG,0,2,A_Chase,S_SARG_RUN3,0,0}, // S_SARG_RUN2 + {SPR_SARG,1,2,A_Chase,S_SARG_RUN4,0,0}, // S_SARG_RUN3 + {SPR_SARG,1,2,A_Chase,S_SARG_RUN5,0,0}, // S_SARG_RUN4 + {SPR_SARG,2,2,A_Chase,S_SARG_RUN6,0,0}, // S_SARG_RUN5 + {SPR_SARG,2,2,A_Chase,S_SARG_RUN7,0,0}, // S_SARG_RUN6 + {SPR_SARG,3,2,A_Chase,S_SARG_RUN8,0,0}, // S_SARG_RUN7 + {SPR_SARG,3,2,A_Chase,S_SARG_RUN1,0,0}, // S_SARG_RUN8 + {SPR_SARG,4,8,A_FaceTarget,S_SARG_ATK2,0,0}, // S_SARG_ATK1 + {SPR_SARG,5,8,A_FaceTarget,S_SARG_ATK3,0,0}, // S_SARG_ATK2 + {SPR_SARG,6,8,A_SargAttack,S_SARG_RUN1,0,0}, // S_SARG_ATK3 + {SPR_SARG,7,2,NULL,S_SARG_PAIN2,0,0}, // S_SARG_PAIN + {SPR_SARG,7,2,A_Pain,S_SARG_RUN1,0,0}, // S_SARG_PAIN2 + {SPR_SARG,8,8,NULL,S_SARG_DIE2,0,0}, // S_SARG_DIE1 + {SPR_SARG,9,8,A_Scream,S_SARG_DIE3,0,0}, // S_SARG_DIE2 + {SPR_SARG,10,4,NULL,S_SARG_DIE4,0,0}, // S_SARG_DIE3 + {SPR_SARG,11,4,A_Fall,S_SARG_DIE5,0,0}, // S_SARG_DIE4 + {SPR_SARG,12,4,NULL,S_SARG_DIE6,0,0}, // S_SARG_DIE5 + {SPR_SARG,13,-1,NULL,S_NULL,0,0}, // S_SARG_DIE6 + {SPR_SARG,13,5,NULL,S_SARG_RAISE2,0,0}, // S_SARG_RAISE1 + {SPR_SARG,12,5,NULL,S_SARG_RAISE3,0,0}, // S_SARG_RAISE2 + {SPR_SARG,11,5,NULL,S_SARG_RAISE4,0,0}, // S_SARG_RAISE3 + {SPR_SARG,10,5,NULL,S_SARG_RAISE5,0,0}, // S_SARG_RAISE4 + {SPR_SARG,9,5,NULL,S_SARG_RAISE6,0,0}, // S_SARG_RAISE5 + {SPR_SARG,8,5,NULL,S_SARG_RUN1,0,0}, // S_SARG_RAISE6 + {SPR_HEAD,0,10,A_Look,S_HEAD_STND,0,0}, // S_HEAD_STND + {SPR_HEAD,0,3,A_Chase,S_HEAD_RUN1,0,0}, // S_HEAD_RUN1 + {SPR_HEAD,1,5,A_FaceTarget,S_HEAD_ATK2,0,0}, // S_HEAD_ATK1 + {SPR_HEAD,2,5,A_FaceTarget,S_HEAD_ATK3,0,0}, // S_HEAD_ATK2 + {SPR_HEAD,32771,5,A_HeadAttack,S_HEAD_RUN1,0,0}, // S_HEAD_ATK3 + {SPR_HEAD,4,3,NULL,S_HEAD_PAIN2,0,0}, // S_HEAD_PAIN + {SPR_HEAD,4,3,A_Pain,S_HEAD_PAIN3,0,0}, // S_HEAD_PAIN2 + {SPR_HEAD,5,6,NULL,S_HEAD_RUN1,0,0}, // S_HEAD_PAIN3 + {SPR_HEAD,6,8,NULL,S_HEAD_DIE2,0,0}, // S_HEAD_DIE1 + {SPR_HEAD,7,8,A_Scream,S_HEAD_DIE3,0,0}, // S_HEAD_DIE2 + {SPR_HEAD,8,8,NULL,S_HEAD_DIE4,0,0}, // S_HEAD_DIE3 + {SPR_HEAD,9,8,NULL,S_HEAD_DIE5,0,0}, // S_HEAD_DIE4 + {SPR_HEAD,10,8,A_Fall,S_HEAD_DIE6,0,0}, // S_HEAD_DIE5 + {SPR_HEAD,11,-1,NULL,S_NULL,0,0}, // S_HEAD_DIE6 + {SPR_HEAD,11,8,NULL,S_HEAD_RAISE2,0,0}, // S_HEAD_RAISE1 + {SPR_HEAD,10,8,NULL,S_HEAD_RAISE3,0,0}, // S_HEAD_RAISE2 + {SPR_HEAD,9,8,NULL,S_HEAD_RAISE4,0,0}, // S_HEAD_RAISE3 + {SPR_HEAD,8,8,NULL,S_HEAD_RAISE5,0,0}, // S_HEAD_RAISE4 + {SPR_HEAD,7,8,NULL,S_HEAD_RAISE6,0,0}, // S_HEAD_RAISE5 + {SPR_HEAD,6,8,NULL,S_HEAD_RUN1,0,0}, // S_HEAD_RAISE6 + {SPR_BAL7,32768,4,NULL,S_BRBALL2,0,0}, // S_BRBALL1 + {SPR_BAL7,32769,4,NULL,S_BRBALL1,0,0}, // S_BRBALL2 + {SPR_BAL7,32770,6,NULL,S_BRBALLX2,0,0}, // S_BRBALLX1 + {SPR_BAL7,32771,6,NULL,S_BRBALLX3,0,0}, // S_BRBALLX2 + {SPR_BAL7,32772,6,NULL,S_NULL,0,0}, // S_BRBALLX3 + {SPR_BOSS,0,10,A_Look,S_BOSS_STND2,0,0}, // S_BOSS_STND + {SPR_BOSS,1,10,A_Look,S_BOSS_STND,0,0}, // S_BOSS_STND2 + {SPR_BOSS,0,3,A_Chase,S_BOSS_RUN2,0,0}, // S_BOSS_RUN1 + {SPR_BOSS,0,3,A_Chase,S_BOSS_RUN3,0,0}, // S_BOSS_RUN2 + {SPR_BOSS,1,3,A_Chase,S_BOSS_RUN4,0,0}, // S_BOSS_RUN3 + {SPR_BOSS,1,3,A_Chase,S_BOSS_RUN5,0,0}, // S_BOSS_RUN4 + {SPR_BOSS,2,3,A_Chase,S_BOSS_RUN6,0,0}, // S_BOSS_RUN5 + {SPR_BOSS,2,3,A_Chase,S_BOSS_RUN7,0,0}, // S_BOSS_RUN6 + {SPR_BOSS,3,3,A_Chase,S_BOSS_RUN8,0,0}, // S_BOSS_RUN7 + {SPR_BOSS,3,3,A_Chase,S_BOSS_RUN1,0,0}, // S_BOSS_RUN8 + {SPR_BOSS,4,8,A_FaceTarget,S_BOSS_ATK2,0,0}, // S_BOSS_ATK1 + {SPR_BOSS,5,8,A_FaceTarget,S_BOSS_ATK3,0,0}, // S_BOSS_ATK2 + {SPR_BOSS,6,8,A_BruisAttack,S_BOSS_RUN1,0,0}, // S_BOSS_ATK3 + {SPR_BOSS,7,2,NULL,S_BOSS_PAIN2,0,0}, // S_BOSS_PAIN + {SPR_BOSS,7,2,A_Pain,S_BOSS_RUN1,0,0}, // S_BOSS_PAIN2 + {SPR_BOSS,8,8,NULL,S_BOSS_DIE2,0,0}, // S_BOSS_DIE1 + {SPR_BOSS,9,8,A_Scream,S_BOSS_DIE3,0,0}, // S_BOSS_DIE2 + {SPR_BOSS,10,8,NULL,S_BOSS_DIE4,0,0}, // S_BOSS_DIE3 + {SPR_BOSS,11,8,A_Fall,S_BOSS_DIE5,0,0}, // S_BOSS_DIE4 + {SPR_BOSS,12,8,NULL,S_BOSS_DIE6,0,0}, // S_BOSS_DIE5 + {SPR_BOSS,13,8,NULL,S_BOSS_DIE7,0,0}, // S_BOSS_DIE6 + {SPR_BOSS,14,-1,A_BossDeath,S_NULL,0,0}, // S_BOSS_DIE7 + {SPR_BOSS,14,8,NULL,S_BOSS_RAISE2,0,0}, // S_BOSS_RAISE1 + {SPR_BOSS,13,8,NULL,S_BOSS_RAISE3,0,0}, // S_BOSS_RAISE2 + {SPR_BOSS,12,8,NULL,S_BOSS_RAISE4,0,0}, // S_BOSS_RAISE3 + {SPR_BOSS,11,8,NULL,S_BOSS_RAISE5,0,0}, // S_BOSS_RAISE4 + {SPR_BOSS,10,8,NULL,S_BOSS_RAISE6,0,0}, // S_BOSS_RAISE5 + {SPR_BOSS,9,8,NULL,S_BOSS_RAISE7,0,0}, // S_BOSS_RAISE6 + {SPR_BOSS,8,8,NULL,S_BOSS_RUN1,0,0}, // S_BOSS_RAISE7 + {SPR_BOS2,0,10,A_Look,S_BOS2_STND2,0,0}, // S_BOS2_STND + {SPR_BOS2,1,10,A_Look,S_BOS2_STND,0,0}, // S_BOS2_STND2 + {SPR_BOS2,0,3,A_Chase,S_BOS2_RUN2,0,0}, // S_BOS2_RUN1 + {SPR_BOS2,0,3,A_Chase,S_BOS2_RUN3,0,0}, // S_BOS2_RUN2 + {SPR_BOS2,1,3,A_Chase,S_BOS2_RUN4,0,0}, // S_BOS2_RUN3 + {SPR_BOS2,1,3,A_Chase,S_BOS2_RUN5,0,0}, // S_BOS2_RUN4 + {SPR_BOS2,2,3,A_Chase,S_BOS2_RUN6,0,0}, // S_BOS2_RUN5 + {SPR_BOS2,2,3,A_Chase,S_BOS2_RUN7,0,0}, // S_BOS2_RUN6 + {SPR_BOS2,3,3,A_Chase,S_BOS2_RUN8,0,0}, // S_BOS2_RUN7 + {SPR_BOS2,3,3,A_Chase,S_BOS2_RUN1,0,0}, // S_BOS2_RUN8 + {SPR_BOS2,4,8,A_FaceTarget,S_BOS2_ATK2,0,0}, // S_BOS2_ATK1 + {SPR_BOS2,5,8,A_FaceTarget,S_BOS2_ATK3,0,0}, // S_BOS2_ATK2 + {SPR_BOS2,6,8,A_BruisAttack,S_BOS2_RUN1,0,0}, // S_BOS2_ATK3 + {SPR_BOS2,7,2,NULL,S_BOS2_PAIN2,0,0}, // S_BOS2_PAIN + {SPR_BOS2,7,2,A_Pain,S_BOS2_RUN1,0,0}, // S_BOS2_PAIN2 + {SPR_BOS2,8,8,NULL,S_BOS2_DIE2,0,0}, // S_BOS2_DIE1 + {SPR_BOS2,9,8,A_Scream,S_BOS2_DIE3,0,0}, // S_BOS2_DIE2 + {SPR_BOS2,10,8,NULL,S_BOS2_DIE4,0,0}, // S_BOS2_DIE3 + {SPR_BOS2,11,8,A_Fall,S_BOS2_DIE5,0,0}, // S_BOS2_DIE4 + {SPR_BOS2,12,8,NULL,S_BOS2_DIE6,0,0}, // S_BOS2_DIE5 + {SPR_BOS2,13,8,NULL,S_BOS2_DIE7,0,0}, // S_BOS2_DIE6 + {SPR_BOS2,14,-1,NULL,S_NULL,0,0}, // S_BOS2_DIE7 + {SPR_BOS2,14,8,NULL,S_BOS2_RAISE2,0,0}, // S_BOS2_RAISE1 + {SPR_BOS2,13,8,NULL,S_BOS2_RAISE3,0,0}, // S_BOS2_RAISE2 + {SPR_BOS2,12,8,NULL,S_BOS2_RAISE4,0,0}, // S_BOS2_RAISE3 + {SPR_BOS2,11,8,NULL,S_BOS2_RAISE5,0,0}, // S_BOS2_RAISE4 + {SPR_BOS2,10,8,NULL,S_BOS2_RAISE6,0,0}, // S_BOS2_RAISE5 + {SPR_BOS2,9,8,NULL,S_BOS2_RAISE7,0,0}, // S_BOS2_RAISE6 + {SPR_BOS2,8,8,NULL,S_BOS2_RUN1,0,0}, // S_BOS2_RAISE7 + {SPR_SKUL,32768,10,A_Look,S_SKULL_STND2,0,0}, // S_SKULL_STND + {SPR_SKUL,32769,10,A_Look,S_SKULL_STND,0,0}, // S_SKULL_STND2 + {SPR_SKUL,32768,6,A_Chase,S_SKULL_RUN2,0,0}, // S_SKULL_RUN1 + {SPR_SKUL,32769,6,A_Chase,S_SKULL_RUN1,0,0}, // S_SKULL_RUN2 + {SPR_SKUL,32770,10,A_FaceTarget,S_SKULL_ATK2,0,0}, // S_SKULL_ATK1 + {SPR_SKUL,32771,4,A_SkullAttack,S_SKULL_ATK3,0,0}, // S_SKULL_ATK2 + {SPR_SKUL,32770,4,NULL,S_SKULL_ATK4,0,0}, // S_SKULL_ATK3 + {SPR_SKUL,32771,4,NULL,S_SKULL_ATK3,0,0}, // S_SKULL_ATK4 + {SPR_SKUL,32772,3,NULL,S_SKULL_PAIN2,0,0}, // S_SKULL_PAIN + {SPR_SKUL,32772,3,A_Pain,S_SKULL_RUN1,0,0}, // S_SKULL_PAIN2 + {SPR_SKUL,32773,6,NULL,S_SKULL_DIE2,0,0}, // S_SKULL_DIE1 + {SPR_SKUL,32774,6,A_Scream,S_SKULL_DIE3,0,0}, // S_SKULL_DIE2 + {SPR_SKUL,32775,6,NULL,S_SKULL_DIE4,0,0}, // S_SKULL_DIE3 + {SPR_SKUL,32776,6,A_Fall,S_SKULL_DIE5,0,0}, // S_SKULL_DIE4 + {SPR_SKUL,9,6,NULL,S_SKULL_DIE6,0,0}, // S_SKULL_DIE5 + {SPR_SKUL,10,6,NULL,S_NULL,0,0}, // S_SKULL_DIE6 + {SPR_SPID,0,10,A_Look,S_SPID_STND2,0,0}, // S_SPID_STND + {SPR_SPID,1,10,A_Look,S_SPID_STND,0,0}, // S_SPID_STND2 + {SPR_SPID,0,3,A_Metal,S_SPID_RUN2,0,0}, // S_SPID_RUN1 + {SPR_SPID,0,3,A_Chase,S_SPID_RUN3,0,0}, // S_SPID_RUN2 + {SPR_SPID,1,3,A_Chase,S_SPID_RUN4,0,0}, // S_SPID_RUN3 + {SPR_SPID,1,3,A_Chase,S_SPID_RUN5,0,0}, // S_SPID_RUN4 + {SPR_SPID,2,3,A_Metal,S_SPID_RUN6,0,0}, // S_SPID_RUN5 + {SPR_SPID,2,3,A_Chase,S_SPID_RUN7,0,0}, // S_SPID_RUN6 + {SPR_SPID,3,3,A_Chase,S_SPID_RUN8,0,0}, // S_SPID_RUN7 + {SPR_SPID,3,3,A_Chase,S_SPID_RUN9,0,0}, // S_SPID_RUN8 + {SPR_SPID,4,3,A_Metal,S_SPID_RUN10,0,0}, // S_SPID_RUN9 + {SPR_SPID,4,3,A_Chase,S_SPID_RUN11,0,0}, // S_SPID_RUN10 + {SPR_SPID,5,3,A_Chase,S_SPID_RUN12,0,0}, // S_SPID_RUN11 + {SPR_SPID,5,3,A_Chase,S_SPID_RUN1,0,0}, // S_SPID_RUN12 + {SPR_SPID,32768,20,A_FaceTarget,S_SPID_ATK2,0,0}, // S_SPID_ATK1 + {SPR_SPID,32774,4,A_SPosAttack,S_SPID_ATK3,0,0}, // S_SPID_ATK2 + {SPR_SPID,32775,4,A_SPosAttack,S_SPID_ATK4,0,0}, // S_SPID_ATK3 + {SPR_SPID,32775,1,A_SpidRefire,S_SPID_ATK2,0,0}, // S_SPID_ATK4 + {SPR_SPID,8,3,NULL,S_SPID_PAIN2,0,0}, // S_SPID_PAIN + {SPR_SPID,8,3,A_Pain,S_SPID_RUN1,0,0}, // S_SPID_PAIN2 + {SPR_SPID,9,20,A_Scream,S_SPID_DIE2,0,0}, // S_SPID_DIE1 + {SPR_SPID,10,10,A_Fall,S_SPID_DIE3,0,0}, // S_SPID_DIE2 + {SPR_SPID,11,10,NULL,S_SPID_DIE4,0,0}, // S_SPID_DIE3 + {SPR_SPID,12,10,NULL,S_SPID_DIE5,0,0}, // S_SPID_DIE4 + {SPR_SPID,13,10,NULL,S_SPID_DIE6,0,0}, // S_SPID_DIE5 + {SPR_SPID,14,10,NULL,S_SPID_DIE7,0,0}, // S_SPID_DIE6 + {SPR_SPID,15,10,NULL,S_SPID_DIE8,0,0}, // S_SPID_DIE7 + {SPR_SPID,16,10,NULL,S_SPID_DIE9,0,0}, // S_SPID_DIE8 + {SPR_SPID,17,10,NULL,S_SPID_DIE10,0,0}, // S_SPID_DIE9 + {SPR_SPID,18,30,NULL,S_SPID_DIE11,0,0}, // S_SPID_DIE10 + {SPR_SPID,18,-1,A_BossDeath,S_NULL,0,0}, // S_SPID_DIE11 + {SPR_BSPI,0,10,A_Look,S_BSPI_STND2,0,0}, // S_BSPI_STND + {SPR_BSPI,1,10,A_Look,S_BSPI_STND,0,0}, // S_BSPI_STND2 + {SPR_BSPI,0,20,NULL,S_BSPI_RUN1,0,0}, // S_BSPI_SIGHT + {SPR_BSPI,0,3,A_BabyMetal,S_BSPI_RUN2,0,0}, // S_BSPI_RUN1 + {SPR_BSPI,0,3,A_Chase,S_BSPI_RUN3,0,0}, // S_BSPI_RUN2 + {SPR_BSPI,1,3,A_Chase,S_BSPI_RUN4,0,0}, // S_BSPI_RUN3 + {SPR_BSPI,1,3,A_Chase,S_BSPI_RUN5,0,0}, // S_BSPI_RUN4 + {SPR_BSPI,2,3,A_Chase,S_BSPI_RUN6,0,0}, // S_BSPI_RUN5 + {SPR_BSPI,2,3,A_Chase,S_BSPI_RUN7,0,0}, // S_BSPI_RUN6 + {SPR_BSPI,3,3,A_BabyMetal,S_BSPI_RUN8,0,0}, // S_BSPI_RUN7 + {SPR_BSPI,3,3,A_Chase,S_BSPI_RUN9,0,0}, // S_BSPI_RUN8 + {SPR_BSPI,4,3,A_Chase,S_BSPI_RUN10,0,0}, // S_BSPI_RUN9 + {SPR_BSPI,4,3,A_Chase,S_BSPI_RUN11,0,0}, // S_BSPI_RUN10 + {SPR_BSPI,5,3,A_Chase,S_BSPI_RUN12,0,0}, // S_BSPI_RUN11 + {SPR_BSPI,5,3,A_Chase,S_BSPI_RUN1,0,0}, // S_BSPI_RUN12 + {SPR_BSPI,32768,20,A_FaceTarget,S_BSPI_ATK2,0,0}, // S_BSPI_ATK1 + {SPR_BSPI,32774,4,A_BspiAttack,S_BSPI_ATK3,0,0}, // S_BSPI_ATK2 + {SPR_BSPI,32775,4,NULL,S_BSPI_ATK4,0,0}, // S_BSPI_ATK3 + {SPR_BSPI,32775,1,A_SpidRefire,S_BSPI_ATK2,0,0}, // S_BSPI_ATK4 + {SPR_BSPI,8,3,NULL,S_BSPI_PAIN2,0,0}, // S_BSPI_PAIN + {SPR_BSPI,8,3,A_Pain,S_BSPI_RUN1,0,0}, // S_BSPI_PAIN2 + {SPR_BSPI,9,20,A_Scream,S_BSPI_DIE2,0,0}, // S_BSPI_DIE1 + {SPR_BSPI,10,7,A_Fall,S_BSPI_DIE3,0,0}, // S_BSPI_DIE2 + {SPR_BSPI,11,7,NULL,S_BSPI_DIE4,0,0}, // S_BSPI_DIE3 + {SPR_BSPI,12,7,NULL,S_BSPI_DIE5,0,0}, // S_BSPI_DIE4 + {SPR_BSPI,13,7,NULL,S_BSPI_DIE6,0,0}, // S_BSPI_DIE5 + {SPR_BSPI,14,7,NULL,S_BSPI_DIE7,0,0}, // S_BSPI_DIE6 + {SPR_BSPI,15,-1,A_BossDeath,S_NULL,0,0}, // S_BSPI_DIE7 + {SPR_BSPI,15,5,NULL,S_BSPI_RAISE2,0,0}, // S_BSPI_RAISE1 + {SPR_BSPI,14,5,NULL,S_BSPI_RAISE3,0,0}, // S_BSPI_RAISE2 + {SPR_BSPI,13,5,NULL,S_BSPI_RAISE4,0,0}, // S_BSPI_RAISE3 + {SPR_BSPI,12,5,NULL,S_BSPI_RAISE5,0,0}, // S_BSPI_RAISE4 + {SPR_BSPI,11,5,NULL,S_BSPI_RAISE6,0,0}, // S_BSPI_RAISE5 + {SPR_BSPI,10,5,NULL,S_BSPI_RAISE7,0,0}, // S_BSPI_RAISE6 + {SPR_BSPI,9,5,NULL,S_BSPI_RUN1,0,0}, // S_BSPI_RAISE7 + {SPR_APLS,32768,5,NULL,S_ARACH_PLAZ2,0,0}, // S_ARACH_PLAZ + {SPR_APLS,32769,5,NULL,S_ARACH_PLAZ,0,0}, // S_ARACH_PLAZ2 + {SPR_APBX,32768,5,NULL,S_ARACH_PLEX2,0,0}, // S_ARACH_PLEX + {SPR_APBX,32769,5,NULL,S_ARACH_PLEX3,0,0}, // S_ARACH_PLEX2 + {SPR_APBX,32770,5,NULL,S_ARACH_PLEX4,0,0}, // S_ARACH_PLEX3 + {SPR_APBX,32771,5,NULL,S_ARACH_PLEX5,0,0}, // S_ARACH_PLEX4 + {SPR_APBX,32772,5,NULL,S_NULL,0,0}, // S_ARACH_PLEX5 + {SPR_CYBR,0,10,A_Look,S_CYBER_STND2,0,0}, // S_CYBER_STND + {SPR_CYBR,1,10,A_Look,S_CYBER_STND,0,0}, // S_CYBER_STND2 + {SPR_CYBR,0,3,A_Hoof,S_CYBER_RUN2,0,0}, // S_CYBER_RUN1 + {SPR_CYBR,0,3,A_Chase,S_CYBER_RUN3,0,0}, // S_CYBER_RUN2 + {SPR_CYBR,1,3,A_Chase,S_CYBER_RUN4,0,0}, // S_CYBER_RUN3 + {SPR_CYBR,1,3,A_Chase,S_CYBER_RUN5,0,0}, // S_CYBER_RUN4 + {SPR_CYBR,2,3,A_Chase,S_CYBER_RUN6,0,0}, // S_CYBER_RUN5 + {SPR_CYBR,2,3,A_Chase,S_CYBER_RUN7,0,0}, // S_CYBER_RUN6 + {SPR_CYBR,3,3,A_Metal,S_CYBER_RUN8,0,0}, // S_CYBER_RUN7 + {SPR_CYBR,3,3,A_Chase,S_CYBER_RUN1,0,0}, // S_CYBER_RUN8 + {SPR_CYBR,4,6,A_FaceTarget,S_CYBER_ATK2,0,0}, // S_CYBER_ATK1 + {SPR_CYBR,5,12,A_CyberAttack,S_CYBER_ATK3,0,0}, // S_CYBER_ATK2 + {SPR_CYBR,4,12,A_FaceTarget,S_CYBER_ATK4,0,0}, // S_CYBER_ATK3 + {SPR_CYBR,5,12,A_CyberAttack,S_CYBER_ATK5,0,0}, // S_CYBER_ATK4 + {SPR_CYBR,4,12,A_FaceTarget,S_CYBER_ATK6,0,0}, // S_CYBER_ATK5 + {SPR_CYBR,5,12,A_CyberAttack,S_CYBER_RUN1,0,0}, // S_CYBER_ATK6 + {SPR_CYBR,6,10,A_Pain,S_CYBER_RUN1,0,0}, // S_CYBER_PAIN + {SPR_CYBR,7,10,NULL,S_CYBER_DIE2,0,0}, // S_CYBER_DIE1 + {SPR_CYBR,8,10,A_Scream,S_CYBER_DIE3,0,0}, // S_CYBER_DIE2 + {SPR_CYBR,9,10,NULL,S_CYBER_DIE4,0,0}, // S_CYBER_DIE3 + {SPR_CYBR,10,10,NULL,S_CYBER_DIE5,0,0}, // S_CYBER_DIE4 + {SPR_CYBR,11,10,NULL,S_CYBER_DIE6,0,0}, // S_CYBER_DIE5 + {SPR_CYBR,12,10,A_Fall,S_CYBER_DIE7,0,0}, // S_CYBER_DIE6 + {SPR_CYBR,13,10,NULL,S_CYBER_DIE8,0,0}, // S_CYBER_DIE7 + {SPR_CYBR,14,10,NULL,S_CYBER_DIE9,0,0}, // S_CYBER_DIE8 + {SPR_CYBR,15,30,NULL,S_CYBER_DIE10,0,0}, // S_CYBER_DIE9 + {SPR_CYBR,15,-1,A_BossDeath,S_NULL,0,0}, // S_CYBER_DIE10 + {SPR_PAIN,0,10,A_Look,S_PAIN_STND,0,0}, // S_PAIN_STND + {SPR_PAIN,0,3,A_Chase,S_PAIN_RUN2,0,0}, // S_PAIN_RUN1 + {SPR_PAIN,0,3,A_Chase,S_PAIN_RUN3,0,0}, // S_PAIN_RUN2 + {SPR_PAIN,1,3,A_Chase,S_PAIN_RUN4,0,0}, // S_PAIN_RUN3 + {SPR_PAIN,1,3,A_Chase,S_PAIN_RUN5,0,0}, // S_PAIN_RUN4 + {SPR_PAIN,2,3,A_Chase,S_PAIN_RUN6,0,0}, // S_PAIN_RUN5 + {SPR_PAIN,2,3,A_Chase,S_PAIN_RUN1,0,0}, // S_PAIN_RUN6 + {SPR_PAIN,3,5,A_FaceTarget,S_PAIN_ATK2,0,0}, // S_PAIN_ATK1 + {SPR_PAIN,4,5,A_FaceTarget,S_PAIN_ATK3,0,0}, // S_PAIN_ATK2 + {SPR_PAIN,32773,5,A_FaceTarget,S_PAIN_ATK4,0,0}, // S_PAIN_ATK3 + {SPR_PAIN,32773,0,A_PainAttack,S_PAIN_RUN1,0,0}, // S_PAIN_ATK4 + {SPR_PAIN,6,6,NULL,S_PAIN_PAIN2,0,0}, // S_PAIN_PAIN + {SPR_PAIN,6,6,A_Pain,S_PAIN_RUN1,0,0}, // S_PAIN_PAIN2 + {SPR_PAIN,32775,8,NULL,S_PAIN_DIE2,0,0}, // S_PAIN_DIE1 + {SPR_PAIN,32776,8,A_Scream,S_PAIN_DIE3,0,0}, // S_PAIN_DIE2 + {SPR_PAIN,32777,8,NULL,S_PAIN_DIE4,0,0}, // S_PAIN_DIE3 + {SPR_PAIN,32778,8,NULL,S_PAIN_DIE5,0,0}, // S_PAIN_DIE4 + {SPR_PAIN,32779,8,A_PainDie,S_PAIN_DIE6,0,0}, // S_PAIN_DIE5 + {SPR_PAIN,32780,8,NULL,S_NULL,0,0}, // S_PAIN_DIE6 + {SPR_PAIN,12,8,NULL,S_PAIN_RAISE2,0,0}, // S_PAIN_RAISE1 + {SPR_PAIN,11,8,NULL,S_PAIN_RAISE3,0,0}, // S_PAIN_RAISE2 + {SPR_PAIN,10,8,NULL,S_PAIN_RAISE4,0,0}, // S_PAIN_RAISE3 + {SPR_PAIN,9,8,NULL,S_PAIN_RAISE5,0,0}, // S_PAIN_RAISE4 + {SPR_PAIN,8,8,NULL,S_PAIN_RAISE6,0,0}, // S_PAIN_RAISE5 + {SPR_PAIN,7,8,NULL,S_PAIN_RUN1,0,0}, // S_PAIN_RAISE6 + {SPR_SSWV,0,10,A_Look,S_SSWV_STND2,0,0}, // S_SSWV_STND + {SPR_SSWV,1,10,A_Look,S_SSWV_STND,0,0}, // S_SSWV_STND2 + {SPR_SSWV,0,3,A_Chase,S_SSWV_RUN2,0,0}, // S_SSWV_RUN1 + {SPR_SSWV,0,3,A_Chase,S_SSWV_RUN3,0,0}, // S_SSWV_RUN2 + {SPR_SSWV,1,3,A_Chase,S_SSWV_RUN4,0,0}, // S_SSWV_RUN3 + {SPR_SSWV,1,3,A_Chase,S_SSWV_RUN5,0,0}, // S_SSWV_RUN4 + {SPR_SSWV,2,3,A_Chase,S_SSWV_RUN6,0,0}, // S_SSWV_RUN5 + {SPR_SSWV,2,3,A_Chase,S_SSWV_RUN7,0,0}, // S_SSWV_RUN6 + {SPR_SSWV,3,3,A_Chase,S_SSWV_RUN8,0,0}, // S_SSWV_RUN7 + {SPR_SSWV,3,3,A_Chase,S_SSWV_RUN1,0,0}, // S_SSWV_RUN8 + {SPR_SSWV,4,10,A_FaceTarget,S_SSWV_ATK2,0,0}, // S_SSWV_ATK1 + {SPR_SSWV,5,10,A_FaceTarget,S_SSWV_ATK3,0,0}, // S_SSWV_ATK2 + {SPR_SSWV,32774,4,A_CPosAttack,S_SSWV_ATK4,0,0}, // S_SSWV_ATK3 + {SPR_SSWV,5,6,A_FaceTarget,S_SSWV_ATK5,0,0}, // S_SSWV_ATK4 + {SPR_SSWV,32774,4,A_CPosAttack,S_SSWV_ATK6,0,0}, // S_SSWV_ATK5 + {SPR_SSWV,5,1,A_CPosRefire,S_SSWV_ATK2,0,0}, // S_SSWV_ATK6 + {SPR_SSWV,7,3,NULL,S_SSWV_PAIN2,0,0}, // S_SSWV_PAIN + {SPR_SSWV,7,3,A_Pain,S_SSWV_RUN1,0,0}, // S_SSWV_PAIN2 + {SPR_SSWV,8,5,NULL,S_SSWV_DIE2,0,0}, // S_SSWV_DIE1 + {SPR_SSWV,9,5,A_Scream,S_SSWV_DIE3,0,0}, // S_SSWV_DIE2 + {SPR_SSWV,10,5,A_Fall,S_SSWV_DIE4,0,0}, // S_SSWV_DIE3 + {SPR_SSWV,11,5,NULL,S_SSWV_DIE5,0,0}, // S_SSWV_DIE4 + {SPR_SSWV,12,-1,NULL,S_NULL,0,0}, // S_SSWV_DIE5 + {SPR_SSWV,13,5,NULL,S_SSWV_XDIE2,0,0}, // S_SSWV_XDIE1 + {SPR_SSWV,14,5,A_XScream,S_SSWV_XDIE3,0,0}, // S_SSWV_XDIE2 + {SPR_SSWV,15,5,A_Fall,S_SSWV_XDIE4,0,0}, // S_SSWV_XDIE3 + {SPR_SSWV,16,5,NULL,S_SSWV_XDIE5,0,0}, // S_SSWV_XDIE4 + {SPR_SSWV,17,5,NULL,S_SSWV_XDIE6,0,0}, // S_SSWV_XDIE5 + {SPR_SSWV,18,5,NULL,S_SSWV_XDIE7,0,0}, // S_SSWV_XDIE6 + {SPR_SSWV,19,5,NULL,S_SSWV_XDIE8,0,0}, // S_SSWV_XDIE7 + {SPR_SSWV,20,5,NULL,S_SSWV_XDIE9,0,0}, // S_SSWV_XDIE8 + {SPR_SSWV,21,-1,NULL,S_NULL,0,0}, // S_SSWV_XDIE9 + {SPR_SSWV,12,5,NULL,S_SSWV_RAISE2,0,0}, // S_SSWV_RAISE1 + {SPR_SSWV,11,5,NULL,S_SSWV_RAISE3,0,0}, // S_SSWV_RAISE2 + {SPR_SSWV,10,5,NULL,S_SSWV_RAISE4,0,0}, // S_SSWV_RAISE3 + {SPR_SSWV,9,5,NULL,S_SSWV_RAISE5,0,0}, // S_SSWV_RAISE4 + {SPR_SSWV,8,5,NULL,S_SSWV_RUN1,0,0}, // S_SSWV_RAISE5 + {SPR_KEEN,0,-1,NULL,S_KEENSTND,0,0}, // S_KEENSTND + {SPR_KEEN,0,6,NULL,S_COMMKEEN2,0,0}, // S_COMMKEEN + {SPR_KEEN,1,6,NULL,S_COMMKEEN3,0,0}, // S_COMMKEEN2 + {SPR_KEEN,2,6,A_Scream,S_COMMKEEN4,0,0}, // S_COMMKEEN3 + {SPR_KEEN,3,6,NULL,S_COMMKEEN5,0,0}, // S_COMMKEEN4 + {SPR_KEEN,4,6,NULL,S_COMMKEEN6,0,0}, // S_COMMKEEN5 + {SPR_KEEN,5,6,NULL,S_COMMKEEN7,0,0}, // S_COMMKEEN6 + {SPR_KEEN,6,6,NULL,S_COMMKEEN8,0,0}, // S_COMMKEEN7 + {SPR_KEEN,7,6,NULL,S_COMMKEEN9,0,0}, // S_COMMKEEN8 + {SPR_KEEN,8,6,NULL,S_COMMKEEN10,0,0}, // S_COMMKEEN9 + {SPR_KEEN,9,6,NULL,S_COMMKEEN11,0,0}, // S_COMMKEEN10 + {SPR_KEEN,10,6,A_KeenDie,S_COMMKEEN12,0,0},// S_COMMKEEN11 + {SPR_KEEN,11,-1,NULL,S_NULL,0,0}, // S_COMMKEEN12 + {SPR_KEEN,12,4,NULL,S_KEENPAIN2,0,0}, // S_KEENPAIN + {SPR_KEEN,12,8,A_Pain,S_KEENSTND,0,0}, // S_KEENPAIN2 + {SPR_BBRN,0,-1,NULL,S_NULL,0,0}, // S_BRAIN + {SPR_BBRN,1,36,A_BrainPain,S_BRAIN,0,0}, // S_BRAIN_PAIN + {SPR_BBRN,0,100,A_BrainScream,S_BRAIN_DIE2,0,0}, // S_BRAIN_DIE1 + {SPR_BBRN,0,10,NULL,S_BRAIN_DIE3,0,0}, // S_BRAIN_DIE2 + {SPR_BBRN,0,10,NULL,S_BRAIN_DIE4,0,0}, // S_BRAIN_DIE3 + {SPR_BBRN,0,-1,A_BrainDie,S_NULL,0,0}, // S_BRAIN_DIE4 + {SPR_SSWV,0,10,A_Look,S_BRAINEYE,0,0}, // S_BRAINEYE + {SPR_SSWV,0,181,A_BrainAwake,S_BRAINEYE1,0,0}, // S_BRAINEYESEE + {SPR_SSWV,0,150,A_BrainSpit,S_BRAINEYE1,0,0}, // S_BRAINEYE1 + {SPR_BOSF,32768,3,A_SpawnSound,S_SPAWN2,0,0}, // S_SPAWN1 + {SPR_BOSF,32769,3,A_SpawnFly,S_SPAWN3,0,0}, // S_SPAWN2 + {SPR_BOSF,32770,3,A_SpawnFly,S_SPAWN4,0,0}, // S_SPAWN3 + {SPR_BOSF,32771,3,A_SpawnFly,S_SPAWN1,0,0}, // S_SPAWN4 + {SPR_FIRE,32768,4,A_Fire,S_SPAWNFIRE2,0,0}, // S_SPAWNFIRE1 + {SPR_FIRE,32769,4,A_Fire,S_SPAWNFIRE3,0,0}, // S_SPAWNFIRE2 + {SPR_FIRE,32770,4,A_Fire,S_SPAWNFIRE4,0,0}, // S_SPAWNFIRE3 + {SPR_FIRE,32771,4,A_Fire,S_SPAWNFIRE5,0,0}, // S_SPAWNFIRE4 + {SPR_FIRE,32772,4,A_Fire,S_SPAWNFIRE6,0,0}, // S_SPAWNFIRE5 + {SPR_FIRE,32773,4,A_Fire,S_SPAWNFIRE7,0,0}, // S_SPAWNFIRE6 + {SPR_FIRE,32774,4,A_Fire,S_SPAWNFIRE8,0,0}, // S_SPAWNFIRE7 + {SPR_FIRE,32775,4,A_Fire,S_NULL,0,0}, // S_SPAWNFIRE8 + {SPR_MISL,32769,10,NULL,S_BRAINEXPLODE2,0,0}, // S_BRAINEXPLODE1 + {SPR_MISL,32770,10,NULL,S_BRAINEXPLODE3,0,0}, // S_BRAINEXPLODE2 + {SPR_MISL,32771,10,A_BrainExplode,S_NULL,0,0}, // S_BRAINEXPLODE3 + {SPR_ARM1,0,6,NULL,S_ARM1A,0,0}, // S_ARM1 + {SPR_ARM1,32769,7,NULL,S_ARM1,0,0}, // S_ARM1A + {SPR_ARM2,0,6,NULL,S_ARM2A,0,0}, // S_ARM2 + {SPR_ARM2,32769,6,NULL,S_ARM2,0,0}, // S_ARM2A + {SPR_BAR1,0,6,NULL,S_BAR2,0,0}, // S_BAR1 + {SPR_BAR1,1,6,NULL,S_BAR1,0,0}, // S_BAR2 + {SPR_BEXP,32768,5,NULL,S_BEXP2,0,0}, // S_BEXP + {SPR_BEXP,32769,5,A_Scream,S_BEXP3,0,0}, // S_BEXP2 + {SPR_BEXP,32770,5,NULL,S_BEXP4,0,0}, // S_BEXP3 + {SPR_BEXP,32771,10,A_Explode,S_BEXP5,0,0}, // S_BEXP4 + {SPR_BEXP,32772,10,NULL,S_NULL,0,0}, // S_BEXP5 + {SPR_FCAN,32768,4,NULL,S_BBAR2,0,0}, // S_BBAR1 + {SPR_FCAN,32769,4,NULL,S_BBAR3,0,0}, // S_BBAR2 + {SPR_FCAN,32770,4,NULL,S_BBAR1,0,0}, // S_BBAR3 + {SPR_BON1,0,6,NULL,S_BON1A,0,0}, // S_BON1 + {SPR_BON1,1,6,NULL,S_BON1B,0,0}, // S_BON1A + {SPR_BON1,2,6,NULL,S_BON1C,0,0}, // S_BON1B + {SPR_BON1,3,6,NULL,S_BON1D,0,0}, // S_BON1C + {SPR_BON1,2,6,NULL,S_BON1E,0,0}, // S_BON1D + {SPR_BON1,1,6,NULL,S_BON1,0,0}, // S_BON1E + {SPR_BON2,0,6,NULL,S_BON2A,0,0}, // S_BON2 + {SPR_BON2,1,6,NULL,S_BON2B,0,0}, // S_BON2A + {SPR_BON2,2,6,NULL,S_BON2C,0,0}, // S_BON2B + {SPR_BON2,3,6,NULL,S_BON2D,0,0}, // S_BON2C + {SPR_BON2,2,6,NULL,S_BON2E,0,0}, // S_BON2D + {SPR_BON2,1,6,NULL,S_BON2,0,0}, // S_BON2E + {SPR_BKEY,0,10,NULL,S_BKEY2,0,0}, // S_BKEY + {SPR_BKEY,32769,10,NULL,S_BKEY,0,0}, // S_BKEY2 + {SPR_RKEY,0,10,NULL,S_RKEY2,0,0}, // S_RKEY + {SPR_RKEY,32769,10,NULL,S_RKEY,0,0}, // S_RKEY2 + {SPR_YKEY,0,10,NULL,S_YKEY2,0,0}, // S_YKEY + {SPR_YKEY,32769,10,NULL,S_YKEY,0,0}, // S_YKEY2 + {SPR_BSKU,0,10,NULL,S_BSKULL2,0,0}, // S_BSKULL + {SPR_BSKU,32769,10,NULL,S_BSKULL,0,0}, // S_BSKULL2 + {SPR_RSKU,0,10,NULL,S_RSKULL2,0,0}, // S_RSKULL + {SPR_RSKU,32769,10,NULL,S_RSKULL,0,0}, // S_RSKULL2 + {SPR_YSKU,0,10,NULL,S_YSKULL2,0,0}, // S_YSKULL + {SPR_YSKU,32769,10,NULL,S_YSKULL,0,0}, // S_YSKULL2 + {SPR_STIM,0,-1,NULL,S_NULL,0,0}, // S_STIM + {SPR_MEDI,0,-1,NULL,S_NULL,0,0}, // S_MEDI + {SPR_SOUL,32768,6,NULL,S_SOUL2,0,0}, // S_SOUL + {SPR_SOUL,32769,6,NULL,S_SOUL3,0,0}, // S_SOUL2 + {SPR_SOUL,32770,6,NULL,S_SOUL4,0,0}, // S_SOUL3 + {SPR_SOUL,32771,6,NULL,S_SOUL5,0,0}, // S_SOUL4 + {SPR_SOUL,32770,6,NULL,S_SOUL6,0,0}, // S_SOUL5 + {SPR_SOUL,32769,6,NULL,S_SOUL,0,0}, // S_SOUL6 + {SPR_PINV,32768,6,NULL,S_PINV2,0,0}, // S_PINV + {SPR_PINV,32769,6,NULL,S_PINV3,0,0}, // S_PINV2 + {SPR_PINV,32770,6,NULL,S_PINV4,0,0}, // S_PINV3 + {SPR_PINV,32771,6,NULL,S_PINV,0,0}, // S_PINV4 + {SPR_PSTR,32768,-1,NULL,S_NULL,0,0}, // S_PSTR + {SPR_PINS,32768,6,NULL,S_PINS2,0,0}, // S_PINS + {SPR_PINS,32769,6,NULL,S_PINS3,0,0}, // S_PINS2 + {SPR_PINS,32770,6,NULL,S_PINS4,0,0}, // S_PINS3 + {SPR_PINS,32771,6,NULL,S_PINS,0,0}, // S_PINS4 + {SPR_MEGA,32768,6,NULL,S_MEGA2,0,0}, // S_MEGA + {SPR_MEGA,32769,6,NULL,S_MEGA3,0,0}, // S_MEGA2 + {SPR_MEGA,32770,6,NULL,S_MEGA4,0,0}, // S_MEGA3 + {SPR_MEGA,32771,6,NULL,S_MEGA,0,0}, // S_MEGA4 + {SPR_SUIT,32768,-1,NULL,S_NULL,0,0}, // S_SUIT + {SPR_PMAP,32768,6,NULL,S_PMAP2,0,0}, // S_PMAP + {SPR_PMAP,32769,6,NULL,S_PMAP3,0,0}, // S_PMAP2 + {SPR_PMAP,32770,6,NULL,S_PMAP4,0,0}, // S_PMAP3 + {SPR_PMAP,32771,6,NULL,S_PMAP5,0,0}, // S_PMAP4 + {SPR_PMAP,32770,6,NULL,S_PMAP6,0,0}, // S_PMAP5 + {SPR_PMAP,32769,6,NULL,S_PMAP,0,0}, // S_PMAP6 + {SPR_PVIS,32768,6,NULL,S_PVIS2,0,0}, // S_PVIS + {SPR_PVIS,1,6,NULL,S_PVIS,0,0}, // S_PVIS2 + {SPR_CLIP,0,-1,NULL,S_NULL,0,0}, // S_CLIP + {SPR_AMMO,0,-1,NULL,S_NULL,0,0}, // S_AMMO + {SPR_ROCK,0,-1,NULL,S_NULL,0,0}, // S_ROCK + {SPR_BROK,0,-1,NULL,S_NULL,0,0}, // S_BROK + {SPR_CELL,0,-1,NULL,S_NULL,0,0}, // S_CELL + {SPR_CELP,0,-1,NULL,S_NULL,0,0}, // S_CELP + {SPR_SHEL,0,-1,NULL,S_NULL,0,0}, // S_SHEL + {SPR_SBOX,0,-1,NULL,S_NULL,0,0}, // S_SBOX + {SPR_BPAK,0,-1,NULL,S_NULL,0,0}, // S_BPAK + {SPR_BFUG,0,-1,NULL,S_NULL,0,0}, // S_BFUG + {SPR_MGUN,0,-1,NULL,S_NULL,0,0}, // S_MGUN + {SPR_CSAW,0,-1,NULL,S_NULL,0,0}, // S_CSAW + {SPR_LAUN,0,-1,NULL,S_NULL,0,0}, // S_LAUN + {SPR_PLAS,0,-1,NULL,S_NULL,0,0}, // S_PLAS + {SPR_SHOT,0,-1,NULL,S_NULL,0,0}, // S_SHOT + {SPR_SGN2,0,-1,NULL,S_NULL,0,0}, // S_SHOT2 + {SPR_COLU,32768,-1,NULL,S_NULL,0,0}, // S_COLU + {SPR_SMT2,0,-1,NULL,S_NULL,0,0}, // S_STALAG + {SPR_GOR1,0,10,NULL,S_BLOODYTWITCH2,0,0}, // S_BLOODYTWITCH + {SPR_GOR1,1,15,NULL,S_BLOODYTWITCH3,0,0}, // S_BLOODYTWITCH2 + {SPR_GOR1,2,8,NULL,S_BLOODYTWITCH4,0,0}, // S_BLOODYTWITCH3 + {SPR_GOR1,1,6,NULL,S_BLOODYTWITCH,0,0}, // S_BLOODYTWITCH4 + {SPR_PLAY,13,-1,NULL,S_NULL,0,0}, // S_DEADTORSO + {SPR_PLAY,18,-1,NULL,S_NULL,0,0}, // S_DEADBOTTOM + {SPR_POL2,0,-1,NULL,S_NULL,0,0}, // S_HEADSONSTICK + {SPR_POL5,0,-1,NULL,S_NULL,0,0}, // S_GIBS + {SPR_POL4,0,-1,NULL,S_NULL,0,0}, // S_HEADONASTICK + {SPR_POL3,32768,6,NULL,S_HEADCANDLES2,0,0}, // S_HEADCANDLES + {SPR_POL3,32769,6,NULL,S_HEADCANDLES,0,0}, // S_HEADCANDLES2 + {SPR_POL1,0,-1,NULL,S_NULL,0,0}, // S_DEADSTICK + {SPR_POL6,0,6,NULL,S_LIVESTICK2,0,0}, // S_LIVESTICK + {SPR_POL6,1,8,NULL,S_LIVESTICK,0,0}, // S_LIVESTICK2 + {SPR_GOR2,0,-1,NULL,S_NULL,0,0}, // S_MEAT2 + {SPR_GOR3,0,-1,NULL,S_NULL,0,0}, // S_MEAT3 + {SPR_GOR4,0,-1,NULL,S_NULL,0,0}, // S_MEAT4 + {SPR_GOR5,0,-1,NULL,S_NULL,0,0}, // S_MEAT5 + {SPR_SMIT,0,-1,NULL,S_NULL,0,0}, // S_STALAGTITE + {SPR_COL1,0,-1,NULL,S_NULL,0,0}, // S_TALLGRNCOL + {SPR_COL2,0,-1,NULL,S_NULL,0,0}, // S_SHRTGRNCOL + {SPR_COL3,0,-1,NULL,S_NULL,0,0}, // S_TALLREDCOL + {SPR_COL4,0,-1,NULL,S_NULL,0,0}, // S_SHRTREDCOL + {SPR_CAND,32768,-1,NULL,S_NULL,0,0}, // S_CANDLESTIK + {SPR_CBRA,32768,-1,NULL,S_NULL,0,0}, // S_CANDELABRA + {SPR_COL6,0,-1,NULL,S_NULL,0,0}, // S_SKULLCOL + {SPR_TRE1,0,-1,NULL,S_NULL,0,0}, // S_TORCHTREE + {SPR_TRE2,0,-1,NULL,S_NULL,0,0}, // S_BIGTREE + {SPR_ELEC,0,-1,NULL,S_NULL,0,0}, // S_TECHPILLAR + {SPR_CEYE,32768,6,NULL,S_EVILEYE2,0,0}, // S_EVILEYE + {SPR_CEYE,32769,6,NULL,S_EVILEYE3,0,0}, // S_EVILEYE2 + {SPR_CEYE,32770,6,NULL,S_EVILEYE4,0,0}, // S_EVILEYE3 + {SPR_CEYE,32769,6,NULL,S_EVILEYE,0,0}, // S_EVILEYE4 + {SPR_FSKU,32768,6,NULL,S_FLOATSKULL2,0,0}, // S_FLOATSKULL + {SPR_FSKU,32769,6,NULL,S_FLOATSKULL3,0,0}, // S_FLOATSKULL2 + {SPR_FSKU,32770,6,NULL,S_FLOATSKULL,0,0}, // S_FLOATSKULL3 + {SPR_COL5,0,14,NULL,S_HEARTCOL2,0,0}, // S_HEARTCOL + {SPR_COL5,1,14,NULL,S_HEARTCOL,0,0}, // S_HEARTCOL2 + {SPR_TBLU,32768,4,NULL,S_BLUETORCH2,0,0}, // S_BLUETORCH + {SPR_TBLU,32769,4,NULL,S_BLUETORCH3,0,0}, // S_BLUETORCH2 + {SPR_TBLU,32770,4,NULL,S_BLUETORCH4,0,0}, // S_BLUETORCH3 + {SPR_TBLU,32771,4,NULL,S_BLUETORCH,0,0}, // S_BLUETORCH4 + {SPR_TGRN,32768,4,NULL,S_GREENTORCH2,0,0}, // S_GREENTORCH + {SPR_TGRN,32769,4,NULL,S_GREENTORCH3,0,0}, // S_GREENTORCH2 + {SPR_TGRN,32770,4,NULL,S_GREENTORCH4,0,0}, // S_GREENTORCH3 + {SPR_TGRN,32771,4,NULL,S_GREENTORCH,0,0}, // S_GREENTORCH4 + {SPR_TRED,32768,4,NULL,S_REDTORCH2,0,0}, // S_REDTORCH + {SPR_TRED,32769,4,NULL,S_REDTORCH3,0,0}, // S_REDTORCH2 + {SPR_TRED,32770,4,NULL,S_REDTORCH4,0,0}, // S_REDTORCH3 + {SPR_TRED,32771,4,NULL,S_REDTORCH,0,0}, // S_REDTORCH4 + {SPR_SMBT,32768,4,NULL,S_BTORCHSHRT2,0,0}, // S_BTORCHSHRT + {SPR_SMBT,32769,4,NULL,S_BTORCHSHRT3,0,0}, // S_BTORCHSHRT2 + {SPR_SMBT,32770,4,NULL,S_BTORCHSHRT4,0,0}, // S_BTORCHSHRT3 + {SPR_SMBT,32771,4,NULL,S_BTORCHSHRT,0,0}, // S_BTORCHSHRT4 + {SPR_SMGT,32768,4,NULL,S_GTORCHSHRT2,0,0}, // S_GTORCHSHRT + {SPR_SMGT,32769,4,NULL,S_GTORCHSHRT3,0,0}, // S_GTORCHSHRT2 + {SPR_SMGT,32770,4,NULL,S_GTORCHSHRT4,0,0}, // S_GTORCHSHRT3 + {SPR_SMGT,32771,4,NULL,S_GTORCHSHRT,0,0}, // S_GTORCHSHRT4 + {SPR_SMRT,32768,4,NULL,S_RTORCHSHRT2,0,0}, // S_RTORCHSHRT + {SPR_SMRT,32769,4,NULL,S_RTORCHSHRT3,0,0}, // S_RTORCHSHRT2 + {SPR_SMRT,32770,4,NULL,S_RTORCHSHRT4,0,0}, // S_RTORCHSHRT3 + {SPR_SMRT,32771,4,NULL,S_RTORCHSHRT,0,0}, // S_RTORCHSHRT4 + {SPR_HDB1,0,-1,NULL,S_NULL,0,0}, // S_HANGNOGUTS + {SPR_HDB2,0,-1,NULL,S_NULL,0,0}, // S_HANGBNOBRAIN + {SPR_HDB3,0,-1,NULL,S_NULL,0,0}, // S_HANGTLOOKDN + {SPR_HDB4,0,-1,NULL,S_NULL,0,0}, // S_HANGTSKULL + {SPR_HDB5,0,-1,NULL,S_NULL,0,0}, // S_HANGTLOOKUP + {SPR_HDB6,0,-1,NULL,S_NULL,0,0}, // S_HANGTNOBRAIN + {SPR_POB1,0,-1,NULL,S_NULL,0,0}, // S_COLONGIBS + {SPR_POB2,0,-1,NULL,S_NULL,0,0}, // S_SMALLPOOL + {SPR_BRS1,0,-1,NULL,S_NULL,0,0}, // S_BRAINSTEM + {SPR_TLMP,32768,4,NULL,S_TECHLAMP2,0,0}, // S_TECHLAMP + {SPR_TLMP,32769,4,NULL,S_TECHLAMP3,0,0}, // S_TECHLAMP2 + {SPR_TLMP,32770,4,NULL,S_TECHLAMP4,0,0}, // S_TECHLAMP3 + {SPR_TLMP,32771,4,NULL,S_TECHLAMP,0,0}, // S_TECHLAMP4 + {SPR_TLP2,32768,4,NULL,S_TECH2LAMP2,0,0}, // S_TECH2LAMP + {SPR_TLP2,32769,4,NULL,S_TECH2LAMP3,0,0}, // S_TECH2LAMP2 + {SPR_TLP2,32770,4,NULL,S_TECH2LAMP4,0,0}, // S_TECH2LAMP3 + {SPR_TLP2,32771,4,NULL,S_TECH2LAMP,0,0}, // S_TECH2LAMP4 + {SPR_TNT1,0,-1,NULL,S_TNT1,0,0}, // S_TNT1 // phares 3/8/98 + + // killough 8/9/98: grenade + {SPR_MISL,32768,1000,A_Die,S_GRENADE,0,0}, // S_GRENADE + + // killough 8/10/98: variable damage explosion + {SPR_MISL,32769,4,A_Scream,S_DETONATE2,0,0}, // S_DETONATE + {SPR_MISL,32770,6,A_Detonate,S_DETONATE3,0,0}, // S_DETONATE2 + {SPR_MISL,32771,10,NULL,S_NULL,0,0}, // S_DETONATE3 + +#ifdef DOGS + // killough 7/19/98: Marine's best friend :) + {SPR_DOGS,0,10,A_Look,S_DOGS_STND2,0,0}, // S_DOGS_STND + {SPR_DOGS,1,10,A_Look,S_DOGS_STND,0,0}, // S_DOGS_STND2 + {SPR_DOGS,0,2,A_Chase,S_DOGS_RUN2,0,0}, // S_DOGS_RUN1 + {SPR_DOGS,0,2,A_Chase,S_DOGS_RUN3,0,0}, // S_DOGS_RUN2 + {SPR_DOGS,1,2,A_Chase,S_DOGS_RUN4,0,0}, // S_DOGS_RUN3 + {SPR_DOGS,1,2,A_Chase,S_DOGS_RUN5,0,0}, // S_DOGS_RUN4 + {SPR_DOGS,2,2,A_Chase,S_DOGS_RUN6,0,0}, // S_DOGS_RUN5 + {SPR_DOGS,2,2,A_Chase,S_DOGS_RUN7,0,0}, // S_DOGS_RUN6 + {SPR_DOGS,3,2,A_Chase,S_DOGS_RUN8,0,0}, // S_DOGS_RUN7 + {SPR_DOGS,3,2,A_Chase,S_DOGS_RUN1,0,0}, // S_DOGS_RUN8 + {SPR_DOGS,4,8,A_FaceTarget,S_DOGS_ATK2,0,0}, // S_DOGS_ATK1 + {SPR_DOGS,5,8,A_FaceTarget,S_DOGS_ATK3,0,0}, // S_DOGS_ATK2 + {SPR_DOGS,6,8,A_SargAttack,S_DOGS_RUN1,0,0}, // S_DOGS_ATK3 + {SPR_DOGS,7,2,NULL,S_DOGS_PAIN2,0,0}, // S_DOGS_PAIN + {SPR_DOGS,7,2,A_Pain,S_DOGS_RUN1,0,0}, // S_DOGS_PAIN2 + {SPR_DOGS,8,8,NULL,S_DOGS_DIE2,0,0}, // S_DOGS_DIE1 + {SPR_DOGS,9,8,A_Scream,S_DOGS_DIE3,0,0}, // S_DOGS_DIE2 + {SPR_DOGS,10,4,NULL,S_DOGS_DIE4,0,0}, // S_DOGS_DIE3 + {SPR_DOGS,11,4,A_Fall,S_DOGS_DIE5,0,0}, // S_DOGS_DIE4 + {SPR_DOGS,12,4,NULL,S_DOGS_DIE6,0,0}, // S_DOGS_DIE5 + {SPR_DOGS,13,-1,NULL,S_NULL,0,0}, // S_DOGS_DIE6 + {SPR_DOGS,13,5,NULL,S_DOGS_RAISE2,0,0}, // S_DOGS_RAISE1 + {SPR_DOGS,12,5,NULL,S_DOGS_RAISE3,0,0}, // S_DOGS_RAISE2 + {SPR_DOGS,11,5,NULL,S_DOGS_RAISE4,0,0}, // S_DOGS_RAISE3 + {SPR_DOGS,10,5,NULL,S_DOGS_RAISE5,0,0}, // S_DOGS_RAISE4 + {SPR_DOGS,9,5,NULL,S_DOGS_RAISE6,0,0}, // S_DOGS_RAISE5 + {SPR_DOGS,8,5,NULL,S_DOGS_RUN1,0,0}, // S_DOGS_RAISE6 +#endif + + // killough 10/98: mushroom effect + {SPR_MISL,32769,8,A_Mushroom,S_EXPLODE2,0,0}, // S_MUSHROOM + }; + +// ******************************************************************** +// Object "Thing" definitions +// ******************************************************************** +// Now we get to the actual objects and their characteristics. If +// you've seen Dehacked, much of this is where the Bits are set, +// commented below as "flags", as well as where you wire in which +// frames are the beginning frames for near and far attack, death, +// and such. Sounds are hooked in here too, as well as how much +// mass, speed and so forth a Thing has. Everything you ever wanted +// to know... +// +// Like all this other stuff, the MT_* entries are enumerated in info.h +// +// Note that these are all just indices of the elements involved, and +// not real pointers to them. For example, the player's death sequence +// is S_PLAY_DIE1, which just evaluates to the index in the states[] +// array above, which actually knows what happens then and what the +// sprite looks like, if it makes noise or not, etc. +// +// Additional comments about each of the entries are located in info.h +// next to the mobjinfo_t structure definition. +// +// This goes on for the next 3000+ lines... + +mobjinfo_t mobjinfo[NUMMOBJTYPES] = { + { // MT_PLAYER + -1, // doomednum + S_PLAY, // spawnstate + 100, // spawnhealth + S_PLAY_RUN1, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_PLAY_PAIN, // painstate + 255, // painchance + sfx_plpain, // painsound + S_NULL, // meleestate + S_PLAY_ATK1, // missilestate + S_PLAY_DIE1, // deathstate + S_PLAY_XDIE1, // xdeathstate + sfx_pldeth, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 56*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SHOOTABLE|MF_DROPOFF|MF_PICKUP|MF_NOTDMATCH, // flags + S_NULL // raisestate + }, + + { // MT_POSSESSED + 3004, // doomednum + S_POSS_STND, // spawnstate + 20, // spawnhealth + S_POSS_RUN1, // seestate + sfx_posit1, // seesound + 8, // reactiontime + sfx_pistol, // attacksound + S_POSS_PAIN, // painstate + 200, // painchance + sfx_popain, // painsound + 0, // meleestate + S_POSS_ATK1, // missilestate + S_POSS_DIE1, // deathstate + S_POSS_XDIE1, // xdeathstate + sfx_podth1, // deathsound + 8, // speed + 20*FRACUNIT, // radius + 56*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_posact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_POSS_RAISE1 // raisestate + }, + + { // MT_SHOTGUY + 9, // doomednum + S_SPOS_STND, // spawnstate + 30, // spawnhealth + S_SPOS_RUN1, // seestate + sfx_posit2, // seesound + 8, // reactiontime + 0, // attacksound + S_SPOS_PAIN, // painstate + 170, // painchance + sfx_popain, // painsound + 0, // meleestate + S_SPOS_ATK1, // missilestate + S_SPOS_DIE1, // deathstate + S_SPOS_XDIE1, // xdeathstate + sfx_podth2, // deathsound + 8, // speed + 20*FRACUNIT, // radius + 56*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_posact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_SPOS_RAISE1 // raisestate + }, + + { // MT_VILE + 64, // doomednum + S_VILE_STND, // spawnstate + 700, // spawnhealth + S_VILE_RUN1, // seestate + sfx_vilsit, // seesound + 8, // reactiontime + 0, // attacksound + S_VILE_PAIN, // painstate + 10, // painchance + sfx_vipain, // painsound + 0, // meleestate + S_VILE_ATK1, // missilestate + S_VILE_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_vildth, // deathsound + 15, // speed + 20*FRACUNIT, // radius + 56*FRACUNIT, // height + 500, // mass + 0, // damage + sfx_vilact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_NULL // raisestate + }, + + { // MT_FIRE + -1, // doomednum + S_FIRE1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // killough 2/21/98 + S_NULL // raisestate + }, + + { // MT_UNDEAD + 66, // doomednum + S_SKEL_STND, // spawnstate + 300, // spawnhealth + S_SKEL_RUN1, // seestate + sfx_skesit, // seesound + 8, // reactiontime + 0, // attacksound + S_SKEL_PAIN, // painstate + 100, // painchance + sfx_popain, // painsound + S_SKEL_FIST1, // meleestate + S_SKEL_MISS1, // missilestate + S_SKEL_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_skedth, // deathsound + 10, // speed + 20*FRACUNIT, // radius + 56*FRACUNIT, // height + 500, // mass + 0, // damage + sfx_skeact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_SKEL_RAISE1 // raisestate + }, + + { // MT_TRACER + -1, // doomednum + S_TRACER, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_skeatk, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_TRACEEXP1, // deathstate + S_NULL, // xdeathstate + sfx_barexp, // deathsound + 10*FRACUNIT, // speed + 11*FRACUNIT, // radius + 8*FRACUNIT, // height + 100, // mass + 10, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_SMOKE + -1, // doomednum + S_SMOKE1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // phares + S_NULL // raisestate + }, + + { // MT_FATSO + 67, // doomednum + S_FATT_STND, // spawnstate + 600, // spawnhealth + S_FATT_RUN1, // seestate + sfx_mansit, // seesound + 8, // reactiontime + 0, // attacksound + S_FATT_PAIN, // painstate + 80, // painchance + sfx_mnpain, // painsound + 0, // meleestate + S_FATT_ATK1, // missilestate + S_FATT_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_mandth, // deathsound + 8, // speed + 48*FRACUNIT, // radius + 64*FRACUNIT, // height + 1000, // mass + 0, // damage + sfx_posact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_FATT_RAISE1 // raisestate + }, + + { // MT_FATSHOT + -1, // doomednum + S_FATSHOT1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_firsht, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_FATSHOTX1, // deathstate + S_NULL, // xdeathstate + sfx_firxpl, // deathsound + 20*FRACUNIT, // speed + 6*FRACUNIT, // radius + 8*FRACUNIT, // height + 100, // mass + 8, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_TRANSLUCENT, // flags \\ killough 2/21/98 + S_NULL // raisestate + }, + + { // MT_CHAINGUY + 65, // doomednum + S_CPOS_STND, // spawnstate + 70, // spawnhealth + S_CPOS_RUN1, // seestate + sfx_posit2, // seesound + 8, // reactiontime + 0, // attacksound + S_CPOS_PAIN, // painstate + 170, // painchance + sfx_popain, // painsound + 0, // meleestate + S_CPOS_ATK1, // missilestate + S_CPOS_DIE1, // deathstate + S_CPOS_XDIE1, // xdeathstate + sfx_podth2, // deathsound + 8, // speed + 20*FRACUNIT, // radius + 56*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_posact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_CPOS_RAISE1 // raisestate + }, + + { // MT_TROOP + 3001, // doomednum + S_TROO_STND, // spawnstate + 60, // spawnhealth + S_TROO_RUN1, // seestate + sfx_bgsit1, // seesound + 8, // reactiontime + 0, // attacksound + S_TROO_PAIN, // painstate + 200, // painchance + sfx_popain, // painsound + S_TROO_ATK1, // meleestate + S_TROO_ATK1, // missilestate + S_TROO_DIE1, // deathstate + S_TROO_XDIE1, // xdeathstate + sfx_bgdth1, // deathsound + 8, // speed + 20*FRACUNIT, // radius + 56*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_bgact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // killough |MF_TRANSLUCENT, // flags // phares + S_TROO_RAISE1 // raisestate + }, + + { // MT_SERGEANT + 3002, // doomednum + S_SARG_STND, // spawnstate + 150, // spawnhealth + S_SARG_RUN1, // seestate + sfx_sgtsit, // seesound + 8, // reactiontime + sfx_sgtatk, // attacksound + S_SARG_PAIN, // painstate + 180, // painchance + sfx_dmpain, // painsound + S_SARG_ATK1, // meleestate + 0, // missilestate + S_SARG_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_sgtdth, // deathsound + 10, // speed + 30*FRACUNIT, // radius + 56*FRACUNIT, // height + 400, // mass + 0, // damage + sfx_dmact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_SARG_RAISE1 // raisestate + }, + + { // MT_SHADOWS + 58, // doomednum + S_SARG_STND, // spawnstate + 150, // spawnhealth + S_SARG_RUN1, // seestate + sfx_sgtsit, // seesound + 8, // reactiontime + sfx_sgtatk, // attacksound + S_SARG_PAIN, // painstate + 180, // painchance + sfx_dmpain, // painsound + S_SARG_ATK1, // meleestate + 0, // missilestate + S_SARG_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_sgtdth, // deathsound + 10, // speed + 30*FRACUNIT, // radius + 56*FRACUNIT, // height + 400, // mass + 0, // damage + sfx_dmact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_SHADOW|MF_COUNTKILL, // flags + S_SARG_RAISE1 // raisestate + }, + + { // MT_HEAD + 3005, // doomednum + S_HEAD_STND, // spawnstate + 400, // spawnhealth + S_HEAD_RUN1, // seestate + sfx_cacsit, // seesound + 8, // reactiontime + 0, // attacksound + S_HEAD_PAIN, // painstate + 128, // painchance + sfx_dmpain, // painsound + 0, // meleestate + S_HEAD_ATK1, // missilestate + S_HEAD_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_cacdth, // deathsound + 8, // speed + 31*FRACUNIT, // radius + 56*FRACUNIT, // height + 400, // mass + 0, // damage + sfx_dmact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_FLOAT|MF_NOGRAVITY|MF_COUNTKILL, // flags + S_HEAD_RAISE1 // raisestate + }, + + { // MT_BRUISER + 3003, // doomednum + S_BOSS_STND, // spawnstate + 1000, // spawnhealth + S_BOSS_RUN1, // seestate + sfx_brssit, // seesound + 8, // reactiontime + 0, // attacksound + S_BOSS_PAIN, // painstate + 50, // painchance + sfx_dmpain, // painsound + S_BOSS_ATK1, // meleestate + S_BOSS_ATK1, // missilestate + S_BOSS_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_brsdth, // deathsound + 8, // speed + 24*FRACUNIT, // radius + 64*FRACUNIT, // height + 1000, // mass + 0, // damage + sfx_dmact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_BOSS_RAISE1 // raisestate + }, + + { // MT_BRUISERSHOT + -1, // doomednum + S_BRBALL1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_firsht, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_BRBALLX1, // deathstate + S_NULL, // xdeathstate + sfx_firxpl, // deathsound + 15*FRACUNIT, // speed + 6*FRACUNIT, // radius + 8*FRACUNIT, // height + 100, // mass + 8, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_TRANSLUCENT, // flags killough 2/21/98 + S_NULL // raisestate + }, + + { // MT_KNIGHT + 69, // doomednum + S_BOS2_STND, // spawnstate + 500, // spawnhealth + S_BOS2_RUN1, // seestate + sfx_kntsit, // seesound + 8, // reactiontime + 0, // attacksound + S_BOS2_PAIN, // painstate + 50, // painchance + sfx_dmpain, // painsound + S_BOS2_ATK1, // meleestate + S_BOS2_ATK1, // missilestate + S_BOS2_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_kntdth, // deathsound + 8, // speed + 24*FRACUNIT, // radius + 64*FRACUNIT, // height + 1000, // mass + 0, // damage + sfx_dmact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_BOS2_RAISE1 // raisestate + }, + + { // MT_SKULL + 3006, // doomednum + S_SKULL_STND, // spawnstate + 100, // spawnhealth + S_SKULL_RUN1, // seestate + 0, // seesound + 8, // reactiontime + sfx_sklatk, // attacksound + S_SKULL_PAIN, // painstate + 256, // painchance + sfx_dmpain, // painsound + 0, // meleestate + S_SKULL_ATK1, // missilestate + S_SKULL_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_firxpl, // deathsound + 8, // speed + 16*FRACUNIT, // radius + 56*FRACUNIT, // height + 50, // mass + 3, // damage + sfx_dmact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_FLOAT|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_SPIDER + 7, // doomednum + S_SPID_STND, // spawnstate + 3000, // spawnhealth + S_SPID_RUN1, // seestate + sfx_spisit, // seesound + 8, // reactiontime + sfx_shotgn, // attacksound + S_SPID_PAIN, // painstate + 40, // painchance + sfx_dmpain, // painsound + 0, // meleestate + S_SPID_ATK1, // missilestate + S_SPID_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_spidth, // deathsound + 12, // speed + 128*FRACUNIT, // radius + 100*FRACUNIT, // height + 1000, // mass + 0, // damage + sfx_dmact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_NULL // raisestate + }, + + { // MT_BABY + 68, // doomednum + S_BSPI_STND, // spawnstate + 500, // spawnhealth + S_BSPI_SIGHT, // seestate + sfx_bspsit, // seesound + 8, // reactiontime + 0, // attacksound + S_BSPI_PAIN, // painstate + 128, // painchance + sfx_dmpain, // painsound + 0, // meleestate + S_BSPI_ATK1, // missilestate + S_BSPI_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_bspdth, // deathsound + 12, // speed + 64*FRACUNIT, // radius + 64*FRACUNIT, // height + 600, // mass + 0, // damage + sfx_bspact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_BSPI_RAISE1 // raisestate + }, + + { // MT_CYBORG + 16, // doomednum + S_CYBER_STND, // spawnstate + 4000, // spawnhealth + S_CYBER_RUN1, // seestate + sfx_cybsit, // seesound + 8, // reactiontime + 0, // attacksound + S_CYBER_PAIN, // painstate + 20, // painchance + sfx_dmpain, // painsound + 0, // meleestate + S_CYBER_ATK1, // missilestate + S_CYBER_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_cybdth, // deathsound + 16, // speed + 40*FRACUNIT, // radius + 110*FRACUNIT, // height + 1000, // mass + 0, // damage + sfx_dmact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_NULL // raisestate + }, + + { // MT_PAIN + 71, // doomednum + S_PAIN_STND, // spawnstate + 400, // spawnhealth + S_PAIN_RUN1, // seestate + sfx_pesit, // seesound + 8, // reactiontime + 0, // attacksound + S_PAIN_PAIN, // painstate + 128, // painchance + sfx_pepain, // painsound + 0, // meleestate + S_PAIN_ATK1, // missilestate + S_PAIN_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_pedth, // deathsound + 8, // speed + 31*FRACUNIT, // radius + 56*FRACUNIT, // height + 400, // mass + 0, // damage + sfx_dmact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_FLOAT|MF_NOGRAVITY|MF_COUNTKILL, // flags + S_PAIN_RAISE1 // raisestate + }, + + { // MT_WOLFSS + 84, // doomednum + S_SSWV_STND, // spawnstate + 50, // spawnhealth + S_SSWV_RUN1, // seestate + sfx_sssit, // seesound + 8, // reactiontime + 0, // attacksound + S_SSWV_PAIN, // painstate + 170, // painchance + sfx_popain, // painsound + 0, // meleestate + S_SSWV_ATK1, // missilestate + S_SSWV_DIE1, // deathstate + S_SSWV_XDIE1, // xdeathstate + sfx_ssdth, // deathsound + 8, // speed + 20*FRACUNIT, // radius + 56*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_posact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_SSWV_RAISE1 // raisestate + }, + + { // MT_KEEN + 72, // doomednum + S_KEENSTND, // spawnstate + 100, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_KEENPAIN, // painstate + 256, // painchance + sfx_keenpn, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_COMMKEEN, // deathstate + S_NULL, // xdeathstate + sfx_keendt, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 72*FRACUNIT, // height + 10000000, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_NULL // raisestate + }, + + { // MT_BOSSBRAIN + 88, // doomednum + S_BRAIN, // spawnstate + 250, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_BRAIN_PAIN, // painstate + 255, // painchance + sfx_bospn, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_BRAIN_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_bosdth, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 10000000, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SHOOTABLE, // flags + S_NULL // raisestate + }, + + { // MT_BOSSSPIT + 89, // doomednum + S_BRAINEYE, // spawnstate + 1000, // spawnhealth + S_BRAINEYESEE, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 32*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOSECTOR, // flags + S_NULL // raisestate + }, + + { // MT_BOSSTARGET + 87, // doomednum + S_NULL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 32*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOSECTOR, // flags + S_NULL // raisestate + }, + + { // MT_SPAWNSHOT + -1, // doomednum + S_SPAWN1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_bospit, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_firxpl, // deathsound + 10*FRACUNIT, // speed + 6*FRACUNIT, // radius + 32*FRACUNIT, // height + 100, // mass + 3, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_NOCLIP, // flags + S_NULL // raisestate + }, + + { // MT_SPAWNFIRE + -1, // doomednum + S_SPAWNFIRE1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // phares + S_NULL // raisestate + }, + + { // MT_BARREL + 2035, // doomednum + S_BAR1, // spawnstate + 20, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_BEXP, // deathstate + S_NULL, // xdeathstate + sfx_barexp, // deathsound + 0, // speed + 10*FRACUNIT, // radius + 42*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SHOOTABLE|MF_NOBLOOD, // flags + S_NULL // raisestate + }, + + { // MT_TROOPSHOT + -1, // doomednum + S_TBALL1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_firsht, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_TBALLX1, // deathstate + S_NULL, // xdeathstate + sfx_firxpl, // deathsound + 10*FRACUNIT, // speed + 6*FRACUNIT, // radius + 8*FRACUNIT, // height + 100, // mass + 3, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // phares + S_NULL // raisestate + }, + + { // MT_HEADSHOT + -1, // doomednum + S_RBALL1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_firsht, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_RBALLX1, // deathstate + S_NULL, // xdeathstate + sfx_firxpl, // deathsound + 10*FRACUNIT, // speed + 6*FRACUNIT, // radius + 8*FRACUNIT, // height + 100, // mass + 5, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // phares, // flags + S_NULL // raisestate + }, + + { // MT_ROCKET + -1, // doomednum + S_ROCKET, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_rlaunc, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_EXPLODE1, // deathstate + S_NULL, // xdeathstate + sfx_barexp, // deathsound + 20*FRACUNIT, // speed + 11*FRACUNIT, // radius + 8*FRACUNIT, // height + 100, // mass + 20, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_PLASMA + -1, // doomednum + S_PLASBALL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_plasma, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_PLASEXP, // deathstate + S_NULL, // xdeathstate + sfx_firxpl, // deathsound + 25*FRACUNIT, // speed + 13*FRACUNIT, // radius + 8*FRACUNIT, // height + 100, // mass + 5, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // phares + S_NULL // raisestate + }, + + { // MT_BFG + -1, // doomednum + S_BFGSHOT, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + 0, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_BFGLAND, // deathstate + S_NULL, // xdeathstate + sfx_rxplod, // deathsound + 25*FRACUNIT, // speed + 13*FRACUNIT, // radius + 8*FRACUNIT, // height + 100, // mass + 100, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // phares + S_NULL // raisestate + }, + + { // MT_ARACHPLAZ + -1, // doomednum + S_ARACH_PLAZ, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_plasma, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_ARACH_PLEX, // deathstate + S_NULL, // xdeathstate + sfx_firxpl, // deathsound + 25*FRACUNIT, // speed + 13*FRACUNIT, // radius + 8*FRACUNIT, // height + 100, // mass + 5, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // phares + S_NULL // raisestate + }, + + { // MT_PUFF + -1, // doomednum + S_PUFF1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // phares + S_NULL // raisestate + }, + + { // MT_BLOOD + -1, // doomednum + S_BLOOD1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP, // flags + S_NULL // raisestate + }, + + { // MT_TFOG + -1, // doomednum + S_TFOG, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // phares + S_NULL // raisestate + }, + + { // MT_IFOG + -1, // doomednum + S_IFOG, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // phares + S_NULL // raisestate + }, + + { // MT_TELEPORTMAN + 14, // doomednum + S_NULL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOSECTOR, // flags + S_NULL // raisestate + }, + + { // MT_EXTRABFG + -1, // doomednum + S_BFGEXP, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC0 + 2018, // doomednum + S_ARM1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC1 + 2019, // doomednum + S_ARM2, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC2 + 2014, // doomednum + S_BON1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_COUNTITEM, // flags + S_NULL // raisestate + }, + + { // MT_MISC3 + 2015, // doomednum + S_BON2, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_COUNTITEM, // flags + S_NULL // raisestate + }, + + { // MT_MISC4 + 5, // doomednum + S_BKEY, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_NOTDMATCH, // flags + S_NULL // raisestate + }, + + { // MT_MISC5 + 13, // doomednum + S_RKEY, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_NOTDMATCH, // flags + S_NULL // raisestate + }, + + { // MT_MISC6 + 6, // doomednum + S_YKEY, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_NOTDMATCH, // flags + S_NULL // raisestate + }, + + { // MT_MISC7 + 39, // doomednum + S_YSKULL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_NOTDMATCH, // flags + S_NULL // raisestate + }, + + { // MT_MISC8 + 38, // doomednum + S_RSKULL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_NOTDMATCH, // flags + S_NULL // raisestate + }, + + { // MT_MISC9 + 40, // doomednum + S_BSKULL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_NOTDMATCH, // flags + S_NULL // raisestate + }, + + { // MT_MISC10 + 2011, // doomednum + S_STIM, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC11 + 2012, // doomednum + S_MEDI, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC12 + 2013, // doomednum + S_SOUL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_COUNTITEM|MF_TRANSLUCENT, // flags // killough 2/21/98 + S_NULL // raisestate + }, + + { // MT_INV + 2022, // doomednum + S_PINV, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_COUNTITEM|MF_TRANSLUCENT, // flags // killough 2/21/98 + S_NULL // raisestate + }, + + { // MT_MISC13 + 2023, // doomednum + S_PSTR, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_COUNTITEM, // flags + S_NULL // raisestate + }, + + { // MT_INS + 2024, // doomednum + S_PINS, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_COUNTITEM|MF_TRANSLUCENT, // flags // killough 2/21/98 + S_NULL // raisestate + }, + + { // MT_MISC14 + 2025, // doomednum + S_SUIT, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC15 + 2026, // doomednum + S_PMAP, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_COUNTITEM, // flags + S_NULL // raisestate + }, + + { // MT_MISC16 + 2045, // doomednum + S_PVIS, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_COUNTITEM, // flags + S_NULL // raisestate + }, + + { // MT_MEGA + 83, // doomednum + S_MEGA, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_COUNTITEM|MF_TRANSLUCENT, // flags // killough 2/21/98 + S_NULL // raisestate + }, + + { // MT_CLIP + 2007, // doomednum + S_CLIP, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC17 + 2048, // doomednum + S_AMMO, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC18 + 2010, // doomednum + S_ROCK, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC19 + 2046, // doomednum + S_BROK, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC20 + 2047, // doomednum + S_CELL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC21 + 17, // doomednum + S_CELP, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC22 + 2008, // doomednum + S_SHEL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC23 + 2049, // doomednum + S_SBOX, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC24 + 8, // doomednum + S_BPAK, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC25 + 2006, // doomednum + S_BFUG, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_CHAINGUN + 2002, // doomednum + S_MGUN, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC26 + 2005, // doomednum + S_CSAW, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC27 + 2003, // doomednum + S_LAUN, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC28 + 2004, // doomednum + S_PLAS, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_SHOTGUN + 2001, // doomednum + S_SHOT, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_SUPERSHOTGUN + 82, // doomednum + S_SHOT2, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC29 + 85, // doomednum + S_TECHLAMP, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC30 + 86, // doomednum + S_TECH2LAMP, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC31 + 2028, // doomednum + S_COLU, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC32 + 30, // doomednum + S_TALLGRNCOL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC33 + 31, // doomednum + S_SHRTGRNCOL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC34 + 32, // doomednum + S_TALLREDCOL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC35 + 33, // doomednum + S_SHRTREDCOL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC36 + 37, // doomednum + S_SKULLCOL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC37 + 36, // doomednum + S_HEARTCOL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC38 + 41, // doomednum + S_EVILEYE, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC39 + 42, // doomednum + S_FLOATSKULL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC40 + 43, // doomednum + S_TORCHTREE, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC41 + 44, // doomednum + S_BLUETORCH, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC42 + 45, // doomednum + S_GREENTORCH, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC43 + 46, // doomednum + S_REDTORCH, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC44 + 55, // doomednum + S_BTORCHSHRT, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC45 + 56, // doomednum + S_GTORCHSHRT, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC46 + 57, // doomednum + S_RTORCHSHRT, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC47 + 47, // doomednum + S_STALAGTITE, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC48 + 48, // doomednum + S_TECHPILLAR, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC49 + 34, // doomednum + S_CANDLESTIK, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + 0, // flags + S_NULL // raisestate + }, + + { // MT_MISC50 + 35, // doomednum + S_CANDELABRA, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC51 + 49, // doomednum + S_BLOODYTWITCH, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 68*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC52 + 50, // doomednum + S_MEAT2, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 84*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC53 + 51, // doomednum + S_MEAT3, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 84*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC54 + 52, // doomednum + S_MEAT4, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 68*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC55 + 53, // doomednum + S_MEAT5, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 52*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC56 + 59, // doomednum + S_MEAT2, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 84*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC57 + 60, // doomednum + S_MEAT4, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 68*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC58 + 61, // doomednum + S_MEAT3, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 52*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC59 + 62, // doomednum + S_MEAT5, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 52*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC60 + 63, // doomednum + S_BLOODYTWITCH, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 68*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC61 + 22, // doomednum + S_HEAD_DIE6, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + 0, // flags + S_NULL // raisestate + }, + + { // MT_MISC62 + 15, // doomednum + S_PLAY_DIE7, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + 0, // flags + S_NULL // raisestate + }, + + { // MT_MISC63 + 18, // doomednum + S_POSS_DIE5, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + 0, // flags + S_NULL // raisestate + }, + + { // MT_MISC64 + 21, // doomednum + S_SARG_DIE6, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + 0, // flags + S_NULL // raisestate + }, + + { // MT_MISC65 + 23, // doomednum + S_SKULL_DIE6, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + 0, // flags + S_NULL // raisestate + }, + + { // MT_MISC66 + 20, // doomednum + S_TROO_DIE5, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + 0, // flags + S_NULL // raisestate + }, + + { // MT_MISC67 + 19, // doomednum + S_SPOS_DIE5, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + 0, // flags + S_NULL // raisestate + }, + + { // MT_MISC68 + 10, // doomednum + S_PLAY_XDIE9, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + 0, // flags + S_NULL // raisestate + }, + + { // MT_MISC69 + 12, // doomednum + S_PLAY_XDIE9, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + 0, // flags + S_NULL // raisestate + }, + + { // MT_MISC70 + 28, // doomednum + S_HEADSONSTICK, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC71 + 24, // doomednum + S_GIBS, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + 0, // flags + S_NULL // raisestate + }, + + { // MT_MISC72 + 27, // doomednum + S_HEADONASTICK, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC73 + 29, // doomednum + S_HEADCANDLES, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC74 + 25, // doomednum + S_DEADSTICK, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC75 + 26, // doomednum + S_LIVESTICK, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC76 + 54, // doomednum + S_BIGTREE, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 32*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC77 + 70, // doomednum + S_BBAR1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC78 + 73, // doomednum + S_HANGNOGUTS, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 88*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC79 + 74, // doomednum + S_HANGBNOBRAIN, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 88*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC80 + 75, // doomednum + S_HANGTLOOKDN, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 64*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC81 + 76, // doomednum + S_HANGTSKULL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 64*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC82 + 77, // doomednum + S_HANGTLOOKUP, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 64*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC83 + 78, // doomednum + S_HANGTNOBRAIN, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 64*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC84 + 79, // doomednum + S_COLONGIBS, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP, // flags + S_NULL // raisestate + }, + + { // MT_MISC85 + 80, // doomednum + S_SMALLPOOL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP, // flags + S_NULL // raisestate + }, + + { // MT_MISC86 + 81, // doomednum + S_BRAINSTEM, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP, // flags + S_NULL // raisestate + }, + + // For use with wind and current effects + { // MT_PUSH // phares + 5001, // doomednum // | //jff 5/11/98 deconflict + S_TNT1, // spawnstate // V // with DOSDoom + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 8, // radius + 8, // height + 10, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP, // flags + S_NULL // raisestate + }, + + // For use with wind and current effects + { // MT_PULL + 5002, // doomednum //jff 5/11/98 deconflict + S_TNT1, // spawnstate // with DOSDoom + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 8, // radius + 8, // height + 10, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP, // flags + S_NULL // raisestate + }, +#ifdef DOGS + // Marine's best friend :) // killough 7/19/98 + { // MT_DOGS + 888, // doomednum + S_DOGS_STND, // spawnstate + 500, // spawnhealth + S_DOGS_RUN1, // seestate + sfx_dgsit, // seesound + 8, // reactiontime + sfx_dgatk, // attacksound + S_DOGS_PAIN, // painstate + 180, // painchance + sfx_dgpain, // painsound + S_DOGS_ATK1, // meleestate + 0, // missilestate + S_DOGS_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_dgdth, // deathsound + 10, // speed + 12*FRACUNIT, // radius + 28*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_dgact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_DOGS_RAISE1 // raisestate + }, +#endif + //proff 11/22/98: Andy Baker's stealth monsters (next 12) + +#define STEALTH_EDNUM_BASE 4050 + + { // MT_STEALTHBABY (ARACHNOTRON) + STEALTH_EDNUM_BASE, // doomednum + S_BSPI_STND, // spawnstate + 500, // spawnhealth + S_BSPI_SIGHT, // seestate + sfx_bspsit, // seesound + 8, // reactiontime + 0, // attacksound + S_BSPI_PAIN, // painstate + 128, // painchance + sfx_dmpain, // painsound + 0, // meleestate + S_BSPI_ATK1, // missilestate + S_BSPI_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_bspdth, // deathsound + 12, // speed + 64*FRACUNIT, // radius + 64*FRACUNIT, // height + 600, // mass + 0, // damage + sfx_bspact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_STEALTH, // flags + S_BSPI_RAISE1 // raisestate + }, + + { // MT_STEALTHVILE + STEALTH_EDNUM_BASE+1, // doomednum + S_VILE_STND, // spawnstate + 700, // spawnhealth + S_VILE_RUN1, // seestate + sfx_vilsit, // seesound + 8, // reactiontime + 0, // attacksound + S_VILE_PAIN, // painstate + 10, // painchance + sfx_vipain, // painsound + 0, // meleestate + S_VILE_ATK1, // missilestate + S_VILE_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_vildth, // deathsound + 15, // speed + 20*FRACUNIT, // radius + 56*FRACUNIT, // height + 500, // mass + 0, // damage + sfx_vilact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_STEALTH, // flags + S_NULL // raisestate + }, + + { // MT_STEALTHBRUISER (BARONOFHELL) + STEALTH_EDNUM_BASE+2, // doomednum + S_BOSS_STND, // spawnstate + 1000, // spawnhealth + S_BOSS_RUN1, // seestate + sfx_brssit, // seesound + 8, // reactiontime + 0, // attacksound + S_BOSS_PAIN, // painstate + 50, // painchance + sfx_dmpain, // painsound + S_BOSS_ATK1, // meleestate + S_BOSS_ATK1, // missilestate + S_BOSS_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_brsdth, // deathsound + 8, // speed + 24*FRACUNIT, // radius + 64*FRACUNIT, // height + 1000, // mass + 0, // damage + sfx_dmact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_STEALTH, // flags + S_BOSS_RAISE1 // raisestate + }, + + { // MT_STEALTHHEAD (CACODEMON) + STEALTH_EDNUM_BASE+3, // doomednum + S_HEAD_STND, // spawnstate + 400, // spawnhealth + S_HEAD_RUN1, // seestate + sfx_cacsit, // seesound + 8, // reactiontime + 0, // attacksound + S_HEAD_PAIN, // painstate + 128, // painchance + sfx_dmpain, // painsound + 0, // meleestate + S_HEAD_ATK1, // missilestate + S_HEAD_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_cacdth, // deathsound + 8, // speed + 31*FRACUNIT, // radius + 56*FRACUNIT, // height + 400, // mass + 0, // damage + sfx_dmact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_FLOAT|MF_NOGRAVITY|MF_COUNTKILL|MF_STEALTH, // flags + S_HEAD_RAISE1 // raisestate + }, + + { // MT_STEALTHCHAINGUY (CHAINGUNNER) + STEALTH_EDNUM_BASE+4, // doomednum + S_CPOS_STND, // spawnstate + 70, // spawnhealth + S_CPOS_RUN1, // seestate + sfx_posit2, // seesound + 8, // reactiontime + 0, // attacksound + S_CPOS_PAIN, // painstate + 170, // painchance + sfx_popain, // painsound + 0, // meleestate + S_CPOS_ATK1, // missilestate + S_CPOS_DIE1, // deathstate + S_CPOS_XDIE1, // xdeathstate + sfx_podth2, // deathsound + 8, // speed + 20*FRACUNIT, // radius + 56*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_posact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_STEALTH, // flags + S_CPOS_RAISE1 // raisestate + }, + + { // MT_STEALTHSERGEANT (DEMON) + STEALTH_EDNUM_BASE+5, // doomednum + S_SARG_STND, // spawnstate + 150, // spawnhealth + S_SARG_RUN1, // seestate + sfx_sgtsit, // seesound + 8, // reactiontime + sfx_sgtatk, // attacksound + S_SARG_PAIN, // painstate + 180, // painchance + sfx_dmpain, // painsound + S_SARG_ATK1, // meleestate + 0, // missilestate + S_SARG_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_sgtdth, // deathsound + 10, // speed + 30*FRACUNIT, // radius + 56*FRACUNIT, // height + 400, // mass + 0, // damage + sfx_dmact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_STEALTH, // flags + S_SARG_RAISE1 // raisestate + }, + + { // MT_STEALTHKNIGHT + STEALTH_EDNUM_BASE+6, // doomednum + S_BOS2_STND, // spawnstate + 500, // spawnhealth + S_BOS2_RUN1, // seestate + sfx_kntsit, // seesound + 8, // reactiontime + 0, // attacksound + S_BOS2_PAIN, // painstate + 50, // painchance + sfx_dmpain, // painsound + S_BOS2_ATK1, // meleestate + S_BOS2_ATK1, // missilestate + S_BOS2_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_kntdth, // deathsound + 8, // speed + 24*FRACUNIT, // radius + 64*FRACUNIT, // height + 1000, // mass + 0, // damage + sfx_dmact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_STEALTH, // flags + S_BOS2_RAISE1 // raisestate + }, + + { // MT_STEALTHTROOP (IMP) + STEALTH_EDNUM_BASE+7, // doomednum + S_TROO_STND, // spawnstate + 60, // spawnhealth + S_TROO_RUN1, // seestate + sfx_bgsit1, // seesound + 8, // reactiontime + 0, // attacksound + S_TROO_PAIN, // painstate + 200, // painchance + sfx_popain, // painsound + S_TROO_ATK1, // meleestate + S_TROO_ATK1, // missilestate + S_TROO_DIE1, // deathstate + S_TROO_XDIE1, // xdeathstate + sfx_bgdth1, // deathsound + 8, // speed + 20*FRACUNIT, // radius + 56*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_bgact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_STEALTH, // flags + S_TROO_RAISE1 // raisestate + }, + + { // MT_STEALTHFATSO + STEALTH_EDNUM_BASE+8, // doomednum + S_FATT_STND, // spawnstate + 600, // spawnhealth + S_FATT_RUN1, // seestate + sfx_mansit, // seesound + 8, // reactiontime + 0, // attacksound + S_FATT_PAIN, // painstate + 80, // painchance + sfx_mnpain, // painsound + 0, // meleestate + S_FATT_ATK1, // missilestate + S_FATT_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_mandth, // deathsound + 8, // speed + 48*FRACUNIT, // radius + 64*FRACUNIT, // height + 1000, // mass + 0, // damage + sfx_posact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_STEALTH, // flags + S_FATT_RAISE1 // raisestate + }, + + { // MT_STEALTHUNDEAD + STEALTH_EDNUM_BASE+9, // doomednum + S_SKEL_STND, // spawnstate + 300, // spawnhealth + S_SKEL_RUN1, // seestate + sfx_skesit, // seesound + 8, // reactiontime + 0, // attacksound + S_SKEL_PAIN, // painstate + 100, // painchance + sfx_popain, // painsound + S_SKEL_FIST1, // meleestate + S_SKEL_MISS1, // missilestate + S_SKEL_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_skedth, // deathsound + 10, // speed + 20*FRACUNIT, // radius + 56*FRACUNIT, // height + 500, // mass + 0, // damage + sfx_skeact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_STEALTH, // flags + S_SKEL_RAISE1 // raisestate + }, + + { // MT_STEALTHSHOTGUY + STEALTH_EDNUM_BASE+10, // doomednum + S_SPOS_STND, // spawnstate + 30, // spawnhealth + S_SPOS_RUN1, // seestate + sfx_posit2, // seesound + 8, // reactiontime + 0, // attacksound + S_SPOS_PAIN, // painstate + 170, // painchance + sfx_popain, // painsound + 0, // meleestate + S_SPOS_ATK1, // missilestate + S_SPOS_DIE1, // deathstate + S_SPOS_XDIE1, // xdeathstate + sfx_podth2, // deathsound + 8, // speed + 20*FRACUNIT, // radius + 56*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_posact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_STEALTH, // flags + S_SPOS_RAISE1 // raisestate + }, + + { // MT_STEALTHPOSSESSED + STEALTH_EDNUM_BASE+11, // doomednum + S_POSS_STND, // spawnstate + 20, // spawnhealth + S_POSS_RUN1, // seestate + sfx_posit1, // seesound + 8, // reactiontime + sfx_pistol, // attacksound + S_POSS_PAIN, // painstate + 200, // painchance + sfx_popain, // painsound + 0, // meleestate + S_POSS_ATK1, // missilestate + S_POSS_DIE1, // deathstate + S_POSS_XDIE1, // xdeathstate + sfx_podth1, // deathsound + 8, // speed + 20*FRACUNIT, // radius + 56*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_posact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_STEALTH, // flags + S_POSS_RAISE1 // raisestate + } + +#undef STEALTH_EDNUM_BASE + + }; + diff --git a/apps/plugins/doom/info.h b/apps/plugins/doom/info.h new file mode 100644 index 0000000000..d6c20f0d5d --- /dev/null +++ b/apps/plugins/doom/info.h @@ -0,0 +1,1454 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Thing frame/state LUT, + * generated by multigen utilitiy. + * This one is the original DOOM version, preserved. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __INFO__ +#define __INFO__ + +// Needed for action function pointer handling. +#include "d_think.h" +#include "doomtype.h" + +/******************************************************************** + * Sprite name enumeration - must match info.c * + ********************************************************************/ +typedef enum +{ + SPR_TROO, + SPR_SHTG, + SPR_PUNG, + SPR_PISG, + SPR_PISF, + SPR_SHTF, + SPR_SHT2, + SPR_CHGG, + SPR_CHGF, + SPR_MISG, + SPR_MISF, + SPR_SAWG, + SPR_PLSG, + SPR_PLSF, + SPR_BFGG, + SPR_BFGF, + SPR_BLUD, + SPR_PUFF, + SPR_BAL1, + SPR_BAL2, + SPR_PLSS, + SPR_PLSE, + SPR_MISL, + SPR_BFS1, + SPR_BFE1, + SPR_BFE2, + SPR_TFOG, + SPR_IFOG, + SPR_PLAY, + SPR_POSS, + SPR_SPOS, + SPR_VILE, + SPR_FIRE, + SPR_FATB, + SPR_FBXP, + SPR_SKEL, + SPR_MANF, + SPR_FATT, + SPR_CPOS, + SPR_SARG, + SPR_HEAD, + SPR_BAL7, + SPR_BOSS, + SPR_BOS2, + SPR_SKUL, + SPR_SPID, + SPR_BSPI, + SPR_APLS, + SPR_APBX, + SPR_CYBR, + SPR_PAIN, + SPR_SSWV, + SPR_KEEN, + SPR_BBRN, + SPR_BOSF, + SPR_ARM1, + SPR_ARM2, + SPR_BAR1, + SPR_BEXP, + SPR_FCAN, + SPR_BON1, + SPR_BON2, + SPR_BKEY, + SPR_RKEY, + SPR_YKEY, + SPR_BSKU, + SPR_RSKU, + SPR_YSKU, + SPR_STIM, + SPR_MEDI, + SPR_SOUL, + SPR_PINV, + SPR_PSTR, + SPR_PINS, + SPR_MEGA, + SPR_SUIT, + SPR_PMAP, + SPR_PVIS, + SPR_CLIP, + SPR_AMMO, + SPR_ROCK, + SPR_BROK, + SPR_CELL, + SPR_CELP, + SPR_SHEL, + SPR_SBOX, + SPR_BPAK, + SPR_BFUG, + SPR_MGUN, + SPR_CSAW, + SPR_LAUN, + SPR_PLAS, + SPR_SHOT, + SPR_SGN2, + SPR_COLU, + SPR_SMT2, + SPR_GOR1, + SPR_POL2, + SPR_POL5, + SPR_POL4, + SPR_POL3, + SPR_POL1, + SPR_POL6, + SPR_GOR2, + SPR_GOR3, + SPR_GOR4, + SPR_GOR5, + SPR_SMIT, + SPR_COL1, + SPR_COL2, + SPR_COL3, + SPR_COL4, + SPR_CAND, + SPR_CBRA, + SPR_COL6, + SPR_TRE1, + SPR_TRE2, + SPR_ELEC, + SPR_CEYE, + SPR_FSKU, + SPR_COL5, + SPR_TBLU, + SPR_TGRN, + SPR_TRED, + SPR_SMBT, + SPR_SMGT, + SPR_SMRT, + SPR_HDB1, + SPR_HDB2, + SPR_HDB3, + SPR_HDB4, + SPR_HDB5, + SPR_HDB6, + SPR_POB1, + SPR_POB2, + SPR_BRS1, + SPR_TLMP, + SPR_TLP2, + SPR_TNT1, /* add invisible sprite phares 3/8/98 */ + +#ifdef DOGS + SPR_DOGS, /* killough 7/19/98: Marine's best friend :) */ +#endif + NUMSPRITES + +} spritenum_t; + +/******************************************************************** + * States (frames) enumeration -- must match info.c * + ********************************************************************/ + +typedef enum +{ + S_NULL, + S_LIGHTDONE, + S_PUNCH, + S_PUNCHDOWN, + S_PUNCHUP, + S_PUNCH1, + S_PUNCH2, + S_PUNCH3, + S_PUNCH4, + S_PUNCH5, + S_PISTOL, + S_PISTOLDOWN, + S_PISTOLUP, + S_PISTOL1, + S_PISTOL2, + S_PISTOL3, + S_PISTOL4, + S_PISTOLFLASH, + S_SGUN, + S_SGUNDOWN, + S_SGUNUP, + S_SGUN1, + S_SGUN2, + S_SGUN3, + S_SGUN4, + S_SGUN5, + S_SGUN6, + S_SGUN7, + S_SGUN8, + S_SGUN9, + S_SGUNFLASH1, + S_SGUNFLASH2, + S_DSGUN, + S_DSGUNDOWN, + S_DSGUNUP, + S_DSGUN1, + S_DSGUN2, + S_DSGUN3, + S_DSGUN4, + S_DSGUN5, + S_DSGUN6, + S_DSGUN7, + S_DSGUN8, + S_DSGUN9, + S_DSGUN10, + S_DSNR1, + S_DSNR2, + S_DSGUNFLASH1, + S_DSGUNFLASH2, + S_CHAIN, + S_CHAINDOWN, + S_CHAINUP, + S_CHAIN1, + S_CHAIN2, + S_CHAIN3, + S_CHAINFLASH1, + S_CHAINFLASH2, + S_MISSILE, + S_MISSILEDOWN, + S_MISSILEUP, + S_MISSILE1, + S_MISSILE2, + S_MISSILE3, + S_MISSILEFLASH1, + S_MISSILEFLASH2, + S_MISSILEFLASH3, + S_MISSILEFLASH4, + S_SAW, + S_SAWB, + S_SAWDOWN, + S_SAWUP, + S_SAW1, + S_SAW2, + S_SAW3, + S_PLASMA, + S_PLASMADOWN, + S_PLASMAUP, + S_PLASMA1, + S_PLASMA2, + S_PLASMAFLASH1, + S_PLASMAFLASH2, + S_BFG, + S_BFGDOWN, + S_BFGUP, + S_BFG1, + S_BFG2, + S_BFG3, + S_BFG4, + S_BFGFLASH1, + S_BFGFLASH2, + S_BLOOD1, + S_BLOOD2, + S_BLOOD3, + S_PUFF1, + S_PUFF2, + S_PUFF3, + S_PUFF4, + S_TBALL1, + S_TBALL2, + S_TBALLX1, + S_TBALLX2, + S_TBALLX3, + S_RBALL1, + S_RBALL2, + S_RBALLX1, + S_RBALLX2, + S_RBALLX3, + S_PLASBALL, + S_PLASBALL2, + S_PLASEXP, + S_PLASEXP2, + S_PLASEXP3, + S_PLASEXP4, + S_PLASEXP5, + S_ROCKET, + S_BFGSHOT, + S_BFGSHOT2, + S_BFGLAND, + S_BFGLAND2, + S_BFGLAND3, + S_BFGLAND4, + S_BFGLAND5, + S_BFGLAND6, + S_BFGEXP, + S_BFGEXP2, + S_BFGEXP3, + S_BFGEXP4, + S_EXPLODE1, + S_EXPLODE2, + S_EXPLODE3, + S_TFOG, + S_TFOG01, + S_TFOG02, + S_TFOG2, + S_TFOG3, + S_TFOG4, + S_TFOG5, + S_TFOG6, + S_TFOG7, + S_TFOG8, + S_TFOG9, + S_TFOG10, + S_IFOG, + S_IFOG01, + S_IFOG02, + S_IFOG2, + S_IFOG3, + S_IFOG4, + S_IFOG5, + S_PLAY, + S_PLAY_RUN1, + S_PLAY_RUN2, + S_PLAY_RUN3, + S_PLAY_RUN4, + S_PLAY_ATK1, + S_PLAY_ATK2, + S_PLAY_PAIN, + S_PLAY_PAIN2, + S_PLAY_DIE1, + S_PLAY_DIE2, + S_PLAY_DIE3, + S_PLAY_DIE4, + S_PLAY_DIE5, + S_PLAY_DIE6, + S_PLAY_DIE7, + S_PLAY_XDIE1, + S_PLAY_XDIE2, + S_PLAY_XDIE3, + S_PLAY_XDIE4, + S_PLAY_XDIE5, + S_PLAY_XDIE6, + S_PLAY_XDIE7, + S_PLAY_XDIE8, + S_PLAY_XDIE9, + S_POSS_STND, + S_POSS_STND2, + S_POSS_RUN1, + S_POSS_RUN2, + S_POSS_RUN3, + S_POSS_RUN4, + S_POSS_RUN5, + S_POSS_RUN6, + S_POSS_RUN7, + S_POSS_RUN8, + S_POSS_ATK1, + S_POSS_ATK2, + S_POSS_ATK3, + S_POSS_PAIN, + S_POSS_PAIN2, + S_POSS_DIE1, + S_POSS_DIE2, + S_POSS_DIE3, + S_POSS_DIE4, + S_POSS_DIE5, + S_POSS_XDIE1, + S_POSS_XDIE2, + S_POSS_XDIE3, + S_POSS_XDIE4, + S_POSS_XDIE5, + S_POSS_XDIE6, + S_POSS_XDIE7, + S_POSS_XDIE8, + S_POSS_XDIE9, + S_POSS_RAISE1, + S_POSS_RAISE2, + S_POSS_RAISE3, + S_POSS_RAISE4, + S_SPOS_STND, + S_SPOS_STND2, + S_SPOS_RUN1, + S_SPOS_RUN2, + S_SPOS_RUN3, + S_SPOS_RUN4, + S_SPOS_RUN5, + S_SPOS_RUN6, + S_SPOS_RUN7, + S_SPOS_RUN8, + S_SPOS_ATK1, + S_SPOS_ATK2, + S_SPOS_ATK3, + S_SPOS_PAIN, + S_SPOS_PAIN2, + S_SPOS_DIE1, + S_SPOS_DIE2, + S_SPOS_DIE3, + S_SPOS_DIE4, + S_SPOS_DIE5, + S_SPOS_XDIE1, + S_SPOS_XDIE2, + S_SPOS_XDIE3, + S_SPOS_XDIE4, + S_SPOS_XDIE5, + S_SPOS_XDIE6, + S_SPOS_XDIE7, + S_SPOS_XDIE8, + S_SPOS_XDIE9, + S_SPOS_RAISE1, + S_SPOS_RAISE2, + S_SPOS_RAISE3, + S_SPOS_RAISE4, + S_SPOS_RAISE5, + S_VILE_STND, + S_VILE_STND2, + S_VILE_RUN1, + S_VILE_RUN2, + S_VILE_RUN3, + S_VILE_RUN4, + S_VILE_RUN5, + S_VILE_RUN6, + S_VILE_RUN7, + S_VILE_RUN8, + S_VILE_RUN9, + S_VILE_RUN10, + S_VILE_RUN11, + S_VILE_RUN12, + S_VILE_ATK1, + S_VILE_ATK2, + S_VILE_ATK3, + S_VILE_ATK4, + S_VILE_ATK5, + S_VILE_ATK6, + S_VILE_ATK7, + S_VILE_ATK8, + S_VILE_ATK9, + S_VILE_ATK10, + S_VILE_ATK11, + S_VILE_HEAL1, + S_VILE_HEAL2, + S_VILE_HEAL3, + S_VILE_PAIN, + S_VILE_PAIN2, + S_VILE_DIE1, + S_VILE_DIE2, + S_VILE_DIE3, + S_VILE_DIE4, + S_VILE_DIE5, + S_VILE_DIE6, + S_VILE_DIE7, + S_VILE_DIE8, + S_VILE_DIE9, + S_VILE_DIE10, + S_FIRE1, + S_FIRE2, + S_FIRE3, + S_FIRE4, + S_FIRE5, + S_FIRE6, + S_FIRE7, + S_FIRE8, + S_FIRE9, + S_FIRE10, + S_FIRE11, + S_FIRE12, + S_FIRE13, + S_FIRE14, + S_FIRE15, + S_FIRE16, + S_FIRE17, + S_FIRE18, + S_FIRE19, + S_FIRE20, + S_FIRE21, + S_FIRE22, + S_FIRE23, + S_FIRE24, + S_FIRE25, + S_FIRE26, + S_FIRE27, + S_FIRE28, + S_FIRE29, + S_FIRE30, + S_SMOKE1, + S_SMOKE2, + S_SMOKE3, + S_SMOKE4, + S_SMOKE5, + S_TRACER, + S_TRACER2, + S_TRACEEXP1, + S_TRACEEXP2, + S_TRACEEXP3, + S_SKEL_STND, + S_SKEL_STND2, + S_SKEL_RUN1, + S_SKEL_RUN2, + S_SKEL_RUN3, + S_SKEL_RUN4, + S_SKEL_RUN5, + S_SKEL_RUN6, + S_SKEL_RUN7, + S_SKEL_RUN8, + S_SKEL_RUN9, + S_SKEL_RUN10, + S_SKEL_RUN11, + S_SKEL_RUN12, + S_SKEL_FIST1, + S_SKEL_FIST2, + S_SKEL_FIST3, + S_SKEL_FIST4, + S_SKEL_MISS1, + S_SKEL_MISS2, + S_SKEL_MISS3, + S_SKEL_MISS4, + S_SKEL_PAIN, + S_SKEL_PAIN2, + S_SKEL_DIE1, + S_SKEL_DIE2, + S_SKEL_DIE3, + S_SKEL_DIE4, + S_SKEL_DIE5, + S_SKEL_DIE6, + S_SKEL_RAISE1, + S_SKEL_RAISE2, + S_SKEL_RAISE3, + S_SKEL_RAISE4, + S_SKEL_RAISE5, + S_SKEL_RAISE6, + S_FATSHOT1, + S_FATSHOT2, + S_FATSHOTX1, + S_FATSHOTX2, + S_FATSHOTX3, + S_FATT_STND, + S_FATT_STND2, + S_FATT_RUN1, + S_FATT_RUN2, + S_FATT_RUN3, + S_FATT_RUN4, + S_FATT_RUN5, + S_FATT_RUN6, + S_FATT_RUN7, + S_FATT_RUN8, + S_FATT_RUN9, + S_FATT_RUN10, + S_FATT_RUN11, + S_FATT_RUN12, + S_FATT_ATK1, + S_FATT_ATK2, + S_FATT_ATK3, + S_FATT_ATK4, + S_FATT_ATK5, + S_FATT_ATK6, + S_FATT_ATK7, + S_FATT_ATK8, + S_FATT_ATK9, + S_FATT_ATK10, + S_FATT_PAIN, + S_FATT_PAIN2, + S_FATT_DIE1, + S_FATT_DIE2, + S_FATT_DIE3, + S_FATT_DIE4, + S_FATT_DIE5, + S_FATT_DIE6, + S_FATT_DIE7, + S_FATT_DIE8, + S_FATT_DIE9, + S_FATT_DIE10, + S_FATT_RAISE1, + S_FATT_RAISE2, + S_FATT_RAISE3, + S_FATT_RAISE4, + S_FATT_RAISE5, + S_FATT_RAISE6, + S_FATT_RAISE7, + S_FATT_RAISE8, + S_CPOS_STND, + S_CPOS_STND2, + S_CPOS_RUN1, + S_CPOS_RUN2, + S_CPOS_RUN3, + S_CPOS_RUN4, + S_CPOS_RUN5, + S_CPOS_RUN6, + S_CPOS_RUN7, + S_CPOS_RUN8, + S_CPOS_ATK1, + S_CPOS_ATK2, + S_CPOS_ATK3, + S_CPOS_ATK4, + S_CPOS_PAIN, + S_CPOS_PAIN2, + S_CPOS_DIE1, + S_CPOS_DIE2, + S_CPOS_DIE3, + S_CPOS_DIE4, + S_CPOS_DIE5, + S_CPOS_DIE6, + S_CPOS_DIE7, + S_CPOS_XDIE1, + S_CPOS_XDIE2, + S_CPOS_XDIE3, + S_CPOS_XDIE4, + S_CPOS_XDIE5, + S_CPOS_XDIE6, + S_CPOS_RAISE1, + S_CPOS_RAISE2, + S_CPOS_RAISE3, + S_CPOS_RAISE4, + S_CPOS_RAISE5, + S_CPOS_RAISE6, + S_CPOS_RAISE7, + S_TROO_STND, + S_TROO_STND2, + S_TROO_RUN1, + S_TROO_RUN2, + S_TROO_RUN3, + S_TROO_RUN4, + S_TROO_RUN5, + S_TROO_RUN6, + S_TROO_RUN7, + S_TROO_RUN8, + S_TROO_ATK1, + S_TROO_ATK2, + S_TROO_ATK3, + S_TROO_PAIN, + S_TROO_PAIN2, + S_TROO_DIE1, + S_TROO_DIE2, + S_TROO_DIE3, + S_TROO_DIE4, + S_TROO_DIE5, + S_TROO_XDIE1, + S_TROO_XDIE2, + S_TROO_XDIE3, + S_TROO_XDIE4, + S_TROO_XDIE5, + S_TROO_XDIE6, + S_TROO_XDIE7, + S_TROO_XDIE8, + S_TROO_RAISE1, + S_TROO_RAISE2, + S_TROO_RAISE3, + S_TROO_RAISE4, + S_TROO_RAISE5, + S_SARG_STND, + S_SARG_STND2, + S_SARG_RUN1, + S_SARG_RUN2, + S_SARG_RUN3, + S_SARG_RUN4, + S_SARG_RUN5, + S_SARG_RUN6, + S_SARG_RUN7, + S_SARG_RUN8, + S_SARG_ATK1, + S_SARG_ATK2, + S_SARG_ATK3, + S_SARG_PAIN, + S_SARG_PAIN2, + S_SARG_DIE1, + S_SARG_DIE2, + S_SARG_DIE3, + S_SARG_DIE4, + S_SARG_DIE5, + S_SARG_DIE6, + S_SARG_RAISE1, + S_SARG_RAISE2, + S_SARG_RAISE3, + S_SARG_RAISE4, + S_SARG_RAISE5, + S_SARG_RAISE6, + S_HEAD_STND, + S_HEAD_RUN1, + S_HEAD_ATK1, + S_HEAD_ATK2, + S_HEAD_ATK3, + S_HEAD_PAIN, + S_HEAD_PAIN2, + S_HEAD_PAIN3, + S_HEAD_DIE1, + S_HEAD_DIE2, + S_HEAD_DIE3, + S_HEAD_DIE4, + S_HEAD_DIE5, + S_HEAD_DIE6, + S_HEAD_RAISE1, + S_HEAD_RAISE2, + S_HEAD_RAISE3, + S_HEAD_RAISE4, + S_HEAD_RAISE5, + S_HEAD_RAISE6, + S_BRBALL1, + S_BRBALL2, + S_BRBALLX1, + S_BRBALLX2, + S_BRBALLX3, + S_BOSS_STND, + S_BOSS_STND2, + S_BOSS_RUN1, + S_BOSS_RUN2, + S_BOSS_RUN3, + S_BOSS_RUN4, + S_BOSS_RUN5, + S_BOSS_RUN6, + S_BOSS_RUN7, + S_BOSS_RUN8, + S_BOSS_ATK1, + S_BOSS_ATK2, + S_BOSS_ATK3, + S_BOSS_PAIN, + S_BOSS_PAIN2, + S_BOSS_DIE1, + S_BOSS_DIE2, + S_BOSS_DIE3, + S_BOSS_DIE4, + S_BOSS_DIE5, + S_BOSS_DIE6, + S_BOSS_DIE7, + S_BOSS_RAISE1, + S_BOSS_RAISE2, + S_BOSS_RAISE3, + S_BOSS_RAISE4, + S_BOSS_RAISE5, + S_BOSS_RAISE6, + S_BOSS_RAISE7, + S_BOS2_STND, + S_BOS2_STND2, + S_BOS2_RUN1, + S_BOS2_RUN2, + S_BOS2_RUN3, + S_BOS2_RUN4, + S_BOS2_RUN5, + S_BOS2_RUN6, + S_BOS2_RUN7, + S_BOS2_RUN8, + S_BOS2_ATK1, + S_BOS2_ATK2, + S_BOS2_ATK3, + S_BOS2_PAIN, + S_BOS2_PAIN2, + S_BOS2_DIE1, + S_BOS2_DIE2, + S_BOS2_DIE3, + S_BOS2_DIE4, + S_BOS2_DIE5, + S_BOS2_DIE6, + S_BOS2_DIE7, + S_BOS2_RAISE1, + S_BOS2_RAISE2, + S_BOS2_RAISE3, + S_BOS2_RAISE4, + S_BOS2_RAISE5, + S_BOS2_RAISE6, + S_BOS2_RAISE7, + S_SKULL_STND, + S_SKULL_STND2, + S_SKULL_RUN1, + S_SKULL_RUN2, + S_SKULL_ATK1, + S_SKULL_ATK2, + S_SKULL_ATK3, + S_SKULL_ATK4, + S_SKULL_PAIN, + S_SKULL_PAIN2, + S_SKULL_DIE1, + S_SKULL_DIE2, + S_SKULL_DIE3, + S_SKULL_DIE4, + S_SKULL_DIE5, + S_SKULL_DIE6, + S_SPID_STND, + S_SPID_STND2, + S_SPID_RUN1, + S_SPID_RUN2, + S_SPID_RUN3, + S_SPID_RUN4, + S_SPID_RUN5, + S_SPID_RUN6, + S_SPID_RUN7, + S_SPID_RUN8, + S_SPID_RUN9, + S_SPID_RUN10, + S_SPID_RUN11, + S_SPID_RUN12, + S_SPID_ATK1, + S_SPID_ATK2, + S_SPID_ATK3, + S_SPID_ATK4, + S_SPID_PAIN, + S_SPID_PAIN2, + S_SPID_DIE1, + S_SPID_DIE2, + S_SPID_DIE3, + S_SPID_DIE4, + S_SPID_DIE5, + S_SPID_DIE6, + S_SPID_DIE7, + S_SPID_DIE8, + S_SPID_DIE9, + S_SPID_DIE10, + S_SPID_DIE11, + S_BSPI_STND, + S_BSPI_STND2, + S_BSPI_SIGHT, + S_BSPI_RUN1, + S_BSPI_RUN2, + S_BSPI_RUN3, + S_BSPI_RUN4, + S_BSPI_RUN5, + S_BSPI_RUN6, + S_BSPI_RUN7, + S_BSPI_RUN8, + S_BSPI_RUN9, + S_BSPI_RUN10, + S_BSPI_RUN11, + S_BSPI_RUN12, + S_BSPI_ATK1, + S_BSPI_ATK2, + S_BSPI_ATK3, + S_BSPI_ATK4, + S_BSPI_PAIN, + S_BSPI_PAIN2, + S_BSPI_DIE1, + S_BSPI_DIE2, + S_BSPI_DIE3, + S_BSPI_DIE4, + S_BSPI_DIE5, + S_BSPI_DIE6, + S_BSPI_DIE7, + S_BSPI_RAISE1, + S_BSPI_RAISE2, + S_BSPI_RAISE3, + S_BSPI_RAISE4, + S_BSPI_RAISE5, + S_BSPI_RAISE6, + S_BSPI_RAISE7, + S_ARACH_PLAZ, + S_ARACH_PLAZ2, + S_ARACH_PLEX, + S_ARACH_PLEX2, + S_ARACH_PLEX3, + S_ARACH_PLEX4, + S_ARACH_PLEX5, + S_CYBER_STND, + S_CYBER_STND2, + S_CYBER_RUN1, + S_CYBER_RUN2, + S_CYBER_RUN3, + S_CYBER_RUN4, + S_CYBER_RUN5, + S_CYBER_RUN6, + S_CYBER_RUN7, + S_CYBER_RUN8, + S_CYBER_ATK1, + S_CYBER_ATK2, + S_CYBER_ATK3, + S_CYBER_ATK4, + S_CYBER_ATK5, + S_CYBER_ATK6, + S_CYBER_PAIN, + S_CYBER_DIE1, + S_CYBER_DIE2, + S_CYBER_DIE3, + S_CYBER_DIE4, + S_CYBER_DIE5, + S_CYBER_DIE6, + S_CYBER_DIE7, + S_CYBER_DIE8, + S_CYBER_DIE9, + S_CYBER_DIE10, + S_PAIN_STND, + S_PAIN_RUN1, + S_PAIN_RUN2, + S_PAIN_RUN3, + S_PAIN_RUN4, + S_PAIN_RUN5, + S_PAIN_RUN6, + S_PAIN_ATK1, + S_PAIN_ATK2, + S_PAIN_ATK3, + S_PAIN_ATK4, + S_PAIN_PAIN, + S_PAIN_PAIN2, + S_PAIN_DIE1, + S_PAIN_DIE2, + S_PAIN_DIE3, + S_PAIN_DIE4, + S_PAIN_DIE5, + S_PAIN_DIE6, + S_PAIN_RAISE1, + S_PAIN_RAISE2, + S_PAIN_RAISE3, + S_PAIN_RAISE4, + S_PAIN_RAISE5, + S_PAIN_RAISE6, + S_SSWV_STND, + S_SSWV_STND2, + S_SSWV_RUN1, + S_SSWV_RUN2, + S_SSWV_RUN3, + S_SSWV_RUN4, + S_SSWV_RUN5, + S_SSWV_RUN6, + S_SSWV_RUN7, + S_SSWV_RUN8, + S_SSWV_ATK1, + S_SSWV_ATK2, + S_SSWV_ATK3, + S_SSWV_ATK4, + S_SSWV_ATK5, + S_SSWV_ATK6, + S_SSWV_PAIN, + S_SSWV_PAIN2, + S_SSWV_DIE1, + S_SSWV_DIE2, + S_SSWV_DIE3, + S_SSWV_DIE4, + S_SSWV_DIE5, + S_SSWV_XDIE1, + S_SSWV_XDIE2, + S_SSWV_XDIE3, + S_SSWV_XDIE4, + S_SSWV_XDIE5, + S_SSWV_XDIE6, + S_SSWV_XDIE7, + S_SSWV_XDIE8, + S_SSWV_XDIE9, + S_SSWV_RAISE1, + S_SSWV_RAISE2, + S_SSWV_RAISE3, + S_SSWV_RAISE4, + S_SSWV_RAISE5, + S_KEENSTND, + S_COMMKEEN, + S_COMMKEEN2, + S_COMMKEEN3, + S_COMMKEEN4, + S_COMMKEEN5, + S_COMMKEEN6, + S_COMMKEEN7, + S_COMMKEEN8, + S_COMMKEEN9, + S_COMMKEEN10, + S_COMMKEEN11, + S_COMMKEEN12, + S_KEENPAIN, + S_KEENPAIN2, + S_BRAIN, + S_BRAIN_PAIN, + S_BRAIN_DIE1, + S_BRAIN_DIE2, + S_BRAIN_DIE3, + S_BRAIN_DIE4, + S_BRAINEYE, + S_BRAINEYESEE, + S_BRAINEYE1, + S_SPAWN1, + S_SPAWN2, + S_SPAWN3, + S_SPAWN4, + S_SPAWNFIRE1, + S_SPAWNFIRE2, + S_SPAWNFIRE3, + S_SPAWNFIRE4, + S_SPAWNFIRE5, + S_SPAWNFIRE6, + S_SPAWNFIRE7, + S_SPAWNFIRE8, + S_BRAINEXPLODE1, + S_BRAINEXPLODE2, + S_BRAINEXPLODE3, + S_ARM1, + S_ARM1A, + S_ARM2, + S_ARM2A, + S_BAR1, + S_BAR2, + S_BEXP, + S_BEXP2, + S_BEXP3, + S_BEXP4, + S_BEXP5, + S_BBAR1, + S_BBAR2, + S_BBAR3, + S_BON1, + S_BON1A, + S_BON1B, + S_BON1C, + S_BON1D, + S_BON1E, + S_BON2, + S_BON2A, + S_BON2B, + S_BON2C, + S_BON2D, + S_BON2E, + S_BKEY, + S_BKEY2, + S_RKEY, + S_RKEY2, + S_YKEY, + S_YKEY2, + S_BSKULL, + S_BSKULL2, + S_RSKULL, + S_RSKULL2, + S_YSKULL, + S_YSKULL2, + S_STIM, + S_MEDI, + S_SOUL, + S_SOUL2, + S_SOUL3, + S_SOUL4, + S_SOUL5, + S_SOUL6, + S_PINV, + S_PINV2, + S_PINV3, + S_PINV4, + S_PSTR, + S_PINS, + S_PINS2, + S_PINS3, + S_PINS4, + S_MEGA, + S_MEGA2, + S_MEGA3, + S_MEGA4, + S_SUIT, + S_PMAP, + S_PMAP2, + S_PMAP3, + S_PMAP4, + S_PMAP5, + S_PMAP6, + S_PVIS, + S_PVIS2, + S_CLIP, + S_AMMO, + S_ROCK, + S_BROK, + S_CELL, + S_CELP, + S_SHEL, + S_SBOX, + S_BPAK, + S_BFUG, + S_MGUN, + S_CSAW, + S_LAUN, + S_PLAS, + S_SHOT, + S_SHOT2, + S_COLU, + S_STALAG, + S_BLOODYTWITCH, + S_BLOODYTWITCH2, + S_BLOODYTWITCH3, + S_BLOODYTWITCH4, + S_DEADTORSO, + S_DEADBOTTOM, + S_HEADSONSTICK, + S_GIBS, + S_HEADONASTICK, + S_HEADCANDLES, + S_HEADCANDLES2, + S_DEADSTICK, + S_LIVESTICK, + S_LIVESTICK2, + S_MEAT2, + S_MEAT3, + S_MEAT4, + S_MEAT5, + S_STALAGTITE, + S_TALLGRNCOL, + S_SHRTGRNCOL, + S_TALLREDCOL, + S_SHRTREDCOL, + S_CANDLESTIK, + S_CANDELABRA, + S_SKULLCOL, + S_TORCHTREE, + S_BIGTREE, + S_TECHPILLAR, + S_EVILEYE, + S_EVILEYE2, + S_EVILEYE3, + S_EVILEYE4, + S_FLOATSKULL, + S_FLOATSKULL2, + S_FLOATSKULL3, + S_HEARTCOL, + S_HEARTCOL2, + S_BLUETORCH, + S_BLUETORCH2, + S_BLUETORCH3, + S_BLUETORCH4, + S_GREENTORCH, + S_GREENTORCH2, + S_GREENTORCH3, + S_GREENTORCH4, + S_REDTORCH, + S_REDTORCH2, + S_REDTORCH3, + S_REDTORCH4, + S_BTORCHSHRT, + S_BTORCHSHRT2, + S_BTORCHSHRT3, + S_BTORCHSHRT4, + S_GTORCHSHRT, + S_GTORCHSHRT2, + S_GTORCHSHRT3, + S_GTORCHSHRT4, + S_RTORCHSHRT, + S_RTORCHSHRT2, + S_RTORCHSHRT3, + S_RTORCHSHRT4, + S_HANGNOGUTS, + S_HANGBNOBRAIN, + S_HANGTLOOKDN, + S_HANGTSKULL, + S_HANGTLOOKUP, + S_HANGTNOBRAIN, + S_COLONGIBS, + S_SMALLPOOL, + S_BRAINSTEM, + S_TECHLAMP, + S_TECHLAMP2, + S_TECHLAMP3, + S_TECHLAMP4, + S_TECH2LAMP, + S_TECH2LAMP2, + S_TECH2LAMP3, + S_TECH2LAMP4, + S_TNT1, /* add state for invisible sprite phares 3/8/98 */ + + S_GRENADE, /* killough 8/9/98: grenade launcher */ + S_DETONATE, /* killough 8/9/98: detonation of objects */ + S_DETONATE2, + S_DETONATE3, + +#ifdef DOGS + S_DOGS_STND, /* killough 7/19/98: Marine's best friend :) */ + S_DOGS_STND2, + S_DOGS_RUN1, + S_DOGS_RUN2, + S_DOGS_RUN3, + S_DOGS_RUN4, + S_DOGS_RUN5, + S_DOGS_RUN6, + S_DOGS_RUN7, + S_DOGS_RUN8, + S_DOGS_ATK1, + S_DOGS_ATK2, + S_DOGS_ATK3, + S_DOGS_PAIN, + S_DOGS_PAIN2, + S_DOGS_DIE1, + S_DOGS_DIE2, + S_DOGS_DIE3, + S_DOGS_DIE4, + S_DOGS_DIE5, + S_DOGS_DIE6, + S_DOGS_RAISE1, + S_DOGS_RAISE2, + S_DOGS_RAISE3, + S_DOGS_RAISE4, + S_DOGS_RAISE5, + S_DOGS_RAISE6, +#endif + + S_MUSHROOM, /* killough 10/98: mushroom explosion effect */ + + NUMSTATES /* Counter of how many there are */ + +} statenum_t; + +/******************************************************************** + * Definition of the state (frames) structure * + ********************************************************************/ + +typedef struct +{ + spritenum_t sprite; /* sprite number to show */ + long frame; /* which frame/subframe of the sprite is shown */ + long tics; /* number of gametics this frame should last */ + actionf_t action; /* code pointer to function for action if any */ + statenum_t nextstate; /* linked list pointer to next state or zero */ + long misc1, misc2; /* apparently never used in DOOM */ +} state_t; + +/* these are in info.c */ +extern state_t states[NUMSTATES]; +extern const char *sprnames[NUMSPRITES+1]; /* 1/17/98 killough - CPhipps - const */ + +/******************************************************************** + * Thing enumeration -- must match info.c * + ******************************************************************** + * Note that many of these are generically named for the ornamentals + */ + +typedef enum { + MT_PLAYER, + MT_POSSESSED, + MT_SHOTGUY, + MT_VILE, + MT_FIRE, + MT_UNDEAD, + MT_TRACER, + MT_SMOKE, + MT_FATSO, + MT_FATSHOT, + MT_CHAINGUY, + MT_TROOP, + MT_SERGEANT, + MT_SHADOWS, + MT_HEAD, + MT_BRUISER, + MT_BRUISERSHOT, + MT_KNIGHT, + MT_SKULL, + MT_SPIDER, + MT_BABY, + MT_CYBORG, + MT_PAIN, + MT_WOLFSS, + MT_KEEN, + MT_BOSSBRAIN, + MT_BOSSSPIT, + MT_BOSSTARGET, + MT_SPAWNSHOT, + MT_SPAWNFIRE, + MT_BARREL, + MT_TROOPSHOT, + MT_HEADSHOT, + MT_ROCKET, + MT_PLASMA, + MT_BFG, + MT_ARACHPLAZ, + MT_PUFF, + MT_BLOOD, + MT_TFOG, + MT_IFOG, + MT_TELEPORTMAN, + MT_EXTRABFG, + MT_MISC0, + MT_MISC1, + MT_MISC2, + MT_MISC3, + MT_MISC4, + MT_MISC5, + MT_MISC6, + MT_MISC7, + MT_MISC8, + MT_MISC9, + MT_MISC10, + MT_MISC11, + MT_MISC12, + MT_INV, + MT_MISC13, + MT_INS, + MT_MISC14, + MT_MISC15, + MT_MISC16, + MT_MEGA, + MT_CLIP, + MT_MISC17, + MT_MISC18, + MT_MISC19, + MT_MISC20, + MT_MISC21, + MT_MISC22, + MT_MISC23, + MT_MISC24, + MT_MISC25, + MT_CHAINGUN, + MT_MISC26, + MT_MISC27, + MT_MISC28, + MT_SHOTGUN, + MT_SUPERSHOTGUN, + MT_MISC29, + MT_MISC30, + MT_MISC31, + MT_MISC32, + MT_MISC33, + MT_MISC34, + MT_MISC35, + MT_MISC36, + MT_MISC37, + MT_MISC38, + MT_MISC39, + MT_MISC40, + MT_MISC41, + MT_MISC42, + MT_MISC43, + MT_MISC44, + MT_MISC45, + MT_MISC46, + MT_MISC47, + MT_MISC48, + MT_MISC49, + MT_MISC50, + MT_MISC51, + MT_MISC52, + MT_MISC53, + MT_MISC54, + MT_MISC55, + MT_MISC56, + MT_MISC57, + MT_MISC58, + MT_MISC59, + MT_MISC60, + MT_MISC61, + MT_MISC62, + MT_MISC63, + MT_MISC64, + MT_MISC65, + MT_MISC66, + MT_MISC67, + MT_MISC68, + MT_MISC69, + MT_MISC70, + MT_MISC71, + MT_MISC72, + MT_MISC73, + MT_MISC74, + MT_MISC75, + MT_MISC76, + MT_MISC77, + MT_MISC78, + MT_MISC79, + MT_MISC80, + MT_MISC81, + MT_MISC82, + MT_MISC83, + MT_MISC84, + MT_MISC85, + MT_MISC86, + MT_PUSH, /* controls push source - phares */ + MT_PULL, /* controls pull source - phares 3/20/98 */ + +#ifdef DOGS + MT_DOGS, /* killough 7/19/98: Marine's best friend */ +#endif + + /* proff 11/22/98: Andy Baker's stealth monsters (next 12) + * cph - moved below the MBF stuff, no need to displace them */ + MT_STEALTHBABY, + MT_STEALTHVILE, + MT_STEALTHBRUISER, + MT_STEALTHHEAD, + MT_STEALTHCHAINGUY, + MT_STEALTHSERGEANT, + MT_STEALTHKNIGHT, + MT_STEALTHIMP, + MT_STEALTHFATSO, + MT_STEALTHUNDEAD, + MT_STEALTHSHOTGUY, + MT_STEALTHZOMBIE, + NUMMOBJTYPES + +} mobjtype_t; + +/******************************************************************** + * Definition of the Thing structure + ********************************************************************/ +/* Note that these are only indices to the state, sound, etc. arrays + * and not actual pointers. Most can be set to zero if the action or + * sound doesn't apply (like lamps generally don't attack or whistle). + */ + +typedef struct +{ + int doomednum; /* Thing number used in id's editor, and now + probably by every other editor too */ + int spawnstate; /* The state (frame) index when this Thing is + first created */ + int spawnhealth; /* The initial hit points for this Thing */ + int seestate; /* The state when it sees you or wakes up */ + int seesound; /* The sound it makes when waking */ + int reactiontime; /* How many tics it waits after it wakes up + before it will start to attack, in normal + skills (halved for nightmare) */ + int attacksound; /* The sound it makes when it attacks */ + int painstate; /* The state to indicate pain */ + int painchance; /* A number that is checked against a random + number 0-255 to see if the Thing is supposed + to go to its painstate or not. Note this + has absolutely nothing to do with the chance + it will get hurt, just the chance of it + reacting visibly. */ + int painsound; /* The sound it emits when it feels pain */ + int meleestate; /* Melee==close attack */ + int missilestate; /* What states to use when it's in the air, if + in fact it is ever used as a missile */ + int deathstate; /* What state begins the death sequence */ + int xdeathstate; /* What state begins the horrible death sequence + like when a rocket takes out a trooper */ + int deathsound; /* The death sound. See also A_Scream() in + p_enemy.c for some tweaking that goes on + for certain monsters */ + int speed; /* How fast it moves. Too fast and it can miss + collision logic. */ + int radius; /* An often incorrect radius */ + int height; /* An often incorrect height, used only to see + if a monster can enter a sector */ + int mass; /* How much an impact will move it. Cacodemons + seem to retreat when shot because they have + very little mass and are moved by impact */ + int damage; /* If this is a missile, how much does it hurt? */ + int activesound; /* What sound it makes wandering around, once + in a while. Chance is 3/256 it will. */ + uint_64_t flags; /* Bit masks for lots of things. See p_mobj.h */ + int raisestate; /* The first state for an Archvile or respawn + resurrection. Zero means it won't come + back to life. */ +} mobjinfo_t; + +/* See p_mobj_h for addition more technical info */ +extern mobjinfo_t mobjinfo[NUMMOBJTYPES]; + +#endif diff --git a/apps/plugins/doom/m_argv.c b/apps/plugins/doom/m_argv.c new file mode 100644 index 0000000000..253fb01aba --- /dev/null +++ b/apps/plugins/doom/m_argv.c @@ -0,0 +1,53 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Some argument handling. + * + *-----------------------------------------------------------------------------*/ + +#include "rockmacros.h" +#include "m_argv.h" + +int myargc; +char** myargv; + +// +// M_CheckParm +// Checks for the given parameter +// in the program's command line arguments. +// Returns the argument number (1 to argc-1) +// or 0 if not present +// + +int M_CheckParm(const char *check) +{ + signed int i = myargc; + while (--i>0) + if (!strcasecmp(check, myargv[i])) + return i; + return 0; +} diff --git a/apps/plugins/doom/m_argv.h b/apps/plugins/doom/m_argv.h new file mode 100644 index 0000000000..61e7a27069 --- /dev/null +++ b/apps/plugins/doom/m_argv.h @@ -0,0 +1,45 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Argument handling. + * + *-----------------------------------------------------------------------------*/ + + +#ifndef __M_ARGV__ +#define __M_ARGV__ + +// +// MISC +// +extern int myargc; +extern char** myargv; + +/* Returns the position of the given parameter in the arg list (0 if not found). */ +int M_CheckParm(const char *check); + +#endif diff --git a/apps/plugins/doom/m_bbox.c b/apps/plugins/doom/m_bbox.c new file mode 100644 index 0000000000..916ed7a401 --- /dev/null +++ b/apps/plugins/doom/m_bbox.c @@ -0,0 +1,58 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Main loop menu stuff. + * Random number LUT. + * Default Config File. + * PCX Screenshots. + * + *-----------------------------------------------------------------------------*/ + +#ifdef __GNUG__ +#pragma implementation "m_bbox.h" +#endif +#include "m_bbox.h" + +#include "rockmacros.h" + +void M_ClearBox (fixed_t *box) +{ + box[BOXTOP] = box[BOXRIGHT] = MININT; + box[BOXBOTTOM] = box[BOXLEFT] = MAXINT; +} + +void M_AddToBox(fixed_t* box,fixed_t x,fixed_t y) +{ + if (xbox[BOXRIGHT]) + box[BOXRIGHT] = x; + if (ybox[BOXTOP]) + box[BOXTOP] = y; +} diff --git a/apps/plugins/doom/m_bbox.h b/apps/plugins/doom/m_bbox.h new file mode 100644 index 0000000000..32202ec543 --- /dev/null +++ b/apps/plugins/doom/m_bbox.h @@ -0,0 +1,54 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Simple bounding box datatype and functions. + * + *-----------------------------------------------------------------------------*/ + + +#ifndef __M_BBOX__ +#define __M_BBOX__ + +#include +#include "m_fixed.h" + +/* Bounding box coordinate storage. */ +enum +{ + BOXTOP, + BOXBOTTOM, + BOXLEFT, + BOXRIGHT +}; /* bbox coordinates */ + +/* Bounding box functions. */ + +void M_ClearBox(fixed_t* box); + +void M_AddToBox(fixed_t* box,fixed_t x,fixed_t y); + +#endif diff --git a/apps/plugins/doom/m_cheat.c b/apps/plugins/doom/m_cheat.c new file mode 100644 index 0000000000..afd68e960d --- /dev/null +++ b/apps/plugins/doom/m_cheat.c @@ -0,0 +1,104 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// $Id$ +// +// Copyright (C) 1993-1996 by id Software, Inc. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// $Log$ +// Revision 1.1 2006/03/28 15:44:01 dave +// Patch #2969 - Doom! Currently only working on the H300. +// +// +// DESCRIPTION: +// Cheat sequence checking. +// +//----------------------------------------------------------------------------- + +#include "m_cheat.h" + +// +// CHEAT SEQUENCE PACKAGE +// + +static int firsttime = 1; +static unsigned char cheat_xlate_table[20]; + + +// +// Called in st_stuff module, which handles the input. +// Returns a 1 if the cheat was successful, 0 if failed. +// +int +cht_CheckCheat +( cheatseq_t* cht, + char key ) +{ + int i; + int rc = 0; + + if (firsttime) + { + firsttime = 0; + for (i=0;i<256;i++) + cheat_xlate_table[i] = SCRAMBLE(i); + } + + if (!cht->p) + cht->p = cht->sequence; // initialize if first time + + if (*cht->p == 0) + *(cht->p++) = key; + else if + (cheat_xlate_table[(unsigned char)key] == *cht->p) + cht->p++; + else + cht->p = cht->sequence; + + if (*cht->p == 1) + cht->p++; + else if (*cht->p == 0xff) // end of sequence character + { + cht->p = cht->sequence; + rc = 1; + } + + return rc; +} + +void +cht_GetParam +( cheatseq_t* cht, + char* buffer ) +{ + + unsigned char *p, c; + + p = cht->sequence; + while (*(p++) != 1) + ; + + do + { + c = *p; + *(buffer++) = c; + *(p++) = 0; + } + while (c && *p!=0xff ); + + if (*p==0xff) + *buffer = 0; + +} + + diff --git a/apps/plugins/doom/m_cheat.h b/apps/plugins/doom/m_cheat.h new file mode 100644 index 0000000000..dfa916ffdb --- /dev/null +++ b/apps/plugins/doom/m_cheat.h @@ -0,0 +1,63 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// $Id$ +// +// Copyright (C) 1993-1996 by id Software, Inc. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// Cheat code checking. +// +//----------------------------------------------------------------------------- + + +#ifndef __M_CHEAT__ +#define __M_CHEAT__ + +// +// CHEAT SEQUENCE PACKAGE +// + +#define SCRAMBLE(a) \ +((((a)&1)<<7) + (((a)&2)<<5) + ((a)&4) + (((a)&8)<<1) \ + + (((a)&16)>>1) + ((a)&32) + (((a)&64)>>5) + (((a)&128)>>7)) + +typedef struct +{ + unsigned char* sequence; + unsigned char* p; + +} +cheatseq_t; + +int +cht_CheckCheat +( cheatseq_t* cht, + char key ); + + +void +cht_GetParam +( cheatseq_t* cht, + char* buffer ); + + +#endif +//----------------------------------------------------------------------------- +// +// $Log$ +// Revision 1.1 2006/03/28 15:44:01 dave +// Patch #2969 - Doom! Currently only working on the H300. +// +// +//----------------------------------------------------------------------------- diff --git a/apps/plugins/doom/m_fixed.h b/apps/plugins/doom/m_fixed.h new file mode 100644 index 0000000000..3c922e8f50 --- /dev/null +++ b/apps/plugins/doom/m_fixed.h @@ -0,0 +1,94 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// $Id$ +// +// Copyright (C) 1993-1996 by id Software, Inc. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// Fixed point arithemtics, implementation. +// +//----------------------------------------------------------------------------- + + +#ifndef __M_FIXED__ +#define __M_FIXED__ + + +#ifdef __GNUG__ +#pragma interface +#endif + +#include "doomtype.h" +#include "rockmacros.h" + +// +// Fixed point, 32bit as 16.16. +// +#define FRACBITS 16 +#define FRACUNIT (1<> (8*sizeof _t-1); (_t^_s)-_s;}) + +typedef int fixed_t; + +inline static int FixedMul( int a, int b ) +{ +#if defined(CPU_COLDFIRE) && !defined(SIMULATOR) + // Code contributed by Thom Johansen + register int result; + asm volatile ( + "mac.l %[x],%[y],%%acc0 \n" /* multiply */ + "move.l %[y],%%d2 \n" + "mulu.l %[x],%%d2 \n" /* get lower half, avoid emac stall */ + "movclr.l %%acc0,%[result] \n" /* get higher half */ + "moveq.l #15,%%d1 \n" + "asl.l %%d1,%[result] \n" /* hi <<= 15, plus one free */ + "moveq.l #16,%%d1 \n" + "lsr.l %%d1,%%d2 \n" /* (unsigned)lo >>= 16 */ + "or.l %%d2 ,%[result] \n" /* combine result */ + : /* outputs */ + [result]"=&d"(result) + : /* inputs */ + [x] "d" (a), + [y] "d" (b) + : /* clobbers */ + "d1", "d2" + ); + return result; +#else + return (fixed_t)((long long) a*b >> FRACBITS); +#endif +} + +inline static fixed_t FixedDiv( fixed_t a, fixed_t b ) +{ + return (D_abs(a)>>14) >= D_abs(b) ? ((a^b)>>31) ^ MAXINT : + (fixed_t)(((long long) a << FRACBITS) / b); +} + +/* CPhipps - + * FixedMod - returns a % b, guaranteeing 0<=a + M_DrawEpisode, // drawing routine -> + 48,63, // x,y + ep1 // lastOn + }; + +// +// NEW GAME +// +enum +{ + killthings, + toorough, + hurtme, + violence, + nightmare, + newg_end +} newgame_e; + +menuitem_t NewGameMenu[]= + { + {1,"M_JKILL", M_ChooseSkill, 'i'}, + {1,"M_ROUGH", M_ChooseSkill, 'h'}, + {1,"M_HURT", M_ChooseSkill, 'h'}, + {1,"M_ULTRA", M_ChooseSkill, 'u'}, + {1,"M_NMARE", M_ChooseSkill, 'n'} + }; + +menu_t NewDef = + { + newg_end, // # of menu items + &EpiDef, // previous menu + NewGameMenu, // menuitem_t -> + M_DrawNewGame, // drawing routine -> + 48,63, // x,y + hurtme // lastOn + }; + + + +// +// OPTIONS MENU +// +enum +{ + endgame, + messages, + scrnsize, + option_empty1, + gamasens, + option_empty2, + soundvol, + opt_end +} options_e; + +menuitem_t OptionsMenu[]= + { + {1,"M_ENDGAM", M_EndGame,'e'}, + {1,"M_MESSG", M_ChangeMessages,'m'}, + {2,"M_SCRNSZ", M_SizeDisplay,'s'}, + {-1,"",0,0}, + {2,"M_MSENS", M_ChangeSensitivity,'m'}, + {-1,"",0,0}, + {1,"M_SVOL", M_Sound,'s'} + }; + +menu_t OptionsDef = + { + opt_end, + &MainDef, + OptionsMenu, + M_DrawOptions, + 60,37, + 0 + }; + +// +// Read This! MENU 1 & 2 +// +enum +{ + rdthsempty1, + read1_end +} read_e; + +menuitem_t ReadMenu1[] = + { + {1,"",M_ReadThis2,0} + }; + +menu_t ReadDef1 = + { + read1_end, + &MainDef, + ReadMenu1, + M_DrawReadThis1, + 280,185, + 0 + }; + +enum +{ + rdthsempty2, + read2_end +} read_e2; + +menuitem_t ReadMenu2[]= + { + {1,"",M_FinishReadThis,0} + }; + +menu_t ReadDef2 = + { + read2_end, + &ReadDef1, + ReadMenu2, + M_DrawReadThis2, + 330,175, + 0 + }; + +// +// SOUND VOLUME MENU +// +enum +{ + sfx_vol, + sfx_empty1, + music_vol, + sfx_empty2, + system_vol, + sfx_empty3, + sound_end +} sound_e; + +menuitem_t SoundMenu[]= + { + {2,"M_SFXVOL",M_SfxVol,'s'}, + {-1,"",0,0}, //ROCKBOX + {2,"M_MUSVOL",M_MusicVol,'m'}, + {-1,"",0,0}, //ROCKBOX + {2,"M_MUSVOL",M_SystemVol,'z'}, + {-1,"",0,0} //ROCKBOX + }; + +menu_t SoundDef = + { + sound_end, + &OptionsDef, + SoundMenu, + M_DrawSound, + 80,64, + 0 + }; + +// +// LOAD GAME MENU +// +enum +{ + load1, + load2, + load3, + load4, + load5, + load6, + load_end +} load_e; + +menuitem_t LoadMenu[]= + { + {1,"", M_LoadSelect,'1'}, + {1,"", M_LoadSelect,'2'}, + {1,"", M_LoadSelect,'3'}, + {1,"", M_LoadSelect,'4'}, + {1,"", M_LoadSelect,'5'}, + {1,"", M_LoadSelect,'6'} + }; + +menu_t LoadDef = + { + load_end, + &MainDef, + LoadMenu, + M_DrawLoad, + 80,54, + 0 + }; + +// +// SAVE GAME MENU +// +menuitem_t SaveMenu[]= + { + {1,"", M_SaveSelect,'1'}, + {1,"", M_SaveSelect,'2'}, + {1,"", M_SaveSelect,'3'}, + {1,"", M_SaveSelect,'4'}, + {1,"", M_SaveSelect,'5'}, + {1,"", M_SaveSelect,'6'} + }; + +menu_t SaveDef = + { + load_end, + &MainDef, + SaveMenu, + M_DrawSave, + 80,54, + 0 + }; + + +// +// M_ReadSaveStrings +// read the strings from the savegame files +// +void M_ReadSaveStrings(void) +{ + int handle; + int count; + int i; + char name[256]; + + for (i = 0;i < load_end;i++) + { + if (M_CheckParm("-cdrom")) + snprintf(name,sizeof(name),"c:\\doomdata\\"SAVEGAMENAME"%d.dsg",i); + else + snprintf(name,sizeof(name),SAVEGAMENAME"%d.dsg",i); + + handle = open (name, O_RDONLY | 0); + if (handle == -1) + { + strcpy(&savegamestrings[i][0],EMPTYSTRING); + LoadMenu[i].status = 0; + continue; + } + count = read (handle, &savegamestrings[i], SAVESTRINGSIZE); + close (handle); + LoadMenu[i].status = 1; + } +} + +#define LOADGRAPHIC_Y 8 +// +// M_LoadGame & Cie. +// +void M_DrawLoad(void) +{ + int i; + + V_DrawNamePatch(72 ,LOADGRAPHIC_Y, 0, "M_LOADG", CR_DEFAULT, VPT_STRETCH); + for (i = 0;i < load_end; i++) + { + M_DrawSaveLoadBorder(LoadDef.x,LoadDef.y+LINEHEIGHT*i); + M_WriteText(LoadDef.x,LoadDef.y+LINEHEIGHT*i,savegamestrings[i]); + } +} + + + +// +// Draw border for the savegame description +// +void M_DrawSaveLoadBorder(int x,int y) +{ + int i; + + V_DrawNamePatch(x-8, y+7, 0, "M_LSLEFT", CR_DEFAULT, VPT_STRETCH); + for (i = 0;i < 24;i++) + { + V_DrawNamePatch(x, y+7, 0, "M_LSCNTR", CR_DEFAULT, VPT_STRETCH); + x += 8; + } + V_DrawNamePatch(x, y+7, 0, "M_LSRGHT", CR_DEFAULT, VPT_STRETCH); +} + + + +// +// User wants to load this game +// +void M_LoadSelect(int choice) +{ + char name[256]; + + if (M_CheckParm("-cdrom")) + snprintf(name,sizeof(name),"c:\\doomdata\\"SAVEGAMENAME"%d.dsg",choice); + else + snprintf(name,sizeof(name),SAVEGAMENAME"%d.dsg",choice); + G_LoadGame (choice, false); + M_ClearMenus (); +} + +// +// Selected from DOOM menu +// +void M_LoadGame (int choice) +{ + (void)choice; + if (netgame) + { + M_StartMessage(LOADNET,NULL,false); + return; + } + + M_SetupNextMenu(&LoadDef); + M_ReadSaveStrings(); +} + + +// +// M_SaveGame & Cie. +// +void M_DrawSave(void) +{ + int i; + + V_DrawNamePatch(72, LOADGRAPHIC_Y, 0, "M_SAVEG", CR_DEFAULT, VPT_STRETCH); + for (i = 0;i < load_end; i++) + { + M_DrawSaveLoadBorder(LoadDef.x,LoadDef.y+LINEHEIGHT*i); + M_WriteText(LoadDef.x,LoadDef.y+LINEHEIGHT*i,savegamestrings[i]); + } + + if (saveStringEnter) + { + i = M_StringWidth(savegamestrings[saveSlot]); + M_WriteText(LoadDef.x + i,LoadDef.y+LINEHEIGHT*saveSlot,"_"); + } +} + +// +// M_Responder calls this when user is finished +// +void M_DoSave(int slot) +{ + G_SaveGame (slot,savegamestrings[slot]); + M_ClearMenus (); + + // PICK QUICKSAVE SLOT YET? + if (quickSaveSlot == -2) + quickSaveSlot = slot; +} + +// +// User wants to save. Start string input for M_Responder +// +void M_SaveSelect(int choice) +{ + // we are going to be intercepting all chars + saveStringEnter = 1; + + saveSlot = choice; + snprintf(savegamestrings[choice], sizeof(savegamestrings[choice]), "Mysave%d", choice); +// strcpy(saveOldString,savegamestrings[choice]); + if (!strcmp(savegamestrings[choice],EMPTYSTRING)) + savegamestrings[choice][0] = 0; + saveCharIndex = strlen(savegamestrings[choice]); +} + +// +// Selected from DOOM menu +// +void M_SaveGame (int choice) +{ + (void)choice; + if (!usergame) + { + M_StartMessage(SAVEDEAD,NULL,false); + return; + } + + if (gamestate != GS_LEVEL) + return; + + M_SetupNextMenu(&SaveDef); + M_ReadSaveStrings(); +} + + + +// +// M_QuickSave +// +char tempstring[80]; + +void M_QuickSaveResponse(int ch) +{ + if (ch == 'y') + { + M_DoSave(quickSaveSlot); + + S_StartSound(NULL,sfx_swtchx); + + } +} + +void M_QuickSave(void) +{ + if (!usergame) + { + S_StartSound(NULL,sfx_oof); + return; + } + + if (gamestate != GS_LEVEL) + return; + + if (quickSaveSlot < 0) + { + M_StartControlPanel(); + M_ReadSaveStrings(); + M_SetupNextMenu(&SaveDef); + quickSaveSlot = -2; // means to pick a slot now + return; + } + snprintf(tempstring,sizeof(tempstring),QSPROMPT,savegamestrings[quickSaveSlot]); + M_StartMessage(tempstring,M_QuickSaveResponse,true); +} + + + +// +// M_QuickLoad +// +void M_QuickLoadResponse(int ch) +{ + if (ch == 'y') + { + M_LoadSelect(quickSaveSlot); + S_StartSound(NULL,sfx_swtchx); + } +} + + +void M_QuickLoad(void) +{ + if (netgame) + { + M_StartMessage(QLOADNET,NULL,false); + return; + } + + if (quickSaveSlot < 0) + { + M_StartMessage(QSAVESPOT,NULL,false); + return; + } + snprintf(tempstring, sizeof(tempstring), QLPROMPT,savegamestrings[quickSaveSlot]); + M_StartMessage(tempstring,M_QuickLoadResponse,true); +} + + + + +// +// Read This Menus +// Had a "quick hack to fix romero bug" +// +void M_DrawReadThis1(void) +{ + inhelpscreens = true; + switch ( gamemode ) + { + case commercial: + V_DrawNamePatch(0, 0, 0, "HELP", CR_DEFAULT, VPT_STRETCH); + break; + case shareware: + case registered: + case retail: + V_DrawNamePatch(0, 0, 0, "HELP1", CR_DEFAULT, VPT_STRETCH); + break; + default: + break; + } + return; +} + + + +// +// Read This Menus - optional second page. +// +void M_DrawReadThis2(void) +{ + inhelpscreens = true; + switch ( gamemode ) + { + case retail: + case commercial: + // This hack keeps us from having to change menus. + V_DrawNamePatch(0, 0, 0, "CREDIT", CR_DEFAULT, VPT_STRETCH); + break; + case shareware: + case registered: + V_DrawNamePatch(0, 0, 0, "HELP2", CR_DEFAULT, VPT_STRETCH); + break; + default: + break; + } + return; +} + + +// +// Change Sfx & Music volumes +// +void M_DrawSound(void) +{ + int sysmax=(rb->sound_max(SOUND_VOLUME)-rb->sound_min(SOUND_VOLUME)); + V_DrawNamePatch(60, 38, 0, "M_SVOL", CR_DEFAULT, VPT_STRETCH); + + M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(sfx_vol+1), + 16,snd_SfxVolume); + + M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(music_vol+1), + 16,snd_MusicVolume); + + M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(system_vol+1), + 16,(sysmax+systemvol)/5); +} + +void M_Sound(int choice) +{ + (void) choice; + M_SetupNextMenu(&SoundDef); +} + +void M_SfxVol(int choice) +{ + switch(choice) + { + case 0: + if (snd_SfxVolume) + snd_SfxVolume--; + break; + case 1: + if (snd_SfxVolume < 15) + snd_SfxVolume++; + break; + } + + S_SetSfxVolume(snd_SfxVolume /* *8 */); +} + +void M_MusicVol(int choice) +{ + switch(choice) + { + case 0: + if (snd_MusicVolume) + snd_MusicVolume--; + break; + case 1: + if (snd_MusicVolume < 15) + snd_MusicVolume++; + break; + } + + S_SetMusicVolume(snd_MusicVolume /* *8 */); +} + +void M_SystemVol(int choice) +{ + switch(choice) + { + case 0: + if (systemvol-5>rb->sound_min(SOUND_VOLUME)) + { + systemvol-=5; + rb->sound_set(SOUND_VOLUME, systemvol); + rb->global_settings->volume = systemvol; + } + break; + case 1: + if (systemvol+5sound_max(SOUND_VOLUME)) + { + systemvol+=5; + rb->sound_set(SOUND_VOLUME, systemvol); + rb->global_settings->volume = systemvol; + } + break; + } +} + +// +// M_DrawMainMenu +// +void M_DrawMainMenu(void) +{ + V_DrawNamePatch(94, 2, 0, "M_DOOM", CR_DEFAULT, VPT_STRETCH); +} + + + + +// +// M_NewGame +// +void M_DrawNewGame(void) +{ + // CPhipps - patch drawing updated + V_DrawNamePatch(96, 14, 0, "M_NEWG", CR_DEFAULT, VPT_STRETCH); + V_DrawNamePatch(54, 38, 0, "M_SKILL",CR_DEFAULT, VPT_STRETCH); +} + +void M_NewGame(int choice) +{ + (void) choice; + if (netgame && !demoplayback) + { + M_StartMessage(NEWGAME,NULL,false); + return; + } + + if ( gamemode == commercial ) + M_SetupNextMenu(&NewDef); + else + M_SetupNextMenu(&EpiDef); +} + + +// +// M_Episode +// +int epi; + +void M_DrawEpisode(void) +{ + // CPhipps - patch drawing updated + V_DrawNamePatch(54, 38, 0, "M_EPISOD", CR_DEFAULT, VPT_STRETCH); +} + +void M_VerifyNightmare(int ch) +{ + if (ch != KEY_ENTER) + return; + + G_DeferedInitNew(nightmare,epi+1,1); + M_ClearMenus (); +} + +void M_ChooseSkill(int choice) +{ + if (choice == nightmare) + { + M_StartMessage(NIGHTMARE,M_VerifyNightmare,true); + return; + } + + //jff 3/24/98 remember last skill selected + // killough 10/98 moved to here + defaultskill = choice+1; + + G_DeferedInitNew(choice,epi+1,1); + M_ClearMenus (); +} + +void M_Episode(int choice) +{ + if ( (gamemode == shareware) + && choice) + { + M_StartMessage(SWSTRING,NULL,false); + M_SetupNextMenu(&ReadDef1); + return; + } + + // Yet another hack... + if ( (gamemode == registered) + && (choice > 2)) + { + /* Digita */ + // fprintf( stderr, + // "M_Episode: 4th episode requires UltimateDOOM\n"); + choice = 0; + } + + epi = choice; + M_SetupNextMenu(&NewDef); +} + + + +// +// M_Options +// +char detailNames[2][9] = {"M_GDHIGH","M_GDLOW"}; +char msgNames[2][9] = {"M_MSGOFF","M_MSGON"}; + + +void M_DrawOptions(void) +{ + // CPhipps - patch drawing updated + V_DrawNamePatch(108, 15, 0, "M_OPTTTL", CR_DEFAULT, VPT_STRETCH); + + V_DrawNamePatch(OptionsDef.x + 120, OptionsDef.y+LINEHEIGHT*messages, 0, + msgNames[showMessages], CR_DEFAULT, VPT_STRETCH); + + M_DrawThermo(OptionsDef.x,OptionsDef.y+LINEHEIGHT*(gamasens+1), + 4,usegamma); + + M_DrawThermo(OptionsDef.x,OptionsDef.y+LINEHEIGHT*(scrnsize+1), + 9,screenSize); +} + +void M_Options(int choice) +{ + (void)choice; + M_SetupNextMenu(&OptionsDef); +} + + + +// +// Toggle messages on/off +// +void M_ChangeMessages(int choice) +{ + // warning: unused parameter `int choice' + choice = 0; + showMessages = 1 - showMessages; + + if (!showMessages) + players[consoleplayer].message = MSGOFF; + else + players[consoleplayer].message = MSGON ; + + message_dontfuckwithme = true; +} + + +// +// M_EndGame +// +void M_EndGameResponse(int ch) +{ + if (ch != KEY_ENTER) + return; + + // killough 5/26/98: make endgame quit if recording or playing back demo + if (demorecording || singledemo) + G_CheckDemoStatus(); + + currentMenu->lastOn = itemOn; + M_ClearMenus (); + D_StartTitle (); +} + +void M_EndGame(int choice) +{ + choice = 0; + if (!usergame) + { + S_StartSound(NULL,sfx_oof); + return; + } + + if (netgame) + { + M_StartMessage(NETEND,NULL,false); + return; + } + + M_StartMessage(ENDGAME,M_EndGameResponse,true); +} + + + + +// +// M_ReadThis +// +void M_ReadThis(int choice) +{ + choice = 0; + M_SetupNextMenu(&ReadDef1); +} + +void M_ReadThis2(int choice) +{ + choice = 0; + M_SetupNextMenu(&ReadDef2); +} + +void M_FinishReadThis(int choice) +{ + choice = 0; + M_SetupNextMenu(&MainDef); +} + + + + +// +// M_QuitDOOM +// +int quitsounds[8] = + { + sfx_pldeth, + sfx_dmpain, + sfx_popain, + sfx_slop, + sfx_telept, + sfx_posit1, + sfx_posit3, + sfx_sgtatk + }; + +int quitsounds2[8] = + { + sfx_vilact, + sfx_getpow, + sfx_boscub, + sfx_slop, + sfx_skeswg, + sfx_kntdth, + sfx_bspact, + sfx_sgtatk + }; + + + +void M_QuitResponse(int ch) +{ + if (ch != KEY_ENTER) + return; + if (!netgame) + { + if (gamemode == commercial) + S_StartSound(NULL,quitsounds2[(gametic>>2)&7]); + else + S_StartSound(NULL,quitsounds[(gametic>>2)&7]); + I_WaitVBL(105); + } + I_Quit (); +} + + + + +void M_QuitDOOM(int choice) +{ + (void)choice; + // We pick index 0 which is language sensitive, + // or one at random, between 1 and maximum number. + if (language != english ) + snprintf(endstring,sizeof(endstring),"%s\n\n"DOSY, endmsg[0] ); + else + snprintf(endstring,sizeof(endstring),"%s\n\n%s", endmsg[gametic%(NUM_QUITMESSAGES-1)+1], DOSY); + + M_StartMessage(endstring,M_QuitResponse,true); +} + + + + +void M_ChangeSensitivity(int choice) +{ + switch(choice) + { + case 0: + if (usegamma) + usegamma--; + break; + case 1: + if (usegamma < 4) + usegamma++; + break; + } + V_SetPalette (0); +} + +void M_SizeDisplay(int choice) +{ + switch(choice) + { + case 0: + if (screenSize > 0) + { + screenblocks--; + screenSize--; + } + break; + case 1: + if (screenSize < 8) + { + screenblocks++; + screenSize++; + } + break; + } + + + R_SetViewSize (screenblocks); +} + + + + +// +// Menu Functions +// +void +M_DrawThermo +( int x, + int y, + int thermWidth, + int thermDot ) +{ + int xx; + int i; + + xx = x; + V_DrawNamePatch(xx, y, 0, "M_THERML", CR_DEFAULT, VPT_STRETCH); + xx += 8; + for (i=0;ix - 10, menu->y+item*LINEHEIGHT - 1, 0, + "M_CELL1", CR_DEFAULT, VPT_STRETCH); +} + +void +M_DrawSelCell +( menu_t* menu, + int item ) +{ + // CPhipps - patch drawing updated + V_DrawNamePatch(menu->x - 10, menu->y+item*LINEHEIGHT - 1, 0, + "M_CELL2", CR_DEFAULT, VPT_STRETCH); +} + + +void +M_StartMessage +( char* string, + void* routine, + boolean input ) +{ + messageLastMenuActive = menuactive; + messageToPrint = 1; + messageString = string; + messageRoutine = routine; + messageNeedsInput = input; + menuactive = true; + return; +} + + + +void M_StopMessage(void) +{ + menuactive = messageLastMenuActive; + messageToPrint = 0; +} + + + +// +// Find string width from hu_font chars +// +int M_StringWidth(const char* string) +{ + int i, c, w = 0; + for (i = 0;(size_t)i < strlen(string);i++) + w += (c = toupper(string[i]) - HU_FONTSTART) < 0 || c >= HU_FONTSIZE ? + 4 : SHORT(hu_font[c].width); + return w; +} + +// +// Find string height from hu_font chars +// + +int M_StringHeight(const char* string) +{ + int i, h, height = h = SHORT(hu_font[0].height); + for (i = 0;string[i];i++) // killough 1/31/98 + if (string[i] == '\n') + h += height; + return h; +} + + +// +// Write a string using the hu_font +// +void +M_WriteText +( int x, + int y, + char* string) +{ + int w; + char* ch; + int c; + int cx; + int cy; + + + ch = string; + cx = x; + cy = y; + + while(1) + { + c = *ch++; + if (!c) + break; + if (c == '\n') + { + cx = x; + cy += 12; + continue; + } + + c = toupper(c) - HU_FONTSTART; + if (c < 0 || c>= HU_FONTSIZE) + { + cx += 4; + continue; + } + + w = SHORT (hu_font[c].width); + if (cx+w > SCREENWIDTH) + break; + // proff/nicolas 09/20/98 -- changed for hi-res + // CPhipps - patch drawing updated + V_DrawNumPatch(cx, cy, 0, hu_font[c].lumpnum, CR_DEFAULT, VPT_STRETCH); + cx+=w; + } +} + + + +// +// CONTROL PANEL +// + +// +// M_Responder +// +boolean M_Responder (event_t* ev) +{ + int ch; + int i; +// static int joywait = 0; +// static int mousewait = 0; +// static int mousey = 0; +// static int lasty = 0; +// static int mousex = 0; +// static int lastx = 0; + + ch = -1; + + // Process joystick input + +/* if (ev->type == ev_joystick && joywait < I_GetTime()) + { + if (ev->data3 == -1) + { + ch = KEY_UPARROW; + joywait = I_GetTime() + 5; + } + else if (ev->data3 == 1) + { + ch = KEY_DOWNARROW; + joywait = I_GetTime() + 5; + } + + if (ev->data2 == -1) + { + ch = KEY_LEFTARROW; + joywait = I_GetTime() + 2; + } + else if (ev->data2 == 1) + { + ch = KEY_RIGHTARROW; + joywait = I_GetTime() + 2; + } + + if (ev->data1&1) + { + ch = KEY_ENTER; + joywait = I_GetTime() + 5; + } + if (ev->data1&2) + { + ch = KEY_BACKSPACE; + joywait = I_GetTime() + 5; + } + } + else + { + // Process mouse input + if (ev->type == ev_mouse && mousewait < I_GetTime()) + { + mousey += ev->data3; + if (mousey < lasty-30) + { + ch = KEY_DOWNARROW; + mousewait = I_GetTime() + 5; + mousey = lasty -= 30; + } + else if (mousey > lasty+30) + { + ch = KEY_UPARROW; + mousewait = I_GetTime() + 5; + mousey = lasty += 30; + } + + mousex += ev->data2; + if (mousex < lastx-30) + { + ch = KEY_LEFTARROW; + mousewait = I_GetTime() + 5; + mousex = lastx -= 30; + } + else if (mousex > lastx+30) + { + ch = KEY_RIGHTARROW; + mousewait = I_GetTime() + 5; + mousex = lastx += 30; + } + + if (ev->data1&1) + { + ch = KEY_ENTER; + mousewait = I_GetTime() + 15; + } + + if (ev->data1&2) + { + ch = KEY_BACKSPACE; + mousewait = I_GetTime() + 15; + } + } + else */if (ev->type == ev_keydown) + { + ch = ev->data1; + } +// } + + if (ch == -1) + return false; + + + // Save Game string input + if (saveStringEnter) + { + switch(ch) + { + case KEY_BACKSPACE: + if (saveCharIndex > 0) + { + saveCharIndex--; + savegamestrings[saveSlot][saveCharIndex] = 0; + } + break; + + case KEY_ESCAPE: + saveStringEnter = 0; + strcpy(&savegamestrings[saveSlot][0],saveOldString); + break; + + case KEY_ENTER: + saveStringEnter = 0; + if (savegamestrings[saveSlot][0]) + M_DoSave(saveSlot); + break; + + default: + ch = toupper(ch); + if (ch != 32) + if (ch-HU_FONTSTART < 0 || ch-HU_FONTSTART >= HU_FONTSIZE) + break; + if (ch >= 32 && ch <= 127 && + saveCharIndex < SAVESTRINGSIZE-1 && + M_StringWidth(savegamestrings[saveSlot]) < + (SAVESTRINGSIZE-2)*8) + { + savegamestrings[saveSlot][saveCharIndex++] = ch; + savegamestrings[saveSlot][saveCharIndex] = 0; + } + break; + } + return true; + } + + // Take care of any messages that need input + if (messageToPrint) + { + if (messageNeedsInput == true && + !(ch == ' ' || ch == 'n' || ch == KEY_ENTER || ch == KEY_ESCAPE)) + return false; + + menuactive = messageLastMenuActive; + messageToPrint = 0; + if (messageRoutine) + messageRoutine(ch); + + menuactive = false; + S_StartSound(NULL,sfx_swtchx); + return true; + } +/* + if (ch == KEY_F1) // devparm && + { + G_ScreenShot (); + return true; + } +*/ + // F-Keys + if (!menuactive) + switch(ch) + { + case KEY_MINUS: // Screen size down + if ((automapmode & am_active) || chat_on) + return false; + M_SizeDisplay(0); + S_StartSound(NULL,sfx_stnmov); + return true; + + case KEY_EQUALS: // Screen size up + if ((automapmode & am_active) || chat_on) + return false; + M_SizeDisplay(1); + S_StartSound(NULL,sfx_stnmov); + return true; +/* + case KEY_F1: // Help key + M_StartControlPanel (); + + if ( gamemode == retail ) + currentMenu = &ReadDef2; + else + currentMenu = &ReadDef1; + + itemOn = 0; + S_StartSound(NULL,sfx_swtchn); + return true; + + case KEY_F6: // Quicksave + S_StartSound(NULL,sfx_swtchn); + M_QuickSave(); + return true; + + case KEY_F9: // Quickload + S_StartSound(NULL,sfx_swtchn); + M_QuickLoad(); + return true; +*/ + } + + + // Pop-up menu? + if (!menuactive) + { + if (ch == KEY_ESCAPE) + { + M_StartControlPanel (); + S_StartSound(NULL,sfx_swtchn); + return true; + } + return false; + } + + + // Keys usable within menu + switch (ch) + { + case KEY_DOWNARROW: + do + { + if (itemOn+1 > currentMenu->numitems-1) + itemOn = 0; + else + itemOn++; + S_StartSound(NULL,sfx_pstop); + } + while(currentMenu->menuitems[itemOn].status==-1); + return true; + + case KEY_UPARROW: + do + { + if (!itemOn) + itemOn = currentMenu->numitems-1; + else + itemOn--; + S_StartSound(NULL,sfx_pstop); + } + while(currentMenu->menuitems[itemOn].status==-1); + return true; + + case KEY_LEFTARROW: + if (currentMenu->menuitems[itemOn].routine && + currentMenu->menuitems[itemOn].status == 2) + { + S_StartSound(NULL,sfx_stnmov); + currentMenu->menuitems[itemOn].routine(0); + } + return true; + + case KEY_RIGHTARROW: + if (currentMenu->menuitems[itemOn].routine && + currentMenu->menuitems[itemOn].status == 2) + { + S_StartSound(NULL,sfx_stnmov); + currentMenu->menuitems[itemOn].routine(1); + } + return true; + + case KEY_ENTER: + if (currentMenu->menuitems[itemOn].routine && + currentMenu->menuitems[itemOn].status) + { + currentMenu->lastOn = itemOn; + if (currentMenu->menuitems[itemOn].status == 2) + { + currentMenu->menuitems[itemOn].routine(1); // right arrow + S_StartSound(NULL,sfx_stnmov); + } + else + { + currentMenu->menuitems[itemOn].routine(itemOn); + S_StartSound(NULL,sfx_pistol); + } + } + return true; + + case KEY_ESCAPE: + currentMenu->lastOn = itemOn; + M_ClearMenus (); + S_StartSound(NULL,sfx_swtchx); + return true; + + case KEY_BACKSPACE: + currentMenu->lastOn = itemOn; + if (currentMenu->prevMenu) + { + currentMenu = currentMenu->prevMenu; + itemOn = currentMenu->lastOn; + S_StartSound(NULL,sfx_swtchn); + } + return true; + + default: + for (i = itemOn+1;i < currentMenu->numitems;i++) + if (currentMenu->menuitems[i].alphaKey == ch) + { + itemOn = i; + S_StartSound(NULL,sfx_pstop); + return true; + } + for (i = 0;i <= itemOn;i++) + if (currentMenu->menuitems[i].alphaKey == ch) + { + itemOn = i; + S_StartSound(NULL,sfx_pstop); + return true; + } + break; + + } + + return false; +} + + + +// +// M_StartControlPanel +// +void M_StartControlPanel (void) +{ + // intro might call this repeatedly + if (menuactive) + return; + + menuactive = 1; + currentMenu = &MainDef; // JDC + itemOn = currentMenu->lastOn; // JDC +} + + +// +// M_Drawer +// Called after the view has been rendered, +// but before it has been blitted. +// +void M_Drawer (void) +{ + static short x; + static short y; + unsigned short i; + short max; + char string[40]; + int start; + + inhelpscreens = false; + + + // Horiz. & Vertically center string and print it. + if (messageToPrint) + { + start = 0; + y = 100 - M_StringHeight(messageString)/2; + while(*(messageString+start)) + { + for (i = 0;i < strlen(messageString+start);i++) + if (*(messageString+start+i) == '\n') + { + memset(string,0,40); + strncpy(string,messageString+start,i); + start += i+1; + break; + } + if (i == strlen(messageString+start)) + { + strcpy(string,messageString+start); + start += i; + } + + x = 160 - M_StringWidth(string)/2; + M_WriteText(x,y,string); + y += SHORT(hu_font[0].height); + } + return; + } + + if (!menuactive) + return; + + if (currentMenu->routine) + currentMenu->routine(); // call Draw routine + + // DRAW MENU + x = currentMenu->x; + y = currentMenu->y; + max = currentMenu->numitems; + + for (i=0;imenuitems[i].name[0]) + V_DrawNamePatch(x,y,0,currentMenu->menuitems[i].name, + CR_DEFAULT, VPT_STRETCH); + y += LINEHEIGHT; + } + + // DRAW SKULL + // CPhipps - patch drawing updated + V_DrawNamePatch(x + SKULLXOFF, currentMenu->y - 5 + itemOn*LINEHEIGHT,0, + skullName[whichSkull], CR_DEFAULT, VPT_STRETCH); + +} + + +// +// M_ClearMenus +// +void M_ClearMenus (void) +{ + menuactive = 0; + // if (!netgame && usergame && paused) + // sendpause = true; +} + + + + +// +// M_SetupNextMenu +// +void M_SetupNextMenu(menu_t *menudef) +{ + currentMenu = menudef; + itemOn = currentMenu->lastOn; +} + + +// +// M_Ticker +// +void M_Ticker (void) +{ + if (--skullAnimCounter <= 0) + { + whichSkull ^= 1; + skullAnimCounter = 8; + } +} + + +// +// M_Init +// +void M_Init (void) +{ + currentMenu = &MainDef; + menuactive = 0; + itemOn = currentMenu->lastOn; + whichSkull = 0; + skullAnimCounter = 10; + screenSize = screenblocks - 3; + messageToPrint = 0; + messageString = NULL; + messageLastMenuActive = menuactive; + quickSaveSlot = -1; + + // Here we could catch other version dependencies, + // like HELP1/2, and four episodes. + + + switch ( gamemode ) + { + case commercial: + // This is used because DOOM 2 had only one HELP + // page. I use CREDIT as second page now, but + // kept this hack for educational purposes. + MainMenu[readthis] = MainMenu[quitdoom]; + MainDef.numitems--; + MainDef.y += 8; + NewDef.prevMenu = &MainDef; + ReadDef1.routine = M_DrawReadThis1; + ReadDef1.x = 330; + ReadDef1.y = 165; + ReadMenu1[0].routine = M_FinishReadThis; + break; + case shareware: + // Episode 2 and 3 are handled, + // branching to an ad screen. + case registered: + // We need to remove the fourth episode. + EpiDef.numitems--; + break; + case retail: + // We are fine. + default: + break; + } + +} + diff --git a/apps/plugins/doom/m_menu.h b/apps/plugins/doom/m_menu.h new file mode 100644 index 0000000000..8444b72a5f --- /dev/null +++ b/apps/plugins/doom/m_menu.h @@ -0,0 +1,121 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// $Id$ +// +// Copyright (C) 1993-1996 by id Software, Inc. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// Menu widget stuff, episode selection and such. +// +//----------------------------------------------------------------------------- + + +#ifndef __M_MENU__ +#define __M_MENU__ + + + +#include "d_event.h" + +// +// MENUS +// +// Called by main loop, +// saves config file and calls I_Quit when user exits. +// Even when the menu is not displayed, +// this can resize the view and change game parameters. +// Does all the real work of the menu interaction. +boolean M_Responder (event_t *ev); + + +// Called by main loop, +// only used for menu (skull cursor) animation. +void M_Ticker (void); + +// Called by main loop, +// draws the menus directly into the screen buffer. +void M_Drawer (void); + +// Called by D_DoomMain, +// loads the config file. +void M_Init (void); + +// Called by intro code to force menu up upon a keypress, +// does nothing if menu is already up. +void M_StartControlPanel (void); + +/**************************** + * + * The setup_group enum is used to show which 'groups' keys fall into so + * that you can bind a key differently in each 'group'. + */ + +typedef enum { + m_null, // Has no meaning; not applicable + m_scrn, // A key can not be assigned to more than one action + m_map, // in the same group. A key can be assigned to one + m_menu, // action in one group, and another action in another. +} setup_group; + +/**************************** + * + * phares 4/17/98: + * State definition for each item. + * This is the definition of the structure for each setup item. Not all + * fields are used by all items. + * + * A setup screen is defined by an array of these items specific to + * that screen. + * + * killough 11/98: + * + * Restructured to allow simpler table entries, + * and to Xref with defaults[] array in m_misc.c. + * Moved from m_menu.c to m_menu.h so that m_misc.c can use it. + */ + +typedef struct setup_menu_s +{ + const char *m_text; /* text to display */ + int m_flags; /* phares 4/17/98: flag bits S_* (defined above) */ + setup_group m_group; /* Group */ + short m_x; /* screen x position (left is 0) */ + short m_y; /* screen y position (top is 0) */ + + union /* killough 11/98: The first field is a union of several types */ + { + const void *var; /* generic variable */ + int *m_key; /* key value, or 0 if not shown */ + const char *name; /* name */ + struct default_s *def; /* default[] table entry */ + struct setup_menu_s *menu; /* next or prev menu */ + } var; + + int *m_mouse; /* mouse button value, or 0 if not shown */ + int *m_joy; /* joystick button value, or 0 if not shown */ + void (*action)(void); /* killough 10/98: function to call after changing */ +} setup_menu_t; + + + + +#endif +//----------------------------------------------------------------------------- +// +// $Log$ +// Revision 1.1 2006/03/28 15:44:01 dave +// Patch #2969 - Doom! Currently only working on the H300. +// +// +//----------------------------------------------------------------------------- diff --git a/apps/plugins/doom/m_misc.c b/apps/plugins/doom/m_misc.c new file mode 100644 index 0000000000..2cde2102e6 --- /dev/null +++ b/apps/plugins/doom/m_misc.c @@ -0,0 +1,1077 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Main loop menu stuff. + * Default Config File. + * PCX Screenshots. + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "m_argv.h" +#include "g_game.h" +#include "m_menu.h" +#include "am_map.h" +#include "w_wad.h" +#include "i_sound.h" +#include "i_video.h" +#include "v_video.h" +#include "hu_stuff.h" +#include "st_stuff.h" +#include "dstrings.h" +#include "m_misc.h" +#include "s_sound.h" +#include "sounds.h" +#include "i_system.h" +#include "d_main.h" +#include "m_swap.h" +#include "p_pspr.h" + +#include "rockmacros.h" + +// +// M_DrawText +// Returns the final X coordinate +// HU_Init must have been called to init the font +// +extern patchnum_t hu_font[HU_FONTSIZE]; + +int M_DrawText(int x,int y,boolean direct,char* string) +{ + (void)direct; + int c; + int w; + + while (*string) { + c = toupper(*string) - HU_FONTSTART; + string++; + if (c < 0 || c> HU_FONTSIZE) { + x += 4; + continue; + } + + w = SHORT (hu_font[c].width); + if (x+w > SCREENWIDTH) + break; + + // proff/nicolas 09/20/98 -- changed for hi-res + // CPhipps - patch drawing updated, reformatted + V_DrawNumPatch(x, y, 0, hu_font[c].lumpnum, CR_DEFAULT, VPT_STRETCH); + x+=w; + } + + return x; +} + +// +// M_WriteFile +// + +boolean M_WriteFile(char const* name,void* source,int length) +{ + int handle; + int count; + + handle = open ( name, O_WRONLY | O_CREAT | O_TRUNC); + + if (handle == -1) + return false; + + count = write (handle, source, length); + close (handle); + + if (count < length) { +// unlink(name); // CPhipps - no corrupt data files around, they only confuse people. + return false; + } + + return true; +} + + +// +// M_ReadFile +// + +int M_ReadFile(char const* name,byte** buffer) +{ + int handle, count, length; + // struct stat fileinfo; + byte *buf; + + handle = open (name, O_RDONLY); + if ((handle < 0)) + I_Error ("M_ReadFile: Couldn't read file %s", name); + + length = filesize(handle); + buf = Z_Malloc (length, PU_STATIC, NULL); + count = read (handle, buf, length); + close (handle); + + if (count < length) + I_Error ("M_ReadFile: Couldn't read file %s", name); + + *buffer = buf; + return length; +} + +// +// DEFAULTS +// + +int usemouse; +boolean precache = true; /* if true, load all graphics at start */ + +extern int mousebfire; +extern int mousebstrafe; +extern int mousebforward; + +extern int viewwidth; +extern int viewheight; +extern int fake_contrast; +extern int mouseSensitivity_horiz,mouseSensitivity_vert; // killough + +extern int realtic_clock_rate; // killough 4/13/98: adjustable timer +extern int tran_filter_pct; // killough 2/21/98 + +extern int screenblocks; +extern int showMessages; + +#ifndef DJGPP +const char* musserver_filename; +const char* sndserver_filename; +const char* snd_device; +int mus_pause_opt; // 0 = kill music, 1 = pause, 2 = continue +#endif + +extern const char* chat_macros[]; + +extern int endoom_mode; +int X_opt; + +extern const char* S_music_files[]; // cournia + +/* cph - Some MBF stuff parked here for now + * killough 10/98 + */ +int map_point_coordinates; + +default_t defaults[] = + { + {"Misc settings",{NULL, NULL},{0, NULL},UL,UL,def_none,ss_none, 0, 0}, + {"default_compatibility_level",{(void *)&default_compatibility_level, NULL}, + {-1, NULL},-1,MAX_COMPATIBILITY_LEVEL-1, + def_int,ss_none, 0, 0}, // compatibility level" - CPhipps +// {"realtic_clock_rate",{&realtic_clock_rate, NULL},{100, NULL},0,UL, +// def_int,ss_none, 0, 0}, // percentage of normal speed (35 fps) realtic clock runs at + {"max_player_corpse", {&bodyquesize, NULL}, {32, NULL},-1,UL, // killough 2/8/98 + def_int,ss_none, 0, 0}, // number of dead bodies in view supported (-1 = no limit) + {"flashing_hom",{&flashing_hom, NULL},{0, NULL},0,1, + def_bool,ss_none, 0, 0}, // killough 10/98 - enable flashing HOM indicator + {"demo_insurance",{&default_demo_insurance, NULL},{2, NULL},0,2, // killough 3/31/98 + def_int,ss_none, 0, 0}, // 1=take special steps ensuring demo sync, 2=only during recordings +// {"endoom_mode", {&endoom_mode, NULL},{5, NULL},0,7, // CPhipps - endoom flags +// def_hex, ss_none, 0, 0}, // 0, +1 for colours, +2 for non-ascii chars, +4 for skip-last-line + {"level_precache",{(void*)&precache, NULL},{1, NULL},0,1, + def_bool,ss_none, 0, 0}, // precache level data? + + {"Files",{NULL, NULL},{0, NULL},UL,UL,def_none,ss_none, 0, 0}, + /* cph - MBF-like wad/deh/bex autoload code + * POSIX targets need to get lumps from prboom.wad */ +// {"wadfile_1",{NULL,&wad_files[0]},{0, +#ifdef ALL_IN_ONE +// "" +#else +// "prboom.wad" +#endif +// },UL,UL,def_str,ss_none, 0, 0}, +// {"wadfile_2",{NULL,&wad_files[1]},{0,""},UL,UL,def_str,ss_none, 0, 0}, +// {"dehfile_1",{NULL,&deh_files[0]},{0,""},UL,UL,def_str,ss_none, 0, 0}, +// {"dehfile_2",{NULL,&deh_files[1]},{0,""},UL,UL,def_str,ss_none, 0, 0}, + + {"Game settings",{NULL, NULL},{0, NULL},UL,UL,def_none,ss_none, 0, 0}, + {"default_skill",{&defaultskill, NULL},{3, NULL},1,5, // jff 3/24/98 allow default skill setting + def_int,ss_none, 0, 0}, // selects default skill 1=TYTD 2=NTR 3=HMP 4=UV 5=NM + {"weapon_recoil",{&default_weapon_recoil, NULL},{0, NULL},0,1, + def_bool,ss_weap, &weapon_recoil, 0}, + /* killough 10/98 - toggle between SG/SSG and Fist/Chainsaw */ + {"doom_weapon_toggles",{&doom_weapon_toggles, NULL}, {1, NULL}, 0, 1, + def_bool, ss_weap , 0, 0}, + {"player_bobbing",{&default_player_bobbing, NULL},{1, NULL},0,1, // phares 2/25/98 + def_bool,ss_weap, &player_bobbing, 0}, + {"monsters_remember",{&default_monsters_remember, NULL},{1, NULL},0,1, // killough 3/1/98 + def_bool,ss_enem, &monsters_remember, 0}, + /* MBF AI enhancement options */ + {"monster_infighting",{&default_monster_infighting, NULL}, {1, NULL}, 0, 1, + def_bool, ss_enem, &monster_infighting, 0}, + {"monster_backing",{&default_monster_backing, NULL}, {0, NULL}, 0, 1, + def_bool, ss_enem, &monster_backing, 0}, + {"monster_avoid_hazards",{&default_monster_avoid_hazards, NULL}, {1, NULL}, 0, 1, + def_bool, ss_enem, &monster_avoid_hazards, 0}, + {"monkeys",{&default_monkeys, NULL}, {0, NULL}, 0, 1, + def_bool, ss_enem, &monkeys, 0}, + {"monster_friction",{&default_monster_friction, NULL}, {1, NULL}, 0, 1, + def_bool, ss_enem, &monster_friction, 0}, + {"help_friends",{&default_help_friends, NULL}, {1, NULL}, 0, 1, + def_bool, ss_enem, &help_friends, 0}, +#ifdef DOGS + {"player_helpers",{&default_dogs, NULL}, {0, NULL}, 0, 3, + def_bool, ss_enem , 0, 0}, + {"friend_distance",{&default_distfriend, NULL}, {128, NULL}, 0, 999, + def_int, ss_enem, &distfriend, 0}, + {"dog_jumping",{&default_dog_jumping, NULL}, {1, NULL}, 0, 1, + def_bool, ss_enem, &dog_jumping, 0}, +#endif + /* End of MBF AI extras */ + {"sts_always_red",{&sts_always_red, NULL},{1, NULL},0,1, // no color changes on status bar + def_bool,ss_stat, 0, 0}, + {"sts_pct_always_gray",{&sts_pct_always_gray, NULL},{0, NULL},0,1, // 2/23/98 chg default + def_bool,ss_stat, 0, 0}, // makes percent signs on status bar always gray + {"sts_traditional_keys",{&sts_traditional_keys, NULL},{0, NULL},0,1, // killough 2/28/98 + def_bool,ss_stat,0,0}, // disables doubled card and skull key display on status bar +// {"traditional_menu",{&traditional_menu, NULL},{1, NULL},0,1, +// def_bool,ss_none, 0, 0}, // force use of Doom's main menu ordering // killough 4/17/98 + {"show_messages",{&showMessages, NULL},{1, NULL},0,1, + def_bool,ss_none,0,0}, // enables message display + {"autorun",{&autorun, NULL},{0, NULL},0,1, // killough 3/6/98: preserve autorun across games + def_bool,ss_none,0,0}, + + {"Compatibility settings",{NULL, NULL},{0, NULL},UL,UL,def_none,ss_none, 0, 0}, + {"comp_zombie",{&default_comp[comp_zombie], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_zombie], 0}, + {"comp_infcheat",{&default_comp[comp_infcheat], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_infcheat], 0}, + {"comp_stairs",{&default_comp[comp_stairs], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_stairs], 0}, + {"comp_telefrag",{&default_comp[comp_telefrag], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_telefrag], 0}, + {"comp_dropoff",{&default_comp[comp_dropoff], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_dropoff], 0}, + {"comp_falloff",{&default_comp[comp_falloff], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_falloff], 0}, + {"comp_staylift",{&default_comp[comp_staylift], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_staylift], 0}, + {"comp_doorstuck",{&default_comp[comp_doorstuck], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_doorstuck], 0}, + {"comp_pursuit",{&default_comp[comp_pursuit], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_pursuit], 0}, + {"comp_vile",{&default_comp[comp_vile], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_vile], 0}, + {"comp_pain",{&default_comp[comp_pain], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_pain], 0}, + {"comp_skull",{&default_comp[comp_skull], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_skull], 0}, + {"comp_blazing",{&default_comp[comp_blazing], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_blazing], 0}, + {"comp_doorlight",{&default_comp[comp_doorlight], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_doorlight], 0}, + {"comp_god",{&default_comp[comp_god], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_god], 0}, + {"comp_skymap",{&default_comp[comp_skymap], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_skymap], 0}, + {"comp_floors",{&default_comp[comp_floors], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_floors], 0}, + {"comp_model",{&default_comp[comp_model], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_model], 0}, + {"comp_zerotags",{&default_comp[comp_zerotags], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_zerotags], 0}, + {"comp_moveblock",{&default_comp[comp_moveblock], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_moveblock], 0}, + {"comp_sound",{&default_comp[comp_sound], NULL},{0, NULL},0,1,def_bool,ss_comp,&comp[comp_sound], 0}, + + {"Sound settings",{NULL, NULL},{0, NULL},UL,UL,def_none,ss_none, 0, 0}, +// {"sound_card",{&snd_card, NULL},{-1, NULL},-1,7, // jff 1/18/98 allow Allegro drivers +// def_int,ss_none, 0, 0}, // select sounds driver (DOS), -1 is autodetect, 0 is none; in Linux, non-zero enables sound +// {"music_card",{&mus_card, NULL},{-1, NULL},-1,9, // to be set, -1 = autodetect +// def_int,ss_none, 0, 0}, // select music driver (DOS), -1 is autodetect, 0 is none"; in Linux, non-zero enables music + {"pitched_sounds",{&pitched_sounds, NULL},{0, NULL},0,1, // killough 2/21/98 + def_bool,ss_none, 0, 0}, // enables variable pitch in sound effects (from id's original code) +// {"samplerate",{&snd_samplerate, NULL},{22050, NULL},11025,48000, def_int,ss_none, 0, 0}, + {"sfx_volume",{&snd_SfxVolume, NULL},{8, NULL},0,15, def_int,ss_none, 0, 0}, + {"music_volume",{&snd_MusicVolume, NULL},{8, NULL},0,15, def_int,ss_none, 0, 0}, + {"mus_pause_opt",{&mus_pause_opt, NULL},{2, NULL},0,2, // CPhipps - music pausing + def_int, ss_none, 0, 0}, // 0 = kill music when paused, 1 = pause music, 2 = let music continue + {"sounddev", {NULL,&snd_device}, {0,"/dev/dsp"},UL,UL, + def_str,ss_none, 0, 0}, // sound output device (UNIX) + {"snd_channels",{&default_numChannels, NULL},{4, NULL},1,32, + def_int,ss_none, 0, 0}, // number of audio events simultaneously // killough + + {"Video settings",{NULL, NULL},{0, NULL},UL,UL,def_none,ss_none, 0, 0}, + // CPhipps - default screensize for targets that support high-res + /* {"screen_width",{&desired_screenwidth, NULL},{320, NULL}, 320, 1600, + def_int,ss_none, 0, 0}, + {"screen_height",{&desired_screenheight, NULL},{200, NULL},200,1200, + def_int,ss_none, 0, 0},*/ + {"fake_contrast",{&fake_contrast, NULL},{1, NULL},0,1, + def_bool,ss_none, 0, 0}, /* cph - allow crappy fake contrast to be disabled */ +// {"use_fullscreen",{&use_fullscreen, NULL},{1, NULL},0,1, /* proff 21/05/2000 */ +// def_bool,ss_none, 0, 0}, +// {"use_doublebuffer",{&use_doublebuffer, NULL},{1, NULL},0,1, // proff 2001-7-4 +// def_bool,ss_none, 0, 0}, // enable doublebuffer to avoid display tearing (fullscreen) + {"translucency",{&default_translucency, NULL},{1, NULL},0,1, // phares + def_bool,ss_none, 0, 0}, // enables translucency + {"tran_filter_pct",{&tran_filter_pct, NULL},{66, NULL},0,100, // killough 2/21/98 + def_int,ss_none, 0, 0}, // set percentage of foreground/background translucency mix + {"screenblocks",{&screenblocks, NULL},{9, NULL},3,11, + def_int,ss_none, 0, 0}, + {"usegamma",{&usegamma, NULL},{1, NULL},0,4, //jff 3/6/98 fix erroneous upper limit in range + def_int,ss_none, 0, 0}, // gamma correction level // killough 1/18/98 + {"X_options",{&X_opt, NULL},{0, NULL},0,3, // CPhipps - misc X options + def_hex,ss_none, 0, 0}, // X options, see l_video_x.c + + {"Mouse settings",{NULL, NULL},{0, NULL},UL,UL,def_none,ss_none, 0, 0}, + {"use_mouse",{&usemouse, NULL},{1, NULL},0,1, + def_bool,ss_none, 0, 0}, // enables use of mouse with DOOM + //jff 4/3/98 allow unlimited sensitivity +// {"mouse_sensitivity_horiz",{&mouseSensitivity_horiz, NULL},{10, NULL},0,UL, +// def_int,ss_none, 0, 0}, /* adjust horizontal (x) mouse sensitivity killough/mead */ + //jff 4/3/98 allow unlimited sensitivity +// {"mouse_sensitivity_vert",{&mouseSensitivity_vert, NULL},{10, NULL},0,UL, +// def_int,ss_none, 0, 0}, /* adjust vertical (y) mouse sensitivity killough/mead */ + //jff 3/8/98 allow -1 in mouse bindings to disable mouse function + {"mouseb_fire",{&mousebfire, NULL},{0, NULL},-1,MAX_MOUSEB, + def_int,ss_keys, 0, 0}, // mouse button number to use for fire + {"mouseb_strafe",{&mousebstrafe, NULL},{1, NULL},-1,MAX_MOUSEB, + def_int,ss_keys, 0, 0}, // mouse button number to use for strafing + {"mouseb_forward",{&mousebforward, NULL},{2, NULL},-1,MAX_MOUSEB, + def_int,ss_keys, 0, 0}, // mouse button number to use for forward motion + //jff 3/8/98 end of lower range change for -1 allowed in mouse binding + + // For key bindings, the values stored in the key_* variables // phares + // are the internal Doom Codes. The values stored in the default.cfg + // file are the keyboard codes. + // CPhipps - now they're the doom codes, so default.cfg can be portable + + {"Key bindings",{NULL, NULL},{0, NULL},UL,UL,def_none,ss_none, 0, 0}, + {"key_right", {&key_right, NULL}, {KEY_RIGHTARROW, NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to turn right + {"key_left", {&key_left, NULL}, {KEY_LEFTARROW, NULL} , + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to turn left + {"key_up", {&key_up, NULL}, {KEY_RCTRL, NULL} , + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to move forward + {"key_down", {&key_down, NULL}, {KEY_DOWNARROW, NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to move backward +/* {"key_menu_right", {&key_menu_right, NULL}, {KEY_RIGHTARROW, NULL},// phares 3/7/98 + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to move right in a menu // | + {"key_menu_left", {&key_menu_left, NULL}, {KEY_LEFTARROW} ,// V + 0,MAX_KEY,def_key,ss_keys, NULL}, // key to move left in a menu + {"key_menu_up", {&key_menu_up, NULL}, {KEY_UPARROW,NULL} , + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to move up in a menu + {"key_menu_down", {&key_menu_down, NULL}, {KEY_DOWNARROW, NULL} , + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to move down in a menu + {"key_menu_backspace",{&key_menu_backspace, NULL},{KEY_BACKSPACE, NULL} , + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // delete key in a menu + {"key_menu_escape", {&key_menu_escape, NULL}, {KEY_ESCAPE, NULL} , + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to leave a menu , // phares 3/7/98 + {"key_menu_enter", {&key_menu_enter, NULL}, {KEY_ENTER, NULL} , + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to select from menu +*/ + {"key_strafeleft", {&key_strafeleft, NULL}, {',', NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to strafe left + {"key_straferight", {&key_straferight, NULL}, {'.', NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to strafe right + + {"key_fire", {&key_fire, NULL}, {' ', NULL} , + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // duh + {"key_use", {&key_use, NULL}, {KEY_DOWNARROW, NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to open a door, use a switch + {"key_strafe", {&key_strafe, NULL}, {'w', NULL} , + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to use with arrows to strafe + {"key_speed", {&key_speed, NULL}, {KEY_RSHIFT, NULL} , + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to run + + {"key_savegame", {&key_savegame, NULL}, {KEY_F2, NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to save current game + {"key_loadgame", {&key_loadgame, NULL}, {KEY_F3, NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to restore from saved games + {"key_soundvolume", {&key_soundvolume, NULL}, {KEY_F4, NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to bring up sound controls + {"key_hud", {&key_hud, NULL}, {KEY_F5, NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to adjust HUD + {"key_quicksave", {&key_quicksave, NULL}, {KEY_F6, NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to to quicksave + {"key_endgame", {&key_endgame, NULL}, {KEY_F7, NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to end the game + {"key_messages", {&key_messages, NULL}, {KEY_F8, NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to toggle message enable + {"key_quickload", {&key_quickload, NULL}, {KEY_F9, NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to load from quicksave + {"key_quit", {&key_quit, NULL}, {KEY_F10, NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to quit game + {"key_gamma", {&key_gamma, NULL}, {KEY_F11, NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to adjust gamma correction + {"key_spy", {&key_spy, NULL}, {KEY_F12, NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to view from another coop player's view + {"key_pause", {&key_pause, NULL}, {KEY_PAUSE, NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to pause the game + {"key_autorun", {&key_autorun, NULL}, {KEY_CAPSLOCK, NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to toggle always run mode + {"key_chat", {&key_chat, NULL}, {'t', NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to enter a chat message + {"key_backspace", {&key_backspace, NULL}, {KEY_BACKSPACE, NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // backspace key + {"key_enter", {&key_enter, NULL}, {KEY_ENTER, NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to select from menu or see last message + {"key_map", {&key_map, NULL}, {KEY_TAB, NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to toggle automap display + {"key_map_right", {&key_map_right, NULL}, {KEY_RIGHTARROW, NULL},// phares 3/7/98 + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to shift automap right // | + {"key_map_left", {&key_map_left, NULL}, {KEY_LEFTARROW, NULL},// V + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to shift automap left + {"key_map_up", {&key_map_up, NULL}, {KEY_UPARROW, NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to shift automap up + {"key_map_down", {&key_map_down, NULL}, {KEY_DOWNARROW, NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to shift automap down + {"key_map_zoomin", {&key_map_zoomin, NULL}, {'=', NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to enlarge automap + {"key_map_zoomout", {&key_map_zoomout, NULL}, {'-', NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to reduce automap + {"key_map_gobig", {&key_map_gobig, NULL}, {'0', NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to get max zoom for automap + {"key_map_follow", {&key_map_follow, NULL}, {'f', NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to toggle follow mode + {"key_map_mark", {&key_map_mark, NULL}, {'m', NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to drop a marker on automap + {"key_map_clear", {&key_map_clear, NULL}, {'c', NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to clear all markers on automap + {"key_map_grid", {&key_map_grid, NULL}, {'g', NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to toggle grid display over automap + {"key_map_rotate", {&key_map_rotate, NULL}, {'r', NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to toggle rotating the automap to match the player's orientation + {"key_map_overlay", {&key_map_overlay, NULL}, {'o', NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to toggle overlaying the automap on the rendered display + {"key_reverse", {&key_reverse, NULL}, {'/', NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to spin 180 instantly + {"key_zoomin", {&key_zoomin, NULL}, {'=', NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to enlarge display + {"key_zoomout", {&key_zoomout, NULL}, {'-', NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to reduce display + {"key_chatplayer1", {&destination_keys[0], NULL}, {'g', NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to chat with player 1 + // killough 11/98: fix 'i'/'b' reversal + {"key_chatplayer2", {&destination_keys[1], NULL}, {'i', NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to chat with player 2 + {"key_chatplayer3", {&destination_keys[2], NULL}, {'b', NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to chat with player 3 + {"key_chatplayer4", {&destination_keys[3], NULL}, {'r', NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to chat with player 4 + {"key_weapon",{&key_weapon, NULL}, {KEY_UPARROW, NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to toggle between two most preferred weapons with ammo + {"key_weapontoggle",{&key_weapontoggle, NULL}, {'0', NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to toggle between two most preferred weapons with ammo + {"key_weapon1", {&key_weapon1, NULL}, {'1', NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to switch to weapon 1 (fist/chainsaw) + {"key_weapon2", {&key_weapon2, NULL}, {'2', NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to switch to weapon 2 (pistol) + {"key_weapon3", {&key_weapon3, NULL}, {'3', NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to switch to weapon 3 (supershotgun/shotgun) + {"key_weapon4", {&key_weapon4, NULL}, {'4', NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to switch to weapon 4 (chaingun) + {"key_weapon5", {&key_weapon5, NULL}, {'5', NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to switch to weapon 5 (rocket launcher) + {"key_weapon6", {&key_weapon6, NULL}, {'6', NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to switch to weapon 6 (plasma rifle) + {"key_weapon7", {&key_weapon7, NULL}, {'7', NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to switch to weapon 7 (bfg9000) // ^ + {"key_weapon8", {&key_weapon8, NULL}, {'8', NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to switch to weapon 8 (chainsaw) // | + {"key_weapon9", {&key_weapon9, NULL}, {'9', NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to switch to weapon 9 (supershotgun) // phares + + // killough 2/22/98: screenshot key + {"key_screenshot", {&key_screenshot, NULL}, {'*', NULL}, + 0,MAX_KEY,def_key,ss_keys, 0, 0}, // key to take a screenshot + + /* {"Joystick settings",{NULL, NULL},{0, NULL},UL,UL,def_none,ss_none, 0, 0}, + {"use_joystick",{&usejoystick, NULL},{0, NULL},0,2, + def_int,ss_none, 0, 0}, // number of joystick to use (0 for none) + {"joy_left",{&joyleft, NULL},{0, NULL}, UL,UL,def_int,ss_none, 0, 0}, + {"joy_right",{&joyright, NULL},{0, NULL},UL,UL,def_int,ss_none, 0, 0}, + {"joy_up", {&joyup, NULL}, {0, NULL}, UL,UL,def_int,ss_none, 0, 0}, + {"joy_down",{&joydown, NULL},{0, NULL}, UL,UL,def_int,ss_none, 0, 0}, + {"joyb_fire",{&joybfire, NULL},{0, NULL},0,UL, + def_int,ss_keys, 0, 0}, // joystick button number to use for fire + {"joyb_strafe",{&joybstrafe, NULL},{1, NULL},0,UL, + def_int,ss_keys, 0, 0}, // joystick button number to use for strafing + {"joyb_speed",{&joybspeed, NULL},{2, NULL},0,UL, + def_int,ss_keys, 0, 0}, // joystick button number to use for running + {"joyb_use",{&joybuse, NULL},{3, NULL},0,UL, + def_int,ss_keys, 0, 0}, // joystick button number to use for use/open +*/ + {"Chat macros",{NULL, NULL},{0, NULL},UL,UL,def_none,ss_none, 0, 0}, + {"chatmacro0", {0,&chat_macros[0]}, {0,HUSTR_CHATMACRO0},UL,UL, + def_str,ss_chat, 0, 0}, // chat string associated with 0 key + {"chatmacro1", {0,&chat_macros[1]}, {0,HUSTR_CHATMACRO1},UL,UL, + def_str,ss_chat, 0, 0}, // chat string associated with 1 key + {"chatmacro2", {0,&chat_macros[2]}, {0,HUSTR_CHATMACRO2},UL,UL, + def_str,ss_chat, 0, 0}, // chat string associated with 2 key + {"chatmacro3", {0,&chat_macros[3]}, {0,HUSTR_CHATMACRO3},UL,UL, + def_str,ss_chat, 0, 0}, // chat string associated with 3 key + {"chatmacro4", {0,&chat_macros[4]}, {0,HUSTR_CHATMACRO4},UL,UL, + def_str,ss_chat, 0, 0}, // chat string associated with 4 key + {"chatmacro5", {0,&chat_macros[5]}, {0,HUSTR_CHATMACRO5},UL,UL, + def_str,ss_chat, 0, 0}, // chat string associated with 5 key + {"chatmacro6", {0,&chat_macros[6]}, {0,HUSTR_CHATMACRO6},UL,UL, + def_str,ss_chat, 0, 0}, // chat string associated with 6 key + {"chatmacro7", {0,&chat_macros[7]}, {0,HUSTR_CHATMACRO7},UL,UL, + def_str,ss_chat, 0, 0}, // chat string associated with 7 key + {"chatmacro8", {0,&chat_macros[8]}, {0,HUSTR_CHATMACRO8},UL,UL, + def_str,ss_chat, 0, 0}, // chat string associated with 8 key + {"chatmacro9", {0,&chat_macros[9]}, {0,HUSTR_CHATMACRO9},UL,UL, + def_str,ss_chat, 0, 0}, // chat string associated with 9 key + + {"Automap settings",{NULL, NULL},{0, NULL},UL,UL,def_none,ss_none, 0, 0}, + //jff 1/7/98 defaults for automap colors + //jff 4/3/98 remove -1 in lower range, 0 now disables new map features + {"mapcolor_back", {&mapcolor_back, NULL}, {247, NULL},0,255, // black //jff 4/6/98 new black + def_colour,ss_auto, 0, 0}, // color used as background for automap + {"mapcolor_grid", {&mapcolor_grid, NULL}, {104, NULL},0,255, // dk gray + def_colour,ss_auto, 0, 0}, // color used for automap grid lines + {"mapcolor_wall", {&mapcolor_wall, NULL}, {23, NULL},0,255, // red-brown + def_colour,ss_auto, 0, 0}, // color used for one side walls on automap + {"mapcolor_fchg", {&mapcolor_fchg, NULL}, {55, NULL},0,255, // lt brown + def_colour,ss_auto, 0, 0}, // color used for lines floor height changes across + {"mapcolor_cchg", {&mapcolor_cchg, NULL}, {215, NULL},0,255, // orange + def_colour,ss_auto, 0, 0}, // color used for lines ceiling height changes across + {"mapcolor_clsd", {&mapcolor_clsd, NULL}, {208, NULL},0,255, // white + def_colour,ss_auto, 0, 0}, // color used for lines denoting closed doors, objects + {"mapcolor_rkey", {&mapcolor_rkey, NULL}, {175, NULL},0,255, // red + def_colour,ss_auto, 0, 0}, // color used for red key sprites + {"mapcolor_bkey", {&mapcolor_bkey, NULL}, {204, NULL},0,255, // blue + def_colour,ss_auto, 0, 0}, // color used for blue key sprites + {"mapcolor_ykey", {&mapcolor_ykey, NULL}, {231, NULL},0,255, // yellow + def_colour,ss_auto, 0, 0}, // color used for yellow key sprites + {"mapcolor_rdor", {&mapcolor_rdor, NULL}, {175, NULL},0,255, // red + def_colour,ss_auto, 0, 0}, // color used for closed red doors + {"mapcolor_bdor", {&mapcolor_bdor, NULL}, {204, NULL},0,255, // blue + def_colour,ss_auto, 0, 0}, // color used for closed blue doors + {"mapcolor_ydor", {&mapcolor_ydor, NULL}, {231, NULL},0,255, // yellow + def_colour,ss_auto, 0, 0}, // color used for closed yellow doors + {"mapcolor_tele", {&mapcolor_tele, NULL}, {119, NULL},0,255, // dk green + def_colour,ss_auto, 0, 0}, // color used for teleporter lines + {"mapcolor_secr", {&mapcolor_secr, NULL}, {252, NULL},0,255, // purple + def_colour,ss_auto, 0, 0}, // color used for lines around secret sectors + {"mapcolor_exit", {&mapcolor_exit, NULL}, {0, NULL},0,255, // none + def_colour,ss_auto, 0, 0}, // color used for exit lines + {"mapcolor_unsn", {&mapcolor_unsn, NULL}, {104, NULL},0,255, // dk gray + def_colour,ss_auto, 0, 0}, // color used for lines not seen without computer map + {"mapcolor_flat", {&mapcolor_flat, NULL}, {88, NULL},0,255, // lt gray + def_colour,ss_auto, 0, 0}, // color used for lines with no height changes + {"mapcolor_sprt", {&mapcolor_sprt, NULL}, {112, NULL},0,255, // green + def_colour,ss_auto, 0, 0}, // color used as things + {"mapcolor_item", {&mapcolor_item, NULL}, {231, NULL},0,255, // yellow + def_colour,ss_auto, 0, 0}, // color used for counted items + {"mapcolor_hair", {&mapcolor_hair, NULL}, {208, NULL},0,255, // white + def_colour,ss_auto, 0, 0}, // color used for dot crosshair denoting center of map + {"mapcolor_sngl", {&mapcolor_sngl, NULL}, {208, NULL},0,255, // white + def_colour,ss_auto, 0, 0}, // color used for the single player arrow +/* {"mapcolor_me", {&mapcolor_me, NULL}, {112, NULL},0,255, // green + def_colour,ss_auto, 0, 0}, // your (player) colour*/ + {"mapcolor_frnd", {&mapcolor_frnd, NULL}, {112, NULL},0,255, + def_colour,ss_auto, 0, 0}, + //jff 3/9/98 add option to not show secrets til after found + {"map_secret_after", {&map_secret_after, NULL}, {0, NULL},0,1, // show secret after gotten + def_bool,ss_auto, 0, 0}, // prevents showing secret sectors till after entered + {"map_point_coord", {&map_point_coordinates, NULL}, {0, NULL},0,1, + def_bool,ss_auto, 0, 0}, + //jff 1/7/98 end additions for automap + {"automapmode", {(void*)&automapmode, NULL}, {0, NULL}, 0, 31, // CPhipps - remember automap mode + def_hex,ss_none, 0, 0}, // automap mode + + {"Heads-up display settings",{NULL, NULL},{0, NULL},UL,UL,def_none,ss_none, 0, 0}, + //jff 2/16/98 defaults for color ranges in hud and status + {"hudcolor_titl", {&hudcolor_titl, NULL}, {5, NULL},0,9, // gold range + def_int,ss_auto, 0, 0}, // color range used for automap level title + {"hudcolor_xyco", {&hudcolor_xyco, NULL}, {3, NULL},0,9, // green range + def_int,ss_auto, 0, 0}, // color range used for automap coordinates + {"hudcolor_mesg", {&hudcolor_mesg, NULL}, {6, NULL},0,9, // red range + def_int,ss_mess, 0, 0}, // color range used for messages during play + {"hudcolor_chat", {&hudcolor_chat, NULL}, {5, NULL},0,9, // gold range + def_int,ss_mess, 0, 0}, // color range used for chat messages and entry + {"hudcolor_list", {&hudcolor_list, NULL}, {5, NULL},0,9, // gold range //jff 2/26/98 + def_int,ss_mess, 0, 0}, // color range used for message review + {"hud_msg_lines", {&hud_msg_lines, NULL}, {1, NULL},1,16, // 1 line scrolling window + def_int,ss_mess, 0, 0}, // number of messages in review display (1=disable) + {"hud_list_bgon", {&hud_list_bgon, NULL}, {0, NULL},0,1, // solid window bg ena //jff 2/26/98 + def_bool,ss_mess, 0, 0}, // enables background window behind message review + {"hud_distributed",{&hud_distributed, NULL},{0, NULL},0,1, // hud broken up into 3 displays //jff 3/4/98 + def_bool,ss_none, 0, 0}, // splits HUD into three 2 line displays + + {"health_red", {&health_red, NULL}, {25, NULL},0,200, // below is red + def_int,ss_stat, 0, 0}, // amount of health for red to yellow transition + {"health_yellow", {&health_yellow, NULL}, {50, NULL},0,200, // below is yellow + def_int,ss_stat, 0, 0}, // amount of health for yellow to green transition + {"health_green", {&health_green, NULL}, {100, NULL},0,200,// below is green, above blue + def_int,ss_stat, 0, 0}, // amount of health for green to blue transition + {"armor_red", {&armor_red, NULL}, {25, NULL},0,200, // below is red + def_int,ss_stat, 0, 0}, // amount of armor for red to yellow transition + {"armor_yellow", {&armor_yellow, NULL}, {50, NULL},0,200, // below is yellow + def_int,ss_stat, 0, 0}, // amount of armor for yellow to green transition + {"armor_green", {&armor_green, NULL}, {100, NULL},0,200,// below is green, above blue + def_int,ss_stat, 0, 0}, // amount of armor for green to blue transition + {"ammo_red", {&ammo_red, NULL}, {25, NULL},0,100, // below 25% is red + def_int,ss_stat, 0, 0}, // percent of ammo for red to yellow transition + {"ammo_yellow", {&ammo_yellow, NULL}, {50, NULL},0,100, // below 50% is yellow, above green + def_int,ss_stat, 0, 0}, // percent of ammo for yellow to green transition + + //jff 2/16/98 HUD and status feature controls + {"hud_active", {&hud_active, NULL}, {1, NULL},0,2, // 0=off, 1=small, 2=full + def_int,ss_none, 0, 0}, // 0 for HUD off, 1 for HUD small, 2 for full HUD + //jff 2/23/98 + {"hud_displayed", {&hud_displayed, NULL}, {0, NULL},0,1, // whether hud is displayed + def_bool,ss_none, 0, 0}, // enables display of HUD + {"hud_nosecrets", {&hud_nosecrets, NULL}, {0, NULL},0,1, // no secrets/items/kills HUD line + def_bool,ss_stat, 0, 0}, // disables display of kills/items/secrets on HUD + + {"Weapon preferences",{NULL, NULL},{0, NULL},UL,UL,def_none,ss_none, 0, 0}, + // killough 2/8/98: weapon preferences set by user: + {"weapon_choice_1", {&weapon_preferences[0][0], NULL}, {6, NULL}, 0,9, + def_int,ss_weap, 0, 0}, // first choice for weapon (best) + {"weapon_choice_2", {&weapon_preferences[0][1], NULL}, {9, NULL}, 0,9, + def_int,ss_weap, 0, 0}, // second choice for weapon + {"weapon_choice_3", {&weapon_preferences[0][2], NULL}, {4, NULL}, 0,9, + def_int,ss_weap, 0, 0}, // third choice for weapon + {"weapon_choice_4", {&weapon_preferences[0][3], NULL}, {3, NULL}, 0,9, + def_int,ss_weap, 0, 0}, // fourth choice for weapon + {"weapon_choice_5", {&weapon_preferences[0][4], NULL}, {2, NULL}, 0,9, + def_int,ss_weap, 0, 0}, // fifth choice for weapon + {"weapon_choice_6", {&weapon_preferences[0][5], NULL}, {8, NULL}, 0,9, + def_int,ss_weap, 0, 0}, // sixth choice for weapon + {"weapon_choice_7", {&weapon_preferences[0][6], NULL}, {5, NULL}, 0,9, + def_int,ss_weap, 0, 0}, // seventh choice for weapon + {"weapon_choice_8", {&weapon_preferences[0][7], NULL}, {7, NULL}, 0,9, + def_int,ss_weap, 0, 0}, // eighth choice for weapon + {"weapon_choice_9", {&weapon_preferences[0][8], NULL}, {1, NULL}, 0,9, + def_int,ss_weap, 0, 0}, // ninth choice for weapon (worst) + +/* // cournia - support for arbitrary music file (defaults are mp3) + {"Music", {NULL, NULL},{0, NULL},UL,UL,def_none,ss_none, 0, 0}, + {"mus_e1m1", {0,&S_music_files[mus_e1m1]}, {0,"e1m1.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_e1m2", {0,&S_music_files[mus_e1m2]}, {0,"e1m2.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_e1m3", {0,&S_music_files[mus_e1m3]}, {0,"e1m3.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_e1m4", {0,&S_music_files[mus_e1m4]}, {0,"e1m4.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_e1m5", {0,&S_music_files[mus_e1m5]}, {0,"e1m5.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_e1m6", {0,&S_music_files[mus_e1m6]}, {0,"e1m6.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_e1m7", {0,&S_music_files[mus_e1m7]}, {0,"e1m7.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_e1m8", {0,&S_music_files[mus_e1m8]}, {0,"e1m8.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_e1m9", {0,&S_music_files[mus_e1m9]}, {0,"e1m9.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_e2m1", {0,&S_music_files[mus_e2m1]}, {0,"e2m1.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_e2m2", {0,&S_music_files[mus_e2m2]}, {0,"e2m2.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_e2m3", {0,&S_music_files[mus_e2m3]}, {0,"e2m3.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_e2m4", {0,&S_music_files[mus_e2m4]}, {0,"e2m4.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_e2m5", {0,&S_music_files[mus_e2m5]}, {0,"e1m7.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_e2m6", {0,&S_music_files[mus_e2m6]}, {0,"e2m6.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_e2m7", {0,&S_music_files[mus_e2m7]}, {0,"e2m7.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_e2m8", {0,&S_music_files[mus_e2m8]}, {0,"e2m8.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_e2m9", {0,&S_music_files[mus_e2m9]}, {0,"e3m1.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_e3m1", {0,&S_music_files[mus_e3m1]}, {0,"e3m1.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_e3m2", {0,&S_music_files[mus_e3m2]}, {0,"e3m2.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_e3m3", {0,&S_music_files[mus_e3m3]}, {0,"e3m3.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_e3m4", {0,&S_music_files[mus_e3m4]}, {0,"e1m8.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_e3m5", {0,&S_music_files[mus_e3m5]}, {0,"e1m7.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_e3m6", {0,&S_music_files[mus_e3m6]}, {0,"e1m6.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_e3m7", {0,&S_music_files[mus_e3m7]}, {0,"e2m7.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_e3m8", {0,&S_music_files[mus_e3m8]}, {0,"e3m8.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_e3m9", {0,&S_music_files[mus_e3m9]}, {0,"e1m9.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_inter", {0,&S_music_files[mus_inter]}, {0,"e2m3.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_intro", {0,&S_music_files[mus_intro]}, {0,"intro.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_bunny", {0,&S_music_files[mus_bunny]}, {0,"bunny.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_victor", {0,&S_music_files[mus_victor]}, {0,"victor.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_introa", {0,&S_music_files[mus_introa]}, {0,"intro.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_runnin", {0,&S_music_files[mus_runnin]}, {0,"runnin.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_stalks", {0,&S_music_files[mus_stalks]}, {0,"stalks.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_countd", {0,&S_music_files[mus_countd]}, {0,"countd.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_betwee", {0,&S_music_files[mus_betwee]}, {0,"betwee.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_doom", {0,&S_music_files[mus_doom]}, {0,"doom.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_the_da", {0,&S_music_files[mus_the_da]}, {0,"the_da.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_shawn", {0,&S_music_files[mus_shawn]}, {0,"shawn.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_ddtblu", {0,&S_music_files[mus_ddtblu]}, {0,"ddtblu.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_in_cit", {0,&S_music_files[mus_in_cit]}, {0,"in_cit.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_dead", {0,&S_music_files[mus_dead]}, {0,"dead.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_stlks2", {0,&S_music_files[mus_stlks2]}, {0,"stalks.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_theda2", {0,&S_music_files[mus_theda2]}, {0,"the_da.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_doom2", {0,&S_music_files[mus_doom2]}, {0,"doom.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_ddtbl2", {0,&S_music_files[mus_ddtbl2]}, {0,"ddtblu.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_runni2", {0,&S_music_files[mus_runni2]}, {0,"runnin.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_dead2", {0,&S_music_files[mus_dead2]}, {0,"dead.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_stlks3", {0,&S_music_files[mus_stlks3]}, {0,"stalks.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_romero", {0,&S_music_files[mus_romero]}, {0,"romero.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_shawn2", {0,&S_music_files[mus_shawn2]}, {0,"shawn.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_messag", {0,&S_music_files[mus_messag]}, {0,"messag.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_count2", {0,&S_music_files[mus_count2]}, {0,"countd.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_ddtbl3", {0,&S_music_files[mus_ddtbl3]}, {0,"ddtblu.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_ampie", {0,&S_music_files[mus_ampie]}, {0,"ampie.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_theda3", {0,&S_music_files[mus_theda3]}, {0,"the_da.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_adrian", {0,&S_music_files[mus_adrian]}, {0,"adrian.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_messg2", {0,&S_music_files[mus_messg2]}, {0,"messag.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_romer2", {0,&S_music_files[mus_romer2]}, {0,"romero.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_tense", {0,&S_music_files[mus_tense]}, {0,"tense.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_shawn3", {0,&S_music_files[mus_shawn3]}, {0,"shawn.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_openin", {0,&S_music_files[mus_openin]}, {0,"openin.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_evil", {0,&S_music_files[mus_evil]}, {0,"evil.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_ultima", {0,&S_music_files[mus_ultima]}, {0,"ultima.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_read_m", {0,&S_music_files[mus_read_m]}, {0,"read_m.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_dm2ttl", {0,&S_music_files[mus_dm2ttl]}, {0,"dm2ttl.mp3"},UL,UL, + def_str,ss_none, 0, 0}, + {"mus_dm2int", {0,&S_music_files[mus_dm2int]}, {0,"dm2int.mp3"},UL,UL, + def_str,ss_none, 0, 0}, +*/ + }; + +int numdefaults; +//static const char* defaultfile; // CPhipps - static, const + +// +// M_SaveDefaults +// + +void M_SaveDefaults (void) +{ + int i,fd; + + fd = open (GAMEBASE"default.dfg", O_WRONLY|O_CREAT|O_TRUNC); + if (fd<0) + return; // can't write the file, but don't complain + + for (i=0 ; i>= 20; + + /* killough 3/30/98: use gametic-levelstarttic to shuffle RNG + * killough 3/31/98: but only if demo insurance requested, + * since it's unnecessary for random shuffling otherwise + * killough 9/29/98: but use basetic now instead of levelstarttic + * cph - DEMOSYNC - this change makes MBF demos work, + * but does it break Boom ones? + */ + + if (demo_insurance) + boom += (gametic-basetic)*7; + + return boom & 255; +} + +// Initialize all the seeds +// +// This initialization method is critical to maintaining demo sync. +// Each seed is initialized according to its class, so if new classes +// are added they must be added to end of pr_class_t list. killough +// + +void M_ClearRandom (void) +{ + int i; + unsigned long seed = rngseed*2+1; // add 3/26/98: add rngseed + for (i=0; i> 8) | \ + (((unsigned long int)(x) & 0xff000000U) >> 24))) +#endif + +#ifndef doom_swap_s +#define doom_swap_s(x) \ + ((short int)((((unsigned short int)(x) & 0x00ff) << 8) | \ + (((unsigned short int)(x) & 0xff00) >> 8))) +#endif + +/* Macros are named doom_XtoYT, where + * X is thing to convert from, Y is thing to convert to, chosen from + * n for network, h for host (i.e our machine's), w for WAD (Doom data files) + * and T is the type, l or s for long or short + * + * CPhipps - all WADs and network packets will be little endian for now + * Use separate macros so network could be converted to big-endian later. + */ + +#ifdef __BIG_ENDIAN__ + +#define doom_wtohl(x) doom_swap_l(x) +#define doom_htowl(x) doom_swap_l(x) +#define doom_wtohs(x) doom_swap_s(x) +#define doom_htows(x) doom_swap_s(x) + +#define doom_ntohl(x) doom_swap_l(x) +#define doom_htonl(x) doom_swap_l(x) +#define doom_ntohs(x) doom_swap_s(x) +#define doom_htons(x) doom_swap_s(x) + +#else + +#define doom_wtohl(x) (long int)(x) +#define doom_htowl(x) (long int)(x) +#define doom_wtohs(x) (short int)(x) +#define doom_htows(x) (short int)(x) + +#define doom_ntohl(x) (long int)(x) +#define doom_htonl(x) (long int)(x) +#define doom_ntohs(x) (short int)(x) +#define doom_htons(x) (short int)(x) + +#endif + +/* CPhipps - Boom's old LONG and SHORT endianness macros are for WAD stuff */ + +#define LONG(x) doom_wtohl(x) +#define SHORT(x) doom_htows(x) + +#endif diff --git a/apps/plugins/doom/p_ceilng.c b/apps/plugins/doom/p_ceilng.c new file mode 100644 index 0000000000..db5a701b1a --- /dev/null +++ b/apps/plugins/doom/p_ceilng.c @@ -0,0 +1,468 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Ceiling aninmation (lowering, crushing, raising) + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "r_main.h" +#include "p_spec.h" +#include "p_tick.h" +#include "s_sound.h" +#include "sounds.h" +#include "z_zone.h" +#include "doomdef.h" +#define PU_LEVSPEC 51 // a special thinker in a level +#include "rockmacros.h" + +// the list of ceilings moving currently, including crushers +ceilinglist_t *activeceilings; + +///////////////////////////////////////////////////////////////// +// +// Ceiling action routine and linedef type handler +// +///////////////////////////////////////////////////////////////// + +// +// T_MoveCeiling +// +// Action routine that moves ceilings. Called once per tick. +// +// Passed a ceiling_t structure that contains all the info about the move. +// see P_SPEC.H for fields. No return. +// +// jff 02/08/98 all cases with labels beginning with gen added to support +// generalized line type behaviors. +// +void T_MoveCeiling (ceiling_t* ceiling) +{ + result_e res; + + switch(ceiling->direction) + { + case 0: + // If ceiling in stasis, do nothing + break; + + case 1: + // Ceiling is moving up + res = T_MovePlane + ( + ceiling->sector, + ceiling->speed, + ceiling->topheight, + false, + 1, + ceiling->direction + ); + + // if not a silent crusher, make moving sound + if (!(leveltime&7)) + { + switch(ceiling->type) + { + case silentCrushAndRaise: + case genSilentCrusher: + break; + default: + S_StartSound((mobj_t *)&ceiling->sector->soundorg,sfx_stnmov); + break; + } + } + + // handle reaching destination height + if (res == pastdest) + { + switch(ceiling->type) + { + // plain movers are just removed + case raiseToHighest: + case genCeiling: + P_RemoveActiveCeiling(ceiling); + break; + + // movers with texture change, change the texture then get removed + case genCeilingChgT: + case genCeilingChg0: + ceiling->sector->special = ceiling->newspecial; + //jff 3/14/98 transfer old special field as well + ceiling->sector->oldspecial = ceiling->oldspecial; + case genCeilingChg: + ceiling->sector->ceilingpic = ceiling->texture; + P_RemoveActiveCeiling(ceiling); + break; + + // crushers reverse direction at the top + case silentCrushAndRaise: + S_StartSound((mobj_t *)&ceiling->sector->soundorg,sfx_pstop); + case genSilentCrusher: + case genCrusher: + case fastCrushAndRaise: + case crushAndRaise: + ceiling->direction = -1; + break; + + default: + break; + } + } + break; + + case -1: + // Ceiling moving down + res = T_MovePlane + ( + ceiling->sector, + ceiling->speed, + ceiling->bottomheight, + ceiling->crush, + 1, + ceiling->direction + ); + + // if not silent crusher type make moving sound + if (!(leveltime&7)) + { + switch(ceiling->type) + { + case silentCrushAndRaise: + case genSilentCrusher: + break; + default: + S_StartSound((mobj_t *)&ceiling->sector->soundorg,sfx_stnmov); + } + } + + // handle reaching destination height + if (res == pastdest) + { + switch(ceiling->type) + { + // 02/09/98 jff change slow crushers' speed back to normal + // start back up + case genSilentCrusher: + case genCrusher: + if (ceiling->oldspeedspeed = ceiling->oldspeed; + ceiling->direction = 1; //jff 2/22/98 make it go back up! + break; + + // make platform stop at bottom of all crusher strokes + // except generalized ones, reset speed, start back up + case silentCrushAndRaise: + S_StartSound((mobj_t *)&ceiling->sector->soundorg,sfx_pstop); + case crushAndRaise: + ceiling->speed = CEILSPEED; + case fastCrushAndRaise: + ceiling->direction = 1; + break; + + // in the case of ceiling mover/changer, change the texture + // then remove the active ceiling + case genCeilingChgT: + case genCeilingChg0: + ceiling->sector->special = ceiling->newspecial; + //jff add to fix bug in special transfers from changes + ceiling->sector->oldspecial = ceiling->oldspecial; + case genCeilingChg: + ceiling->sector->ceilingpic = ceiling->texture; + P_RemoveActiveCeiling(ceiling); + break; + + // all other case, just remove the active ceiling + case lowerAndCrush: + case lowerToFloor: + case lowerToLowest: + case lowerToMaxFloor: + case genCeiling: + P_RemoveActiveCeiling(ceiling); + break; + + default: + break; + } + } + else // ( res != pastdest ) + { + // handle the crusher encountering an obstacle + if (res == crushed) + { + switch(ceiling->type) + { + //jff 02/08/98 slow down slow crushers on obstacle + case genCrusher: + case genSilentCrusher: + if (ceiling->oldspeed < CEILSPEED*3) + ceiling->speed = CEILSPEED / 8; + break; + case silentCrushAndRaise: + case crushAndRaise: + case lowerAndCrush: + ceiling->speed = CEILSPEED / 8; + break; + + default: + break; + } + } + } + break; + } +} + + +// +// EV_DoCeiling +// +// Move a ceiling up/down or start a crusher +// +// Passed the linedef activating the function and the type of function desired +// returns true if a thinker started +// +int EV_DoCeiling +( line_t* line, + ceiling_e type ) +{ + int secnum; + int rtn; + sector_t* sec; + ceiling_t* ceiling; + + secnum = -1; + rtn = 0; + + // Reactivate in-stasis ceilings...for certain types. + // This restarts a crusher after it has been stopped + switch(type) + { + case fastCrushAndRaise: + case silentCrushAndRaise: + case crushAndRaise: + //jff 4/5/98 return if activated + rtn = P_ActivateInStasisCeiling(line); + default: + break; + } + + // affects all sectors with the same tag as the linedef + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; + + // if ceiling already moving, don't start a second function on it + if (P_SectorActive(ceiling_special,sec)) //jff 2/22/98 + continue; + + // create a new ceiling thinker + rtn = 1; + ceiling = Z_Malloc (sizeof(*ceiling), PU_LEVSPEC, 0); + P_AddThinker (&ceiling->thinker); + sec->ceilingdata = ceiling; //jff 2/22/98 + ceiling->thinker.function = T_MoveCeiling; + ceiling->sector = sec; + ceiling->crush = false; + + // setup ceiling structure according to type of function + switch(type) + { + case fastCrushAndRaise: + ceiling->crush = true; + ceiling->topheight = sec->ceilingheight; + ceiling->bottomheight = sec->floorheight + (8*FRACUNIT); + ceiling->direction = -1; + ceiling->speed = CEILSPEED * 2; + break; + + case silentCrushAndRaise: + case crushAndRaise: + ceiling->crush = true; + ceiling->topheight = sec->ceilingheight; + case lowerAndCrush: + case lowerToFloor: + ceiling->bottomheight = sec->floorheight; + if (type != lowerToFloor) + ceiling->bottomheight += 8*FRACUNIT; + ceiling->direction = -1; + ceiling->speed = CEILSPEED; + break; + + case raiseToHighest: + ceiling->topheight = P_FindHighestCeilingSurrounding(sec); + ceiling->direction = 1; + ceiling->speed = CEILSPEED; + break; + + case lowerToLowest: + ceiling->bottomheight = P_FindLowestCeilingSurrounding(sec); + ceiling->direction = -1; + ceiling->speed = CEILSPEED; + break; + + case lowerToMaxFloor: + ceiling->bottomheight = P_FindHighestFloorSurrounding(sec); + ceiling->direction = -1; + ceiling->speed = CEILSPEED; + break; + + default: + break; + } + + // add the ceiling to the active list + ceiling->tag = sec->tag; + ceiling->type = type; + P_AddActiveCeiling(ceiling); + } + return rtn; +} + +////////////////////////////////////////////////////////////////////// +// +// Active ceiling list primitives +// +///////////////////////////////////////////////////////////////////// + +// jff 2/22/98 - modified Lee's plat code to work for ceilings +// +// The following were all rewritten by Lee Killough +// to use the new structure which places no limits +// on active ceilings. It also avoids spending as much +// time searching for active ceilings. Previously a +// fixed-size array was used, with NULL indicating +// empty entries, while now a doubly-linked list +// is used. + +// +// P_ActivateInStasisCeiling() +// +// Reactivates all stopped crushers with the right tag +// +// Passed the line reactivating the crusher +// Returns true if a ceiling reactivated +// +//jff 4/5/98 return if activated +int P_ActivateInStasisCeiling(line_t *line) +{ + ceilinglist_t *cl; + int rtn=0; + + for (cl=activeceilings; cl; cl=cl->next) + { + ceiling_t *ceiling = cl->ceiling; + if (ceiling->tag == line->tag && ceiling->direction == 0) + { + ceiling->direction = ceiling->olddirection; + ceiling->thinker.function = T_MoveCeiling; + //jff 4/5/98 return if activated + rtn=1; + } + } + return rtn; +} + +// +// EV_CeilingCrushStop() +// +// Stops all active ceilings with the right tag +// +// Passed the linedef stopping the ceilings +// Returns true if a ceiling put in stasis +// +int EV_CeilingCrushStop(line_t* line) +{ + int rtn=0; + + ceilinglist_t *cl; + for (cl=activeceilings; cl; cl=cl->next) + { + ceiling_t *ceiling = cl->ceiling; + if (ceiling->direction != 0 && ceiling->tag == line->tag) + { + ceiling->olddirection = ceiling->direction; + ceiling->direction = 0; + ceiling->thinker.function = NULL; + rtn=1; + } + } + return rtn; +} + +// +// P_AddActiveCeiling() +// +// Adds a ceiling to the head of the list of active ceilings +// +// Passed the ceiling motion structure +// Returns nothing +// +void P_AddActiveCeiling(ceiling_t* ceiling) +{ + ceilinglist_t *list = malloc(sizeof *list); + list->ceiling = ceiling; + ceiling->list = list; + if ((list->next = activeceilings)) + list->next->prev = &list->next; + list->prev = &activeceilings; + activeceilings = list; +} + +// +// P_RemoveActiveCeiling() +// +// Removes a ceiling from the list of active ceilings +// +// Passed the ceiling motion structure +// Returns nothing +// +void P_RemoveActiveCeiling(ceiling_t* ceiling) +{ + ceilinglist_t *list = ceiling->list; + ceiling->sector->ceilingdata = NULL; //jff 2/22/98 + P_RemoveThinker(&ceiling->thinker); + if ((*list->prev = list->next)) + list->next->prev = list->prev; + free(list); +} + +// +// P_RemoveAllActiveCeilings() +// +// Removes all ceilings from the active ceiling list +// +// Passed nothing, returns nothing +// +void P_RemoveAllActiveCeilings(void) +{ + while (activeceilings) + { + ceilinglist_t *next = activeceilings->next; + free(activeceilings); + activeceilings = next; + } +} diff --git a/apps/plugins/doom/p_doors.c b/apps/plugins/doom/p_doors.c new file mode 100644 index 0000000000..9d8f28cd7a --- /dev/null +++ b/apps/plugins/doom/p_doors.c @@ -0,0 +1,672 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Door animation code (opening/closing) + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "p_spec.h" +#include "p_tick.h" +#include "s_sound.h" +#include "sounds.h" +#include "r_main.h" +#include "dstrings.h" +//#include "d_deh.h" // Ty 03/27/98 - externalized + +#include "rockmacros.h" + +/////////////////////////////////////////////////////////////// +// +// Door action routines, called once per tick +// +/////////////////////////////////////////////////////////////// + +// +// T_VerticalDoor +// +// Passed a door structure containing all info about the door. +// See P_SPEC.H for fields. +// Returns nothing. +// +// jff 02/08/98 all cases with labels beginning with gen added to support +// generalized line type behaviors. + +void T_VerticalDoor (vldoor_t* door) +{ + result_e res; + + // Is the door waiting, going up, or going down? + switch(door->direction) + { + case 0: + // Door is waiting + if (!--door->topcountdown) // downcount and check + { + switch(door->type) + { + case blazeRaise: + case genBlazeRaise: + door->direction = -1; // time to go back down + S_StartSound((mobj_t *)&door->sector->soundorg,sfx_bdcls); + break; + + case normal: + case genRaise: + door->direction = -1; // time to go back down + S_StartSound((mobj_t *)&door->sector->soundorg,sfx_dorcls); + break; + + case close30ThenOpen: + case genCdO: + door->direction = 1; // time to go back up + S_StartSound((mobj_t *)&door->sector->soundorg,sfx_doropn); + break; + + case genBlazeCdO: + door->direction = 1; // time to go back up + S_StartSound((mobj_t *)&door->sector->soundorg,sfx_bdopn); + break; + + default: + break; + } + } + break; + + case 2: + // Special case for sector type door that opens in 5 mins + if (!--door->topcountdown) // 5 minutes up? + { + switch(door->type) + { + case raiseIn5Mins: + door->direction = 1; // time to raise then + door->type = normal; // door acts just like normal 1 DR door now + S_StartSound((mobj_t *)&door->sector->soundorg,sfx_doropn); + break; + + default: + break; + } + } + break; + + case -1: + // Door is moving down + res = T_MovePlane + ( + door->sector, + door->speed, + door->sector->floorheight, + false, + 1, + door->direction + ); + + /* killough 10/98: implement gradual lighting effects */ + if (door->lighttag && door->topheight - door->sector->floorheight) + EV_LightTurnOnPartway(door->line, + FixedDiv(door->sector->ceilingheight - + door->sector->floorheight, + door->topheight - + door->sector->floorheight)); + + // handle door reaching bottom + if (res == pastdest) + { + switch(door->type) + { + // regular open and close doors are all done, remove them + case blazeRaise: + case blazeClose: + case genBlazeRaise: + case genBlazeClose: + door->sector->ceilingdata = NULL; //jff 2/22/98 + P_RemoveThinker (&door->thinker); // unlink and free + // killough 4/15/98: remove double-closing sound of blazing doors + if (comp[comp_blazing]) + S_StartSound((mobj_t *)&door->sector->soundorg,sfx_bdcls); + break; + + case normal: + case p_close: + case genRaise: + case genClose: + door->sector->ceilingdata = NULL; //jff 2/22/98 + P_RemoveThinker (&door->thinker); // unlink and free + break; + + // close then open doors start waiting + case close30ThenOpen: + door->direction = 0; + door->topcountdown = TICRATE*30; + break; + + case genCdO: + case genBlazeCdO: + door->direction = 0; + door->topcountdown = door->topwait; // jff 5/8/98 insert delay + break; + + default: + break; + } + } + /* jff 1/31/98 turn lighting off in tagged sectors of manual doors + * killough 10/98: replaced with gradual lighting code + */ + else if (res == crushed) // handle door meeting obstruction on way down + { + switch(door->type) + { + case genClose: + case genBlazeClose: + case blazeClose: + case p_close: // Close types do not bounce, merely wait + break; + + case blazeRaise: + case genBlazeRaise: + door->direction = 1; + if (!comp[comp_blazing]) { + S_StartSound((mobj_t *)&door->sector->soundorg,sfx_bdopn); + break; + } + + default: // other types bounce off the obstruction + door->direction = 1; + S_StartSound((mobj_t *)&door->sector->soundorg,sfx_doropn); + break; + } + } + break; + + case 1: + // Door is moving up + res = T_MovePlane + ( + door->sector, + door->speed, + door->topheight, + false, + 1, + door->direction + ); + + /* killough 10/98: implement gradual lighting effects */ + if (door->lighttag && door->topheight - door->sector->floorheight) + EV_LightTurnOnPartway(door->line, + FixedDiv(door->sector->ceilingheight - + door->sector->floorheight, + door->topheight - + door->sector->floorheight)); + + // handle door reaching the top + if (res == pastdest) + { + switch(door->type) + { + case blazeRaise: // regular open/close doors start waiting + case normal: + case genRaise: + case genBlazeRaise: + door->direction = 0; // wait at top with delay + door->topcountdown = door->topwait; + break; + + case close30ThenOpen: // close and close/open doors are done + case blazeOpen: + case p_open: + case genBlazeOpen: + case genOpen: + case genCdO: + case genBlazeCdO: + door->sector->ceilingdata = NULL; //jff 2/22/98 + P_RemoveThinker (&door->thinker); // unlink and free + break; + + default: + break; + } + + /* jff 1/31/98 turn lighting on in tagged sectors of manual doors + * killough 10/98: replaced with gradual lighting code */ + } + break; + } +} + +/////////////////////////////////////////////////////////////// +// +// Door linedef handlers +// +/////////////////////////////////////////////////////////////// + +// +// EV_DoLockedDoor +// +// Handle opening a tagged locked door +// +// Passed the line activating the door, the type of door, +// and the thing that activated the line +// Returns true if a thinker created +// +int EV_DoLockedDoor +( line_t* line, + vldoor_e type, + mobj_t* thing ) +{ + player_t* p; + + // only players can open locked doors + p = thing->player; + if (!p) + return 0; + + // check type of linedef, and if key is possessed to open it + switch(line->special) + { + case 99: // Blue Lock + case 133: + if (!p->cards[it_bluecard] && !p->cards[it_blueskull]) + { + p->message = PD_BLUEO; // Ty 03/27/98 - externalized + S_StartSound(p->mo,sfx_oof); // killough 3/20/98 + return 0; + } + break; + + case 134: // Red Lock + case 135: + if (!p->cards[it_redcard] && !p->cards[it_redskull]) + { + p->message = PD_REDO; // Ty 03/27/98 - externalized + S_StartSound(p->mo,sfx_oof); // killough 3/20/98 + return 0; + } + break; + + case 136: // Yellow Lock + case 137: + if (!p->cards[it_yellowcard] && !p->cards[it_yellowskull]) + { + p->message = PD_YELLOWO; // Ty 03/27/98 - externalized + S_StartSound(p->mo,sfx_oof); // killough 3/20/98 + return 0; + } + break; + } + + // got the key, so open the door + return EV_DoDoor(line,type); +} + + +// +// EV_DoDoor +// +// Handle opening a tagged door +// +// Passed the line activating the door and the type of door +// Returns true if a thinker created +// +int EV_DoDoor +( line_t* line, + vldoor_e type ) +{ + int secnum,rtn; + sector_t* sec; + vldoor_t* door; + + secnum = -1; + rtn = 0; + + // open all doors with the same tag as the activating line + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; + // if the ceiling already moving, don't start the door action + if (P_SectorActive(ceiling_special,sec)) //jff 2/22/98 + continue; + + // new door thinker + rtn = 1; + door = Z_Malloc (sizeof(*door), PU_LEVSPEC, 0); + P_AddThinker (&door->thinker); + sec->ceilingdata = door; //jff 2/22/98 + + door->thinker.function = T_VerticalDoor; + door->sector = sec; + door->type = type; + door->topwait = VDOORWAIT; + door->speed = VDOORSPEED; + door->line = line; // jff 1/31/98 remember line that triggered us + door->lighttag = 0; /* killough 10/98: no light effects with tagged doors */ + + // setup door parameters according to type of door + switch(type) + { + case blazeClose: + door->topheight = P_FindLowestCeilingSurrounding(sec); + door->topheight -= 4*FRACUNIT; + door->direction = -1; + door->speed = VDOORSPEED * 4; + S_StartSound((mobj_t *)&door->sector->soundorg,sfx_bdcls); + break; + + case p_close: + door->topheight = P_FindLowestCeilingSurrounding(sec); + door->topheight -= 4*FRACUNIT; + door->direction = -1; + S_StartSound((mobj_t *)&door->sector->soundorg,sfx_dorcls); + break; + + case close30ThenOpen: + door->topheight = sec->ceilingheight; + door->direction = -1; + S_StartSound((mobj_t *)&door->sector->soundorg,sfx_dorcls); + break; + + case blazeRaise: + case blazeOpen: + door->direction = 1; + door->topheight = P_FindLowestCeilingSurrounding(sec); + door->topheight -= 4*FRACUNIT; + door->speed = VDOORSPEED * 4; + if (door->topheight != sec->ceilingheight) + S_StartSound((mobj_t *)&door->sector->soundorg,sfx_bdopn); + break; + + case normal: + case p_open: + door->direction = 1; + door->topheight = P_FindLowestCeilingSurrounding(sec); + door->topheight -= 4*FRACUNIT; + if (door->topheight != sec->ceilingheight) + S_StartSound((mobj_t *)&door->sector->soundorg,sfx_doropn); + break; + + default: + break; + } + } + return rtn; +} + + +// +// EV_VerticalDoor +// +// Handle opening a door manually, no tag value +// +// Passed the line activating the door and the thing activating it +// Returns true if a thinker created +// +// jff 2/12/98 added int return value, fixed all returns +// +int EV_VerticalDoor +( line_t* line, + mobj_t* thing ) +{ + player_t* player; + int secnum; + sector_t* sec; + vldoor_t* door; + + // Check for locks + player = thing->player; + + switch(line->special) + { + case 26: // Blue Lock + case 32: + if ( !player ) + return 0; + if (!player->cards[it_bluecard] && !player->cards[it_blueskull]) + { + player->message = PD_BLUEK; // Ty 03/27/98 - externalized + S_StartSound(player->mo,sfx_oof); // killough 3/20/98 + return 0; + } + break; + + case 27: // Yellow Lock + case 34: + if ( !player ) + return 0; + if (!player->cards[it_yellowcard] && !player->cards[it_yellowskull]) + { + player->message = PD_YELLOWK; // Ty 03/27/98 - externalized + S_StartSound(player->mo,sfx_oof); // killough 3/20/98 + return 0; + } + break; + + case 28: // Red Lock + case 33: + if ( !player ) + return 0; + if (!player->cards[it_redcard] && !player->cards[it_redskull]) + { + player->message = PD_REDK; // Ty 03/27/98 - externalized + S_StartSound(player->mo,sfx_oof); // killough 3/20/98 + return 0; + } + break; + + default: + break; + } + + // if the wrong side of door is pushed, give oof sound + if (line->sidenum[1]==-1) // killough + { + S_StartSound(player->mo,sfx_oof); // killough 3/20/98 + return 0; + } + + // get the sector on the second side of activating linedef + sec = sides[line->sidenum[1]].sector; + secnum = sec-sectors; + + /* if door already has a thinker, use it + * cph 2001/04/05 - + * Ok, this is a disaster area. We're assuming that sec->ceilingdata + * is a vldoor_t! What if this door is controlled by both DR lines + * and by switches? I don't know how to fix that. + * Secondly, original Doom didn't distinguish floor/lighting/ceiling + * actions, so we need to do the same in demo compatibility mode. + */ + door = sec->ceilingdata; + if (demo_compatibility) { + if (!door) door = sec->floordata; + if (!door) door = sec->lightingdata; + } + if (door) + { + switch(line->special) + { + case 1: // only for "raise" doors, not "open"s + case 26: + case 27: + case 28: + case 117: + if (door->direction == -1) + door->direction = 1; // go back up + else + { + if (!thing->player) + return 0; // JDC: bad guys never close doors + + door->direction = -1; // start going down immediately + } + return 1; + } + } + + // emit proper sound + switch(line->special) + { + case 117: // blazing door raise + case 118: // blazing door open + S_StartSound((mobj_t *)&sec->soundorg,sfx_bdopn); + break; + + case 1: // normal door sound + case 31: + S_StartSound((mobj_t *)&sec->soundorg,sfx_doropn); + break; + + default: // locked door sound + S_StartSound((mobj_t *)&sec->soundorg,sfx_doropn); + break; + } + + // new door thinker + door = Z_Malloc (sizeof(*door), PU_LEVSPEC, 0); + P_AddThinker (&door->thinker); + sec->ceilingdata = door; //jff 2/22/98 + door->thinker.function = T_VerticalDoor; + door->sector = sec; + door->direction = 1; + door->speed = VDOORSPEED; + door->topwait = VDOORWAIT; + door->line = line; // jff 1/31/98 remember line that triggered us + + /* killough 10/98: use gradual lighting changes if nonzero tag given */ + door->lighttag = comp[comp_doorlight] ? 0 : line->tag; + + // set the type of door from the activating linedef type + switch(line->special) + { + case 1: + case 26: + case 27: + case 28: + door->type = normal; + break; + + case 31: + case 32: + case 33: + case 34: + door->type = p_open; + line->special = 0; + break; + + case 117: // blazing door raise + door->type = blazeRaise; + door->speed = VDOORSPEED*4; + break; + case 118: // blazing door open + door->type = blazeOpen; + line->special = 0; + door->speed = VDOORSPEED*4; + break; + + default: + door->lighttag = 0; // killough 10/98 + break; + } + + // find the top and bottom of the movement range + door->topheight = P_FindLowestCeilingSurrounding(sec); + door->topheight -= 4*FRACUNIT; + return 1; +} + + +/////////////////////////////////////////////////////////////// +// +// Sector type door spawners +// +/////////////////////////////////////////////////////////////// + +// +// P_SpawnDoorCloseIn30() +// +// Spawn a door that closes after 30 seconds (called at level init) +// +// Passed the sector of the door, whose type specified the door action +// Returns nothing +// +void P_SpawnDoorCloseIn30 (sector_t* sec) +{ + vldoor_t* door; + + door = Z_Malloc ( sizeof(*door), PU_LEVSPEC, 0); + + P_AddThinker (&door->thinker); + + sec->ceilingdata = door; //jff 2/22/98 + sec->special = 0; + + door->thinker.function = T_VerticalDoor; + door->sector = sec; + door->direction = 0; + door->type = normal; + door->speed = VDOORSPEED; + door->topcountdown = 30 * 35; + door->line = NULL; // jff 1/31/98 remember line that triggered us + door->lighttag = 0; /* killough 10/98: no lighting changes */ +} + +// +// P_SpawnDoorRaiseIn5Mins() +// +// Spawn a door that opens after 5 minutes (called at level init) +// +// Passed the sector of the door, whose type specified the door action +// Returns nothing +// +void P_SpawnDoorRaiseIn5Mins +( sector_t* sec, + int secnum ) +{ + (void)secnum; + vldoor_t* door; + + door = Z_Malloc ( sizeof(*door), PU_LEVSPEC, 0); + + P_AddThinker (&door->thinker); + + sec->ceilingdata = door; //jff 2/22/98 + sec->special = 0; + + door->thinker.function = T_VerticalDoor; + door->sector = sec; + door->direction = 2; + door->type = raiseIn5Mins; + door->speed = VDOORSPEED; + door->topheight = P_FindLowestCeilingSurrounding(sec); + door->topheight -= 4*FRACUNIT; + door->topwait = VDOORWAIT; + door->topcountdown = 5 * 60 * 35; + door->line = NULL; // jff 1/31/98 remember line that triggered us + door->lighttag = 0; /* killough 10/98: no lighting changes */ +} diff --git a/apps/plugins/doom/p_enemy.c b/apps/plugins/doom/p_enemy.c new file mode 100644 index 0000000000..b1f40bc5b8 --- /dev/null +++ b/apps/plugins/doom/p_enemy.c @@ -0,0 +1,2623 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Enemy thinking, AI. + * Action Pointer Functions + * that are associated with states/frames. + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "m_random.h" +#include "r_main.h" +#include "p_maputl.h" +#include "p_map.h" +#include "p_setup.h" +#include "p_spec.h" +#include "s_sound.h" +#include "sounds.h" +#include "p_inter.h" +#include "g_game.h" +#include "p_enemy.h" +#include "p_tick.h" +#include "m_bbox.h" + +#include "rockmacros.h" + +static mobj_t *current_actor; + +typedef enum { + DI_EAST, + DI_NORTHEAST, + DI_NORTH, + DI_NORTHWEST, + DI_WEST, + DI_SOUTHWEST, + DI_SOUTH, + DI_SOUTHEAST, + DI_NODIR, + NUMDIRS +} dirtype_t; + +void A_Fall(mobj_t *actor); +void A_FaceTarget(mobj_t *actor); +static void P_NewChaseDir(mobj_t *actor); +void P_ZBumpCheck(mobj_t *); // phares + +// +// ENEMY THINKING +// Enemies are allways spawned +// with targetplayer = -1, threshold = 0 +// Most monsters are spawned unaware of all players, +// but some can be made preaware +// + +// +// Called by P_NoiseAlert. +// Recursively traverse adjacent sectors, +// sound blocking lines cut off traversal. +// +// killough 5/5/98: reformatted, cleaned up + +static void P_RecursiveSound(sector_t *sec, int soundblocks, + mobj_t *soundtarget) +{ + int i; + + // wake up all monsters in this sector + if (sec->validcount == validcount && sec->soundtraversed <= soundblocks+1) + return; // already flooded + + sec->validcount = validcount; + sec->soundtraversed = soundblocks+1; + P_SetTarget(&sec->soundtarget, soundtarget); + + for (i=0; ilinecount; i++) + { + sector_t *other; + line_t *check = sec->lines[i]; + + if (!(check->flags & ML_TWOSIDED)) + continue; + + P_LineOpening(check); + + if (openrange <= 0) + continue; // closed door + + other=sides[check->sidenum[sides[check->sidenum[0]].sector==sec]].sector; + + if (!(check->flags & ML_SOUNDBLOCK)) + P_RecursiveSound(other, soundblocks, soundtarget); + else + if (!soundblocks) + P_RecursiveSound(other, 1, soundtarget); + } +} + +// +// P_NoiseAlert +// If a monster yells at a player, +// it will alert other monsters to the player. +// +void P_NoiseAlert(mobj_t *target, mobj_t *emitter) +{ + validcount++; + P_RecursiveSound(emitter->subsector->sector, 0, target); +} + +// +// P_CheckMeleeRange +// + +static boolean P_CheckMeleeRange(mobj_t *actor) +{ + mobj_t *pl = actor->target; + + return // killough 7/18/98: friendly monsters don't attack other friends + pl && !(actor->flags & pl->flags & MF_FRIEND) && + (P_AproxDistance(pl->x-actor->x, pl->y-actor->y) < + MELEERANGE - 20*FRACUNIT + pl->info->radius) && + P_CheckSight(actor, actor->target); +} + +// +// P_HitFriend() +// +// killough 12/98 +// This function tries to prevent shooting at friends + +static boolean P_HitFriend(mobj_t *actor) +{ + return actor->flags & MF_FRIEND && actor->target && + (P_AimLineAttack(actor, + R_PointToAngle2(actor->x, actor->y, + actor->target->x, actor->target->y), + P_AproxDistance(actor->x-actor->target->x, + actor->y-actor->target->y), 0), + linetarget) && linetarget != actor->target && + !((linetarget->flags ^ actor->flags) & MF_FRIEND); +} + +// +// P_CheckMissileRange +// +boolean P_CheckMissileRange(mobj_t *actor) +{ + fixed_t dist; + + if (!P_CheckSight(actor, actor->target)) + return false; + + if (actor->flags & MF_JUSTHIT) + { // the target just hit the enemy, so fight back! + actor->flags &= ~MF_JUSTHIT; + + /* killough 7/18/98: no friendly fire at corpses + * killough 11/98: prevent too much infighting among friends + * cph - yikes, talk about fitting everything on one line... */ + + return + !(actor->flags & MF_FRIEND) || + (actor->target->health > 0 && + (!(actor->target->flags & MF_FRIEND) || + (actor->target->player ? + monster_infighting || P_Random(pr_defect) >128 : + !(actor->target->flags & MF_JUSTHIT) && P_Random(pr_defect) >128))); + } + + /* killough 7/18/98: friendly monsters don't attack other friendly + * monsters or players (except when attacked, and then only once) + */ + if (actor->flags & actor->target->flags & MF_FRIEND) + return false; + + if (actor->reactiontime) + return false; // do not attack yet + + // OPTIMIZE: get this from a global checksight + dist = P_AproxDistance ( actor->x-actor->target->x, + actor->y-actor->target->y) - 64*FRACUNIT; + + if (!actor->info->meleestate) + dist -= 128*FRACUNIT; // no melee attack, so fire more + + dist >>= FRACBITS; + + if (actor->type == MT_VILE) + if (dist > 14*64) + return false; // too far away + + + if (actor->type == MT_UNDEAD) + { + if (dist < 196) + return false; // close for fist attack + dist >>= 1; + } + + if (actor->type == MT_CYBORG || + actor->type == MT_SPIDER || + actor->type == MT_SKULL) + dist >>= 1; + + if (dist > 200) + dist = 200; + + if (actor->type == MT_CYBORG && dist > 160) + dist = 160; + + if (P_Random(pr_missrange) < dist) + return false; + + if (P_HitFriend(actor)) + return false; + + return true; +} + +/* + * P_IsOnLift + * + * killough 9/9/98: + * + * Returns true if the object is on a lift. Used for AI, + * since it may indicate the need for crowded conditions, + * or that a monster should stay on the lift for a while + * while it goes up or down. + */ + +static boolean P_IsOnLift(const mobj_t *actor) +{ + const sector_t *sec = actor->subsector->sector; + line_t line; + int l; + + // Short-circuit: it's on a lift which is active. + if (sec->floordata && ((thinker_t *) sec->floordata)->function==T_PlatRaise) + return true; + + // Check to see if it's in a sector which can be activated as a lift. + if ((line.tag = sec->tag)) + for (l = -1; (l = P_FindLineFromLineTag(&line, l)) >= 0;) + switch (lines[l].special) + { +case 10: case 14: case 15: case 20: case 21: case 22: +case 47: case 53: case 62: case 66: case 67: case 68: +case 87: case 88: case 95: case 120: case 121: case 122: +case 123: case 143: case 162: case 163: case 181: case 182: +case 144: case 148: case 149: case 211: case 227: case 228: +case 231: case 232: case 235: case 236: + return true; + } + + return false; +} + +/* + * P_IsUnderDamage + * + * killough 9/9/98: + * + * Returns nonzero if the object is under damage based on + * their current position. Returns 1 if the damage is moderate, + * -1 if it is serious. Used for AI. + */ + +static int P_IsUnderDamage(mobj_t *actor) +{ + const struct msecnode_s *seclist; + const ceiling_t *cl; // Crushing ceiling + int dir = 0; + for (seclist=actor->touching_sectorlist; seclist; seclist=seclist->m_tnext) + if ((cl = seclist->m_sector->ceilingdata) && + cl->thinker.function == T_MoveCeiling) + dir |= cl->direction; + return dir; +} + +// +// P_Move +// Move in the current direction, +// returns false if the move is blocked. +// + +static fixed_t xspeed[8] = {FRACUNIT,47000,0,-47000,-FRACUNIT,-47000,0,47000}; +static fixed_t yspeed[8] = {0,47000,FRACUNIT,47000,0,-47000,-FRACUNIT,-47000}; + +// 1/11/98 killough: Limit removed on special lines crossed +extern line_t **spechit; // New code -- killough +extern int numspechit; + +static boolean P_Move(mobj_t *actor, boolean dropoff) /* killough 9/12/98 */ +{ + fixed_t tryx, tryy, deltax, deltay, origx, origy; + boolean try_ok; + int movefactor = ORIG_FRICTION_FACTOR; // killough 10/98 + int friction = ORIG_FRICTION; + int speed; + + if (actor->movedir == DI_NODIR) + return false; + +#ifdef RANGECHECK + if ((unsigned)actor->movedir >= 8) + I_Error ("P_Move: Weird actor->movedir!"); +#endif + + // killough 10/98: make monsters get affected by ice and sludge too: + + if (monster_friction) + movefactor = P_GetMoveFactor(actor, &friction); + + speed = actor->info->speed; + + if (friction < ORIG_FRICTION && // sludge + !(speed = ((ORIG_FRICTION_FACTOR - (ORIG_FRICTION_FACTOR-movefactor)/2) + * speed) / ORIG_FRICTION_FACTOR)) + speed = 1; // always give the monster a little bit of speed + + tryx = (origx = actor->x) + (deltax = speed * xspeed[actor->movedir]); + tryy = (origy = actor->y) + (deltay = speed * yspeed[actor->movedir]); + + try_ok = P_TryMove(actor, tryx, tryy, dropoff); + + // killough 10/98: + // Let normal momentum carry them, instead of steptoeing them across ice. + + if (try_ok && friction > ORIG_FRICTION) + { + actor->x = origx; + actor->y = origy; + movefactor *= FRACUNIT / ORIG_FRICTION_FACTOR / 4; + actor->momx += FixedMul(deltax, movefactor); + actor->momy += FixedMul(deltay, movefactor); + } + + if (!try_ok) + { // open any specials + int good; + + if (actor->flags & MF_FLOAT && floatok) + { + if (actor->z < tmfloorz) // must adjust height + actor->z += FLOATSPEED; + else + actor->z -= FLOATSPEED; + + actor->flags |= MF_INFLOAT; + + return true; + } + + if (!numspechit) + return false; + + actor->movedir = DI_NODIR; + + /* if the special is not a door that can be opened, return false + * + * killough 8/9/98: this is what caused monsters to get stuck in + * doortracks, because it thought that the monster freed itself + * by opening a door, even if it was moving towards the doortrack, + * and not the door itself. + * + * killough 9/9/98: If a line blocking the monster is activated, + * return true 90% of the time. If a line blocking the monster is + * not activated, but some other line is, return false 90% of the + * time. A bit of randomness is needed to ensure it's free from + * lockups, but for most cases, it returns the correct result. + * + * Do NOT simply return false 1/4th of the time (causes monsters to + * back out when they shouldn't, and creates secondary stickiness). + */ + + for (good = false; numspechit--; ) + if (P_UseSpecialLine(actor, spechit[numspechit], 0)) + good |= spechit[numspechit] == blockline ? 1 : 2; + + /* cph - compatibility maze here + * Boom v2.01 and orig. Doom return "good" + * Boom v2.02 and LxDoom return good && (P_Random(pr_trywalk)&3) + * MBF plays even more games + */ + if (!good || comp[comp_doorstuck]) return good; + if (!mbf_features) + return (P_Random(pr_trywalk)&3); /* jff 8/13/98 */ + else /* finally, MBF code */ + return ((P_Random(pr_opendoor) >= 230) ^ (good & 1)); + } + else + actor->flags &= ~MF_INFLOAT; + + /* killough 11/98: fall more slowly, under gravity, if felldown==true */ + if (!(actor->flags & MF_FLOAT) && + (!felldown || !mbf_features)) + actor->z = actor->floorz; + + return true; +} + +/* + * P_SmartMove + * + * killough 9/12/98: Same as P_Move, except smarter + */ + +static boolean P_SmartMove(mobj_t *actor) +{ + mobj_t *target = actor->target; + int on_lift, dropoff = false, under_damage; + + /* killough 9/12/98: Stay on a lift if target is on one */ + on_lift = !comp[comp_staylift] + && target && target->health > 0 + && target->subsector->sector->tag==actor->subsector->sector->tag && + P_IsOnLift(actor); + + under_damage = monster_avoid_hazards && P_IsUnderDamage(actor); + + // killough 10/98: allow dogs to drop off of taller ledges sometimes. + // dropoff==1 means always allow it, dropoff==2 means only up to 128 high, + // and only if the target is immediately on the other side of the line. + +#ifdef DOGS + if (actor->type == MT_DOGS && target && dog_jumping && + !((target->flags ^ actor->flags) & MF_FRIEND) && + P_AproxDistance(actor->x - target->x, + actor->y - target->y) < FRACUNIT*144 && + P_Random(pr_dropoff) < 235) + dropoff = 2; +#endif + + if (!P_Move(actor, dropoff)) + return false; + + // killough 9/9/98: avoid crushing ceilings or other damaging areas + if ( + (on_lift && P_Random(pr_stayonlift) < 230 && // Stay on lift + !P_IsOnLift(actor)) + || + (monster_avoid_hazards && !under_damage && // Get away from damage + (under_damage = P_IsUnderDamage(actor)) && + (under_damage < 0 || P_Random(pr_avoidcrush) < 200)) + ) + actor->movedir = DI_NODIR; // avoid the area (most of the time anyway) + + return true; +} + +// +// TryWalk +// Attempts to move actor on +// in its current (ob->moveangle) 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... +// If a door is in the way, +// an OpenDoor call is made to start it opening. +// + +boolean P_TryWalk(mobj_t *actor) +{ + if (!P_SmartMove(actor)) + return false; + actor->movecount = P_Random(pr_trywalk)&15; + return true; +} + +// +// P_DoNewChaseDir +// +// killough 9/8/98: +// +// Most of P_NewChaseDir(), except for what +// determines the new direction to take +// + +static void P_DoNewChaseDir(mobj_t *actor, fixed_t deltax, fixed_t deltay) +{ + dirtype_t xdir, ydir, tdir; + dirtype_t olddir = actor->movedir; + dirtype_t turnaround = olddir; + + if (turnaround != DI_NODIR) // find reverse direction + turnaround ^= 4; + + xdir = + deltax > 10*FRACUNIT ? DI_EAST : + deltax < -10*FRACUNIT ? DI_WEST : DI_NODIR; + + ydir = + deltay < -10*FRACUNIT ? DI_SOUTH : + deltay > 10*FRACUNIT ? DI_NORTH : DI_NODIR; + + // try direct route + if (xdir != DI_NODIR && ydir != DI_NODIR && turnaround != + (actor->movedir = deltay < 0 ? deltax > 0 ? DI_SOUTHEAST : DI_SOUTHWEST : + deltax > 0 ? DI_NORTHEAST : DI_NORTHWEST) && P_TryWalk(actor)) + return; + + // try other directions + if (P_Random(pr_newchase) > 200 || abs(deltay)>abs(deltax)) + tdir = xdir, xdir = ydir, ydir = tdir; + + if ((xdir == turnaround ? xdir = DI_NODIR : xdir) != DI_NODIR && + (actor->movedir = xdir, P_TryWalk(actor))) + return; // either moved forward or attacked + + if ((ydir == turnaround ? ydir = DI_NODIR : ydir) != DI_NODIR && + (actor->movedir = ydir, P_TryWalk(actor))) + return; + + // there is no direct path to the player, so pick another direction. + if (olddir != DI_NODIR && (actor->movedir = olddir, P_TryWalk(actor))) + return; + + // randomly determine direction of search + if (P_Random(pr_newchasedir) & 1) + { + for (tdir = DI_EAST; tdir <= DI_SOUTHEAST; tdir++) + if (tdir != turnaround && (actor->movedir = tdir, P_TryWalk(actor))) + return; + } + else + for (tdir = DI_SOUTHEAST; tdir != (unsigned)(DI_EAST-1); tdir--) + if (tdir != turnaround && (actor->movedir = tdir, P_TryWalk(actor))) + return; + + if ((actor->movedir = turnaround) != DI_NODIR && !P_TryWalk(actor)) + actor->movedir = DI_NODIR; +} + +// +// killough 11/98: +// +// Monsters try to move away from tall dropoffs. +// +// In Doom, they were never allowed to hang over dropoffs, +// and would remain stuck if involuntarily forced over one. +// This logic, combined with p_map.c (P_TryMove), allows +// monsters to free themselves without making them tend to +// hang over dropoffs. + +static fixed_t dropoff_deltax, dropoff_deltay, floorz; + +static boolean PIT_AvoidDropoff(line_t *line) +{ + if (line->backsector && // Ignore one-sided linedefs + tmbbox[BOXRIGHT] > line->bbox[BOXLEFT] && + tmbbox[BOXLEFT] < line->bbox[BOXRIGHT] && + tmbbox[BOXTOP] > line->bbox[BOXBOTTOM] && // Linedef must be contacted + tmbbox[BOXBOTTOM] < line->bbox[BOXTOP] && + P_BoxOnLineSide(tmbbox, line) == -1) + { + fixed_t front = line->frontsector->floorheight; + fixed_t back = line->backsector->floorheight; + angle_t angle; + + // The monster must contact one of the two floors, + // and the other must be a tall dropoff (more than 24). + + if (back == floorz && front < floorz - FRACUNIT*24) + angle = R_PointToAngle2(0,0,line->dx,line->dy); // front side dropoff + else + if (front == floorz && back < floorz - FRACUNIT*24) + angle = R_PointToAngle2(line->dx,line->dy,0,0); // back side dropoff + else + return true; + + // Move away from dropoff at a standard speed. + // Multiple contacted linedefs are cumulative (e.g. hanging over corner) + dropoff_deltax -= finesine[angle >> ANGLETOFINESHIFT]*32; + dropoff_deltay += finecosine[angle >> ANGLETOFINESHIFT]*32; + } + return true; +} + +// +// Driver for above +// + +static fixed_t P_AvoidDropoff(mobj_t *actor) +{ + int yh=((tmbbox[BOXTOP] = actor->y+actor->radius)-bmaporgy)>>MAPBLOCKSHIFT; + int yl=((tmbbox[BOXBOTTOM]= actor->y-actor->radius)-bmaporgy)>>MAPBLOCKSHIFT; + int xh=((tmbbox[BOXRIGHT] = actor->x+actor->radius)-bmaporgx)>>MAPBLOCKSHIFT; + int xl=((tmbbox[BOXLEFT] = actor->x-actor->radius)-bmaporgx)>>MAPBLOCKSHIFT; + int bx, by; + + floorz = actor->z; // remember floor height + + dropoff_deltax = dropoff_deltay = 0; + + // check lines + + validcount++; + for (bx=xl ; bx<=xh ; bx++) + for (by=yl ; by<=yh ; by++) + P_BlockLinesIterator(bx, by, PIT_AvoidDropoff); // all contacted lines + + return dropoff_deltax | dropoff_deltay; // Non-zero if movement prescribed +} + +// +// P_NewChaseDir +// +// killough 9/8/98: Split into two functions +// + +static void P_NewChaseDir(mobj_t *actor) +{ + mobj_t *target = actor->target; + fixed_t deltax = target->x - actor->x; + fixed_t deltay = target->y - actor->y; + + // killough 8/8/98: sometimes move away from target, keeping distance + // + // 1) Stay a certain distance away from a friend, to avoid being in their way + // 2) Take advantage over an enemy without missiles, by keeping distance + + actor->strafecount = 0; + + if (mbf_features) { + if (actor->floorz - actor->dropoffz > FRACUNIT*24 && + actor->z <= actor->floorz && + !(actor->flags & (MF_DROPOFF|MF_FLOAT)) && + !comp[comp_dropoff] && + P_AvoidDropoff(actor)) /* Move away from dropoff */ + { + P_DoNewChaseDir(actor, dropoff_deltax, dropoff_deltay); + + // If moving away from dropoff, set movecount to 1 so that + // small steps are taken to get monster away from dropoff. + + actor->movecount = 1; + return; + } + else + { + fixed_t dist = P_AproxDistance(deltax, deltay); + + // Move away from friends when too close, except + // in certain situations (e.g. a crowded lift) + + if (actor->flags & target->flags & MF_FRIEND && + distfriend << FRACBITS > dist && + !P_IsOnLift(target) && !P_IsUnderDamage(actor)) + { + deltax = -deltax, deltay = -deltay; + } else + if (target->health > 0 && (actor->flags ^ target->flags) & MF_FRIEND) + { // Live enemy target + if (monster_backing && + actor->info->missilestate && actor->type != MT_SKULL && + ((!target->info->missilestate && dist < MELEERANGE*2) || + (target->player && dist < MELEERANGE*3 && + (target->player->readyweapon == wp_fist || + target->player->readyweapon == wp_chainsaw)))) + { // Back away from melee attacker + actor->strafecount = P_Random(pr_enemystrafe) & 15; + deltax = -deltax, deltay = -deltay; + } + } + } + } + + P_DoNewChaseDir(actor, deltax, deltay); + + // If strafing, set movecount to strafecount so that old Doom + // logic still works the same, except in the strafing part + + if (actor->strafecount) + actor->movecount = actor->strafecount; +} + +// +// P_IsVisible +// +// killough 9/9/98: whether a target is visible to a monster +// + +static boolean P_IsVisible(mobj_t *actor, mobj_t *mo, boolean allaround) +{ + if (!allaround) + { + angle_t an = R_PointToAngle2(actor->x, actor->y, + mo->x, mo->y) - actor->angle; + if (an > ANG90 && an < ANG270 && + P_AproxDistance(mo->x-actor->x, mo->y-actor->y) > MELEERANGE) + return false; + } + return P_CheckSight(actor, mo); +} + +// +// PIT_FindTarget +// +// killough 9/5/98 +// +// Finds monster targets for other monsters +// + +static int current_allaround; + +static boolean PIT_FindTarget(mobj_t *mo) +{ + mobj_t *actor = current_actor; + + if (!((mo->flags ^ actor->flags) & MF_FRIEND && // Invalid target + mo->health > 0 && (mo->flags & MF_COUNTKILL || mo->type == MT_SKULL))) + return true; + + // If the monster is already engaged in a one-on-one attack + // with a healthy friend, don't attack around 60% the time + { + const mobj_t *targ = mo->target; + if (targ && targ->target == mo && + P_Random(pr_skiptarget) > 100 && + (targ->flags ^ mo->flags) & MF_FRIEND && + targ->health*2 >= targ->info->spawnhealth) + return true; + } + + if (!P_IsVisible(actor, mo, current_allaround)) + return true; + + P_SetTarget(&actor->lastenemy, actor->target); // Remember previous target + P_SetTarget(&actor->target, mo); // Found target + + // Move the selected monster to the end of its associated + // list, so that it gets searched last next time. + + { + thinker_t *cap = &thinkerclasscap[mo->flags & MF_FRIEND ? + th_friends : th_enemies]; + (mo->thinker.cprev->cnext = mo->thinker.cnext)->cprev = mo->thinker.cprev; + (mo->thinker.cprev = cap->cprev)->cnext = &mo->thinker; + (mo->thinker.cnext = cap)->cprev = &mo->thinker; + } + + return false; +} + +// +// P_LookForPlayers +// If allaround is false, only look 180 degrees in front. +// Returns true if a player is targeted. +// + +static boolean P_LookForPlayers(mobj_t *actor, boolean allaround) +{ + player_t *player; + int stop, stopc, c; + + if (actor->flags & MF_FRIEND) + { // killough 9/9/98: friendly monsters go about players differently + int anyone; + +#if 0 + if (!allaround) // If you want friendly monsters not to awaken unprovoked + return false; +#endif + + // Go back to a player, no matter whether it's visible or not + for (anyone=0; anyone<=1; anyone++) + for (c=0; ctarget, players[c].mo); + + // killough 12/98: + // get out of refiring loop, to avoid hitting player accidentally + + if (actor->info->missilestate) + { + P_SetMobjState(actor, actor->info->seestate); + actor->flags &= ~MF_JUSTHIT; + } + + return true; + } + + return false; + } + + // Change mask of 3 to (MAXPLAYERS-1) -- killough 2/15/98: + stop = (actor->lastlook-1)&(MAXPLAYERS-1); + + c = 0; + + stopc = !mbf_features && + !demo_compatibility && monsters_remember ? + MAXPLAYERS : 2; // killough 9/9/98 + + for (;; actor->lastlook = (actor->lastlook+1)&(MAXPLAYERS-1)) + { + if (!playeringame[actor->lastlook]) + continue; + + // killough 2/15/98, 9/9/98: + if (c++ == stopc || actor->lastlook == stop) // done looking + return false; + + player = &players[actor->lastlook]; + + if (player->health <= 0) + continue; // dead + + if (!P_IsVisible(actor, player->mo, allaround)) + continue; + + P_SetTarget(&actor->target, player->mo); + + /* killough 9/9/98: give monsters a threshold towards getting players + * (we don't want it to be too easy for a player with dogs :) + */ + if (!comp[comp_pursuit]) + actor->threshold = 60; + + return true; + } +} + +// +// Friendly monsters, by Lee Killough 7/18/98 +// +// Friendly monsters go after other monsters first, but +// also return to owner if they cannot find any targets. +// A marine's best friend :) killough 7/18/98, 9/98 +// + +static boolean P_LookForMonsters(mobj_t *actor, boolean allaround) +{ + thinker_t *cap, *th; + + if (demo_compatibility) + return false; + + if (actor->lastenemy && actor->lastenemy->health > 0 && monsters_remember && + !(actor->lastenemy->flags & actor->flags & MF_FRIEND)) // not friends + { + P_SetTarget(&actor->target, actor->lastenemy); + P_SetTarget(&actor->lastenemy, NULL); + return true; + } + + /* Old demos do not support monster-seeking bots */ + if (!mbf_features) + return false; + + // Search the threaded list corresponding to this object's potential targets + cap = &thinkerclasscap[actor->flags & MF_FRIEND ? th_enemies : th_friends]; + + // Search for new enemy + + if (cap->cnext != cap) // Empty list? bail out early + { + int x = (actor->x - bmaporgx)>>MAPBLOCKSHIFT; + int y = (actor->y - bmaporgy)>>MAPBLOCKSHIFT; + int d; + + current_actor = actor; + current_allaround = allaround; + + // Search first in the immediate vicinity. + + if (!P_BlockThingsIterator(x, y, PIT_FindTarget)) + return true; + + for (d=1; d<5; d++) + { + int i = 1 - d; + do + if (!P_BlockThingsIterator(x+i, y-d, PIT_FindTarget) || + !P_BlockThingsIterator(x+i, y+d, PIT_FindTarget)) + return true; + while (++i < d); + do + if (!P_BlockThingsIterator(x-d, y+i, PIT_FindTarget) || + !P_BlockThingsIterator(x+d, y+i, PIT_FindTarget)) + return true; + while (--i + d >= 0); + } + + { // Random number of monsters, to prevent patterns from forming + int n = (P_Random(pr_friends) & 31) + 15; + + for (th = cap->cnext; th != cap; th = th->cnext) + if (--n < 0) + { + // Only a subset of the monsters were searched. Move all of + // the ones which were searched so far, to the end of the list. + + (cap->cnext->cprev = cap->cprev)->cnext = cap->cnext; + (cap->cprev = th->cprev)->cnext = cap; + (th->cprev = cap)->cnext = th; + break; + } + else + if (!PIT_FindTarget((mobj_t *) th)) // If target sighted + return true; + } + } + + return false; // No monster found +} + +// +// P_LookForTargets +// +// killough 9/5/98: look for targets to go after, depending on kind of monster +// + +static boolean P_LookForTargets(mobj_t *actor, int allaround) +{ + return actor->flags & MF_FRIEND ? + P_LookForMonsters(actor, allaround) || P_LookForPlayers (actor, allaround): + P_LookForPlayers (actor, allaround) || P_LookForMonsters(actor, allaround); +} + +// +// P_HelpFriend +// +// killough 9/8/98: Help friends in danger of dying +// + +static boolean P_HelpFriend(mobj_t *actor) +{ + thinker_t *cap, *th; + + // If less than 33% health, self-preservation rules + if (actor->health*3 < actor->info->spawnhealth) + return false; + + current_actor = actor; + current_allaround = true; + + // Possibly help a friend under 50% health + cap = &thinkerclasscap[actor->flags & MF_FRIEND ? th_friends : th_enemies]; + + for (th = cap->cnext; th != cap; th = th->cnext) + if (((mobj_t *) th)->health*2 >= ((mobj_t *) th)->info->spawnhealth) + { + if (P_Random(pr_helpfriend) < 180) + break; + } + else + if (((mobj_t *) th)->flags & MF_JUSTHIT && + ((mobj_t *) th)->target && + ((mobj_t *) th)->target != actor->target && + !PIT_FindTarget(((mobj_t *) th)->target)) + { + // Ignore any attacking monsters, while searching for friend + actor->threshold = BASETHRESHOLD; + return true; + } + + return false; +} + +// +// A_KeenDie +// DOOM II special, map 32. +// Uses special tag 666. +// +void A_KeenDie(mobj_t* mo) +{ + thinker_t *th; + line_t junk; + + A_Fall(mo); + + // scan the remaining thinkers to see if all Keens are dead + + for (th = thinkercap.next ; th != &thinkercap ; th=th->next) + if (th->function == P_MobjThinker) + { + mobj_t *mo2 = (mobj_t *) th; + if (mo2 != mo && mo2->type == mo->type && mo2->health > 0) + return; // other Keen not dead + } + + junk.tag = 666; + EV_DoDoor(&junk,p_open); +} + + +// +// ACTION ROUTINES +// + +// +// A_Look +// Stay in state until a player is sighted. +// + +void A_Look(mobj_t *actor) +{ + mobj_t *targ = actor->subsector->sector->soundtarget; + actor->threshold = 0; // any shot will wake up + + /* killough 7/18/98: + * Friendly monsters go after other monsters first, but + * also return to player, without attacking them, if they + * cannot find any targets. A marine's best friend :) + */ + actor->pursuecount = 0; + + if (!(actor->flags & MF_FRIEND && P_LookForTargets(actor, false)) && + !((targ = actor->subsector->sector->soundtarget) && + targ->flags & MF_SHOOTABLE && + (P_SetTarget(&actor->target, targ), + !(actor->flags & MF_AMBUSH) || P_CheckSight(actor, targ))) && + (actor->flags & MF_FRIEND || !P_LookForTargets(actor, false))) + return; + + // go into chase state + + if (actor->info->seesound) + { + int sound; + switch (actor->info->seesound) + { + case sfx_posit1: + case sfx_posit2: + case sfx_posit3: + sound = sfx_posit1+P_Random(pr_see)%3; + break; + + case sfx_bgsit1: + case sfx_bgsit2: + sound = sfx_bgsit1+P_Random(pr_see)%2; + break; + + default: + sound = actor->info->seesound; + break; + } + if (actor->type==MT_SPIDER || actor->type == MT_CYBORG) + S_StartSound(NULL, sound); // full volume + else + S_StartSound(actor, sound); + } + P_SetMobjState(actor, actor->info->seestate); +} + +// +// A_KeepChasing +// +// killough 10/98: +// Allows monsters to continue movement while attacking +// + +void A_KeepChasing(mobj_t *actor) +{ + if (actor->movecount) + { + actor->movecount--; + if (actor->strafecount) + actor->strafecount--; + P_SmartMove(actor); + } +} + +// +// A_Chase +// Actor has a melee attack, +// so it tries to close as fast as possible +// + +void A_Chase(mobj_t *actor) +{ + if (actor->reactiontime) + actor->reactiontime--; + + if (actor->threshold) { /* modify target threshold */ + if (!actor->target || actor->target->health <= 0) + actor->threshold = 0; + else + actor->threshold--; + } + + /* turn towards movement direction if not there yet + * killough 9/7/98: keep facing towards target if strafing or backing out + */ + + if (actor->strafecount) + A_FaceTarget(actor); + else if (actor->movedir < 8) + { + int delta = (actor->angle &= (7<<29)) - (actor->movedir << 29); + if (delta > 0) + actor->angle -= ANG90/2; + else + if (delta < 0) + actor->angle += ANG90/2; + } + + if (!actor->target || !(actor->target->flags&MF_SHOOTABLE)) + { + if (!P_LookForTargets(actor,true)) // look for a new target + P_SetMobjState(actor, actor->info->spawnstate); // no new target + return; + } + + // do not attack twice in a row + if (actor->flags & MF_JUSTATTACKED) + { + actor->flags &= ~MF_JUSTATTACKED; + if (gameskill != sk_nightmare && !fastparm) + P_NewChaseDir(actor); + return; + } + + // check for melee attack + if (actor->info->meleestate && P_CheckMeleeRange(actor)) + { + if (actor->info->attacksound) + S_StartSound(actor, actor->info->attacksound); + P_SetMobjState(actor, actor->info->meleestate); + /* killough 8/98: remember an attack + * cph - DEMOSYNC? */ + if (!actor->info->missilestate) + actor->flags |= MF_JUSTHIT; + return; + } + + // check for missile attack + if (actor->info->missilestate) + if (!(gameskill < sk_nightmare && !fastparm && actor->movecount)) + if (P_CheckMissileRange(actor)) + { + P_SetMobjState(actor, actor->info->missilestate); + actor->flags |= MF_JUSTATTACKED; + return; + } + + if (!actor->threshold) { + if (!mbf_features) + { /* killough 9/9/98: for backward demo compatibility */ + if (netgame && !P_CheckSight(actor, actor->target) && + P_LookForPlayers(actor, true)) + return; + } + /* killough 7/18/98, 9/9/98: new monster AI */ + else if (help_friends && P_HelpFriend(actor)) + return; /* killough 9/8/98: Help friends in need */ + /* Look for new targets if current one is bad or is out of view */ + else if (actor->pursuecount) + actor->pursuecount--; + else { + /* Our pursuit time has expired. We're going to think about + * changing targets */ + actor->pursuecount = BASETHRESHOLD; + + /* Unless (we have a live target + * and it's not friendly + * and we can see it) + * try to find a new one; return if sucessful */ + + if (!(actor->target && actor->target->health > 0 && + ((comp[comp_pursuit] && !netgame) || + (((actor->target->flags ^ actor->flags) & MF_FRIEND || + (!(actor->flags & MF_FRIEND) && monster_infighting)) && + P_CheckSight(actor, actor->target)))) + && P_LookForTargets(actor, true)) + return; + + /* (Current target was good, or no new target was found.) + * + * If monster is a missile-less friend, give up pursuit and + * return to player, if no attacks have occurred recently. + */ + + if (!actor->info->missilestate && actor->flags & MF_FRIEND) { + if (actor->flags & MF_JUSTHIT) /* if recent action, */ + actor->flags &= ~MF_JUSTHIT; /* keep fighting */ + else if (P_LookForPlayers(actor, true)) /* else return to player */ + return; + } + } + } + + if (actor->strafecount) + actor->strafecount--; + + // chase towards player + if (--actor->movecount<0 || !P_SmartMove(actor)) + P_NewChaseDir(actor); + + // make active sound + if (actor->info->activesound && P_Random(pr_see)<3) + S_StartSound(actor, actor->info->activesound); +} + +// +// A_FaceTarget +// +void A_FaceTarget(mobj_t *actor) +{ + if (!actor->target) + return; + actor->flags &= ~MF_AMBUSH; + actor->angle = R_PointToAngle2(actor->x, actor->y, + actor->target->x, actor->target->y); + if (actor->target->flags & MF_SHADOW) + { // killough 5/5/98: remove dependence on order of evaluation: + int t = P_Random(pr_facetarget); + actor->angle += (t-P_Random(pr_facetarget))<<21; + } +} + +// +// A_PosAttack +// + +void A_PosAttack(mobj_t *actor) +{ + int angle, damage, slope, t; + + if (!actor->target) + return; + A_FaceTarget(actor); + angle = actor->angle; + slope = P_AimLineAttack(actor, angle, MISSILERANGE, 0); /* killough 8/2/98 */ + S_StartSound(actor, sfx_pistol); + + // killough 5/5/98: remove dependence on order of evaluation: + t = P_Random(pr_posattack); + angle += (t - P_Random(pr_posattack))<<20; + damage = (P_Random(pr_posattack)%5 + 1)*3; + P_LineAttack(actor, angle, MISSILERANGE, slope, damage); +} + +void A_SPosAttack(mobj_t* actor) +{ + int i, bangle, slope; + + if (!actor->target) + return; + S_StartSound(actor, sfx_shotgn); + A_FaceTarget(actor); + bangle = actor->angle; + slope = P_AimLineAttack(actor, bangle, MISSILERANGE, 0); /* killough 8/2/98 */ + for (i=0; i<3; i++) + { // killough 5/5/98: remove dependence on order of evaluation: + int t = P_Random(pr_sposattack); + int angle = bangle + ((t - P_Random(pr_sposattack))<<20); + int damage = ((P_Random(pr_sposattack)%5)+1)*3; + P_LineAttack(actor, angle, MISSILERANGE, slope, damage); + } +} + +void A_CPosAttack(mobj_t *actor) +{ + int angle, bangle, damage, slope, t; + + if (!actor->target) + return; + S_StartSound(actor, sfx_shotgn); + A_FaceTarget(actor); + bangle = actor->angle; + slope = P_AimLineAttack(actor, bangle, MISSILERANGE, 0); /* killough 8/2/98 */ + + // killough 5/5/98: remove dependence on order of evaluation: + t = P_Random(pr_cposattack); + angle = bangle + ((t - P_Random(pr_cposattack))<<20); + damage = ((P_Random(pr_cposattack)%5)+1)*3; + P_LineAttack(actor, angle, MISSILERANGE, slope, damage); +} + +void A_CPosRefire(mobj_t *actor) +{ + // keep firing unless target got out of sight + A_FaceTarget(actor); + + /* killough 12/98: Stop firing if a friend has gotten in the way */ + if (P_HitFriend(actor)) + goto stop; + + /* killough 11/98: prevent refiring on friends continuously */ + if (P_Random(pr_cposrefire) < 40) { + if (actor->target && actor->flags & actor->target->flags & MF_FRIEND) + goto stop; + else + return; + } + + if (!actor->target || actor->target->health <= 0 + || !P_CheckSight(actor, actor->target)) +stop: P_SetMobjState(actor, actor->info->seestate); +} + +void A_SpidRefire(mobj_t* actor) +{ + // keep firing unless target got out of sight + A_FaceTarget(actor); + + /* killough 12/98: Stop firing if a friend has gotten in the way */ + if (P_HitFriend(actor)) + goto stop; + + if (P_Random(pr_spidrefire) < 10) + return; + + // killough 11/98: prevent refiring on friends continuously + if (!actor->target || actor->target->health <= 0 + || actor->flags & actor->target->flags & MF_FRIEND + || !P_CheckSight(actor, actor->target)) +stop: P_SetMobjState(actor, actor->info->seestate); +} + +void A_BspiAttack(mobj_t *actor) +{ + if (!actor->target) + return; + A_FaceTarget(actor); + P_SpawnMissile(actor, actor->target, MT_ARACHPLAZ); // launch a missile +} + +// +// A_TroopAttack +// + +void A_TroopAttack(mobj_t *actor) +{ + if (!actor->target) + return; + A_FaceTarget(actor); + if (P_CheckMeleeRange(actor)) + { + int damage; + S_StartSound(actor, sfx_claw); + damage = (P_Random(pr_troopattack)%8+1)*3; + P_DamageMobj(actor->target, actor, actor, damage); + return; + } + P_SpawnMissile(actor, actor->target, MT_TROOPSHOT); // launch a missile +} + +void A_SargAttack(mobj_t *actor) +{ + if (!actor->target) + return; + A_FaceTarget(actor); + if (P_CheckMeleeRange(actor)) + { + int damage = ((P_Random(pr_sargattack)%10)+1)*4; + P_DamageMobj(actor->target, actor, actor, damage); + } +} + +void A_HeadAttack(mobj_t *actor) +{ + if (!actor->target) + return; + A_FaceTarget (actor); + if (P_CheckMeleeRange(actor)) + { + int damage = (P_Random(pr_headattack)%6+1)*10; + P_DamageMobj(actor->target, actor, actor, damage); + return; + } + P_SpawnMissile(actor, actor->target, MT_HEADSHOT); // launch a missile +} + +void A_CyberAttack(mobj_t *actor) +{ + if (!actor->target) + return; + A_FaceTarget(actor); + P_SpawnMissile(actor, actor->target, MT_ROCKET); +} + +void A_BruisAttack(mobj_t *actor) +{ + if (!actor->target) + return; + if (P_CheckMeleeRange(actor)) + { + int damage; + S_StartSound(actor, sfx_claw); + damage = (P_Random(pr_bruisattack)%8+1)*10; + P_DamageMobj(actor->target, actor, actor, damage); + return; + } + P_SpawnMissile(actor, actor->target, MT_BRUISERSHOT); // launch a missile +} + +// +// A_SkelMissile +// + +void A_SkelMissile(mobj_t *actor) +{ + mobj_t *mo; + + if (!actor->target) + return; + + A_FaceTarget (actor); + actor->z += 16*FRACUNIT; // so missile spawns higher + mo = P_SpawnMissile (actor, actor->target, MT_TRACER); + actor->z -= 16*FRACUNIT; // back to normal + + mo->x += mo->momx; + mo->y += mo->momy; + P_SetTarget(&mo->tracer, actor->target); +} + +int TRACEANGLE = 0xc000000; + +void A_Tracer(mobj_t *actor) +{ + angle_t exact; + fixed_t dist; + fixed_t slope; + mobj_t *dest; + mobj_t *th; + + /* killough 1/18/98: this is why some missiles do not have smoke + * and some do. Also, internal demos start at random gametics, thus + * the bug in which revenants cause internal demos to go out of sync. + * + * killough 3/6/98: fix revenant internal demo bug by subtracting + * levelstarttic from gametic. + * + * killough 9/29/98: use new "basetic" so that demos stay in sync + * during pauses and menu activations, while retaining old demo sync. + * + * leveltime would have been better to use to start with in Doom, but + * since old demos were recorded using gametic, we must stick with it, + * and improvise around it (using leveltime causes desync across levels). + */ + + if ((gametic-basetic) & 3) + return; + + // spawn a puff of smoke behind the rocket + P_SpawnPuff(actor->x, actor->y, actor->z); + + th = P_SpawnMobj (actor->x-actor->momx, + actor->y-actor->momy, + actor->z, MT_SMOKE); + + th->momz = FRACUNIT; + th->tics -= P_Random(pr_tracer) & 3; + if (th->tics < 1) + th->tics = 1; + + // adjust direction + dest = actor->tracer; + + if (!dest || dest->health <= 0) + return; + + // change angle + exact = R_PointToAngle2(actor->x, actor->y, dest->x, dest->y); + + if (exact != actor->angle) { + if (exact - actor->angle > 0x80000000) + { + actor->angle -= TRACEANGLE; + if (exact - actor->angle < 0x80000000) + actor->angle = exact; + } + else + { + actor->angle += TRACEANGLE; + if (exact - actor->angle > 0x80000000) + actor->angle = exact; + } + } + + exact = actor->angle>>ANGLETOFINESHIFT; + actor->momx = FixedMul(actor->info->speed, finecosine[exact]); + actor->momy = FixedMul(actor->info->speed, finesine[exact]); + + // change slope + dist = P_AproxDistance(dest->x - actor->x, dest->y - actor->y); + + dist = dist / actor->info->speed; + + if (dist < 1) + dist = 1; + + slope = (dest->z+40*FRACUNIT - actor->z) / dist; + + if (slope < actor->momz) + actor->momz -= FRACUNIT/8; + else + actor->momz += FRACUNIT/8; +} + +void A_SkelWhoosh(mobj_t *actor) +{ + if (!actor->target) + return; + A_FaceTarget(actor); + S_StartSound(actor,sfx_skeswg); +} + +void A_SkelFist(mobj_t *actor) +{ + if (!actor->target) + return; + A_FaceTarget(actor); + if (P_CheckMeleeRange(actor)) + { + int damage = ((P_Random(pr_skelfist)%10)+1)*6; + S_StartSound(actor, sfx_skepch); + P_DamageMobj(actor->target, actor, actor, damage); + } +} + +// +// PIT_VileCheck +// Detect a corpse that could be raised. +// + +mobj_t* corpsehit; +mobj_t* vileobj; +fixed_t viletryx; +fixed_t viletryy; + +boolean PIT_VileCheck(mobj_t *thing) +{ + int maxdist; + boolean check; + + if (!(thing->flags & MF_CORPSE) ) + return true; // not a monster + + if (thing->tics != -1) + return true; // not lying still yet + + if (thing->info->raisestate == S_NULL) + return true; // monster doesn't have a raise state + + maxdist = thing->info->radius + mobjinfo[MT_VILE].radius; + + if (D_abs(thing->x-viletryx) > maxdist || D_abs(thing->y-viletryy) > maxdist) + return true; // not actually touching + + // Check to see if the radius and height are zero. If they are // phares + // then this is a crushed monster that has been turned into a // | + // gib. One of the options may be to ignore this guy. // V + + // Option 1: the original, buggy method, -> ghost (compatibility) + // Option 2: ressurect the monster, but not as a ghost + // Option 3: ignore the gib + + // if (Option3) // ^ + // if ((thing->height == 0) && (thing->radius == 0)) // | + // return true; // phares + + corpsehit = thing; + corpsehit->momx = corpsehit->momy = 0; + if (comp[comp_vile]) // phares + { // | + corpsehit->height <<= 2; // V + check = P_CheckPosition(corpsehit,corpsehit->x,corpsehit->y); + corpsehit->height >>= 2; + } + else + { + int height,radius; + + height = corpsehit->height; // save temporarily + radius = corpsehit->radius; // save temporarily + corpsehit->height = corpsehit->info->height; + corpsehit->radius = corpsehit->info->radius; + corpsehit->flags |= MF_SOLID; + check = P_CheckPosition(corpsehit,corpsehit->x,corpsehit->y); + corpsehit->height = height; // restore + corpsehit->radius = radius; // restore // ^ + corpsehit->flags &= ~MF_SOLID; + } // | + // phares + if (!check) + return true; // doesn't fit here + return false; // got one, so stop checking +} + +// +// A_VileChase +// Check for ressurecting a body +// + +void A_VileChase(mobj_t* actor) +{ + int xl, xh; + int yl, yh; + int bx, by; + + if (actor->movedir != DI_NODIR) + { + // check for corpses to raise + viletryx = + actor->x + actor->info->speed*xspeed[actor->movedir]; + viletryy = + actor->y + actor->info->speed*yspeed[actor->movedir]; + + xl = (viletryx - bmaporgx - MAXRADIUS*2)>>MAPBLOCKSHIFT; + xh = (viletryx - bmaporgx + MAXRADIUS*2)>>MAPBLOCKSHIFT; + yl = (viletryy - bmaporgy - MAXRADIUS*2)>>MAPBLOCKSHIFT; + yh = (viletryy - bmaporgy + MAXRADIUS*2)>>MAPBLOCKSHIFT; + + vileobj = actor; + for (bx=xl ; bx<=xh ; bx++) + { + for (by=yl ; by<=yh ; by++) + { + // Call PIT_VileCheck to check + // whether object is a corpse + // that canbe raised. + if (!P_BlockThingsIterator(bx,by,PIT_VileCheck)) + { + mobjinfo_t *info; + + // got one! + mobj_t* temp = actor->target; + actor->target = corpsehit; + A_FaceTarget(actor); + actor->target = temp; + + P_SetMobjState(actor, S_VILE_HEAL1); + S_StartSound(corpsehit, sfx_slop); + info = corpsehit->info; + + P_SetMobjState(corpsehit,info->raisestate); + + if (comp[comp_vile]) // phares + corpsehit->height <<= 2; // | + else // V + { + corpsehit->height = info->height; // fix Ghost bug + corpsehit->radius = info->radius; // fix Ghost bug + } // phares + + /* killough 7/18/98: + * friendliness is transferred from AV to raised corpse + */ + corpsehit->flags = + (info->flags & ~MF_FRIEND) | (actor->flags & MF_FRIEND); + + if (!((corpsehit->flags ^ MF_COUNTKILL) & (MF_FRIEND | MF_COUNTKILL))) + totallive++; + + corpsehit->health = info->spawnhealth; + P_SetTarget(&corpsehit->target, NULL); // killough 11/98 + + if (mbf_features) + { /* kilough 9/9/98 */ + P_SetTarget(&corpsehit->lastenemy, NULL); + corpsehit->flags &= ~MF_JUSTHIT; + } + + /* killough 8/29/98: add to appropriate thread */ + P_UpdateThinker(&corpsehit->thinker); + + return; + } + } + } + } + A_Chase(actor); // Return to normal attack. +} + +// +// A_VileStart +// + +void A_VileStart(mobj_t *actor) +{ + S_StartSound(actor, sfx_vilatk); +} + +// +// A_Fire +// Keep fire in front of player unless out of sight +// + +void A_Fire(mobj_t *actor); + +void A_StartFire(mobj_t *actor) +{ + S_StartSound(actor,sfx_flamst); + A_Fire(actor); +} + +void A_FireCrackle(mobj_t* actor) +{ + S_StartSound(actor,sfx_flame); + A_Fire(actor); +} + +void A_Fire(mobj_t *actor) +{ + unsigned an; + mobj_t *dest = actor->tracer; + + if (!dest) + return; + + // don't move it if the vile lost sight + if (!P_CheckSight(actor->target, dest) ) + return; + + an = dest->angle >> ANGLETOFINESHIFT; + + P_UnsetThingPosition(actor); + actor->x = dest->x + FixedMul(24*FRACUNIT, finecosine[an]); + actor->y = dest->y + FixedMul(24*FRACUNIT, finesine[an]); + actor->z = dest->z; + P_SetThingPosition(actor); +} + +// +// A_VileTarget +// Spawn the hellfire +// + +void A_VileTarget(mobj_t *actor) +{ + mobj_t *fog; + + if (!actor->target) + return; + + A_FaceTarget(actor); + + // killough 12/98: fix Vile fog coordinates // CPhipps - compatibility optioned + fog = P_SpawnMobj(actor->target->x, + (compatibility_level < lxdoom_1_compatibility) ? actor->target->x : actor->target->y, + actor->target->z,MT_FIRE); + + P_SetTarget(&actor->tracer, fog); + P_SetTarget(&fog->target, actor); + P_SetTarget(&fog->tracer, actor->target); + A_Fire(fog); +} + +// +// A_VileAttack +// + +void A_VileAttack(mobj_t *actor) +{ + mobj_t *fire; + int an; + + if (!actor->target) + return; + + A_FaceTarget(actor); + + if (!P_CheckSight(actor, actor->target)) + return; + + S_StartSound(actor, sfx_barexp); + P_DamageMobj(actor->target, actor, actor, 20); + actor->target->momz = 1000*FRACUNIT/actor->target->info->mass; + + an = actor->angle >> ANGLETOFINESHIFT; + + fire = actor->tracer; + + if (!fire) + return; + + // move the fire between the vile and the player + fire->x = actor->target->x - FixedMul (24*FRACUNIT, finecosine[an]); + fire->y = actor->target->y - FixedMul (24*FRACUNIT, finesine[an]); + P_RadiusAttack(fire, actor, 70); +} + +// +// Mancubus attack, +// firing three missiles (bruisers) +// in three different directions? +// Doesn't look like it. +// + +#define FATSPREAD (ANG90/8) + +void A_FatRaise(mobj_t *actor) +{ + A_FaceTarget(actor); + S_StartSound(actor, sfx_manatk); +} + +void A_FatAttack1(mobj_t *actor) +{ + mobj_t *mo; + int an; + + A_FaceTarget(actor); + + // Change direction to ... + actor->angle += FATSPREAD; + + P_SpawnMissile(actor, actor->target, MT_FATSHOT); + + mo = P_SpawnMissile (actor, actor->target, MT_FATSHOT); + mo->angle += FATSPREAD; + an = mo->angle >> ANGLETOFINESHIFT; + mo->momx = FixedMul(mo->info->speed, finecosine[an]); + mo->momy = FixedMul(mo->info->speed, finesine[an]); +} + +void A_FatAttack2(mobj_t *actor) +{ + mobj_t *mo; + int an; + + A_FaceTarget(actor); + // Now here choose opposite deviation. + actor->angle -= FATSPREAD; + P_SpawnMissile(actor, actor->target, MT_FATSHOT); + + mo = P_SpawnMissile(actor, actor->target, MT_FATSHOT); + mo->angle -= FATSPREAD*2; + an = mo->angle >> ANGLETOFINESHIFT; + mo->momx = FixedMul(mo->info->speed, finecosine[an]); + mo->momy = FixedMul(mo->info->speed, finesine[an]); +} + +void A_FatAttack3(mobj_t *actor) +{ + mobj_t *mo; + int an; + + A_FaceTarget(actor); + + mo = P_SpawnMissile(actor, actor->target, MT_FATSHOT); + mo->angle -= FATSPREAD/2; + an = mo->angle >> ANGLETOFINESHIFT; + mo->momx = FixedMul(mo->info->speed, finecosine[an]); + mo->momy = FixedMul(mo->info->speed, finesine[an]); + + mo = P_SpawnMissile(actor, actor->target, MT_FATSHOT); + mo->angle += FATSPREAD/2; + an = mo->angle >> ANGLETOFINESHIFT; + mo->momx = FixedMul(mo->info->speed, finecosine[an]); + mo->momy = FixedMul(mo->info->speed, finesine[an]); +} + + +// +// SkullAttack +// Fly at the player like a missile. +// +#define SKULLSPEED (20*FRACUNIT) + +void A_SkullAttack(mobj_t *actor) +{ + mobj_t *dest; + angle_t an; + int dist; + + if (!actor->target) + return; + + dest = actor->target; + actor->flags |= MF_SKULLFLY; + + S_StartSound(actor, actor->info->attacksound); + A_FaceTarget(actor); + an = actor->angle >> ANGLETOFINESHIFT; + actor->momx = FixedMul(SKULLSPEED, finecosine[an]); + actor->momy = FixedMul(SKULLSPEED, finesine[an]); + dist = P_AproxDistance(dest->x - actor->x, dest->y - actor->y); + dist = dist / SKULLSPEED; + + if (dist < 1) + dist = 1; + actor->momz = (dest->z+(dest->height>>1) - actor->z) / dist; +} + +// +// A_PainShootSkull +// Spawn a lost soul and launch it at the target +// + +void A_PainShootSkull(mobj_t *actor, angle_t angle) +{ + fixed_t x,y,z; + mobj_t *newmobj; + angle_t an; + int prestep; + + // The original code checked for 20 skulls on the level, // phares + // and wouldn't spit another one if there were. If not in // phares + // compatibility mode, we remove the limit. // phares + // phares + if (comp[comp_pain]) /* killough 10/98: compatibility-optioned */ + { + // count total number of skulls currently on the level + int count = 0; + thinker_t *currentthinker; + for (currentthinker = thinkercap.next; + currentthinker != &thinkercap; + currentthinker = currentthinker->next) + if ((currentthinker->function == P_MobjThinker) + && ((mobj_t *)currentthinker)->type == MT_SKULL) + count++; + if (count > 20) // phares + return; // phares + } + + // okay, there's room for another one + + an = angle >> ANGLETOFINESHIFT; + + prestep = 4*FRACUNIT + 3*(actor->info->radius + mobjinfo[MT_SKULL].radius)/2; + + x = actor->x + FixedMul(prestep, finecosine[an]); + y = actor->y + FixedMul(prestep, finesine[an]); + z = actor->z + 8*FRACUNIT; + + if (comp[comp_skull]) /* killough 10/98: compatibility-optioned */ + newmobj = P_SpawnMobj(x, y, z, MT_SKULL); // phares + else // V + { + // Check whether the Lost Soul is being fired through a 1-sided + // wall or an impassible line, or a "monsters can't cross" line. + // If it is, then we don't allow the spawn. This is a bug fix, but + // it should be considered an enhancement, since it may disturb + // existing demos, so don't do it in compatibility mode. + + if (Check_Sides(actor,x,y)) + return; + + newmobj = P_SpawnMobj(x, y, z, MT_SKULL); + + // Check to see if the new Lost Soul's z value is above the + // ceiling of its new sector, or below the floor. If so, kill it. + + if ((newmobj->z > + (newmobj->subsector->sector->ceilingheight - newmobj->height)) || + (newmobj->z < newmobj->subsector->sector->floorheight)) + { + // kill it immediately + P_DamageMobj(newmobj,actor,actor,10000); + return; // ^ + } // | + } // phares + + /* killough 7/20/98: PEs shoot lost souls with the same friendliness */ + newmobj->flags = (newmobj->flags & ~MF_FRIEND) | (actor->flags & MF_FRIEND); + + /* killough 8/29/98: add to appropriate thread */ + P_UpdateThinker(&newmobj->thinker); + + // Check for movements. + // killough 3/15/98: don't jump over dropoffs: + + if (!P_TryMove(newmobj, newmobj->x, newmobj->y, false)) + { + // kill it immediately + P_DamageMobj(newmobj, actor, actor, 10000); + return; + } + + P_SetTarget(&newmobj->target, actor->target); + A_SkullAttack(newmobj); +} + +// +// A_PainAttack +// Spawn a lost soul and launch it at the target +// + +void A_PainAttack(mobj_t *actor) +{ + if (!actor->target) + return; + A_FaceTarget(actor); + A_PainShootSkull(actor, actor->angle); +} + +void A_PainDie(mobj_t *actor) +{ + A_Fall(actor); + A_PainShootSkull(actor, actor->angle+ANG90); + A_PainShootSkull(actor, actor->angle+ANG180); + A_PainShootSkull(actor, actor->angle+ANG270); +} + +void A_Scream(mobj_t *actor) +{ + int sound; + + switch (actor->info->deathsound) + { + case 0: + return; + + case sfx_podth1: + case sfx_podth2: + case sfx_podth3: + sound = sfx_podth1 + P_Random(pr_scream)%3; + break; + + case sfx_bgdth1: + case sfx_bgdth2: + sound = sfx_bgdth1 + P_Random(pr_scream)%2; + break; + + default: + sound = actor->info->deathsound; + break; + } + + // Check for bosses. + if (actor->type==MT_SPIDER || actor->type == MT_CYBORG) + S_StartSound(NULL, sound); // full volume + else + S_StartSound(actor, sound); +} + +void A_XScream(mobj_t *actor) +{ + S_StartSound(actor, sfx_slop); +} + +void A_Pain(mobj_t *actor) +{ + if (actor->info->painsound) + S_StartSound(actor, actor->info->painsound); +} + +void A_Fall(mobj_t *actor) +{ + // actor is on ground, it can be walked over + actor->flags &= ~MF_SOLID; +} + +// +// A_Explode +// +void A_Explode(mobj_t *thingy) +{ + P_RadiusAttack( thingy, thingy->target, 128 ); +} + +// +// A_BossDeath +// Possibly trigger special effects +// if on first boss level +// + +void A_BossDeath(mobj_t *mo) +{ + thinker_t *th; + line_t junk; + int i; + + if (gamemode == commercial) + { + if (gamemap != 7) + return; + + if ((mo->type != MT_FATSO) + && (mo->type != MT_BABY)) + return; + } + else + { + switch(gameepisode) + { + case 1: + if (gamemap != 8) + return; + + if (mo->type != MT_BRUISER) + return; + break; + + case 2: + if (gamemap != 8) + return; + + if (mo->type != MT_CYBORG) + return; + break; + + case 3: + if (gamemap != 8) + return; + + if (mo->type != MT_SPIDER) + return; + + break; + + case 4: + switch(gamemap) + { + case 6: + if (mo->type != MT_CYBORG) + return; + break; + + case 8: + if (mo->type != MT_SPIDER) + return; + break; + + default: + return; + break; + } + break; + + default: + if (gamemap != 8) + return; + break; + } + + } + + // make sure there is a player alive for victory + for (i=0; i 0) + break; + + if (i==MAXPLAYERS) + return; // no one left alive, so do not end game + + // scan the remaining thinkers to see + // if all bosses are dead + for (th = thinkercap.next ; th != &thinkercap ; th=th->next) + if (th->function == P_MobjThinker) + { + mobj_t *mo2 = (mobj_t *) th; + if (mo2 != mo && mo2->type == mo->type && mo2->health > 0) + return; // other boss not dead + } + + // victory! + if ( gamemode == commercial) + { + if (gamemap == 7) + { + if (mo->type == MT_FATSO) + { + junk.tag = 666; + EV_DoFloor(&junk,lowerFloorToLowest); + return; + } + + if (mo->type == MT_BABY) + { + junk.tag = 667; + EV_DoFloor(&junk,raiseToTexture); + return; + } + } + } + else + { + switch(gameepisode) + { + case 1: + junk.tag = 666; + EV_DoFloor(&junk, lowerFloorToLowest); + return; + break; + + case 4: + switch(gamemap) + { + case 6: + junk.tag = 666; + EV_DoDoor(&junk, blazeOpen); + return; + break; + + case 8: + junk.tag = 666; + EV_DoFloor(&junk, lowerFloorToLowest); + return; + break; + } + } + } + G_ExitLevel(); +} + + +void A_Hoof (mobj_t* mo) +{ + S_StartSound(mo, sfx_hoof); + A_Chase(mo); +} + +void A_Metal(mobj_t *mo) +{ + S_StartSound(mo, sfx_metal); + A_Chase(mo); +} + +void A_BabyMetal(mobj_t *mo) +{ + S_StartSound(mo, sfx_bspwlk); + A_Chase(mo); +} + +void A_OpenShotgun2(player_t *player, pspdef_t *psp) +{ + (void)psp; + S_StartSound(player->mo, sfx_dbopn); +} + +void A_LoadShotgun2(player_t *player, pspdef_t *psp) +{ + (void)psp; + S_StartSound(player->mo, sfx_dbload); +} + +void A_ReFire(player_t *player, pspdef_t *psp); + +void A_CloseShotgun2(player_t *player, pspdef_t *psp) +{ + S_StartSound(player->mo, sfx_dbcls); + A_ReFire(player,psp); +} + +// killough 2/7/98: Remove limit on icon landings: +mobj_t **braintargets; +int numbraintargets_alloc; +int numbraintargets; + +struct brain_s brain; // killough 3/26/98: global state of boss brain + +// killough 3/26/98: initialize icon landings at level startup, +// rather than at boss wakeup, to prevent savegame-related crashes + +void P_SpawnBrainTargets(void) // killough 3/26/98: renamed old function +{ + thinker_t *thinker; + + // find all the target spots + numbraintargets = 0; + brain.targeton = 0; + brain.easy = 0; // killough 3/26/98: always init easy to 0 + + for (thinker = thinkercap.next ; + thinker != &thinkercap ; + thinker = thinker->next) + if (thinker->function == P_MobjThinker) + { + mobj_t *m = (mobj_t *) thinker; + + if (m->type == MT_BOSSTARGET ) + { // killough 2/7/98: remove limit on icon landings: + if (numbraintargets >= numbraintargets_alloc) + braintargets = realloc(braintargets, + (numbraintargets_alloc = numbraintargets_alloc ? + numbraintargets_alloc*2 : 32) *sizeof *braintargets); + braintargets[numbraintargets++] = m; + } + } +} + +void A_BrainAwake(mobj_t *mo) +{ + (void)mo; + S_StartSound(NULL,sfx_bossit); // killough 3/26/98: only generates sound now +} + +void A_BrainPain(mobj_t *mo) +{ + (void)mo; + S_StartSound(NULL,sfx_bospn); +} + +void A_BrainScream(mobj_t *mo) +{ + int x; + for (x=mo->x - 196*FRACUNIT ; x< mo->x + 320*FRACUNIT ; x+= FRACUNIT*8) + { + int y = mo->y - 320*FRACUNIT; + int z = 128 + P_Random(pr_brainscream)*2*FRACUNIT; + mobj_t *th = P_SpawnMobj (x,y,z, MT_ROCKET); + th->momz = P_Random(pr_brainscream)*512; + P_SetMobjState(th, S_BRAINEXPLODE1); + th->tics -= P_Random(pr_brainscream)&7; + if (th->tics < 1) + th->tics = 1; + } + S_StartSound(NULL,sfx_bosdth); +} + +void A_BrainExplode(mobj_t *mo) +{ // killough 5/5/98: remove dependence on order of evaluation: + (void)mo; + int t = P_Random(pr_brainexp); + int x = mo->x + (t - P_Random(pr_brainexp))*2048; + int y = mo->y; + int z = 128 + P_Random(pr_brainexp)*2*FRACUNIT; + mobj_t *th = P_SpawnMobj(x,y,z, MT_ROCKET); + th->momz = P_Random(pr_brainexp)*512; + P_SetMobjState(th, S_BRAINEXPLODE1); + th->tics -= P_Random(pr_brainexp)&7; + if (th->tics < 1) + th->tics = 1; +} + +void A_BrainDie(mobj_t *mo) +{ + (void)mo; + G_ExitLevel(); +} + +void A_BrainSpit(mobj_t *mo) +{ + mobj_t *targ, *newmobj; + + if (!numbraintargets) // killough 4/1/98: ignore if no targets + return; + + brain.easy ^= 1; // killough 3/26/98: use brain struct + if (gameskill <= sk_easy && !brain.easy) + return; + + // shoot a cube at current target + targ = braintargets[brain.targeton++]; // killough 3/26/98: + brain.targeton %= numbraintargets; // Use brain struct for targets + + // spawn brain missile + newmobj = P_SpawnMissile(mo, targ, MT_SPAWNSHOT); + P_SetTarget(&newmobj->target, targ); + newmobj->reactiontime = (short)(((targ->y-mo->y)/newmobj->momy)/newmobj->state->tics); + + // killough 7/18/98: brain friendliness is transferred + newmobj->flags = (newmobj->flags & ~MF_FRIEND) | (mo->flags & MF_FRIEND); + + // killough 8/29/98: add to appropriate thread + P_UpdateThinker(&newmobj->thinker); + + S_StartSound(NULL, sfx_bospit); +} + +void A_SpawnFly(mobj_t *mo); + +// travelling cube sound +void A_SpawnSound(mobj_t *mo) +{ + S_StartSound(mo,sfx_boscub); + A_SpawnFly(mo); +} + +void A_SpawnFly(mobj_t *mo) +{ + mobj_t *newmobj; + mobj_t *fog; + mobj_t *targ; + int r; + mobjtype_t type; + + if (--mo->reactiontime) + return; // still flying + + targ = mo->target; + + // First spawn teleport fog. + fog = P_SpawnMobj(targ->x, targ->y, targ->z, MT_SPAWNFIRE); + S_StartSound(fog, sfx_telept); + + // Randomly select monster to spawn. + r = P_Random(pr_spawnfly); + + // Probability distribution (kind of :), decreasing likelihood. + if ( r<50 ) + type = MT_TROOP; + else if (r<90) + type = MT_SERGEANT; + else if (r<120) + type = MT_SHADOWS; + else if (r<130) + type = MT_PAIN; + else if (r<160) + type = MT_HEAD; + else if (r<162) + type = MT_VILE; + else if (r<172) + type = MT_UNDEAD; + else if (r<192) + type = MT_BABY; + else if (r<222) + type = MT_FATSO; + else if (r<246) + type = MT_KNIGHT; + else + type = MT_BRUISER; + + newmobj = P_SpawnMobj(targ->x, targ->y, targ->z, type); + + /* killough 7/18/98: brain friendliness is transferred */ + newmobj->flags = (newmobj->flags & ~MF_FRIEND) | (mo->flags & MF_FRIEND); + + /* killough 8/29/98: add to appropriate thread */ + P_UpdateThinker(&newmobj->thinker); + + if (P_LookForTargets(newmobj,true)) /* killough 9/4/98 */ + P_SetMobjState(newmobj, newmobj->info->seestate); + + // telefrag anything in this spot + P_TeleportMove(newmobj, newmobj->x, newmobj->y, true); /* killough 8/9/98 */ + + // remove self (i.e., cube). + P_RemoveMobj(mo); +} + +void A_PlayerScream(mobj_t *mo) +{ + int sound = sfx_pldeth; // Default death sound. + if (gamemode != shareware && mo->health < -50) + sound = sfx_pdiehi; // IF THE PLAYER DIES LESS THAN -50% WITHOUT GIBBING + S_StartSound(mo, sound); +} + +/* cph - MBF-added codepointer functions */ + +// killough 11/98: kill an object +void A_Die(mobj_t *actor) +{ + P_DamageMobj(actor, NULL, NULL, actor->health); +} + +// +// A_Detonate +// killough 8/9/98: same as A_Explode, except that the damage is variable +// + +void A_Detonate(mobj_t *mo) +{ + P_RadiusAttack(mo, mo->target, mo->info->damage); +} + +// +// killough 9/98: a mushroom explosion effect, sorta :) +// Original idea: Linguica +// + +void A_Mushroom(mobj_t *actor) +{ + int i, j, n = actor->info->damage; + + A_Explode(actor); // First make normal explosion + + // Now launch mushroom cloud + for (i = -n; i <= n; i += 8) + for (j = -n; j <= n; j += 8) + { + mobj_t target = *actor, *mo; + target.x += i << FRACBITS; // Aim in many directions from source + target.y += j << FRACBITS; + target.z += P_AproxDistance(i,j) << (FRACBITS+2); // Aim up fairly high + mo = P_SpawnMissile(actor, &target, MT_FATSHOT); // Launch fireball + mo->momx >>= 1; + mo->momy >>= 1; // Slow it down a bit + mo->momz >>= 1; + mo->flags &= ~MF_NOGRAVITY; // Make debris fall under gravity + } +} + +// +// killough 11/98 +// +// The following were inspired by Len Pitre +// +// A small set of highly-sought-after code pointers +// + +void A_Spawn(mobj_t *mo) +{ + if (mo->state->misc1) + { + /* mobj_t *newmobj = */ + P_SpawnMobj(mo->x, mo->y, (mo->state->misc2 << FRACBITS) + mo->z, + mo->state->misc1 - 1); + /* CPhipps - no friendlyness (yet) + newmobj->flags = (newmobj->flags & ~MF_FRIEND) | (mo->flags & MF_FRIEND); + */ + } +} + +void A_Turn(mobj_t *mo) +{ + mo->angle += (unsigned int)(((uint_64_t) mo->state->misc1 << 32) / 360); +} + +void A_Face(mobj_t *mo) +{ + mo->angle = (unsigned int)(((uint_64_t) mo->state->misc1 << 32) / 360); +} + +void A_Scratch(mobj_t *mo) +{ + mo->target && (A_FaceTarget(mo), P_CheckMeleeRange(mo)) ? + mo->state->misc2 ? S_StartSound(mo, mo->state->misc2) : (void) 0, + P_DamageMobj(mo->target, mo, mo, mo->state->misc1) : (void) 0; +} + +void A_PlaySound(mobj_t *mo) +{ + S_StartSound(mo->state->misc2 ? NULL : mo, mo->state->misc1); +} + +void A_RandomJump(mobj_t *mo) +{ + if (P_Random(pr_randomjump) < mo->state->misc2) + P_SetMobjState(mo, mo->state->misc1); +} + +// +// This allows linedef effects to be activated inside deh frames. +// + +void A_LineEffect(mobj_t *mo) +{ + static line_t junk; + player_t player; + player_t *oldplayer; + junk = *lines; + oldplayer = mo->player; + mo->player = &player; + player.health = 100; + junk.special = (short)mo->state->misc1; + if (!junk.special) + return; + junk.tag = (short)mo->state->misc2; + if (!P_UseSpecialLine(mo, &junk, 0)) + P_CrossSpecialLine(&junk, 0, mo); + mo->state->misc1 = junk.special; + mo->player = oldplayer; +} + +/***** Start of new functions for Andy Baker's stealth monsters ******/ + +void P_BecomeVisible(mobj_t* actor) +{ + actor->invisible = false; + actor->flags &= ~MF_TRANSLUCBITS; +}; + +void P_IncreaseVisibility(mobj_t* actor) +{ + if (actor->invisible) { + actor->invisible = false; + actor->flags |= MF_TRANSLUC25; + } else switch (actor->flags & MF_TRANSLUCBITS) { + case MF_TRANSLUC25: + actor->flags &= ~MF_TRANSLUCBITS; + actor->flags |= MF_TRANSLUC50; + break; + case MF_TRANSLUC50: + actor->flags &= ~MF_TRANSLUCBITS; + actor->flags |= MF_TRANSLUC25; + actor->flags |= MF_TRANSLUC50; + break; + case MF_TRANSLUC75: + actor->flags &= ~MF_TRANSLUCBITS; + break; + } +} + +void P_DecreaseVisibility(mobj_t* actor) +{ + if (actor->invisible) + return; // already invisible + + switch (actor->flags & MF_TRANSLUCBITS) { + case 0: + actor->flags &= ~MF_TRANSLUCBITS; + actor->flags |= MF_TRANSLUC75; + break; + case MF_TRANSLUC75: + actor->flags &= ~MF_TRANSLUCBITS; + actor->flags |= MF_TRANSLUC50; + break; + case MF_TRANSLUC50: + actor->flags &= ~MF_TRANSLUCBITS; + actor->flags |= MF_TRANSLUC25; + break; + case MF_TRANSLUC25: + actor->flags &= ~MF_TRANSLUCBITS; + actor->invisible = true; + } +} +/***** End of new functions for Andy Baker's stealth monsters ******/ + diff --git a/apps/plugins/doom/p_enemy.h b/apps/plugins/doom/p_enemy.h new file mode 100644 index 0000000000..edf59af6ef --- /dev/null +++ b/apps/plugins/doom/p_enemy.h @@ -0,0 +1,50 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Enemy thinking, AI. + * Action Pointer Functions + * that are associated with states/frames. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __P_ENEMY__ +#define __P_ENEMY__ + +#include "p_mobj.h" + +void P_NoiseAlert (mobj_t *target, mobj_t *emmiter); +void P_SpawnBrainTargets(void); /* killough 3/26/98: spawn icon landings */ +/* proff 11/22/98: Andy Baker's stealth monsters */ +void P_BecomeVisible (mobj_t *actor); +void P_IncreaseVisibility (mobj_t *actor); +void P_DecreaseVisibility (mobj_t *actor); + +extern struct brain_s { /* killough 3/26/98: global state of boss brain */ + int easy, targeton; + } brain; + +#endif // __P_ENEMY__ diff --git a/apps/plugins/doom/p_floor.c b/apps/plugins/doom/p_floor.c new file mode 100644 index 0000000000..bbcf2bc358 --- /dev/null +++ b/apps/plugins/doom/p_floor.c @@ -0,0 +1,1035 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * General plane mover and floor mover action routines + * Floor motion, pure changer types, raising stairs. donuts, elevators + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "r_main.h" +#include "p_map.h" +#include "p_spec.h" +#include "p_tick.h" +#include "s_sound.h" +#include "sounds.h" + +#include "rockmacros.h" + +/////////////////////////////////////////////////////////////////////// +// +// Plane (floor or ceiling), Floor motion and Elevator action routines +// +/////////////////////////////////////////////////////////////////////// + +// +// T_MovePlane() +// +// Move a plane (floor or ceiling) and check for crushing. Called +// every tick by all actions that move floors or ceilings. +// +// Passed the sector to move a plane in, the speed to move it at, +// the dest height it is to achieve, whether it crushes obstacles, +// whether it moves a floor or ceiling, and the direction up or down +// to move. +// +// Returns a result_e: +// ok - plane moved normally, has not achieved destination yet +// pastdest - plane moved normally and is now at destination height +// crushed - plane encountered an obstacle, is holding until removed +// +result_e T_MovePlane +( sector_t* sector, + fixed_t speed, + fixed_t dest, + boolean crush, + int floorOrCeiling, + int direction ) +{ + boolean flag; + fixed_t lastpos; + fixed_t destheight; //jff 02/04/98 used to keep floors/ceilings + // from moving thru each other + + switch(floorOrCeiling) + { + case 0: + // Moving a floor + switch(direction) + { + case -1: + // Moving a floor down + if (sector->floorheight - speed < dest) + { + lastpos = sector->floorheight; + sector->floorheight = dest; + flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + if (flag == true) + { + sector->floorheight =lastpos; + P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + } + return pastdest; + } + else + { + lastpos = sector->floorheight; + sector->floorheight -= speed; + flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + /* cph - make more compatible with original Doom, by + * reintroducing this code. This means floors can't lower + * if objects are stuck in the ceiling */ + if ((flag == true) && comp[comp_floors]) { + sector->floorheight = lastpos; + P_ChangeSector(sector,crush); + return crushed; + } + } + break; + + case 1: + // Moving a floor up + // jff 02/04/98 keep floor from moving thru ceilings + // jff 2/22/98 weaken check to demo_compatibility + destheight = (comp[comp_floors] || destceilingheight)? + dest : sector->ceilingheight; + if (sector->floorheight + speed > destheight) + { + lastpos = sector->floorheight; + sector->floorheight = destheight; + flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + if (flag == true) + { + sector->floorheight = lastpos; + P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + } + return pastdest; + } + else + { + // crushing is possible + lastpos = sector->floorheight; + sector->floorheight += speed; + flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + if (flag == true) + { + /* jff 1/25/98 fix floor crusher */ + if (comp[comp_floors]) { + if (crush == true) + return crushed; + } + sector->floorheight = lastpos; + P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + return crushed; + } + } + break; + } + break; + + case 1: + // moving a ceiling + switch(direction) + { + case -1: + // moving a ceiling down + // jff 02/04/98 keep ceiling from moving thru floors + // jff 2/22/98 weaken check to demo_compatibility + destheight = (comp[comp_floors] || dest>sector->floorheight)? + dest : sector->floorheight; + if (sector->ceilingheight - speed < destheight) + { + lastpos = sector->ceilingheight; + sector->ceilingheight = destheight; + flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + + if (flag == true) + { + sector->ceilingheight = lastpos; + P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + } + return pastdest; + } + else + { + // crushing is possible + lastpos = sector->ceilingheight; + sector->ceilingheight -= speed; + flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + + if (flag == true) + { + if (crush == true) + return crushed; + sector->ceilingheight = lastpos; + P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + return crushed; + } + } + break; + + case 1: + // moving a ceiling up + if (sector->ceilingheight + speed > dest) + { + lastpos = sector->ceilingheight; + sector->ceilingheight = dest; + flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + if (flag == true) + { + sector->ceilingheight = lastpos; + P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + } + return pastdest; + } + else + { + lastpos = sector->ceilingheight; + sector->ceilingheight += speed; + flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + } + break; + } + break; + } + return ok; +} + +// +// T_MoveFloor() +// +// Move a floor to it's destination (up or down). +// Called once per tick for each moving floor. +// +// Passed a floormove_t structure that contains all pertinent info about the +// move. See P_SPEC.H for fields. +// No return. +// +// jff 02/08/98 all cases with labels beginning with gen added to support +// generalized line type behaviors. +void T_MoveFloor(floormove_t* floor) +{ + result_e res; + + res = T_MovePlane // move the floor + ( + floor->sector, + floor->speed, + floor->floordestheight, + floor->crush, + 0, + floor->direction + ); + + if (!(leveltime&7)) // make the floormove sound + S_StartSound((mobj_t *)&floor->sector->soundorg, sfx_stnmov); + + if (res == pastdest) // if destination height is reached + { + if (floor->direction == 1) // going up + { + switch(floor->type) // handle texture/type changes + { + case donutRaise: + floor->sector->special = floor->newspecial; + floor->sector->floorpic = floor->texture; + break; + case genFloorChgT: + case genFloorChg0: + floor->sector->special = floor->newspecial; + //jff add to fix bug in special transfers from changes + floor->sector->oldspecial = floor->oldspecial; + //fall thru + case genFloorChg: + floor->sector->floorpic = floor->texture; + break; + default: + break; + } + } + else if (floor->direction == -1) // going down + { + switch(floor->type) // handle texture/type changes + { + case lowerAndChange: + floor->sector->special = floor->newspecial; + //jff add to fix bug in special transfers from changes + floor->sector->oldspecial = floor->oldspecial; + floor->sector->floorpic = floor->texture; + break; + case genFloorChgT: + case genFloorChg0: + floor->sector->special = floor->newspecial; + //jff add to fix bug in special transfers from changes + floor->sector->oldspecial = floor->oldspecial; + //fall thru + case genFloorChg: + floor->sector->floorpic = floor->texture; + break; + default: + break; + } + } + + floor->sector->floordata = NULL; //jff 2/22/98 + P_RemoveThinker(&floor->thinker);//remove this floor from list of movers + + //jff 2/26/98 implement stair retrigger lockout while still building + // note this only applies to the retriggerable generalized stairs + + if (floor->sector->stairlock==-2) // if this sector is stairlocked + { + sector_t *sec = floor->sector; + sec->stairlock=-1; // thinker done, promote lock to -1 + + while (sec->prevsec!=-1 && sectors[sec->prevsec].stairlock!=-2) + sec = §ors[sec->prevsec]; // search for a non-done thinker + if (sec->prevsec==-1) // if all thinkers previous are done + { + sec = floor->sector; // search forward + while (sec->nextsec!=-1 && sectors[sec->nextsec].stairlock!=-2) + sec = §ors[sec->nextsec]; + if (sec->nextsec==-1) // if all thinkers ahead are done too + { + while (sec->prevsec!=-1) // clear all locks + { + sec->stairlock = 0; + sec = §ors[sec->prevsec]; + } + sec->stairlock = 0; + } + } + } + + // make floor stop sound + S_StartSound((mobj_t *)&floor->sector->soundorg, sfx_pstop); + } +} + +// +// T_MoveElevator() +// +// Move an elevator to it's destination (up or down) +// Called once per tick for each moving floor. +// +// Passed an elevator_t structure that contains all pertinent info about the +// move. See P_SPEC.H for fields. +// No return. +// +// jff 02/22/98 added to support parallel floor/ceiling motion +// +void T_MoveElevator(elevator_t* elevator) +{ + result_e res; + + if (elevator->direction<0) // moving down + { + res = T_MovePlane //jff 4/7/98 reverse order of ceiling/floor + ( + elevator->sector, + elevator->speed, + elevator->ceilingdestheight, + 0, + 1, // move floor + elevator->direction + ); + if (res==ok || res==pastdest) // jff 4/7/98 don't move ceil if blocked + T_MovePlane + ( + elevator->sector, + elevator->speed, + elevator->floordestheight, + 0, + 0, // move ceiling + elevator->direction + ); + } + else // up + { + res = T_MovePlane //jff 4/7/98 reverse order of ceiling/floor + ( + elevator->sector, + elevator->speed, + elevator->floordestheight, + 0, + 0, // move ceiling + elevator->direction + ); + if (res==ok || res==pastdest) // jff 4/7/98 don't move floor if blocked + T_MovePlane + ( + elevator->sector, + elevator->speed, + elevator->ceilingdestheight, + 0, + 1, // move floor + elevator->direction + ); + } + + // make floor move sound + if (!(leveltime&7)) + S_StartSound((mobj_t *)&elevator->sector->soundorg, sfx_stnmov); + + if (res == pastdest) // if destination height acheived + { + elevator->sector->floordata = NULL; //jff 2/22/98 + elevator->sector->ceilingdata = NULL; //jff 2/22/98 + P_RemoveThinker(&elevator->thinker); // remove elevator from actives + + // make floor stop sound + S_StartSound((mobj_t *)&elevator->sector->soundorg, sfx_pstop); + } +} + +/////////////////////////////////////////////////////////////////////// +// +// Floor motion linedef handlers +// +/////////////////////////////////////////////////////////////////////// + +// +// EV_DoFloor() +// +// Handle regular and extended floor types +// +// Passed the line that activated the floor and the type of floor motion +// Returns true if a thinker was created. +// +int EV_DoFloor +( line_t* line, + floor_e floortype ) +{ + int secnum; + int rtn; + int i; + sector_t* sec; + floormove_t* floor; + + secnum = -1; + rtn = 0; + // move all floors with the same tag as the linedef + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; + + // Don't start a second thinker on the same floor + if (P_SectorActive(floor_special,sec)) //jff 2/23/98 + continue; + + // new floor thinker + rtn = 1; + floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); + P_AddThinker (&floor->thinker); + sec->floordata = floor; //jff 2/22/98 + floor->thinker.function = T_MoveFloor; + floor->type = floortype; + floor->crush = false; + + // setup the thinker according to the linedef type + switch(floortype) + { + case lowerFloor: + floor->direction = -1; + floor->sector = sec; + floor->speed = FLOORSPEED; + floor->floordestheight = P_FindHighestFloorSurrounding(sec); + break; + + //jff 02/03/30 support lowering floor by 24 absolute + case lowerFloor24: + floor->direction = -1; + floor->sector = sec; + floor->speed = FLOORSPEED; + floor->floordestheight = floor->sector->floorheight + 24 * FRACUNIT; + break; + + //jff 02/03/30 support lowering floor by 32 absolute (fast) + case lowerFloor32Turbo: + floor->direction = -1; + floor->sector = sec; + floor->speed = FLOORSPEED*4; + floor->floordestheight = floor->sector->floorheight + 32 * FRACUNIT; + break; + + case lowerFloorToLowest: + floor->direction = -1; + floor->sector = sec; + floor->speed = FLOORSPEED; + floor->floordestheight = P_FindLowestFloorSurrounding(sec); + break; + + //jff 02/03/30 support lowering floor to next lowest floor + case lowerFloorToNearest: + floor->direction = -1; + floor->sector = sec; + floor->speed = FLOORSPEED; + floor->floordestheight = + P_FindNextLowestFloor(sec,floor->sector->floorheight); + break; + + case turboLower: + floor->direction = -1; + floor->sector = sec; + floor->speed = FLOORSPEED * 4; + floor->floordestheight = P_FindHighestFloorSurrounding(sec); + if (floor->floordestheight != sec->floorheight) + floor->floordestheight += 8*FRACUNIT; + break; + + case raiseFloorCrush: + floor->crush = true; + case raiseFloor: + floor->direction = 1; + floor->sector = sec; + floor->speed = FLOORSPEED; + floor->floordestheight = P_FindLowestCeilingSurrounding(sec); + if (floor->floordestheight > sec->ceilingheight) + floor->floordestheight = sec->ceilingheight; + floor->floordestheight -= (8*FRACUNIT)*(floortype == raiseFloorCrush); + break; + + case raiseFloorTurbo: + floor->direction = 1; + floor->sector = sec; + floor->speed = FLOORSPEED*4; + floor->floordestheight = P_FindNextHighestFloor(sec,sec->floorheight); + break; + + case raiseFloorToNearest: + floor->direction = 1; + floor->sector = sec; + floor->speed = FLOORSPEED; + floor->floordestheight = P_FindNextHighestFloor(sec,sec->floorheight); + break; + + case raiseFloor24: + floor->direction = 1; + floor->sector = sec; + floor->speed = FLOORSPEED; + floor->floordestheight = floor->sector->floorheight + 24 * FRACUNIT; + break; + + // jff 2/03/30 support straight raise by 32 (fast) + case raiseFloor32Turbo: + floor->direction = 1; + floor->sector = sec; + floor->speed = FLOORSPEED*4; + floor->floordestheight = floor->sector->floorheight + 32 * FRACUNIT; + break; + + case raiseFloor512: + floor->direction = 1; + floor->sector = sec; + floor->speed = FLOORSPEED; + floor->floordestheight = floor->sector->floorheight + 512 * FRACUNIT; + break; + + case raiseFloor24AndChange: + floor->direction = 1; + floor->sector = sec; + floor->speed = FLOORSPEED; + floor->floordestheight = floor->sector->floorheight + 24 * FRACUNIT; + sec->floorpic = line->frontsector->floorpic; + sec->special = line->frontsector->special; + //jff 3/14/98 transfer both old and new special + sec->oldspecial = line->frontsector->oldspecial; + break; + + case raiseToTexture: + { + int minsize = INT_MAX; + side_t* side; + + /* jff 3/13/98 no ovf */ + if (!comp[comp_model]) minsize = 32000<direction = 1; + floor->sector = sec; + floor->speed = FLOORSPEED; + for (i = 0; i < sec->linecount; i++) + { + if (twoSided (secnum, i) ) + { + side = getSide(secnum,i,0); + // jff 8/14/98 don't scan texture 0, its not real + if (side->bottomtexture > 0 || + (comp[comp_model] && !side->bottomtexture)) + if (textureheight[side->bottomtexture] < minsize) + minsize = textureheight[side->bottomtexture]; + side = getSide(secnum,i,1); + // jff 8/14/98 don't scan texture 0, its not real + if (side->bottomtexture > 0 || + (comp[comp_model] && !side->bottomtexture)) + if (textureheight[side->bottomtexture] < minsize) + minsize = textureheight[side->bottomtexture]; + } + } + if (comp[comp_model]) + floor->floordestheight = floor->sector->floorheight + minsize; + else + { + floor->floordestheight = + (floor->sector->floorheight>>FRACBITS) + (minsize>>FRACBITS); + if (floor->floordestheight>32000) + floor->floordestheight = 32000; //jff 3/13/98 do not + floor->floordestheight<<=FRACBITS; // allow height overflow + } + } + break; + + case lowerAndChange: + floor->direction = -1; + floor->sector = sec; + floor->speed = FLOORSPEED; + floor->floordestheight = P_FindLowestFloorSurrounding(sec); + floor->texture = sec->floorpic; + + // jff 1/24/98 make sure floor->newspecial gets initialized + // in case no surrounding sector is at floordestheight + // --> should not affect compatibility <-- + floor->newspecial = sec->special; + //jff 3/14/98 transfer both old and new special + floor->oldspecial = sec->oldspecial; + + //jff 5/23/98 use model subroutine to unify fixes and handling + sec = P_FindModelFloorSector(floor->floordestheight,sec-sectors); + if (sec) + { + floor->texture = sec->floorpic; + floor->newspecial = sec->special; + //jff 3/14/98 transfer both old and new special + floor->oldspecial = sec->oldspecial; + } + break; + default: + break; + } + } + return rtn; +} + +// +// EV_DoChange() +// +// Handle pure change types. These change floor texture and sector type +// by trigger or numeric model without moving the floor. +// +// The linedef causing the change and the type of change is passed +// Returns true if any sector changes +// +// jff 3/15/98 added to better support generalized sector types +// +int EV_DoChange +( line_t* line, + change_e changetype ) +{ + int secnum; + int rtn; + sector_t* sec; + sector_t* secm; + + secnum = -1; + rtn = 0; + // change all sectors with the same tag as the linedef + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; + + rtn = 1; + + // handle trigger or numeric change type + switch(changetype) + { + case trigChangeOnly: + sec->floorpic = line->frontsector->floorpic; + sec->special = line->frontsector->special; + sec->oldspecial = line->frontsector->oldspecial; + break; + case numChangeOnly: + secm = P_FindModelFloorSector(sec->floorheight,secnum); + if (secm) // if no model, no change + { + sec->floorpic = secm->floorpic; + sec->special = secm->special; + sec->oldspecial = secm->oldspecial; + } + break; + default: + break; + } + } + return rtn; +} + +/* + * EV_BuildStairs() + * + * Handles staircase building. A sequence of sectors chosen by algorithm + * rise at a speed indicated to a height that increases by the stepsize + * each step. + * + * Passed the linedef triggering the stairs and the type of stair rise + * Returns true if any thinkers are created + * + * cph 2001/09/21 - compatibility nightmares again + * There are three different ways this function has, during its history, stepped + * through all the stairs to be triggered by the single switch + * - original Doom used a linear P_FindSectorFromLineTag, but failed to preserve + * the index of the previous sector found, so instead it would restart its + * linear search from the last sector of the previous staircase + * - MBF/PrBoom with comp_stairs fail to emulate this, because their + * P_FindSectorFromLineTag is a chained hash table implementation. Instead they + * start following the hash chain from the last sector of the previous + * staircase, which will (probably) have the wrong tag, so they miss any further + * stairs + * - Boom fixed the bug, and MBF/PrBoom without comp_stairs work right + */ +static inline int P_FindSectorFromLineTagWithLowerBound +(line_t* l, int start, int min) +{ + /* Emulate original Doom's linear lower-bounded P_FindSectorFromLineTag + * as needed */ + do { + start = P_FindSectorFromLineTag(l,start); + } while (start >= 0 && start <= min); + return start; +} + +int EV_BuildStairs +( line_t* line, + stair_e type ) +{ + /* cph 2001/09/22 - cleaned up this function to save my sanity. A separate + * outer loop index makes the logic much cleared, and local variables moved + * into the inner blocks helps too */ + int ssec = -1; + int minssec = -1; + int rtn = 0; + + // start a stair at each sector tagged the same as the linedef + while ((ssec = P_FindSectorFromLineTagWithLowerBound(line,ssec,minssec)) >= 0) + { + int secnum = ssec; + sector_t* sec = §ors[secnum]; + + // don't start a stair if the first step's floor is already moving + if (!P_SectorActive(floor_special,sec)) { //jff 2/22/98 + floormove_t* floor; + int texture, height; + fixed_t stairsize; + fixed_t speed; + int ok; + + // create new floor thinker for first step + rtn = 1; + floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); + P_AddThinker (&floor->thinker); + sec->floordata = floor; + floor->thinker.function = T_MoveFloor; + floor->direction = 1; + floor->sector = sec; + floor->type = buildStair; //jff 3/31/98 do not leave uninited + + // set up the speed and stepsize according to the stairs type + switch(type) + { + default: // killough -- prevent compiler warning + case build8: + speed = FLOORSPEED/4; + stairsize = 8*FRACUNIT; + if (!demo_compatibility) + floor->crush = false; //jff 2/27/98 fix uninitialized crush field + break; + case turbo16: + speed = FLOORSPEED*4; + stairsize = 16*FRACUNIT; + if (!demo_compatibility) + floor->crush = true; //jff 2/27/98 fix uninitialized crush field + break; + } + floor->speed = speed; + height = sec->floorheight + stairsize; + floor->floordestheight = height; + + texture = sec->floorpic; + + // Find next sector to raise + // 1. Find 2-sided line with same sector side[0] (lowest numbered) + // 2. Other side is the next sector to raise + // 3. Unless already moving, or different texture, then stop building + do + { + int i; + ok = 0; + + for (i = 0;i < sec->linecount;i++) + { + sector_t* tsec = (sec->lines[i])->frontsector; + int newsecnum; + if ( !((sec->lines[i])->flags & ML_TWOSIDED) ) + continue; + + newsecnum = tsec-sectors; + + if (secnum != newsecnum) + continue; + + tsec = (sec->lines[i])->backsector; + if (!tsec) continue; //jff 5/7/98 if no backside, continue + newsecnum = tsec - sectors; + + // if sector's floor is different texture, look for another + if (tsec->floorpic != texture) + continue; + + /* jff 6/19/98 prevent double stepsize + * killough 10/98: intentionally left this way [MBF comment] + * cph 2001/02/06: stair bug fix should be controlled by comp_stairs, + * except if we're emulating MBF which perversly reverted the fix + */ + if (comp[comp_stairs] || (compatibility_level == mbf_compatibility)) + height += stairsize; // jff 6/28/98 change demo compatibility + + // if sector's floor already moving, look for another + if (P_SectorActive(floor_special,tsec)) //jff 2/22/98 + continue; + + /* cph - see comment above - do this iff we didn't do so above */ + if (!comp[comp_stairs] && (compatibility_level != mbf_compatibility)) + height += stairsize; + + sec = tsec; + secnum = newsecnum; + + // create and initialize a thinker for the next step + floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); + P_AddThinker (&floor->thinker); + + sec->floordata = floor; //jff 2/22/98 + floor->thinker.function = T_MoveFloor; + floor->direction = 1; + floor->sector = sec; + floor->speed = speed; + floor->floordestheight = height; + floor->type = buildStair; //jff 3/31/98 do not leave uninited + //jff 2/27/98 fix uninitialized crush field + if (!demo_compatibility) + floor->crush = type==build8? false : true; + ok = 1; + break; + } + } while(ok); // continue until no next step is found + + } + /* killough 10/98: compatibility option */ + if (comp[comp_stairs]) { + /* cph 2001/09/22 - emulate buggy MBF comp_stairs for demos, with logic + * reversed since we now have a separate outer loop index. + * DEMOSYNC - what about boom_compatibility_compatibility? + */ + if ((compatibility_level >= mbf_compatibility) && (compatibility_level < + prboom_3_compatibility)) ssec = secnum; /* Trash outer loop index */ + else { + /* cph 2001/09/22 - now the correct comp_stairs - Doom used a linear + * search from the last secnum, so we set that as a minimum value and do + * a fresh tag search + */ + ssec = -1; minssec = secnum; + } + } + } + return rtn; +} + +// +// EV_DoDonut() +// +// Handle donut function: lower pillar, raise surrounding pool, both to height, +// texture and type of the sector surrounding the pool. +// +// Passed the linedef that triggered the donut +// Returns whether a thinker was created +// +int EV_DoDonut(line_t* line) +{ + sector_t* s1; + sector_t* s2; + sector_t* s3; + int secnum; + int rtn; + int i; + floormove_t* floor; + + secnum = -1; + rtn = 0; + // do function on all sectors with same tag as linedef + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + s1 = §ors[secnum]; // s1 is pillar's sector + + // do not start the donut if the pillar is already moving + if (P_SectorActive(floor_special,s1)) //jff 2/22/98 + continue; + + s2 = getNextSector(s1->lines[0],s1); // s2 is pool's sector + if (!s2) continue; // note lowest numbered line around + // pillar must be two-sided + + /* do not start the donut if the pool is already moving + * cph - DEMOSYNC - was !compatibility */ + if (!comp[comp_floors] && P_SectorActive(floor_special,s2)) + continue; //jff 5/7/98 + + // find a two sided line around the pool whose other side isn't the pillar + for (i = 0;i < s2->linecount;i++) + { + //jff 3/29/98 use true two-sidedness, not the flag + // killough 4/5/98: changed demo_compatibility to compatibility + if (comp[comp_model]) + { + if ((!s2->lines[i]->flags & ML_TWOSIDED) || + (s2->lines[i]->backsector == s1)) + continue; + } + else if (!s2->lines[i]->backsector || s2->lines[i]->backsector == s1) + continue; + + rtn = 1; //jff 1/26/98 no donut action - no switch change on return + + s3 = s2->lines[i]->backsector; // s3 is model sector for changes + + // Spawn rising slime + floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); + P_AddThinker (&floor->thinker); + s2->floordata = floor; //jff 2/22/98 + floor->thinker.function = T_MoveFloor; + floor->type = donutRaise; + floor->crush = false; + floor->direction = 1; + floor->sector = s2; + floor->speed = FLOORSPEED / 2; + floor->texture = s3->floorpic; + floor->newspecial = 0; + floor->floordestheight = s3->floorheight; + + // Spawn lowering donut-hole pillar + floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); + P_AddThinker (&floor->thinker); + s1->floordata = floor; //jff 2/22/98 + floor->thinker.function = T_MoveFloor; + floor->type = lowerFloor; + floor->crush = false; + floor->direction = -1; + floor->sector = s1; + floor->speed = FLOORSPEED / 2; + floor->floordestheight = s3->floorheight; + break; + } + } + return rtn; +} + +// +// EV_DoElevator +// +// Handle elevator linedef types +// +// Passed the linedef that triggered the elevator and the elevator action +// +// jff 2/22/98 new type to move floor and ceiling in parallel +// +int EV_DoElevator +( line_t* line, + elevator_e elevtype ) +{ + int secnum; + int rtn; + sector_t* sec; + elevator_t* elevator; + + secnum = -1; + rtn = 0; + // act on all sectors with the same tag as the triggering linedef + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; + + // If either floor or ceiling is already activated, skip it + if (sec->floordata || sec->ceilingdata) //jff 2/22/98 + continue; + + // create and initialize new elevator thinker + rtn = 1; + elevator = Z_Malloc (sizeof(*elevator), PU_LEVSPEC, 0); + P_AddThinker (&elevator->thinker); + sec->floordata = elevator; //jff 2/22/98 + sec->ceilingdata = elevator; //jff 2/22/98 + elevator->thinker.function = T_MoveElevator; + elevator->type = elevtype; + + // set up the fields according to the type of elevator action + switch(elevtype) + { + // elevator down to next floor + case elevateDown: + elevator->direction = -1; + elevator->sector = sec; + elevator->speed = ELEVATORSPEED; + elevator->floordestheight = + P_FindNextLowestFloor(sec,sec->floorheight); + elevator->ceilingdestheight = + elevator->floordestheight + sec->ceilingheight - sec->floorheight; + break; + + // elevator up to next floor + case elevateUp: + elevator->direction = 1; + elevator->sector = sec; + elevator->speed = ELEVATORSPEED; + elevator->floordestheight = + P_FindNextHighestFloor(sec,sec->floorheight); + elevator->ceilingdestheight = + elevator->floordestheight + sec->ceilingheight - sec->floorheight; + break; + + // elevator to floor height of activating switch's front sector + case elevateCurrent: + elevator->sector = sec; + elevator->speed = ELEVATORSPEED; + elevator->floordestheight = line->frontsector->floorheight; + elevator->ceilingdestheight = + elevator->floordestheight + sec->ceilingheight - sec->floorheight; + elevator->direction = + elevator->floordestheight>sec->floorheight? 1 : -1; + break; + + default: + break; + } + } + return rtn; +} diff --git a/apps/plugins/doom/p_genlin.c b/apps/plugins/doom/p_genlin.c new file mode 100644 index 0000000000..a521210c64 --- /dev/null +++ b/apps/plugins/doom/p_genlin.c @@ -0,0 +1,1154 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Generalized linedef type handlers + * Floors, Ceilings, Doors, Locked Doors, Lifts, Stairs, Crushers + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" //jff 6/19/98 for demo_compatibility +#include "r_main.h" +#include "p_spec.h" +#include "p_tick.h" +#include "m_random.h" +#include "s_sound.h" +#include "sounds.h" + +////////////////////////////////////////////////////////// +// +// Generalized Linedef Type handlers +// +////////////////////////////////////////////////////////// + +// +// EV_DoGenFloor() +// +// Handle generalized floor types +// +// Passed the line activating the generalized floor function +// Returns true if a thinker is created +// +// jff 02/04/98 Added this routine (and file) to handle generalized +// floor movers using bit fields in the line special type. +// +int EV_DoGenFloor +( line_t* line ) +{ + int secnum; + int rtn; + boolean manual; + sector_t* sec; + floormove_t* floor; + unsigned value = (unsigned)line->special - GenFloorBase; + + // parse the bit fields in the line's special type + + int Crsh = (value & FloorCrush) >> FloorCrushShift; + int ChgT = (value & FloorChange) >> FloorChangeShift; + int Targ = (value & FloorTarget) >> FloorTargetShift; + int Dirn = (value & FloorDirection) >> FloorDirectionShift; + int ChgM = (value & FloorModel) >> FloorModelShift; + int Sped = (value & FloorSpeed) >> FloorSpeedShift; + int Trig = (value & TriggerType) >> TriggerTypeShift; + + rtn = 0; + + // check if a manual trigger, if so do just the sector on the backside + manual = false; + if (Trig==PushOnce || Trig==PushMany) + { + if (!(sec = line->backsector)) + return rtn; + secnum = sec-sectors; + manual = true; + goto manual_floor; + } + + secnum = -1; + // if not manual do all sectors tagged the same as the line + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; + +manual_floor: + // Do not start another function if floor already moving + if (P_SectorActive(floor_special,sec)) + { + if (!manual) + continue; + else + return rtn; + } + + // new floor thinker + rtn = 1; + floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); + P_AddThinker (&floor->thinker); + sec->floordata = floor; + floor->thinker.function = T_MoveFloor; + floor->crush = Crsh; + floor->direction = Dirn? 1 : -1; + floor->sector = sec; + floor->texture = sec->floorpic; + floor->newspecial = sec->special; + //jff 3/14/98 transfer old special field too + floor->oldspecial = sec->oldspecial; + floor->type = genFloor; + + // set the speed of motion + switch (Sped) + { + case SpeedSlow: + floor->speed = FLOORSPEED; + break; + case SpeedNormal: + floor->speed = FLOORSPEED*2; + break; + case SpeedFast: + floor->speed = FLOORSPEED*4; + break; + case SpeedTurbo: + floor->speed = FLOORSPEED*8; + break; + default: + break; + } + + // set the destination height + switch(Targ) + { + case FtoHnF: + floor->floordestheight = P_FindHighestFloorSurrounding(sec); + break; + case FtoLnF: + floor->floordestheight = P_FindLowestFloorSurrounding(sec); + break; + case FtoNnF: + floor->floordestheight = Dirn? + P_FindNextHighestFloor(sec,sec->floorheight) : + P_FindNextLowestFloor(sec,sec->floorheight); + break; + case FtoLnC: + floor->floordestheight = P_FindLowestCeilingSurrounding(sec); + break; + case FtoC: + floor->floordestheight = sec->ceilingheight; + break; + case FbyST: + floor->floordestheight = (floor->sector->floorheight>>FRACBITS) + + floor->direction * (P_FindShortestTextureAround(secnum)>>FRACBITS); + if (floor->floordestheight>32000) //jff 3/13/98 prevent overflow + floor->floordestheight=32000; // wraparound in floor height + if (floor->floordestheight<-32000) + floor->floordestheight=-32000; + floor->floordestheight<<=FRACBITS; + break; + case Fby24: + floor->floordestheight = floor->sector->floorheight + + floor->direction * 24*FRACUNIT; + break; + case Fby32: + floor->floordestheight = floor->sector->floorheight + + floor->direction * 32*FRACUNIT; + break; + default: + break; + } + + // set texture/type change properties + if (ChgT) // if a texture change is indicated + { + if (ChgM) // if a numeric model change + { + sector_t *sec; + + //jff 5/23/98 find model with ceiling at target height if target + //is a ceiling type + sec = (Targ==FtoLnC || Targ==FtoC)? + P_FindModelCeilingSector(floor->floordestheight,secnum) : + P_FindModelFloorSector(floor->floordestheight,secnum); + if (sec) + { + floor->texture = sec->floorpic; + switch(ChgT) + { + case FChgZero: // zero type + floor->newspecial = 0; + //jff 3/14/98 change old field too + floor->oldspecial = 0; + floor->type = genFloorChg0; + break; + case FChgTyp: // copy type + floor->newspecial = sec->special; + //jff 3/14/98 change old field too + floor->oldspecial = sec->oldspecial; + floor->type = genFloorChgT; + break; + case FChgTxt: // leave type be + floor->type = genFloorChg; + break; + default: + break; + } + } + } + else // else if a trigger model change + { + floor->texture = line->frontsector->floorpic; + switch (ChgT) + { + case FChgZero: // zero type + floor->newspecial = 0; + //jff 3/14/98 change old field too + floor->oldspecial = 0; + floor->type = genFloorChg0; + break; + case FChgTyp: // copy type + floor->newspecial = line->frontsector->special; + //jff 3/14/98 change old field too + floor->oldspecial = line->frontsector->oldspecial; + floor->type = genFloorChgT; + break; + case FChgTxt: // leave type be + floor->type = genFloorChg; + default: + break; + } + } + } + if (manual) return rtn; + } + return rtn; +} + + +// +// EV_DoGenCeiling() +// +// Handle generalized ceiling types +// +// Passed the linedef activating the ceiling function +// Returns true if a thinker created +// +// jff 02/04/98 Added this routine (and file) to handle generalized +// floor movers using bit fields in the line special type. +// +int EV_DoGenCeiling +( line_t* line ) +{ + int secnum; + int rtn; + boolean manual; + fixed_t targheight; + sector_t* sec; + ceiling_t* ceiling; + unsigned value = (unsigned)line->special - GenCeilingBase; + + // parse the bit fields in the line's special type + + int Crsh = (value & CeilingCrush) >> CeilingCrushShift; + int ChgT = (value & CeilingChange) >> CeilingChangeShift; + int Targ = (value & CeilingTarget) >> CeilingTargetShift; + int Dirn = (value & CeilingDirection) >> CeilingDirectionShift; + int ChgM = (value & CeilingModel) >> CeilingModelShift; + int Sped = (value & CeilingSpeed) >> CeilingSpeedShift; + int Trig = (value & TriggerType) >> TriggerTypeShift; + + rtn = 0; + + // check if a manual trigger, if so do just the sector on the backside + manual = false; + if (Trig==PushOnce || Trig==PushMany) + { + if (!(sec = line->backsector)) + return rtn; + secnum = sec-sectors; + manual = true; + goto manual_ceiling; + } + + secnum = -1; + // if not manual do all sectors tagged the same as the line + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; + +manual_ceiling: + // Do not start another function if ceiling already moving + if (P_SectorActive(ceiling_special,sec)) //jff 2/22/98 + { + if (!manual) + continue; + else + return rtn; + } + + // new ceiling thinker + rtn = 1; + ceiling = Z_Malloc (sizeof(*ceiling), PU_LEVSPEC, 0); + P_AddThinker (&ceiling->thinker); + sec->ceilingdata = ceiling; //jff 2/22/98 + ceiling->thinker.function = T_MoveCeiling; + ceiling->crush = Crsh; + ceiling->direction = Dirn? 1 : -1; + ceiling->sector = sec; + ceiling->texture = sec->ceilingpic; + ceiling->newspecial = sec->special; + //jff 3/14/98 change old field too + ceiling->oldspecial = sec->oldspecial; + ceiling->tag = sec->tag; + ceiling->type = genCeiling; + + // set speed of motion + switch (Sped) + { + case SpeedSlow: + ceiling->speed = CEILSPEED; + break; + case SpeedNormal: + ceiling->speed = CEILSPEED*2; + break; + case SpeedFast: + ceiling->speed = CEILSPEED*4; + break; + case SpeedTurbo: + ceiling->speed = CEILSPEED*8; + break; + default: + break; + } + + // set destination target height + targheight = sec->ceilingheight; + switch(Targ) + { + case CtoHnC: + targheight = P_FindHighestCeilingSurrounding(sec); + break; + case CtoLnC: + targheight = P_FindLowestCeilingSurrounding(sec); + break; + case CtoNnC: + targheight = Dirn? + P_FindNextHighestCeiling(sec,sec->ceilingheight) : + P_FindNextLowestCeiling(sec,sec->ceilingheight); + break; + case CtoHnF: + targheight = P_FindHighestFloorSurrounding(sec); + break; + case CtoF: + targheight = sec->floorheight; + break; + case CbyST: + targheight = (ceiling->sector->ceilingheight>>FRACBITS) + + ceiling->direction * (P_FindShortestUpperAround(secnum)>>FRACBITS); + if (targheight>32000) //jff 3/13/98 prevent overflow + targheight=32000; // wraparound in ceiling height + if (targheight<-32000) + targheight=-32000; + targheight<<=FRACBITS; + break; + case Cby24: + targheight = ceiling->sector->ceilingheight + + ceiling->direction * 24*FRACUNIT; + break; + case Cby32: + targheight = ceiling->sector->ceilingheight + + ceiling->direction * 32*FRACUNIT; + break; + default: + break; + } + if (Dirn) ceiling->topheight = targheight; + else ceiling->bottomheight = targheight; + + // set texture/type change properties + if (ChgT) // if a texture change is indicated + { + if (ChgM) // if a numeric model change + { + sector_t *sec; + + //jff 5/23/98 find model with floor at target height if target + //is a floor type + sec = (Targ==CtoHnF || Targ==CtoF)? + P_FindModelFloorSector(targheight,secnum) : + P_FindModelCeilingSector(targheight,secnum); + if (sec) + { + ceiling->texture = sec->ceilingpic; + switch (ChgT) + { + case CChgZero: // type is zeroed + ceiling->newspecial = 0; + //jff 3/14/98 change old field too + ceiling->oldspecial = 0; + ceiling->type = genCeilingChg0; + break; + case CChgTyp: // type is copied + ceiling->newspecial = sec->special; + //jff 3/14/98 change old field too + ceiling->oldspecial = sec->oldspecial; + ceiling->type = genCeilingChgT; + break; + case CChgTxt: // type is left alone + ceiling->type = genCeilingChg; + break; + default: + break; + } + } + } + else // else if a trigger model change + { + ceiling->texture = line->frontsector->ceilingpic; + switch (ChgT) + { + case CChgZero: // type is zeroed + ceiling->newspecial = 0; + //jff 3/14/98 change old field too + ceiling->oldspecial = 0; + ceiling->type = genCeilingChg0; + break; + case CChgTyp: // type is copied + ceiling->newspecial = line->frontsector->special; + //jff 3/14/98 change old field too + ceiling->oldspecial = line->frontsector->oldspecial; + ceiling->type = genCeilingChgT; + break; + case CChgTxt: // type is left alone + ceiling->type = genCeilingChg; + break; + default: + break; + } + } + } + P_AddActiveCeiling(ceiling); // add this ceiling to the active list + if (manual) return rtn; + } + return rtn; +} + +// +// EV_DoGenLift() +// +// Handle generalized lift types +// +// Passed the linedef activating the lift +// Returns true if a thinker is created +// +int EV_DoGenLift +( line_t* line ) +{ + plat_t* plat; + int secnum; + int rtn; + boolean manual; + sector_t* sec; + unsigned value = (unsigned)line->special - GenLiftBase; + + // parse the bit fields in the line's special type + + int Targ = (value & LiftTarget) >> LiftTargetShift; + int Dely = (value & LiftDelay) >> LiftDelayShift; + int Sped = (value & LiftSpeed) >> LiftSpeedShift; + int Trig = (value & TriggerType) >> TriggerTypeShift; + + secnum = -1; + rtn = 0; + + // Activate all plats that are in_stasis + + if (Targ==LnF2HnF) + P_ActivateInStasis(line->tag); + + // check if a manual trigger, if so do just the sector on the backside + manual = false; + if (Trig==PushOnce || Trig==PushMany) + { + if (!(sec = line->backsector)) + return rtn; + secnum = sec-sectors; + manual = true; + goto manual_lift; + } + + // if not manual do all sectors tagged the same as the line + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; + +manual_lift: + // Do not start another function if floor already moving + if (P_SectorActive(floor_special,sec)) + { + if (!manual) + continue; + else + return rtn; + } + + // Setup the plat thinker + rtn = 1; + plat = Z_Malloc( sizeof(*plat), PU_LEVSPEC, 0); + P_AddThinker(&plat->thinker); + + plat->sector = sec; + plat->sector->floordata = plat; + plat->thinker.function = T_PlatRaise; + plat->crush = false; + plat->tag = line->tag; + + plat->type = genLift; + plat->high = sec->floorheight; + plat->status = down; + + // setup the target destination height + switch(Targ) + { + case F2LnF: + plat->low = P_FindLowestFloorSurrounding(sec); + if (plat->low > sec->floorheight) + plat->low = sec->floorheight; + break; + case F2NnF: + plat->low = P_FindNextLowestFloor(sec,sec->floorheight); + break; + case F2LnC: + plat->low = P_FindLowestCeilingSurrounding(sec); + if (plat->low > sec->floorheight) + plat->low = sec->floorheight; + break; + case LnF2HnF: + plat->type = genPerpetual; + plat->low = P_FindLowestFloorSurrounding(sec); + if (plat->low > sec->floorheight) + plat->low = sec->floorheight; + plat->high = P_FindHighestFloorSurrounding(sec); + if (plat->high < sec->floorheight) + plat->high = sec->floorheight; + plat->status = P_Random(pr_genlift)&1; + break; + default: + break; + } + + // setup the speed of motion + switch(Sped) + { + case SpeedSlow: + plat->speed = PLATSPEED * 2; + break; + case SpeedNormal: + plat->speed = PLATSPEED * 4; + break; + case SpeedFast: + plat->speed = PLATSPEED * 8; + break; + case SpeedTurbo: + plat->speed = PLATSPEED * 16; + break; + default: + break; + } + + // setup the delay time before the floor returns + switch(Dely) + { + case 0: + plat->wait = 1*35; + break; + case 1: + plat->wait = PLATWAIT*35; + break; + case 2: + plat->wait = 5*35; + break; + case 3: + plat->wait = 10*35; + break; + } + + S_StartSound((mobj_t *)&sec->soundorg,sfx_pstart); + P_AddActivePlat(plat); // add this plat to the list of active plats + + if (manual) + return rtn; + } + return rtn; +} + +// +// EV_DoGenStairs() +// +// Handle generalized stair building +// +// Passed the linedef activating the stairs +// Returns true if a thinker is created +// +int EV_DoGenStairs +( line_t* line ) +{ + int secnum; + int osecnum; //jff 3/4/98 preserve loop index + int height; + int i; + int newsecnum; + int texture; + int ok; + int rtn; + boolean manual; + + sector_t* sec; + sector_t* tsec; + + floormove_t* floor; + + fixed_t stairsize; + fixed_t speed; + + unsigned value = (unsigned)line->special - GenStairsBase; + + // parse the bit fields in the line's special type + + int Igno = (value & StairIgnore) >> StairIgnoreShift; + int Dirn = (value & StairDirection) >> StairDirectionShift; + int Step = (value & StairStep) >> StairStepShift; + int Sped = (value & StairSpeed) >> StairSpeedShift; + int Trig = (value & TriggerType) >> TriggerTypeShift; + + rtn = 0; + + // check if a manual trigger, if so do just the sector on the backside + manual = false; + if (Trig==PushOnce || Trig==PushMany) + { + if (!(sec = line->backsector)) + return rtn; + secnum = sec-sectors; + manual = true; + goto manual_stair; + } + + secnum = -1; + // if not manual do all sectors tagged the same as the line + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; + +manual_stair: + //Do not start another function if floor already moving + //jff 2/26/98 add special lockout condition to wait for entire + //staircase to build before retriggering + if (P_SectorActive(floor_special,sec) || sec->stairlock) + { + if (!manual) + continue; + else + return rtn; + } + + // new floor thinker + rtn = 1; + floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); + P_AddThinker (&floor->thinker); + sec->floordata = floor; + floor->thinker.function = T_MoveFloor; + floor->direction = Dirn? 1 : -1; + floor->sector = sec; + + // setup speed of stair building + switch(Sped) + { + default: + case SpeedSlow: + floor->speed = FLOORSPEED/4; + break; + case SpeedNormal: + floor->speed = FLOORSPEED/2; + break; + case SpeedFast: + floor->speed = FLOORSPEED*2; + break; + case SpeedTurbo: + floor->speed = FLOORSPEED*4; + break; + } + + // setup stepsize for stairs + switch(Step) + { + default: + case 0: + stairsize = 4*FRACUNIT; + break; + case 1: + stairsize = 8*FRACUNIT; + break; + case 2: + stairsize = 16*FRACUNIT; + break; + case 3: + stairsize = 24*FRACUNIT; + break; + } + + speed = floor->speed; + height = sec->floorheight + floor->direction * stairsize; + floor->floordestheight = height; + texture = sec->floorpic; + floor->crush = false; + floor->type = genBuildStair; // jff 3/31/98 do not leave uninited + + sec->stairlock = -2; // jff 2/26/98 set up lock on current sector + sec->nextsec = -1; + sec->prevsec = -1; + + osecnum = secnum; //jff 3/4/98 preserve loop index + // Find next sector to raise + // 1. Find 2-sided line with same sector side[0] + // 2. Other side is the next sector to raise + do + { + ok = 0; + for (i = 0;i < sec->linecount;i++) + { + if ( !((sec->lines[i])->backsector) ) + continue; + + tsec = (sec->lines[i])->frontsector; + newsecnum = tsec-sectors; + + if (secnum != newsecnum) + continue; + + tsec = (sec->lines[i])->backsector; + newsecnum = tsec - sectors; + + if (!Igno && tsec->floorpic != texture) + continue; + + /* jff 6/19/98 prevent double stepsize */ + if (compatibility_level < boom_202_compatibility) + height += floor->direction * stairsize; + + //jff 2/26/98 special lockout condition for retriggering + if (P_SectorActive(floor_special,tsec) || tsec->stairlock) + continue; + + /* jff 6/19/98 increase height AFTER continue */ + if (compatibility_level >= boom_202_compatibility) + height += floor->direction * stairsize; + + // jff 2/26/98 + // link the stair chain in both directions + // lock the stair sector until building complete + sec->nextsec = newsecnum; // link step to next + tsec->prevsec = secnum; // link next back + tsec->nextsec = -1; // set next forward link as end + tsec->stairlock = -2; // lock the step + + sec = tsec; + secnum = newsecnum; + floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); + + P_AddThinker (&floor->thinker); + + sec->floordata = floor; + floor->thinker.function = T_MoveFloor; + floor->direction = Dirn? 1 : -1; + floor->sector = sec; + floor->speed = speed; + floor->floordestheight = height; + floor->crush = false; + floor->type = genBuildStair; // jff 3/31/98 do not leave uninited + + ok = 1; + break; + } + } while(ok); + if (manual) + return rtn; + secnum = osecnum; //jff 3/4/98 restore old loop index + } + // retriggerable generalized stairs build up or down alternately + if (rtn) + line->special ^= StairDirection; // alternate dir on succ activations + return rtn; +} + +// +// EV_DoGenCrusher() +// +// Handle generalized crusher types +// +// Passed the linedef activating the crusher +// Returns true if a thinker created +// +int EV_DoGenCrusher +( line_t* line ) +{ + int secnum; + int rtn; + boolean manual; + sector_t* sec; + ceiling_t* ceiling; + unsigned value = (unsigned)line->special - GenCrusherBase; + + // parse the bit fields in the line's special type + + int Slnt = (value & CrusherSilent) >> CrusherSilentShift; + int Sped = (value & CrusherSpeed) >> CrusherSpeedShift; + int Trig = (value & TriggerType) >> TriggerTypeShift; + + //jff 2/22/98 Reactivate in-stasis ceilings...for certain types. + //jff 4/5/98 return if activated + rtn = P_ActivateInStasisCeiling(line); + + // check if a manual trigger, if so do just the sector on the backside + manual = false; + if (Trig==PushOnce || Trig==PushMany) + { + if (!(sec = line->backsector)) + return rtn; + secnum = sec-sectors; + manual = true; + goto manual_crusher; + } + + secnum = -1; + // if not manual do all sectors tagged the same as the line + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; + +manual_crusher: + // Do not start another function if ceiling already moving + if (P_SectorActive(ceiling_special,sec)) //jff 2/22/98 + { + if (!manual) + continue; + else + return rtn; + } + + // new ceiling thinker + rtn = 1; + ceiling = Z_Malloc (sizeof(*ceiling), PU_LEVSPEC, 0); + P_AddThinker (&ceiling->thinker); + sec->ceilingdata = ceiling; //jff 2/22/98 + ceiling->thinker.function = T_MoveCeiling; + ceiling->crush = true; + ceiling->direction = -1; + ceiling->sector = sec; + ceiling->texture = sec->ceilingpic; + ceiling->newspecial = sec->special; + ceiling->tag = sec->tag; + ceiling->type = Slnt? genSilentCrusher : genCrusher; + ceiling->topheight = sec->ceilingheight; + ceiling->bottomheight = sec->floorheight + (8*FRACUNIT); + + // setup ceiling motion speed + switch (Sped) + { + case SpeedSlow: + ceiling->speed = CEILSPEED; + break; + case SpeedNormal: + ceiling->speed = CEILSPEED*2; + break; + case SpeedFast: + ceiling->speed = CEILSPEED*4; + break; + case SpeedTurbo: + ceiling->speed = CEILSPEED*8; + break; + default: + break; + } + ceiling->oldspeed=ceiling->speed; + + P_AddActiveCeiling(ceiling); // add to list of active ceilings + if (manual) return rtn; + } + return rtn; +} + +// +// EV_DoGenLockedDoor() +// +// Handle generalized locked door types +// +// Passed the linedef activating the generalized locked door +// Returns true if a thinker created +// +int EV_DoGenLockedDoor +( line_t* line ) +{ + int secnum,rtn; + sector_t* sec; + vldoor_t* door; + boolean manual; + unsigned value = (unsigned)line->special - GenLockedBase; + + // parse the bit fields in the line's special type + + int Kind = (value & LockedKind) >> LockedKindShift; + int Sped = (value & LockedSpeed) >> LockedSpeedShift; + int Trig = (value & TriggerType) >> TriggerTypeShift; + + rtn = 0; + + // check if a manual trigger, if so do just the sector on the backside + manual = false; + if (Trig==PushOnce || Trig==PushMany) + { + if (!(sec = line->backsector)) + return rtn; + secnum = sec-sectors; + manual = true; + goto manual_locked; + } + + secnum = -1; + rtn = 0; + + // if not manual do all sectors tagged the same as the line + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; +manual_locked: + // Do not start another function if ceiling already moving + if (P_SectorActive(ceiling_special,sec)) //jff 2/22/98 + { + if (!manual) + continue; + else + return rtn; + } + + // new door thinker + rtn = 1; + door = Z_Malloc (sizeof(*door), PU_LEVSPEC, 0); + P_AddThinker (&door->thinker); + sec->ceilingdata = door; //jff 2/22/98 + + door->thinker.function = T_VerticalDoor; + door->sector = sec; + door->topwait = VDOORWAIT; + door->line = line; + door->topheight = P_FindLowestCeilingSurrounding(sec); + door->topheight -= 4*FRACUNIT; + door->direction = 1; + + /* killough 10/98: implement gradual lighting */ + door->lighttag = !comp[comp_doorlight] && + (line->special&6) == 6 && + line->special > GenLockedBase ? line->tag : 0; + + // setup speed of door motion + switch(Sped) + { + default: + case SpeedSlow: + door->type = Kind? genOpen : genRaise; + door->speed = VDOORSPEED; + break; + case SpeedNormal: + door->type = Kind? genOpen : genRaise; + door->speed = VDOORSPEED*2; + break; + case SpeedFast: + door->type = Kind? genBlazeOpen : genBlazeRaise; + door->speed = VDOORSPEED*4; + break; + case SpeedTurbo: + door->type = Kind? genBlazeOpen : genBlazeRaise; + door->speed = VDOORSPEED*8; + + break; + } + + // killough 4/15/98: fix generalized door opening sounds + // (previously they always had the blazing door close sound) + + S_StartSound((mobj_t *)&door->sector->soundorg, // killough 4/15/98 + door->speed >= VDOORSPEED*4 ? sfx_bdopn : sfx_doropn); + + if (manual) + return rtn; + } + return rtn; +} + +// +// EV_DoGenDoor() +// +// Handle generalized door types +// +// Passed the linedef activating the generalized door +// Returns true if a thinker created +// +int EV_DoGenDoor +( line_t* line ) +{ + int secnum,rtn; + sector_t* sec; + boolean manual; + vldoor_t* door; + unsigned value = (unsigned)line->special - GenDoorBase; + + // parse the bit fields in the line's special type + + int Dely = (value & DoorDelay) >> DoorDelayShift; + int Kind = (value & DoorKind) >> DoorKindShift; + int Sped = (value & DoorSpeed) >> DoorSpeedShift; + int Trig = (value & TriggerType) >> TriggerTypeShift; + + rtn = 0; + + // check if a manual trigger, if so do just the sector on the backside + manual = false; + if (Trig==PushOnce || Trig==PushMany) + { + if (!(sec = line->backsector)) + return rtn; + secnum = sec-sectors; + manual = true; + goto manual_door; + } + + + secnum = -1; + rtn = 0; + + // if not manual do all sectors tagged the same as the line + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; +manual_door: + // Do not start another function if ceiling already moving + if (P_SectorActive(ceiling_special,sec)) //jff 2/22/98 + { + if (!manual) + continue; + else + return rtn; + } + + // new door thinker + rtn = 1; + door = Z_Malloc (sizeof(*door), PU_LEVSPEC, 0); + P_AddThinker (&door->thinker); + sec->ceilingdata = door; //jff 2/22/98 + + door->thinker.function = T_VerticalDoor; + door->sector = sec; + // setup delay for door remaining open/closed + switch(Dely) + { + default: + case 0: + door->topwait = 35; + break; + case 1: + door->topwait = VDOORWAIT; + break; + case 2: + door->topwait = 2*VDOORWAIT; + break; + case 3: + door->topwait = 7*VDOORWAIT; + break; + } + + // setup speed of door motion + switch(Sped) + { + default: + case SpeedSlow: + door->speed = VDOORSPEED; + break; + case SpeedNormal: + door->speed = VDOORSPEED*2; + break; + case SpeedFast: + door->speed = VDOORSPEED*4; + break; + case SpeedTurbo: + door->speed = VDOORSPEED*8; + break; + } + door->line = line; // jff 1/31/98 remember line that triggered us + + /* killough 10/98: implement gradual lighting */ + door->lighttag = !comp[comp_doorlight] && + (line->special&6) == 6 && + line->special > GenLockedBase ? line->tag : 0; + + // set kind of door, whether it opens then close, opens, closes etc. + // assign target heights accordingly + switch(Kind) + { + case OdCDoor: + door->direction = 1; + door->topheight = P_FindLowestCeilingSurrounding(sec); + door->topheight -= 4*FRACUNIT; + if (door->topheight != sec->ceilingheight) + S_StartSound((mobj_t *)&door->sector->soundorg,Sped>=SpeedFast || comp[comp_sound] ? sfx_bdopn : sfx_doropn); + door->type = Sped>=SpeedFast? genBlazeRaise : genRaise; + break; + case ODoor: + door->direction = 1; + door->topheight = P_FindLowestCeilingSurrounding(sec); + door->topheight -= 4*FRACUNIT; + if (door->topheight != sec->ceilingheight) + S_StartSound((mobj_t *)&door->sector->soundorg,Sped>=SpeedFast || comp[comp_sound] ? sfx_bdopn : sfx_doropn); + door->type = Sped>=SpeedFast? genBlazeOpen : genOpen; + break; + case CdODoor: + door->topheight = sec->ceilingheight; + door->direction = -1; + S_StartSound((mobj_t *)&door->sector->soundorg,Sped>=SpeedFast && !comp[comp_sound] ? sfx_bdcls : sfx_dorcls); + door->type = Sped>=SpeedFast? genBlazeCdO : genCdO; + break; + case CDoor: + door->topheight = P_FindLowestCeilingSurrounding(sec); + door->topheight -= 4*FRACUNIT; + door->direction = -1; + S_StartSound((mobj_t *)&door->sector->soundorg,Sped>=SpeedFast && !comp[comp_sound] ? sfx_bdcls : sfx_dorcls); + door->type = Sped>=SpeedFast? genBlazeClose : genClose; + break; + default: + break; + } + if (manual) + return rtn; + } + return rtn; +} diff --git a/apps/plugins/doom/p_inter.c b/apps/plugins/doom/p_inter.c new file mode 100644 index 0000000000..f4a0f80c8f --- /dev/null +++ b/apps/plugins/doom/p_inter.c @@ -0,0 +1,904 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Handling interactions (i.e., collisions). + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "dstrings.h" +#include "m_random.h" +#include "am_map.h" +#include "r_main.h" +#include "s_sound.h" +#include "sounds.h" +//#include "d_deh.h" // Ty 03/22/98 - externalized strings +#include "p_tick.h" +#include "i_system.h" +#include "p_inter.h" +#include "p_enemy.h" + +#ifdef __GNUG__ +#pragma implementation "p_inter.h" +#endif +#include "p_inter.h" + +#define BONUSADD 6 + +// Ty 03/07/98 - add deh externals +// Maximums and such were hardcoded values. Need to externalize those for +// dehacked support (and future flexibility). Most var names came from the key +// strings used in dehacked. + +int initial_health = 100; +int initial_bullets = 50; +int maxhealth = 100; // was MAXHEALTH as a #define, used only in this module +int max_armor = 200; +int green_armor_class = 1; // these are involved with armortype below +int blue_armor_class = 2; +int max_soul = 200; +int soul_health = 100; +int mega_health = 200; +int god_health = 100; // these are used in cheats (see st_stuff.c) +int idfa_armor = 200; +int idfa_armor_class = 2; +// not actually used due to pairing of cheat_k and cheat_fa +int idkfa_armor = 200; +int idkfa_armor_class = 2; + +int bfgcells = 40; // used in p_pspr.c +// Ty 03/07/98 - end deh externals + +// a weapon is found with two clip loads, +// a big item has five clip loads +int maxammo[NUMAMMO] = {200, 50, 300, 50}; +int clipammo[NUMAMMO] = { 10, 4, 20, 1}; + +// +// GET STUFF +// + +// +// P_GiveAmmo +// Num is the number of clip loads, +// not the individual count (0= 1/2 clip). +// Returns false if the ammo can't be picked up at all +// + +boolean P_GiveAmmo(player_t *player, ammotype_t ammo, int num) +{ + int oldammo; + + if (ammo == am_noammo) + return false; + +#ifdef RANGECHECK + if (ammo < 0 || ammo > NUMAMMO) + I_Error ("P_GiveAmmo: bad type %i", ammo); +#endif + + if ( player->ammo[ammo] == player->maxammo[ammo] ) + return false; + + if (num) + num *= clipammo[ammo]; + else + num = clipammo[ammo]/2; + + // give double ammo in trainer mode, you'll need in nightmare + if (gameskill == sk_baby || gameskill == sk_nightmare) + num <<= 1; + + oldammo = player->ammo[ammo]; + player->ammo[ammo] += num; + + if (player->ammo[ammo] > player->maxammo[ammo]) + player->ammo[ammo] = player->maxammo[ammo]; + + // If non zero ammo, don't change up weapons, player was lower on purpose. + if (oldammo) + return true; + + // We were down to zero, so select a new weapon. + // Preferences are not user selectable. + + switch (ammo) + { + case am_clip: + if (player->readyweapon == wp_fist) { + if (player->weaponowned[wp_chaingun]) + player->pendingweapon = wp_chaingun; + else + player->pendingweapon = wp_pistol; + } + break; + + case am_shell: + if (player->readyweapon == wp_fist || player->readyweapon == wp_pistol) + if (player->weaponowned[wp_shotgun]) + player->pendingweapon = wp_shotgun; + break; + + case am_cell: + if (player->readyweapon == wp_fist || player->readyweapon == wp_pistol) + if (player->weaponowned[wp_plasma]) + player->pendingweapon = wp_plasma; + break; + + case am_misl: + if (player->readyweapon == wp_fist) + if (player->weaponowned[wp_missile]) + player->pendingweapon = wp_missile; + default: + break; + } + return true; +} + +// +// P_GiveWeapon +// The weapon name may have a MF_DROPPED flag ored in. +// + +boolean P_GiveWeapon(player_t *player, weapontype_t weapon, boolean dropped) +{ + boolean gaveammo; + boolean gaveweapon; + + if (netgame && deathmatch!=2 && !dropped) + { + // leave placed weapons forever on net games + if (player->weaponowned[weapon]) + return false; + + player->bonuscount += BONUSADD; + player->weaponowned[weapon] = true; + + P_GiveAmmo(player, weaponinfo[weapon].ammo, deathmatch ? 5 : 2); + + player->pendingweapon = weapon; + /* cph 20028/10 - for old-school DM addicts, allow old behavior + * where only consoleplayer's pickup sounds are heard */ + if (!comp[comp_sound] || player == &players[consoleplayer]) + S_StartSound (player->mo, sfx_wpnup|PICKUP_SOUND); // killough 4/25/98 + return false; + } + + if (weaponinfo[weapon].ammo != am_noammo) + { + // give one clip with a dropped weapon, + // two clips with a found weapon + gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, dropped ? 1 : 2); + } + else + gaveammo = false; + + if (player->weaponowned[weapon]) + gaveweapon = false; + else + { + gaveweapon = true; + player->weaponowned[weapon] = true; + player->pendingweapon = weapon; + } + return gaveweapon || gaveammo; +} + +// +// P_GiveBody +// Returns false if the body isn't needed at all +// + +boolean P_GiveBody(player_t *player, int num) +{ + if (player->health >= maxhealth) + return false; // Ty 03/09/98 externalized MAXHEALTH to maxhealth + player->health += num; + if (player->health > maxhealth) + player->health = maxhealth; + player->mo->health = player->health; + return true; +} + +// +// P_GiveArmor +// Returns false if the armor is worse +// than the current armor. +// + +boolean P_GiveArmor(player_t *player, int armortype) +{ + int hits = armortype*100; + if (player->armorpoints >= hits) + return false; // don't pick up + player->armortype = armortype; + player->armorpoints = hits; + return true; +} + +// +// P_GiveCard +// + +void P_GiveCard(player_t *player, card_t card) +{ + if (player->cards[card]) + return; + player->bonuscount = BONUSADD; + player->cards[card] = 1; +} + +// +// P_GivePower +// +// Rewritten by Lee Killough +// + +boolean P_GivePower(player_t *player, int power) +{ + static const int tics[NUMPOWERS] = { + INVULNTICS, 1 /* strength */, INVISTICS, + IRONTICS, 1 /* allmap */, INFRATICS, + }; + + switch (power) + { + case pw_invisibility: + player->mo->flags |= MF_SHADOW; + break; + case pw_allmap: + if (player->powers[pw_allmap]) + return false; + break; + case pw_strength: + P_GiveBody(player,100); + break; + } + + // Unless player has infinite duration cheat, set duration (killough) + + if (player->powers[power] >= 0) + player->powers[power] = tics[power]; + return true; +} + +// +// P_TouchSpecialThing +// + +void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher) +{ + player_t *player; + int i; + int sound; + fixed_t delta = special->z - toucher->z; + + if (delta > toucher->height || delta < -8*FRACUNIT) + return; // out of reach + + sound = sfx_itemup; + player = toucher->player; + + // Dead thing touching. + // Can happen with a sliding player corpse. + if (toucher->health <= 0) + return; + + // Identify by sprite. + switch (special->sprite) + { + // armor + case SPR_ARM1: + if (!P_GiveArmor (player, green_armor_class)) + return; + player->message = GOTARMOR; // Ty 03/22/98 - externalized + break; + + case SPR_ARM2: + if (!P_GiveArmor (player, blue_armor_class)) + return; + player->message = GOTMEGA; // Ty 03/22/98 - externalized + break; + + // bonus items + case SPR_BON1: + player->health++; // can go over 100% + if (player->health > (maxhealth * 2)) + player->health = (maxhealth * 2); + player->mo->health = player->health; + player->message = GOTHTHBONUS; // Ty 03/22/98 - externalized + break; + + case SPR_BON2: + player->armorpoints++; // can go over 100% + if (player->armorpoints > max_armor) + player->armorpoints = max_armor; + if (!player->armortype) + player->armortype = green_armor_class; + player->message = GOTARMBONUS; // Ty 03/22/98 - externalized + break; + + case SPR_SOUL: + player->health += soul_health; + if (player->health > max_soul) + player->health = max_soul; + player->mo->health = player->health; + player->message = GOTSUPER; // Ty 03/22/98 - externalized + sound = sfx_getpow; + break; + + case SPR_MEGA: + if (gamemode != commercial) + return; + player->health = mega_health; + player->mo->health = player->health; + P_GiveArmor (player,blue_armor_class); + player->message = GOTMSPHERE; // Ty 03/22/98 - externalized + sound = sfx_getpow; + break; + + // cards + // leave cards for everyone + case SPR_BKEY: + if (!player->cards[it_bluecard]) + player->message = GOTBLUECARD; // Ty 03/22/98 - externalized + P_GiveCard (player, it_bluecard); + if (!netgame) + break; + return; + + case SPR_YKEY: + if (!player->cards[it_yellowcard]) + player->message = GOTYELWCARD; // Ty 03/22/98 - externalized + P_GiveCard (player, it_yellowcard); + if (!netgame) + break; + return; + + case SPR_RKEY: + if (!player->cards[it_redcard]) + player->message = GOTREDCARD; // Ty 03/22/98 - externalized + P_GiveCard (player, it_redcard); + if (!netgame) + break; + return; + + case SPR_BSKU: + if (!player->cards[it_blueskull]) + player->message = GOTBLUESKUL; // Ty 03/22/98 - externalized + P_GiveCard (player, it_blueskull); + if (!netgame) + break; + return; + + case SPR_YSKU: + if (!player->cards[it_yellowskull]) + player->message = GOTYELWSKUL; // Ty 03/22/98 - externalized + P_GiveCard (player, it_yellowskull); + if (!netgame) + break; + return; + + case SPR_RSKU: + if (!player->cards[it_redskull]) + player->message = GOTREDSKULL; // Ty 03/22/98 - externalized + P_GiveCard (player, it_redskull); + if (!netgame) + break; + return; + + // medikits, heals + case SPR_STIM: + if (!P_GiveBody (player, 10)) + return; + player->message = GOTSTIM; // Ty 03/22/98 - externalized + break; + + case SPR_MEDI: + if (!P_GiveBody (player, 25)) + return; + + if (player->health < 50) // cph - 25 + the 25 just added, thanks to Quasar for reporting this bug + player->message = GOTMEDINEED; // Ty 03/22/98 - externalized + else + player->message = GOTMEDIKIT; // Ty 03/22/98 - externalized + break; + + + // power ups + case SPR_PINV: + if (!P_GivePower (player, pw_invulnerability)) + return; + player->message = GOTINVUL; // Ty 03/22/98 - externalized + sound = sfx_getpow; + break; + + case SPR_PSTR: + if (!P_GivePower (player, pw_strength)) + return; + player->message = GOTBERSERK; // Ty 03/22/98 - externalized + if (player->readyweapon != wp_fist) + player->pendingweapon = wp_fist; + sound = sfx_getpow; + break; + + case SPR_PINS: + if (!P_GivePower (player, pw_invisibility)) + return; + player->message = GOTINVIS; // Ty 03/22/98 - externalized + sound = sfx_getpow; + break; + + case SPR_SUIT: + if (!P_GivePower (player, pw_ironfeet)) + return; + player->message = GOTSUIT; // Ty 03/22/98 - externalized + sound = sfx_getpow; + break; + + case SPR_PMAP: + if (!P_GivePower (player, pw_allmap)) + return; + player->message = GOTMAP; // Ty 03/22/98 - externalized + sound = sfx_getpow; + break; + + case SPR_PVIS: + if (!P_GivePower (player, pw_infrared)) + return; + player->message = GOTVISOR; // Ty 03/22/98 - externalized + sound = sfx_getpow; + break; + + // ammo + case SPR_CLIP: + if (special->flags & MF_DROPPED) + { + if (!P_GiveAmmo (player,am_clip,0)) + return; + } + else + { + if (!P_GiveAmmo (player,am_clip,1)) + return; + } + player->message = GOTCLIP; // Ty 03/22/98 - externalized + break; + + case SPR_AMMO: + if (!P_GiveAmmo (player, am_clip,5)) + return; + player->message = GOTCLIPBOX; // Ty 03/22/98 - externalized + break; + + case SPR_ROCK: + if (!P_GiveAmmo (player, am_misl,1)) + return; + player->message = GOTROCKET; // Ty 03/22/98 - externalized + break; + + case SPR_BROK: + if (!P_GiveAmmo (player, am_misl,5)) + return; + player->message = GOTROCKBOX; // Ty 03/22/98 - externalized + break; + + case SPR_CELL: + if (!P_GiveAmmo (player, am_cell,1)) + return; + player->message = GOTCELL; // Ty 03/22/98 - externalized + break; + + case SPR_CELP: + if (!P_GiveAmmo (player, am_cell,5)) + return; + player->message = GOTCELLBOX; // Ty 03/22/98 - externalized + break; + + case SPR_SHEL: + if (!P_GiveAmmo (player, am_shell,1)) + return; + player->message = GOTSHELLS; // Ty 03/22/98 - externalized + break; + + case SPR_SBOX: + if (!P_GiveAmmo (player, am_shell,5)) + return; + player->message = GOTSHELLBOX; // Ty 03/22/98 - externalized + break; + + case SPR_BPAK: + if (!player->backpack) + { + for (i=0 ; imaxammo[i] *= 2; + player->backpack = true; + } + for (i=0 ; imessage = GOTBACKPACK; // Ty 03/22/98 - externalized + break; + + // weapons + case SPR_BFUG: + if (!P_GiveWeapon (player, wp_bfg, false) ) + return; + player->message = GOTBFG9000; // Ty 03/22/98 - externalized + sound = sfx_wpnup; + break; + + case SPR_MGUN: + if (!P_GiveWeapon (player, wp_chaingun, (special->flags&MF_DROPPED)!=0) ) + return; + player->message = GOTCHAINGUN; // Ty 03/22/98 - externalized + sound = sfx_wpnup; + break; + + case SPR_CSAW: + if (!P_GiveWeapon (player, wp_chainsaw, false) ) + return; + player->message = GOTCHAINSAW; // Ty 03/22/98 - externalized + sound = sfx_wpnup; + break; + + case SPR_LAUN: + if (!P_GiveWeapon (player, wp_missile, false) ) + return; + player->message = GOTLAUNCHER; // Ty 03/22/98 - externalized + sound = sfx_wpnup; + break; + + case SPR_PLAS: + if (!P_GiveWeapon (player, wp_plasma, false) ) + return; + player->message = GOTPLASMA; // Ty 03/22/98 - externalized + sound = sfx_wpnup; + break; + + case SPR_SHOT: + if (!P_GiveWeapon (player, wp_shotgun, (special->flags&MF_DROPPED)!=0 ) ) + return; + player->message = GOTSHOTGUN; // Ty 03/22/98 - externalized + sound = sfx_wpnup; + break; + + case SPR_SGN2: + if (!P_GiveWeapon(player, wp_supershotgun, (special->flags&MF_DROPPED)!=0)) + return; + player->message = GOTSHOTGUN2; // Ty 03/22/98 - externalized + sound = sfx_wpnup; + break; + + default: + I_Error ("P_SpecialThing: Unknown gettable thing"); + } + + if (special->flags & MF_COUNTITEM) + player->itemcount++; + P_RemoveMobj (special); + player->bonuscount += BONUSADD; + + /* cph 20028/10 - for old-school DM addicts, allow old behavior + * where only consoleplayer's pickup sounds are heard */ + if (!comp[comp_sound] || player == &players[consoleplayer]) + S_StartSound (player->mo, sound | PICKUP_SOUND); // killough 4/25/98 +} + +// +// KillMobj +// +// killough 11/98: make static +static void P_KillMobj(mobj_t *source, mobj_t *target) +{ + mobjtype_t item; + mobj_t *mo; + + target->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SKULLFLY); + + if (target->type != MT_SKULL) + target->flags &= ~MF_NOGRAVITY; + + target->flags |= MF_CORPSE|MF_DROPOFF; + target->height >>= 2; + + if (!((target->flags ^ MF_COUNTKILL) & (MF_FRIEND | MF_COUNTKILL))) + totallive--; + + if (source && source->player) + { + // count for intermission + if (target->flags & MF_COUNTKILL) + source->player->killcount++; + if (target->player) + source->player->frags[target->player-players]++; + } + else + if (target->flags & MF_COUNTKILL) { /* Add to kills tally */ + if ((compatibility_level < lxdoom_1_compatibility) || !netgame) { + if (!netgame) + // count all monster deaths, + // even those caused by other monsters + players[0].killcount++; + } else + if (!deathmatch) { + // try and find a player to give the kill to, otherwise give the + // kill to a random player. this fixes the missing monsters bug + // in coop - rain + // CPhipps - not a bug as such, but certainly an inconsistency. + if (target->lastenemy && target->lastenemy->health > 0 + && target->lastenemy->player) // Fighting a player + target->lastenemy->player->killcount++; + else { + // cph - randomely choose a player in the game to be credited + // and do it uniformly between the active players + unsigned int activeplayers = 0, player, i; + + for (player = 0; playerplayer) + { + // count environment kills against you + if (!source) + target->player->frags[target->player-players]++; + + target->flags &= ~MF_SOLID; + target->player->playerstate = PST_DEAD; + P_DropWeapon (target->player); + + if (target->player == &players[consoleplayer] && (automapmode & am_active)) + AM_Stop(); // don't die in auto map; switch view prior to dying + } + + if (target->health < -target->info->spawnhealth && target->info->xdeathstate) + P_SetMobjState (target, target->info->xdeathstate); + else + P_SetMobjState (target, target->info->deathstate); + + target->tics -= P_Random(pr_killtics)&3; + + if (target->tics < 1) + target->tics = 1; + + // Drop stuff. + // This determines the kind of object spawned + // during the death frame of a thing. + + switch (target->type) + { + case MT_WOLFSS: + case MT_POSSESSED: + item = MT_CLIP; + break; + + case MT_SHOTGUY: + item = MT_SHOTGUN; + break; + + case MT_CHAINGUY: + item = MT_CHAINGUN; + break; + + default: + return; + } + + mo = P_SpawnMobj (target->x,target->y,ONFLOORZ, item); + mo->flags |= MF_DROPPED; // special versions of items +} + +// +// P_DamageMobj +// Damages both enemies and players +// "inflictor" is the thing that caused the damage +// creature or missile, can be NULL (slime, etc) +// "source" is the thing to target after taking damage +// creature or NULL +// Source and inflictor are the same for melee attacks. +// Source can be NULL for slime, barrel explosions +// and other environmental stuff. +// + +void P_DamageMobj(mobj_t *target,mobj_t *inflictor, mobj_t *source, int damage) +{ + player_t *player; + boolean justhit; /* killough 11/98 */ + + /* killough 8/31/98: allow bouncers to take damage */ + if (!(target->flags & (MF_SHOOTABLE | MF_BOUNCES))) + return; // shouldn't happen... + + if (target->health <= 0) + return; + + /* proff 11/22/98: Andy Baker's Stealth monsters */ + if (target->flags & MF_STEALTH) + P_BecomeVisible(target); + + if (target->flags & MF_SKULLFLY) + target->momx = target->momy = target->momz = 0; + + player = target->player; + if (player && gameskill == sk_baby) + damage >>= 1; // take half damage in trainer mode + + // Some close combat weapons should not + // inflict thrust and push the victim out of reach, + // thus kick away unless using the chainsaw. + + if (inflictor && !(target->flags & MF_NOCLIP) && + (!source || !source->player || + source->player->readyweapon != wp_chainsaw)) + { + unsigned ang = R_PointToAngle2 (inflictor->x, inflictor->y, + target->x, target->y); + + fixed_t thrust = damage*(FRACUNIT>>3)*100/target->info->mass; + + // make fall forwards sometimes + if ( damage < 40 && damage > target->health + && target->z - inflictor->z > 64*FRACUNIT + && P_Random(pr_damagemobj) & 1) + { + ang += ANG180; + thrust *= 4; + } + + ang >>= ANGLETOFINESHIFT; + target->momx += FixedMul (thrust, finecosine[ang]); + target->momy += FixedMul (thrust, finesine[ang]); + + /* killough 11/98: thrust objects hanging off ledges */ + if (target->intflags & MIF_FALLING && target->gear >= MAXGEAR) + target->gear = 0; + } + + // player specific + if (player) + { + // end of game hell hack + if (target->subsector->sector->special == 11 && damage >= target->health) + damage = target->health - 1; + + // Below certain threshold, + // ignore damage in GOD mode, or with INVUL power. + // killough 3/26/98: make god mode 100% god mode in non-compat mode + + if ((damage < 1000 || (!comp[comp_god] && (player->cheats&CF_GODMODE))) && + (player->cheats&CF_GODMODE || player->powers[pw_invulnerability])) + return; + + if (player->armortype) + { + int saved = player->armortype == 1 ? damage/3 : damage/2; + if (player->armorpoints <= saved) + { + // armor is used up + saved = player->armorpoints; + player->armortype = 0; + } + player->armorpoints -= saved; + damage -= saved; + } + + player->health -= damage; // mirror mobj health here for Dave + if (player->health < 0) + player->health = 0; + + player->attacker = source; + player->damagecount += damage; // add damage after armor / invuln + + if (player->damagecount > 100) + player->damagecount = 100; // teleport stomp does 10k points... + } + + // do the damage + target->health -= damage; + if (target->health <= 0) + { + P_KillMobj (source, target); + return; + } + + // killough 9/7/98: keep track of targets so that friends can help friends + if (mbf_features) + { + /* If target is a player, set player's target to source, + * so that a friend can tell who's hurting a player + */ + if (player) + P_SetTarget(&target->target, source); + + /* killough 9/8/98: + * If target's health is less than 50%, move it to the front of its list. + * This will slightly increase the chances that enemies will choose to + * "finish it off", but its main purpose is to alert friends of danger. + */ + if (target->health*2 < target->info->spawnhealth) + { + thinker_t *cap = &thinkerclasscap[target->flags & MF_FRIEND ? + th_friends : th_enemies]; + (target->thinker.cprev->cnext = target->thinker.cnext)->cprev = + target->thinker.cprev; + (target->thinker.cnext = cap->cnext)->cprev = &target->thinker; + (target->thinker.cprev = cap)->cnext = &target->thinker; + } + } + + if ((justhit = (P_Random (pr_painchance) < target->info->painchance && + !(target->flags & MF_SKULLFLY)))) //killough 11/98: see below + P_SetMobjState(target, target->info->painstate); + + target->reactiontime = 0; // we're awake now... + + /* killough 9/9/98: cleaned up, made more consistent: */ + + if (source && source != target && source->type != MT_VILE && + (!target->threshold || target->type == MT_VILE) && + ((source->flags ^ target->flags) & MF_FRIEND || + monster_infighting || + !mbf_features)) + { + /* if not intent on another player, chase after this one + * + * killough 2/15/98: remember last enemy, to prevent + * sleeping early; 2/21/98: Place priority on players + * killough 9/9/98: cleaned up, made more consistent: + */ + + if (!target->lastenemy || target->lastenemy->health <= 0 || + (!mbf_features ? + !target->lastenemy->player : + !((target->flags ^ target->lastenemy->flags) & MF_FRIEND) && + target->target != source)) // remember last enemy - killough + P_SetTarget(&target->lastenemy, target->target); + + P_SetTarget(&target->target, source); // killough 11/98 + target->threshold = BASETHRESHOLD; + if (target->state == &states[target->info->spawnstate] + && target->info->seestate != S_NULL) + P_SetMobjState (target, target->info->seestate); + } + + /* killough 11/98: Don't attack a friend, unless hit by that friend. */ + if (justhit && (target->target == source || !target->target || + !(target->flags & target->target->flags & MF_FRIEND))) + target->flags |= MF_JUSTHIT; // fight back! +} diff --git a/apps/plugins/doom/p_inter.h b/apps/plugins/doom/p_inter.h new file mode 100644 index 0000000000..669a9585f8 --- /dev/null +++ b/apps/plugins/doom/p_inter.h @@ -0,0 +1,77 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Thing events, and dehacked specified numbers controlling them. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __P_INTER__ +#define __P_INTER__ + +#include "d_player.h" +#include "p_mobj.h" + +#ifdef __GNUG__ +#pragma interface +#endif + +/* Ty 03/09/98 Moved to an int in p_inter.c for deh and externalization */ +#define MAXHEALTH 100//maxhealth + +/* follow a player exlusively for 3 seconds */ +#define BASETHRESHOLD (100) + +boolean P_GivePower(player_t *, int); +void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher); +void P_DamageMobj(mobj_t *target,mobj_t *inflictor,mobj_t *source,int damage); + +/* killough 5/2/98: moved from d_deh.c, g_game.c, m_misc.c, others: */ + +extern int god_health; /* Ty 03/09/98 - deh support, see also p_inter.c */ +extern int idfa_armor; +extern int idfa_armor_class; +extern int idkfa_armor; +extern int idkfa_armor_class; /* Ty - end */ +/* Ty 03/13/98 - externalized initial settings for respawned player */ +extern int initial_health; +extern int initial_bullets; +extern int maxhealth; +extern int max_armor; +extern int green_armor_class; +extern int blue_armor_class; +extern int max_soul; +extern int soul_health; +extern int mega_health; +extern int god_health; +extern int idfa_armor; +extern int idfa_armor_class; +extern int idkfa_armor; +extern int idkfa_armor_class; +extern int bfgcells; +extern int maxammo[], clipammo[]; + +#endif diff --git a/apps/plugins/doom/p_lights.c b/apps/plugins/doom/p_lights.c new file mode 100644 index 0000000000..44d151b7b5 --- /dev/null +++ b/apps/plugins/doom/p_lights.c @@ -0,0 +1,437 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Action routines for lighting thinkers + * Spawn sector based lighting effects. + * Handle lighting linedef types + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" //jff 5/18/98 +#include "doomdef.h" +#include "m_random.h" +#include "r_main.h" +#include "p_spec.h" +#include "p_tick.h" + +////////////////////////////////////////////////////////// +// +// Lighting action routines, called once per tick +// +////////////////////////////////////////////////////////// + +// +// T_FireFlicker() +// +// Firelight flicker action routine, called once per tick +// +// Passed a fireflicker_t structure containing light levels and timing +// Returns nothing +// +void T_FireFlicker (fireflicker_t* flick) +{ + int amount; + + if (--flick->count) + return; + + amount = (P_Random(pr_lights)&3)*16; + + if (flick->sector->lightlevel - amount < flick->minlight) + flick->sector->lightlevel = flick->minlight; + else + flick->sector->lightlevel = flick->maxlight - amount; + + flick->count = 4; +} + +// +// T_LightFlash() +// +// Broken light flashing action routine, called once per tick +// +// Passed a lightflash_t structure containing light levels and timing +// Returns nothing +// +void T_LightFlash (lightflash_t* flash) +{ + if (--flash->count) + return; + + if (flash->sector->lightlevel == flash->maxlight) + { + flash-> sector->lightlevel = flash->minlight; + flash->count = (P_Random(pr_lights)&flash->mintime)+1; + } + else + { + flash-> sector->lightlevel = flash->maxlight; + flash->count = (P_Random(pr_lights)&flash->maxtime)+1; + } + +} + +// +// T_StrobeFlash() +// +// Strobe light flashing action routine, called once per tick +// +// Passed a strobe_t structure containing light levels and timing +// Returns nothing +// +void T_StrobeFlash (strobe_t* flash) +{ + if (--flash->count) + return; + + if (flash->sector->lightlevel == flash->minlight) + { + flash-> sector->lightlevel = flash->maxlight; + flash->count = flash->brighttime; + } + else + { + flash-> sector->lightlevel = flash->minlight; + flash->count =flash->darktime; + } +} + +// +// T_Glow() +// +// Glowing light action routine, called once per tick +// +// Passed a glow_t structure containing light levels and timing +// Returns nothing +// + +void T_Glow(glow_t* g) +{ + switch(g->direction) + { + case -1: + // light dims + g->sector->lightlevel -= GLOWSPEED; + if (g->sector->lightlevel <= g->minlight) + { + g->sector->lightlevel += GLOWSPEED; + g->direction = 1; + } + break; + + case 1: + // light brightens + g->sector->lightlevel += GLOWSPEED; + if (g->sector->lightlevel >= g->maxlight) + { + g->sector->lightlevel -= GLOWSPEED; + g->direction = -1; + } + break; + } +} + +////////////////////////////////////////////////////////// +// +// Sector lighting type spawners +// +// After the map has been loaded, each sector is scanned +// for specials that spawn thinkers +// +////////////////////////////////////////////////////////// + +// +// P_SpawnFireFlicker() +// +// Spawns a fire flicker lighting thinker +// +// Passed the sector that spawned the thinker +// Returns nothing +// +void P_SpawnFireFlicker (sector_t* sector) +{ + fireflicker_t* flick; + + // Note that we are resetting sector attributes. + // Nothing special about it during gameplay. + sector->special &= ~31; //jff 3/14/98 clear non-generalized sector type + + flick = Z_Malloc ( sizeof(*flick), PU_LEVSPEC, 0); + + P_AddThinker (&flick->thinker); + + flick->thinker.function = T_FireFlicker; + flick->sector = sector; + flick->maxlight = sector->lightlevel; + flick->minlight = P_FindMinSurroundingLight(sector,sector->lightlevel)+16; + flick->count = 4; +} + +// +// P_SpawnLightFlash() +// +// Spawns a broken light flash lighting thinker +// +// Passed the sector that spawned the thinker +// Returns nothing +// +void P_SpawnLightFlash (sector_t* sector) +{ + lightflash_t* flash; + + // nothing special about it during gameplay + sector->special &= ~31; //jff 3/14/98 clear non-generalized sector type + + flash = Z_Malloc ( sizeof(*flash), PU_LEVSPEC, 0); + + P_AddThinker (&flash->thinker); + + flash->thinker.function = T_LightFlash; + flash->sector = sector; + flash->maxlight = sector->lightlevel; + + flash->minlight = P_FindMinSurroundingLight(sector,sector->lightlevel); + flash->maxtime = 64; + flash->mintime = 7; + flash->count = (P_Random(pr_lights)&flash->maxtime)+1; +} + +// +// P_SpawnStrobeFlash +// +// Spawns a blinking light thinker +// +// Passed the sector that spawned the thinker, speed of blinking +// and whether blinking is to by syncrhonous with other sectors +// +// Returns nothing +// +void P_SpawnStrobeFlash +( sector_t* sector, + int fastOrSlow, + int inSync ) +{ + strobe_t* flash; + + flash = Z_Malloc ( sizeof(*flash), PU_LEVSPEC, 0); + + P_AddThinker (&flash->thinker); + + flash->sector = sector; + flash->darktime = fastOrSlow; + flash->brighttime = STROBEBRIGHT; + flash->thinker.function = T_StrobeFlash; + flash->maxlight = sector->lightlevel; + flash->minlight = P_FindMinSurroundingLight(sector, sector->lightlevel); + + if (flash->minlight == flash->maxlight) + flash->minlight = 0; + + // nothing special about it during gameplay + sector->special &= ~31; //jff 3/14/98 clear non-generalized sector type + + if (!inSync) + flash->count = (P_Random(pr_lights)&7)+1; + else + flash->count = 1; +} + +// +// P_SpawnGlowingLight() +// +// Spawns a glowing light (smooth oscillation from min to max) thinker +// +// Passed the sector that spawned the thinker +// Returns nothing +// +void P_SpawnGlowingLight(sector_t* sector) +{ + glow_t* g; + + g = Z_Malloc( sizeof(*g), PU_LEVSPEC, 0); + + P_AddThinker(&g->thinker); + + g->sector = sector; + g->minlight = P_FindMinSurroundingLight(sector,sector->lightlevel); + g->maxlight = sector->lightlevel; + g->thinker.function = T_Glow; + g->direction = -1; + + sector->special &= ~31; //jff 3/14/98 clear non-generalized sector type +} + +////////////////////////////////////////////////////////// +// +// Linedef lighting function handlers +// +////////////////////////////////////////////////////////// + +// +// EV_StartLightStrobing() +// +// Start strobing lights (usually from a trigger) +// +// Passed the line that activated the strobing +// Returns true +// +// jff 2/12/98 added int return value, fixed return +// +int EV_StartLightStrobing(line_t* line) +{ + int secnum; + sector_t* sec; + + secnum = -1; + // start lights strobing in all sectors tagged same as line + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; + // if already doing a lighting function, don't start a second + if (P_SectorActive(lighting_special,sec)) //jff 2/22/98 + continue; + + P_SpawnStrobeFlash (sec,SLOWDARK, 0); + } + return 1; +} + +// +// EV_TurnTagLightsOff() +// +// Turn line's tagged sector's lights to min adjacent neighbor level +// +// Passed the line that activated the lights being turned off +// Returns true +// +// jff 2/12/98 added int return value, fixed return +// +int EV_TurnTagLightsOff(line_t* line) +{ + int j; + + // search sectors for those with same tag as activating line + + // killough 10/98: replaced inefficient search with fast search + for (j = -1; (j = P_FindSectorFromLineTag(line,j)) >= 0;) + { + sector_t *sector = sectors + j, *tsec; + int i, min = sector->lightlevel; + // find min neighbor light level + for (i = 0;i < sector->linecount; i++) + if ((tsec = getNextSector(sector->lines[i], sector)) && + tsec->lightlevel < min) + min = tsec->lightlevel; + sector->lightlevel = min; + } + return 1; +} + +// +// EV_LightTurnOn() +// +// Turn sectors tagged to line lights on to specified or max neighbor level +// +// Passed the activating line, and a level to set the light to +// If level passed is 0, the maximum neighbor lighting is used +// Returns true +// +// jff 2/12/98 added int return value, fixed return +// +int EV_LightTurnOn(line_t *line, int bright) +{ + int i; + + // search all sectors for ones with same tag as activating line + + // killough 10/98: replace inefficient search with fast search + for (i = -1; (i = P_FindSectorFromLineTag(line,i)) >= 0;) + { + sector_t *temp, *sector = sectors+i; + int j, tbright = bright; //jff 5/17/98 search for maximum PER sector + + // bright = 0 means to search for highest light level surrounding sector + + if (!bright) + for (j = 0;j < sector->linecount; j++) + if ((temp = getNextSector(sector->lines[j],sector)) && + temp->lightlevel > tbright) + tbright = temp->lightlevel; + + sector->lightlevel = tbright; + + //jff 5/17/98 unless compatibility optioned + //then maximum near ANY tagged sector + if (comp[comp_model]) + bright = tbright; + } + return 1; +} + +/* killough 10/98: + * + * EV_LightTurnOnPartway() + * + * Turn sectors tagged to line lights on to specified or max neighbor level + * + * Passed the activating line, and a light level fraction between 0 and 1. + * Sets the light to min on 0, max on 1, and interpolates in-between. + * Used for doors with gradual lighting effects. + * + * Returns true + */ + +int EV_LightTurnOnPartway(line_t *line, fixed_t level) +{ + int i; + + if (level < 0) // clip at extremes + level = 0; + if (level > FRACUNIT) + level = FRACUNIT; + + // search all sectors for ones with same tag as activating line + for (i = -1; (i = P_FindSectorFromLineTag(line,i)) >= 0;) + { + sector_t *temp, *sector = sectors+i; + int j, bright = 0, min = sector->lightlevel; + + for (j = 0; j < sector->linecount; j++) + if ((temp = getNextSector(sector->lines[j],sector))) + { + if (temp->lightlevel > bright) + bright = temp->lightlevel; + if (temp->lightlevel < min) + min = temp->lightlevel; + } + + sector->lightlevel = // Set level in-between extremes + (level * bright + (FRACUNIT-level) * min) >> FRACBITS; + } + return 1; +} + diff --git a/apps/plugins/doom/p_map.c b/apps/plugins/doom/p_map.c new file mode 100644 index 0000000000..35194dec14 --- /dev/null +++ b/apps/plugins/doom/p_map.c @@ -0,0 +1,2207 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Movement, collision handling. + * Shooting and aiming. + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "r_main.h" +#include "p_mobj.h" +#include "p_maputl.h" +#include "p_map.h" +#include "p_setup.h" +#include "p_spec.h" +#include "s_sound.h" +#include "sounds.h" +#include "p_inter.h" +#include "m_random.h" +#include "m_bbox.h" +#include "i_system.h" +#include "rockmacros.h" + +static mobj_t *tmthing; +static fixed_t tmx; +static fixed_t tmy; +static int pe_x; // Pain Elemental position for Lost Soul checks // phares +static int pe_y; // Pain Elemental position for Lost Soul checks // phares +static int ls_x; // Lost Soul position for Lost Soul checks // phares +static int ls_y; // Lost Soul position for Lost Soul checks // phares + +// If "floatok" true, move would be ok +// if within "tmfloorz - tmceilingz". + +boolean floatok; + +/* killough 11/98: if "felldown" true, object was pushed down ledge */ +boolean felldown; + +// The tm* items are used to hold information globally, usually for +// line or object intersection checking + +fixed_t tmbbox[4]; // bounding box for line intersection checks +fixed_t tmfloorz; // floor you'd hit if free to fall +fixed_t tmceilingz; // ceiling of sector you're in +fixed_t tmdropoffz; // dropoff on other side of line you're crossing + +// keep track of the line that lowers the ceiling, +// so missiles don't explode against sky hack walls + +line_t *ceilingline; +line_t *blockline; /* killough 8/11/98: blocking linedef */ +line_t *floorline; /* killough 8/1/98: Highest touched floor */ +static int tmunstuck; /* killough 8/1/98: whether to allow unsticking */ + +// keep track of special lines as they are hit, +// but don't process them until the move is proven valid + +// 1/11/98 killough: removed limit on special lines crossed +line_t **spechit; // new code -- killough +static int spechit_max; // killough + +int numspechit; + +// Temporary holder for thing_sectorlist threads +msecnode_t* sector_list = NULL; // phares 3/16/98 + +// +// TELEPORT MOVE +// + +// +// PIT_StompThing +// + +static boolean telefrag; /* killough 8/9/98: whether to telefrag at exit */ + +boolean PIT_StompThing (mobj_t* thing) +{ + fixed_t blockdist; + + // phares 9/10/98: moved this self-check to start of routine + + // don't clip against self + + if (thing == tmthing) + return true; + + if (!(thing->flags & MF_SHOOTABLE)) // Can't shoot it? Can't stomp it! + return true; + + blockdist = thing->radius + tmthing->radius; + + if (D_abs(thing->x - tmx) >= blockdist || D_abs(thing->y - tmy) >= blockdist) + return true; // didn't hit it + + // monsters don't stomp things except on boss level + if (!telefrag) // killough 8/9/98: make consistent across all levels + return false; + + P_DamageMobj (thing, tmthing, tmthing, 10000); // Stomp! + + return true; +} + + +/* + * killough 8/28/98: + * + * P_GetFriction() + * + * Returns the friction associated with a particular mobj. + */ + +int P_GetFriction(const mobj_t *mo, int *frictionfactor) +{ + int friction = ORIG_FRICTION; + int movefactor = ORIG_FRICTION_FACTOR; + const msecnode_t *m; + const sector_t *sec; + + /* Assign the friction value to objects on the floor, non-floating, + * and clipped. Normally the object's friction value is kept at + * ORIG_FRICTION and this thinker changes it for icy or muddy floors. + * + * When the object is straddling sectors with the same + * floorheight that have different frictions, use the lowest + * friction value (muddy has precedence over icy). + */ + + if (!(mo->flags & (MF_NOCLIP|MF_NOGRAVITY)) + && (mbf_features || (mo->player && !compatibility)) && + variable_friction) + for (m = mo->touching_sectorlist; m; m = m->m_tnext) + if ((sec = m->m_sector)->special & FRICTION_MASK && + (sec->friction < friction || friction == ORIG_FRICTION) && + (mo->z <= sec->floorheight || + (sec->heightsec != -1 && + mo->z <= sectors[sec->heightsec].floorheight && + mbf_features))) + friction = sec->friction, movefactor = sec->movefactor; + + if (frictionfactor) + *frictionfactor = movefactor; + + return friction; +} + +/* phares 3/19/98 + * P_GetMoveFactor() returns the value by which the x,y + * movements are multiplied to add to player movement. + * + * killough 8/28/98: rewritten + */ + +int P_GetMoveFactor(const mobj_t *mo, int *frictionp) +{ + int movefactor, friction; + + // If the floor is icy or muddy, it's harder to get moving. This is where + // the different friction factors are applied to 'trying to move'. In + // p_mobj.c, the friction factors are applied as you coast and slow down. + + if ((friction = P_GetFriction(mo, &movefactor)) < ORIG_FRICTION) + { + // phares 3/11/98: you start off slowly, then increase as + // you get better footing + + int momentum = P_AproxDistance(mo->momx,mo->momy); + + if (momentum > MORE_FRICTION_MOMENTUM<<2) + movefactor <<= 3; + else if (momentum > MORE_FRICTION_MOMENTUM<<1) + movefactor <<= 2; + else if (momentum > MORE_FRICTION_MOMENTUM) + movefactor <<= 1; + } + + if (frictionp) + *frictionp = friction; + + return movefactor; +} + +// +// P_TeleportMove +// + +boolean P_TeleportMove (mobj_t* thing,fixed_t x,fixed_t y, boolean boss) +{ + int xl; + int xh; + int yl; + int yh; + int bx; + int by; + + subsector_t* newsubsec; + + /* killough 8/9/98: make telefragging more consistent, preserve compatibility */ + telefrag = thing->player || + (!comp[comp_telefrag] ? boss : (gamemap==30)); + + // kill anything occupying the position + + tmthing = thing; + + tmx = x; + tmy = y; + + tmbbox[BOXTOP] = y + tmthing->radius; + tmbbox[BOXBOTTOM] = y - tmthing->radius; + tmbbox[BOXRIGHT] = x + tmthing->radius; + tmbbox[BOXLEFT] = x - tmthing->radius; + + newsubsec = R_PointInSubsector (x,y); + ceilingline = NULL; + + // The base floor/ceiling is from the subsector + // that contains the point. + // Any contacted lines the step closer together + // will adjust them. + + tmfloorz = tmdropoffz = newsubsec->sector->floorheight; + tmceilingz = newsubsec->sector->ceilingheight; + + validcount++; + numspechit = 0; + + // stomp on any things contacted + + xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT; + xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT; + yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT; + yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT; + + for (bx=xl ; bx<=xh ; bx++) + for (by=yl ; by<=yh ; by++) + if (!P_BlockThingsIterator(bx,by,PIT_StompThing)) + return false; + + // the move is ok, + // so unlink from the old position & link into the new position + + P_UnsetThingPosition (thing); + + thing->floorz = tmfloorz; + thing->ceilingz = tmceilingz; + thing->dropoffz = tmdropoffz; // killough 11/98 + + thing->x = x; + thing->y = y; + + P_SetThingPosition (thing); + + return true; +} + + +// +// MOVEMENT ITERATOR FUNCTIONS +// + +// // phares +// PIT_CrossLine // | +// Checks to see if a PE->LS trajectory line crosses a blocking // V +// line. Returns false if it does. +// +// tmbbox holds the bounding box of the trajectory. If that box +// does not touch the bounding box of the line in question, +// then the trajectory is not blocked. If the PE is on one side +// of the line and the LS is on the other side, then the +// trajectory is blocked. +// +// Currently this assumes an infinite line, which is not quite +// correct. A more correct solution would be to check for an +// intersection of the trajectory and the line, but that takes +// longer and probably really isn't worth the effort. +// + +static // killough 3/26/98: make static +boolean PIT_CrossLine (line_t* ld) +{ + if (!(ld->flags & ML_TWOSIDED) || + (ld->flags & (ML_BLOCKING|ML_BLOCKMONSTERS))) + if (!(tmbbox[BOXLEFT] > ld->bbox[BOXRIGHT] || + tmbbox[BOXRIGHT] < ld->bbox[BOXLEFT] || + tmbbox[BOXTOP] < ld->bbox[BOXBOTTOM] || + tmbbox[BOXBOTTOM] > ld->bbox[BOXTOP])) + if (P_PointOnLineSide(pe_x,pe_y,ld) != P_PointOnLineSide(ls_x,ls_y,ld)) + return(false); // line blocks trajectory // ^ + return(true); // line doesn't block trajectory // | +} // phares + + +/* killough 8/1/98: used to test intersection between thing and line + * assuming NO movement occurs -- used to avoid sticky situations. + */ + +static int untouched(line_t *ld) +{ + fixed_t x, y, tmbbox[4]; + return + (tmbbox[BOXRIGHT] = (x=tmthing->x)+tmthing->radius) <= ld->bbox[BOXLEFT] || + (tmbbox[BOXLEFT] = x-tmthing->radius) >= ld->bbox[BOXRIGHT] || + (tmbbox[BOXTOP] = (y=tmthing->y)+tmthing->radius) <= ld->bbox[BOXBOTTOM] || + (tmbbox[BOXBOTTOM] = y-tmthing->radius) >= ld->bbox[BOXTOP] || + P_BoxOnLineSide(tmbbox, ld) != -1; +} + +// +// PIT_CheckLine +// Adjusts tmfloorz and tmceilingz as lines are contacted +// + +static // killough 3/26/98: make static +boolean PIT_CheckLine (line_t* ld) +{ + if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT] + || tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT] + || tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM] + || tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP] ) + return true; // didn't hit it + + if (P_BoxOnLineSide(tmbbox, ld) != -1) + return true; // didn't hit it + + // A line has been hit + + // The moving thing's destination position will cross the given line. + // If this should not be allowed, return false. + // If the line is special, keep track of it + // to process later if the move is proven ok. + // NOTE: specials are NOT sorted by order, + // so two special lines that are only 8 pixels apart + // could be crossed in either order. + + // killough 7/24/98: allow player to move out of 1s wall, to prevent sticking + if (!ld->backsector) // one sided line + { + blockline = ld; + return tmunstuck && !untouched(ld) && + FixedMul(tmx-tmthing->x,ld->dy) > FixedMul(tmy-tmthing->y,ld->dx); + } + + // killough 8/10/98: allow bouncing objects to pass through as missiles + if (!(tmthing->flags & (MF_MISSILE | MF_BOUNCES))) + { + if (ld->flags & ML_BLOCKING) // explicitly blocking everything + return tmunstuck && !untouched(ld); // killough 8/1/98: allow escape + + // killough 8/9/98: monster-blockers don't affect friends + if (!(tmthing->flags & MF_FRIEND || tmthing->player) + && ld->flags & ML_BLOCKMONSTERS) + return false; // block monsters only + } + + // set openrange, opentop, openbottom + // these define a 'window' from one sector to another across this line + + P_LineOpening (ld); + + // adjust floor & ceiling heights + + if (opentop < tmceilingz) + { + tmceilingz = opentop; + ceilingline = ld; + blockline = ld; + } + + if (openbottom > tmfloorz) + { + tmfloorz = openbottom; + floorline = ld; // killough 8/1/98: remember floor linedef + blockline = ld; + } + + if (lowfloor < tmdropoffz) + tmdropoffz = lowfloor; + + // if contacted a special line, add it to the list + + if (ld->special) + { + // 1/11/98 killough: remove limit on lines hit, by array doubling + if (numspechit >= spechit_max) + { + spechit_max = spechit_max ? spechit_max*2 : 8; + spechit = realloc(spechit,sizeof *spechit*spechit_max); // killough + } + spechit[numspechit++] = ld; + } + + return true; +} + +// +// PIT_CheckThing +// + +static boolean PIT_CheckThing(mobj_t *thing) // killough 3/26/98: make static +{ + fixed_t blockdist; + int damage; + + // killough 11/98: add touchy things + if (!(thing->flags & (MF_SOLID|MF_SPECIAL|MF_SHOOTABLE|MF_TOUCHY))) + return true; + + blockdist = thing->radius + tmthing->radius; + + if (D_abs(thing->x - tmx) >= blockdist || D_abs(thing->y - tmy) >= blockdist) + return true; // didn't hit it + + // killough 11/98: + // + // This test has less information content (it's almost always false), so it + // should not be moved up to first, as it adds more overhead than it removes. + + // don't clip against self + + if (thing == tmthing) + return true; + + /* killough 11/98: + * + * TOUCHY flag, for mines or other objects which die on contact with solids. + * If a solid object of a different type comes in contact with a touchy + * thing, and the touchy thing is not the sole one moving relative to fixed + * surroundings such as walls, then the touchy thing dies immediately. + */ + + if (thing->flags & MF_TOUCHY && // touchy object + tmthing->flags & MF_SOLID && // solid object touches it + thing->health > 0 && // touchy object is alive + (thing->intflags & MIF_ARMED || // Thing is an armed mine + sentient(thing)) && // ... or a sentient thing + (thing->type != tmthing->type || // only different species + thing->type == MT_PLAYER) && // ... or different players + thing->z + thing->height >= tmthing->z && // touches vertically + tmthing->z + tmthing->height >= thing->z && + (thing->type ^ MT_PAIN) | // PEs and lost souls + (tmthing->type ^ MT_SKULL) && // are considered same + (thing->type ^ MT_SKULL) | // (but Barons & Knights + (tmthing->type ^ MT_PAIN)) // are intentionally not) + { + P_DamageMobj(thing, NULL, NULL, thing->health); // kill object + return true; + } + + // check for skulls slamming into things + + if (tmthing->flags & MF_SKULLFLY) + { + // A flying skull is smacking something. + // Determine damage amount, and the skull comes to a dead stop. + + int damage = ((P_Random(pr_skullfly)%8)+1)*tmthing->info->damage; + + P_DamageMobj (thing, tmthing, tmthing, damage); + + tmthing->flags &= ~MF_SKULLFLY; + tmthing->momx = tmthing->momy = tmthing->momz = 0; + + P_SetMobjState (tmthing, tmthing->info->spawnstate); + + return false; // stop moving + } + + // missiles can hit other things + // killough 8/10/98: bouncing non-solid things can hit other things too + + if (tmthing->flags & MF_MISSILE || (tmthing->flags & MF_BOUNCES && + !(tmthing->flags & MF_SOLID))) + { + // see if it went over / under + + if (tmthing->z > thing->z + thing->height) + return true; // overhead + + if (tmthing->z+tmthing->height < thing->z) + return true; // underneath + + if (tmthing->target && (tmthing->target->type == thing->type || + (tmthing->target->type == MT_KNIGHT && thing->type == MT_BRUISER)|| + (tmthing->target->type == MT_BRUISER && thing->type == MT_KNIGHT))) + { + if (thing == tmthing->target) + return true; // Don't hit same species as originator. + else + if (thing->type != MT_PLAYER) // Explode, but do no damage. + return false; // Let players missile other players. + } + + // killough 8/10/98: if moving thing is not a missile, no damage + // is inflicted, and momentum is reduced if object hit is solid. + + if (!(tmthing->flags & MF_MISSILE)) { + if (!(thing->flags & MF_SOLID)) { + return true; + } else { + tmthing->momx = -tmthing->momx; + tmthing->momy = -tmthing->momy; + if (!(tmthing->flags & MF_NOGRAVITY)) + { + tmthing->momx >>= 2; + tmthing->momy >>= 2; + } + return false; + } + } + + if (!(thing->flags & MF_SHOOTABLE)) + return !(thing->flags & MF_SOLID); // didn't do any damage + + // damage / explode + + damage = ((P_Random(pr_damage)%8)+1)*tmthing->info->damage; + P_DamageMobj (thing, tmthing, tmthing->target, damage); + + // don't traverse any more + return false; + } + + // check for special pickup + + if (thing->flags & MF_SPECIAL) + { + uint_64_t solid = thing->flags & MF_SOLID; + if (tmthing->flags & MF_PICKUP) + P_TouchSpecialThing(thing, tmthing); // can remove thing + return !solid; + } + + // killough 3/16/98: Allow non-solid moving objects to move through solid + // ones, by allowing the moving thing (tmthing) to move if it's non-solid, + // despite another solid thing being in the way. + // killough 4/11/98: Treat no-clipping things as not blocking + + return !((thing->flags & MF_SOLID && !(thing->flags & MF_NOCLIP)) + && (tmthing->flags & MF_SOLID || demo_compatibility)); + + // return !(thing->flags & MF_SOLID); // old code -- killough +} + +// This routine checks for Lost Souls trying to be spawned // phares +// across 1-sided lines, impassible lines, or "monsters can't // | +// cross" lines. Draw an imaginary line between the PE // V +// and the new Lost Soul spawn spot. If that line crosses +// a 'blocking' line, then disallow the spawn. Only search +// lines in the blocks of the blockmap where the bounding box +// of the trajectory line resides. Then check bounding box +// of the trajectory vs. the bounding box of each blocking +// line to see if the trajectory and the blocking line cross. +// Then check the PE and LS to see if they're on different +// sides of the blocking line. If so, return true, otherwise +// false. + +boolean Check_Sides(mobj_t* actor, int x, int y) +{ + int bx,by,xl,xh,yl,yh; + + pe_x = actor->x; + pe_y = actor->y; + ls_x = x; + ls_y = y; + + // Here is the bounding box of the trajectory + + tmbbox[BOXLEFT] = pe_x < x ? pe_x : x; + tmbbox[BOXRIGHT] = pe_x > x ? pe_x : x; + tmbbox[BOXTOP] = pe_y > y ? pe_y : y; + tmbbox[BOXBOTTOM] = pe_y < y ? pe_y : y; + + // Determine which blocks to look in for blocking lines + + xl = (tmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT; + xh = (tmbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT; + yl = (tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT; + yh = (tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT; + + // xl->xh, yl->yh determine the mapblock set to search + + validcount++; // prevents checking same line twice + for (bx = xl ; bx <= xh ; bx++) + for (by = yl ; by <= yh ; by++) + if (!P_BlockLinesIterator(bx,by,PIT_CrossLine)) + return true; // ^ + return(false); // | +} // phares + +// +// MOVEMENT CLIPPING +// + +// +// P_CheckPosition +// This is purely informative, nothing is modified +// (except things picked up). +// +// in: +// a mobj_t (can be valid or invalid) +// a position to be checked +// (doesn't need to be related to the mobj_t->x,y) +// +// during: +// special things are touched if MF_PICKUP +// early out on solid lines? +// +// out: +// newsubsec +// floorz +// ceilingz +// tmdropoffz +// the lowest point contacted +// (monsters won't move to a dropoff) +// speciallines[] +// numspeciallines +// + +boolean P_CheckPosition (mobj_t* thing,fixed_t x,fixed_t y) +{ + int xl; + int xh; + int yl; + int yh; + int bx; + int by; + subsector_t* newsubsec; + + tmthing = thing; + + tmx = x; + tmy = y; + + tmbbox[BOXTOP] = y + tmthing->radius; + tmbbox[BOXBOTTOM] = y - tmthing->radius; + tmbbox[BOXRIGHT] = x + tmthing->radius; + tmbbox[BOXLEFT] = x - tmthing->radius; + + newsubsec = R_PointInSubsector (x,y); + floorline = blockline = ceilingline = NULL; // killough 8/1/98 + + // Whether object can get out of a sticky situation: + tmunstuck = thing->player && /* only players */ + thing->player->mo == thing && /* not voodoo dolls */ + mbf_features; /* not under old demos */ + + // The base floor / ceiling is from the subsector + // that contains the point. + // Any contacted lines the step closer together + // will adjust them. + + tmfloorz = tmdropoffz = newsubsec->sector->floorheight; + tmceilingz = newsubsec->sector->ceilingheight; + validcount++; + numspechit = 0; + + if ( tmthing->flags & MF_NOCLIP ) + return true; + + // Check things first, possibly picking things up. + // The bounding box is extended by MAXRADIUS + // because mobj_ts are grouped into mapblocks + // based on their origin point, and can overlap + // into adjacent blocks by up to MAXRADIUS units. + + xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT; + xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT; + yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT; + yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT; + + + for (bx=xl ; bx<=xh ; bx++) + for (by=yl ; by<=yh ; by++) + if (!P_BlockThingsIterator(bx,by,PIT_CheckThing)) + return false; + + // check lines + + xl = (tmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT; + xh = (tmbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT; + yl = (tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT; + yh = (tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT; + + for (bx=xl ; bx<=xh ; bx++) + for (by=yl ; by<=yh ; by++) + if (!P_BlockLinesIterator (bx,by,PIT_CheckLine)) + return false; // doesn't fit + + return true; +} + + +// +// P_TryMove +// Attempt to move to a new position, +// crossing special lines unless MF_TELEPORT is set. +// +boolean P_TryMove(mobj_t* thing,fixed_t x,fixed_t y, + boolean dropoff) // killough 3/15/98: allow dropoff as option +{ + fixed_t oldx; + fixed_t oldy; + + felldown = floatok = false; // killough 11/98 + + if (!P_CheckPosition (thing, x, y)) + return false; // solid wall or thing + + if ( !(thing->flags & MF_NOCLIP) ) + { + // killough 7/26/98: reformatted slightly + // killough 8/1/98: Possibly allow escape if otherwise stuck + + if (tmceilingz - tmfloorz < thing->height || // doesn't fit + // mobj must lower to fit + (floatok = true, !(thing->flags & MF_TELEPORT) && + tmceilingz - thing->z < thing->height) || + // too big a step up + (!(thing->flags & MF_TELEPORT) && + tmfloorz - thing->z > 24*FRACUNIT)) + return tmunstuck + && !(ceilingline && untouched(ceilingline)) + && !( floorline && untouched( floorline)); + + /* killough 3/15/98: Allow certain objects to drop off + * killough 7/24/98, 8/1/98: + * Prevent monsters from getting stuck hanging off ledges + * killough 10/98: Allow dropoffs in controlled circumstances + * killough 11/98: Improve symmetry of clipping on stairs + */ + + if (!(thing->flags & (MF_DROPOFF|MF_FLOAT))) { + if (comp[comp_dropoff]) + { + if ((compatibility || !dropoff) && (tmfloorz - tmdropoffz > 24*FRACUNIT)) + return false; // don't stand over a dropoff + } + else + if (!dropoff || (dropoff==2 && // large jump down (e.g. dogs) + (tmfloorz-tmdropoffz > 128*FRACUNIT || + !thing->target || thing->target->z >tmdropoffz))) + { + if (!monkeys || !mbf_features ? + tmfloorz - tmdropoffz > 24*FRACUNIT : + thing->floorz - tmfloorz > 24*FRACUNIT || + thing->dropoffz - tmdropoffz > 24*FRACUNIT) + return false; + } + else { /* dropoff allowed -- check for whether it fell more than 24 */ + felldown = !(thing->flags & MF_NOGRAVITY) && + thing->z - tmfloorz > 24*FRACUNIT; + } + } + + if (thing->flags & MF_BOUNCES && // killough 8/13/98 + !(thing->flags & (MF_MISSILE|MF_NOGRAVITY)) && + !sentient(thing) && tmfloorz - thing->z > 16*FRACUNIT) + return false; // too big a step up for bouncers under gravity + + // killough 11/98: prevent falling objects from going up too many steps + if (thing->intflags & MIF_FALLING && tmfloorz - thing->z > + FixedMul(thing->momx,thing->momx)+FixedMul(thing->momy,thing->momy)) + return false; + } + + // the move is ok, + // so unlink from the old position and link into the new position + + P_UnsetThingPosition (thing); + + oldx = thing->x; + oldy = thing->y; + thing->floorz = tmfloorz; + thing->ceilingz = tmceilingz; + thing->dropoffz = tmdropoffz; // killough 11/98: keep track of dropoffs + thing->x = x; + thing->y = y; + + P_SetThingPosition (thing); + + // if any special lines were hit, do the effect + + if (! (thing->flags&(MF_TELEPORT|MF_NOCLIP)) ) + while (numspechit--) + if (spechit[numspechit]->special) // see if the line was crossed + { + int oldside; + if ((oldside = P_PointOnLineSide(oldx, oldy, spechit[numspechit])) != + P_PointOnLineSide(thing->x, thing->y, spechit[numspechit])) + P_CrossSpecialLine(spechit[numspechit], oldside, thing); + } + + return true; +} + +/* + * killough 9/12/98: + * + * Apply "torque" to objects hanging off of ledges, so that they + * fall off. It's not really torque, since Doom has no concept of + * rotation, but it's a convincing effect which avoids anomalies + * such as lifeless objects hanging more than halfway off of ledges, + * and allows objects to roll off of the edges of moving lifts, or + * to slide up and then back down stairs, or to fall into a ditch. + * If more than one linedef is contacted, the effects are cumulative, + * so balancing is possible. + */ + +static boolean PIT_ApplyTorque(line_t *ld) +{ + if (ld->backsector && // If thing touches two-sided pivot linedef + tmbbox[BOXRIGHT] > ld->bbox[BOXLEFT] && + tmbbox[BOXLEFT] < ld->bbox[BOXRIGHT] && + tmbbox[BOXTOP] > ld->bbox[BOXBOTTOM] && + tmbbox[BOXBOTTOM] < ld->bbox[BOXTOP] && + P_BoxOnLineSide(tmbbox, ld) == -1) + { + mobj_t *mo = tmthing; + + fixed_t dist = // lever arm + + (ld->dx >> FRACBITS) * (mo->y >> FRACBITS) + - (ld->dy >> FRACBITS) * (mo->x >> FRACBITS) + - (ld->dx >> FRACBITS) * (ld->v1->y >> FRACBITS) + + (ld->dy >> FRACBITS) * (ld->v1->x >> FRACBITS); + + if (dist < 0 ? // dropoff direction + ld->frontsector->floorheight < mo->z && + ld->backsector->floorheight >= mo->z : + ld->backsector->floorheight < mo->z && + ld->frontsector->floorheight >= mo->z) + { + /* At this point, we know that the object straddles a two-sided + * linedef, and that the object's center of mass is above-ground. + */ + + fixed_t x = D_abs(ld->dx), y = D_abs(ld->dy); + + if (y > x) + { + fixed_t t = x; + x = y; + y = t; + } + + y = finesine[(tantoangle[FixedDiv(y,x)>>DBITS] + + ANG90) >> ANGLETOFINESHIFT]; + + /* Momentum is proportional to distance between the + * object's center of mass and the pivot linedef. + * + * It is scaled by 2^(OVERDRIVE - gear). When gear is + * increased, the momentum gradually decreases to 0 for + * the same amount of pseudotorque, so that oscillations + * are prevented, yet it has a chance to reach equilibrium. + */ + dist = FixedDiv(FixedMul(dist, (mo->gear < OVERDRIVE) ? + y << -(mo->gear - OVERDRIVE) : + y >> +(mo->gear - OVERDRIVE)), x); + + /* Apply momentum away from the pivot linedef. */ + + x = FixedMul(ld->dy, dist); + y = FixedMul(ld->dx, dist); + + /* Avoid moving too fast all of a sudden (step into "overdrive") */ + + dist = FixedMul(x,x) + FixedMul(y,y); + + while (dist > FRACUNIT*4 && mo->gear < MAXGEAR) + ++mo->gear, x >>= 1, y >>= 1, dist >>= 1; + + mo->momx -= x; + mo->momy += y; + } + } + return true; +} + +/* + * killough 9/12/98 + * + * Applies "torque" to objects, based on all contacted linedefs + */ + +void P_ApplyTorque(mobj_t *mo) +{ + int xl = ((tmbbox[BOXLEFT] = + mo->x - mo->radius) - bmaporgx) >> MAPBLOCKSHIFT; + int xh = ((tmbbox[BOXRIGHT] = + mo->x + mo->radius) - bmaporgx) >> MAPBLOCKSHIFT; + int yl = ((tmbbox[BOXBOTTOM] = + mo->y - mo->radius) - bmaporgy) >> MAPBLOCKSHIFT; + int yh = ((tmbbox[BOXTOP] = + mo->y + mo->radius) - bmaporgy) >> MAPBLOCKSHIFT; + int bx,by,flags = mo->intflags; //Remember the current state, for gear-change + + tmthing = mo; + validcount++; /* prevents checking same line twice */ + + for (bx = xl ; bx <= xh ; bx++) + for (by = yl ; by <= yh ; by++) + P_BlockLinesIterator(bx, by, PIT_ApplyTorque); + + /* If any momentum, mark object as 'falling' using engine-internal flags */ + if (mo->momx | mo->momy) + mo->intflags |= MIF_FALLING; + else // Clear the engine-internal flag indicating falling object. + mo->intflags &= ~MIF_FALLING; + + /* If the object has been moving, step up the gear. + * This helps reach equilibrium and avoid oscillations. + * + * Doom has no concept of potential energy, much less + * of rotation, so we have to creatively simulate these + * systems somehow :) + */ + + if (!((mo->intflags | flags) & MIF_FALLING)) // If not falling for a while, + mo->gear = 0; // Reset it to full strength + else + if (mo->gear < MAXGEAR) // Else if not at max gear, + mo->gear++; // move up a gear +} + +// +// P_ThingHeightClip +// Takes a valid thing and adjusts the thing->floorz, +// thing->ceilingz, and possibly thing->z. +// This is called for all nearby monsters +// whenever a sector changes height. +// If the thing doesn't fit, +// the z will be set to the lowest value +// and false will be returned. +// + +boolean P_ThingHeightClip (mobj_t* thing) +{ + boolean onfloor; + + onfloor = (thing->z == thing->floorz); + + P_CheckPosition (thing, thing->x, thing->y); + + /* what about stranding a monster partially off an edge? + * killough 11/98: Answer: see below (upset balance if hanging off ledge) + */ + + thing->floorz = tmfloorz; + thing->ceilingz = tmceilingz; + thing->dropoffz = tmdropoffz; /* killough 11/98: remember dropoffs */ + + if (onfloor) + { + + // walking monsters rise and fall with the floor + + thing->z = thing->floorz; + + /* killough 11/98: Possibly upset balance of objects hanging off ledges */ + if (thing->intflags & MIF_FALLING && thing->gear >= MAXGEAR) + thing->gear = 0; + } + else + { + + // don't adjust a floating monster unless forced to + + if (thing->z+thing->height > thing->ceilingz) + thing->z = thing->ceilingz - thing->height; + } + + return thing->ceilingz - thing->floorz >= thing->height; +} + + +// +// SLIDE MOVE +// Allows the player to slide along any angled walls. +// + +/* killough 8/2/98: make variables static */ +static fixed_t bestslidefrac; +static fixed_t secondslidefrac; +static line_t* bestslideline; +static line_t* secondslideline; +static mobj_t* slidemo; +static fixed_t tmxmove; +static fixed_t tmymove; + + +// +// P_HitSlideLine +// Adjusts the xmove / ymove +// so that the next move will slide along the wall. +// If the floor is icy, then you can bounce off a wall. // phares +// + +void P_HitSlideLine (line_t* ld) +{ + int side; + angle_t lineangle; + angle_t moveangle; + angle_t deltaangle; + fixed_t movelen; + fixed_t newlen; + boolean icyfloor; // is floor icy? // phares + // | + // Under icy conditions, if the angle of approach to the wall // V + // is more than 45 degrees, then you'll bounce and lose half + // your momentum. If less than 45 degrees, you'll slide along + // the wall. 45 is arbitrary and is believable. + + // Check for the special cases of horz or vert walls. + + /* killough 10/98: only bounce if hit hard (prevents wobbling) + * cph - DEMOSYNC - should only affect players in Boom demos? */ + icyfloor = + (mbf_features ? + P_AproxDistance(tmxmove, tmymove) > 4*FRACUNIT : !compatibility) && + variable_friction && // killough 8/28/98: calc friction on demand + slidemo->z <= slidemo->floorz && + P_GetFriction(slidemo, NULL) > ORIG_FRICTION; + + if (ld->slopetype == ST_HORIZONTAL) + { + if (icyfloor && (D_abs(tmymove) > D_abs(tmxmove))) + { + tmxmove /= 2; // absorb half the momentum + tmymove = -tmymove/2; + S_StartSound(slidemo,sfx_oof); // oooff! + } + else + tmymove = 0; // no more movement in the Y direction + return; + } + + if (ld->slopetype == ST_VERTICAL) + { + if (icyfloor && (D_abs(tmxmove) > D_abs(tmymove))) + { + tmxmove = -tmxmove/2; // absorb half the momentum + tmymove /= 2; + S_StartSound(slidemo,sfx_oof); // oooff! // ^ + } // | + else // phares + tmxmove = 0; // no more movement in the X direction + return; + } + + // The wall is angled. Bounce if the angle of approach is // phares + // less than 45 degrees. // phares + + side = P_PointOnLineSide (slidemo->x, slidemo->y, ld); + + lineangle = R_PointToAngle2 (0,0, ld->dx, ld->dy); + if (side == 1) + lineangle += ANG180; + moveangle = R_PointToAngle2 (0,0, tmxmove, tmymove); + + // killough 3/2/98: + // The moveangle+=10 breaks v1.9 demo compatibility in + // some demos, so it needs demo_compatibility switch. + + if (!demo_compatibility) + moveangle += 10; // prevents sudden path reversal due to // phares + // rounding error // | + deltaangle = moveangle-lineangle; // V + movelen = P_AproxDistance (tmxmove, tmymove); + if (icyfloor && (deltaangle > ANG45) && (deltaangle < ANG90+ANG45)) + { + moveangle = lineangle - deltaangle; + movelen /= 2; // absorb + S_StartSound(slidemo,sfx_oof); // oooff! + moveangle >>= ANGLETOFINESHIFT; + tmxmove = FixedMul (movelen, finecosine[moveangle]); + tmymove = FixedMul (movelen, finesine[moveangle]); + } // ^ + else // | + { // phares + if (deltaangle > ANG180) + deltaangle += ANG180; + + // I_Error ("SlideLine: ang>ANG180"); + + lineangle >>= ANGLETOFINESHIFT; + deltaangle >>= ANGLETOFINESHIFT; + newlen = FixedMul (movelen, finecosine[deltaangle]); + tmxmove = FixedMul (newlen, finecosine[lineangle]); + tmymove = FixedMul (newlen, finesine[lineangle]); + } // phares +} + + +// +// PTR_SlideTraverse +// + +boolean PTR_SlideTraverse (intercept_t* in) +{ + line_t* li; + + if (!in->isaline) + I_Error ("PTR_SlideTraverse: not a line?"); + + li = in->d.line; + + if ( ! (li->flags & ML_TWOSIDED) ) + { + if (P_PointOnLineSide (slidemo->x, slidemo->y, li)) + return true; // don't hit the back side + goto isblocking; + } + + // set openrange, opentop, openbottom. + // These define a 'window' from one sector to another across a line + + P_LineOpening (li); + + if (openrange < slidemo->height) + goto isblocking; // doesn't fit + + if (opentop - slidemo->z < slidemo->height) + goto isblocking; // mobj is too high + + if (openbottom - slidemo->z > 24*FRACUNIT ) + goto isblocking; // too big a step up + + // this line doesn't block movement + + return true; + + // the line does block movement, + // see if it is closer than best so far + +isblocking: + + if (in->frac < bestslidefrac) + { + secondslidefrac = bestslidefrac; + secondslideline = bestslideline; + bestslidefrac = in->frac; + bestslideline = li; + } + + return false; // stop +} + + +// +// P_SlideMove +// The momx / momy move is bad, so try to slide +// along a wall. +// Find the first line hit, move flush to it, +// and slide along it +// +// This is a kludgy mess. +// +// killough 11/98: reformatted + +void P_SlideMove(mobj_t *mo) +{ + int hitcount = 3; + + slidemo = mo; // the object that's sliding + + do + { + fixed_t leadx, leady, trailx, traily; + + if (!--hitcount) + goto stairstep; // don't loop forever + + // trace along the three leading corners + + if (mo->momx > 0) + leadx = mo->x + mo->radius, trailx = mo->x - mo->radius; + else + leadx = mo->x - mo->radius, trailx = mo->x + mo->radius; + + if (mo->momy > 0) + leady = mo->y + mo->radius, traily = mo->y - mo->radius; + else + leady = mo->y - mo->radius, traily = mo->y + mo->radius; + + bestslidefrac = FRACUNIT+1; + + P_PathTraverse(leadx, leady, leadx+mo->momx, leady+mo->momy, + PT_ADDLINES, PTR_SlideTraverse); + P_PathTraverse(trailx, leady, trailx+mo->momx, leady+mo->momy, + PT_ADDLINES, PTR_SlideTraverse); + P_PathTraverse(leadx, traily, leadx+mo->momx, traily+mo->momy, + PT_ADDLINES, PTR_SlideTraverse); + + // move up to the wall + + if (bestslidefrac == FRACUNIT+1) + { + // the move must have hit the middle, so stairstep + +stairstep: + + /* killough 3/15/98: Allow objects to drop off ledges + * + * phares 5/4/98: kill momentum if you can't move at all + * This eliminates player bobbing if pressed against a wall + * while on ice. + * + * killough 10/98: keep buggy code around for old Boom demos + * + * cph 2000/09//23: buggy code was only in Boom v2.01 + */ + + if (!P_TryMove(mo, mo->x, mo->y + mo->momy, true)) + if (!P_TryMove(mo, mo->x + mo->momx, mo->y, true)) + if (compatibility_level == boom_201_compatibility) + mo->momx = mo->momy = 0; + + break; + } + + // fudge a bit to make sure it doesn't hit + + if ((bestslidefrac -= 0x800) > 0) + { + fixed_t newx = FixedMul(mo->momx, bestslidefrac); + fixed_t newy = FixedMul(mo->momy, bestslidefrac); + + // killough 3/15/98: Allow objects to drop off ledges + + if (!P_TryMove(mo, mo->x+newx, mo->y+newy, true)) + goto stairstep; + } + + // Now continue along the wall. + // First calculate remainder. + + bestslidefrac = FRACUNIT-(bestslidefrac+0x800); + + if (bestslidefrac > FRACUNIT) + bestslidefrac = FRACUNIT; + + if (bestslidefrac <= 0) + break; + + tmxmove = FixedMul(mo->momx, bestslidefrac); + tmymove = FixedMul(mo->momy, bestslidefrac); + + P_HitSlideLine(bestslideline); // clip the moves + + mo->momx = tmxmove; + mo->momy = tmymove; + + /* killough 10/98: affect the bobbing the same way (but not voodoo dolls) + * cph - DEMOSYNC? */ + if (mo->player && mo->player->mo == mo) + { + if (D_abs(mo->player->momx) > D_abs(tmxmove)) + mo->player->momx = tmxmove; + if (D_abs(mo->player->momy) > D_abs(tmymove)) + mo->player->momy = tmymove; + } + } // killough 3/15/98: Allow objects to drop off ledges: + while (!P_TryMove(mo, mo->x+tmxmove, mo->y+tmymove, true)); +} + +// +// P_LineAttack +// +mobj_t* linetarget; // who got hit (or NULL) +static mobj_t* shootthing; + +/* killough 8/2/98: for more intelligent autoaiming */ +static uint_64_t aim_flags_mask; + +// Height if not aiming up or down +fixed_t shootz; + +int la_damage; +fixed_t attackrange; + +static fixed_t aimslope; + +// slopes to top and bottom of target +// killough 4/20/98: make static instead of using ones in p_sight.c + +static fixed_t topslope; +static fixed_t bottomslope; + + +// +// PTR_AimTraverse +// Sets linetaget and aimslope when a target is aimed at. +// +boolean PTR_AimTraverse (intercept_t* in) +{ + line_t* li; + mobj_t* th; + fixed_t slope; + fixed_t thingtopslope; + fixed_t thingbottomslope; + fixed_t dist; + + if (in->isaline) + { + li = in->d.line; + + if ( !(li->flags & ML_TWOSIDED) ) + return false; // stop + + // Crosses a two sided line. + // A two sided line will restrict + // the possible target ranges. + + P_LineOpening (li); + + if (openbottom >= opentop) + return false; // stop + + dist = FixedMul (attackrange, in->frac); + + if (li->frontsector->floorheight != li->backsector->floorheight) + { + slope = FixedDiv (openbottom - shootz , dist); + if (slope > bottomslope) + bottomslope = slope; + } + + if (li->frontsector->ceilingheight != li->backsector->ceilingheight) + { + slope = FixedDiv (opentop - shootz , dist); + if (slope < topslope) + topslope = slope; + } + + if (topslope <= bottomslope) + return false; // stop + + return true; // shot continues + } + + // shoot a thing + + th = in->d.thing; + if (th == shootthing) + return true; // can't shoot self + + if (!(th->flags&MF_SHOOTABLE)) + return true; // corpse or something + + /* killough 7/19/98, 8/2/98: + * friends don't aim at friends (except players), at least not first + */ + if (th->flags & shootthing->flags & aim_flags_mask && !th->player) + return true; + + // check angles to see if the thing can be aimed at + + dist = FixedMul (attackrange, in->frac); + thingtopslope = FixedDiv (th->z+th->height - shootz , dist); + + if (thingtopslope < bottomslope) + return true; // shot over the thing + + thingbottomslope = FixedDiv (th->z - shootz, dist); + + if (thingbottomslope > topslope) + return true; // shot under the thing + + // this thing can be hit! + + if (thingtopslope > topslope) + thingtopslope = topslope; + + if (thingbottomslope < bottomslope) + thingbottomslope = bottomslope; + + aimslope = (thingtopslope+thingbottomslope)/2; + linetarget = th; + + return false; // don't go any farther +} + + +// +// PTR_ShootTraverse +// +boolean PTR_ShootTraverse (intercept_t* in) +{ + fixed_t x; + fixed_t y; + fixed_t z; + fixed_t frac; + + mobj_t* th; + + fixed_t slope; + fixed_t dist; + fixed_t thingtopslope; + fixed_t thingbottomslope; + + if (in->isaline) + { + line_t *li = in->d.line; + + if (li->special) + P_ShootSpecialLine (shootthing, li); + + if (li->flags & ML_TWOSIDED) + { // crosses a two sided (really 2s) line + P_LineOpening (li); + dist = FixedMul(attackrange, in->frac); + + // killough 11/98: simplify + + if ((li->frontsector->floorheight==li->backsector->floorheight || + (slope = FixedDiv(openbottom - shootz , dist)) <= aimslope) && + (li->frontsector->ceilingheight==li->backsector->ceilingheight || + (slope = FixedDiv (opentop - shootz , dist)) >= aimslope)) + return true; // shot continues + } + + // hit line + // position a bit closer + + frac = in->frac - FixedDiv (4*FRACUNIT,attackrange); + x = trace.x + FixedMul (trace.dx, frac); + y = trace.y + FixedMul (trace.dy, frac); + z = shootz + FixedMul (aimslope, FixedMul(frac, attackrange)); + + if (li->frontsector->ceilingpic == skyflatnum) + { + // don't shoot the sky! + + if (z > li->frontsector->ceilingheight) + return false; + + // it's a sky hack wall + + if (li->backsector && li->backsector->ceilingpic == skyflatnum) + + // fix bullet-eaters -- killough: + // WARNING: Almost all demos will lose sync without this + // demo_compatibility flag check!!! killough 1/18/98 + if (demo_compatibility || li->backsector->ceilingheight < z) + return false; + } + + // Spawn bullet puffs. + + P_SpawnPuff (x,y,z); + + // don't go any farther + + return false; + } + + // shoot a thing + + th = in->d.thing; + if (th == shootthing) + return true; // can't shoot self + + if (!(th->flags&MF_SHOOTABLE)) + return true; // corpse or something + + // check angles to see if the thing can be aimed at + + dist = FixedMul (attackrange, in->frac); + thingtopslope = FixedDiv (th->z+th->height - shootz , dist); + + if (thingtopslope < aimslope) + return true; // shot over the thing + + thingbottomslope = FixedDiv (th->z - shootz, dist); + + if (thingbottomslope > aimslope) + return true; // shot under the thing + + // hit thing + // position a bit closer + + frac = in->frac - FixedDiv (10*FRACUNIT,attackrange); + + x = trace.x + FixedMul (trace.dx, frac); + y = trace.y + FixedMul (trace.dy, frac); + z = shootz + FixedMul (aimslope, FixedMul(frac, attackrange)); + + // Spawn bullet puffs or blod spots, + // depending on target type. + if (in->d.thing->flags & MF_NOBLOOD) + P_SpawnPuff (x,y,z); + else + P_SpawnBlood (x,y,z, la_damage); + + if (la_damage) + P_DamageMobj (th, shootthing, shootthing, la_damage); + + // don't go any farther + return false; +} + + +// +// P_AimLineAttack +// +fixed_t P_AimLineAttack(mobj_t* t1,angle_t angle,fixed_t distance, uint_64_t mask) +{ + fixed_t x2; + fixed_t y2; + + angle >>= ANGLETOFINESHIFT; + shootthing = t1; + + x2 = t1->x + (distance>>FRACBITS)*finecosine[angle]; + y2 = t1->y + (distance>>FRACBITS)*finesine[angle]; + shootz = t1->z + (t1->height>>1) + 8*FRACUNIT; + + // can't shoot outside view angles + + topslope = 100*FRACUNIT/160; + bottomslope = -100*FRACUNIT/160; + + attackrange = distance; + linetarget = NULL; + + /* killough 8/2/98: prevent friends from aiming at friends */ + aim_flags_mask = mask; + + P_PathTraverse(t1->x,t1->y,x2,y2,PT_ADDLINES|PT_ADDTHINGS,PTR_AimTraverse); + + if (linetarget) + return aimslope; + + return 0; +} + + +// +// P_LineAttack +// If damage == 0, it is just a test trace +// that will leave linetarget set. +// + +void P_LineAttack +(mobj_t* t1, + angle_t angle, + fixed_t distance, + fixed_t slope, + int damage) +{ + fixed_t x2; + fixed_t y2; + + angle >>= ANGLETOFINESHIFT; + shootthing = t1; + la_damage = damage; + x2 = t1->x + (distance>>FRACBITS)*finecosine[angle]; + y2 = t1->y + (distance>>FRACBITS)*finesine[angle]; + shootz = t1->z + (t1->height>>1) + 8*FRACUNIT; + attackrange = distance; + aimslope = slope; + + P_PathTraverse(t1->x,t1->y,x2,y2,PT_ADDLINES|PT_ADDTHINGS,PTR_ShootTraverse); +} + + +// +// USE LINES +// + +mobj_t* usething; + +boolean PTR_UseTraverse (intercept_t* in) +{ + int side; + + if (!in->d.line->special) + { + P_LineOpening (in->d.line); + if (openrange <= 0) + { + S_StartSound (usething, sfx_noway); + + // can't use through a wall + return false; + } + + // not a special line, but keep checking + + return true; + } + + side = 0; + if (P_PointOnLineSide (usething->x, usething->y, in->d.line) == 1) + side = 1; + + // return false; // don't use back side + + P_UseSpecialLine (usething, in->d.line, side); + + //WAS can't use for than one special line in a row + //jff 3/21/98 NOW multiple use allowed with enabling line flag + + return (!demo_compatibility && (in->d.line->flags&ML_PASSUSE))? + true : false; +} + +// Returns false if a "oof" sound should be made because of a blocking +// linedef. Makes 2s middles which are impassable, as well as 2s uppers +// and lowers which block the player, cause the sound effect when the +// player tries to activate them. Specials are excluded, although it is +// assumed that all special linedefs within reach have been considered +// and rejected already (see P_UseLines). +// +// by Lee Killough +// + +boolean PTR_NoWayTraverse(intercept_t* in) +{ + line_t *ld = in->d.line; + // This linedef + return ld->special || !( // Ignore specials + ld->flags & ML_BLOCKING || ( // Always blocking + P_LineOpening(ld), // Find openings + openrange <= 0 || // No opening + openbottom > usething->z+24*FRACUNIT || // Too high it blocks + opentop < usething->z+usething->height // Too low it blocks + ) + ); +} + +// +// P_UseLines +// Looks for special lines in front of the player to activate. +// +void P_UseLines (player_t* player) +{ + int angle; + fixed_t x1; + fixed_t y1; + fixed_t x2; + fixed_t y2; + + usething = player->mo; + + angle = player->mo->angle >> ANGLETOFINESHIFT; + + x1 = player->mo->x; + y1 = player->mo->y; + x2 = x1 + (USERANGE>>FRACBITS)*finecosine[angle]; + y2 = y1 + (USERANGE>>FRACBITS)*finesine[angle]; + + // old code: + // + // P_PathTraverse ( x1, y1, x2, y2, PT_ADDLINES, PTR_UseTraverse ); + // + // This added test makes the "oof" sound work on 2s lines -- killough: + + if (P_PathTraverse ( x1, y1, x2, y2, PT_ADDLINES, PTR_UseTraverse )) + if (!comp[comp_sound] && !P_PathTraverse ( x1, y1, x2, y2, PT_ADDLINES, PTR_NoWayTraverse )) + S_StartSound (usething, sfx_noway); +} + + +// +// RADIUS ATTACK +// + +static mobj_t *bombsource, *bombspot; +static int bombdamage; + + +// +// PIT_RadiusAttack +// "bombsource" is the creature +// that caused the explosion at "bombspot". +// + +boolean PIT_RadiusAttack (mobj_t* thing) +{ + fixed_t dx; + fixed_t dy; + fixed_t dist; + + /* killough 8/20/98: allow bouncers to take damage + * (missile bouncers are already excluded with MF_NOBLOCKMAP) + */ + + if (!(thing->flags & (MF_SHOOTABLE | MF_BOUNCES))) + return true; + + // Boss spider and cyborg + // take no damage from concussion. + + // killough 8/10/98: allow grenades to hurt anyone, unless + // fired by Cyberdemons, in which case it won't hurt Cybers. + + if (bombspot->flags & MF_BOUNCES ? + thing->type == MT_CYBORG && bombsource->type == MT_CYBORG : + thing->type == MT_CYBORG || thing->type == MT_SPIDER) + return true; + + dx = D_abs(thing->x - bombspot->x); + dy = D_abs(thing->y - bombspot->y); + + dist = dx>dy ? dx : dy; + dist = (dist - thing->radius) >> FRACBITS; + + if (dist < 0) + dist = 0; + + if (dist >= bombdamage) + return true; // out of range + + if ( P_CheckSight (thing, bombspot) ) + { + // must be in direct path + P_DamageMobj (thing, bombspot, bombsource, bombdamage - dist); + } + + return true; +} + + +// +// P_RadiusAttack +// Source is the creature that caused the explosion at spot. +// +void P_RadiusAttack(mobj_t* spot,mobj_t* source,int damage) +{ + int x; + int y; + + int xl; + int xh; + int yl; + int yh; + + fixed_t dist; + + dist = (damage+MAXRADIUS)<y + dist - bmaporgy)>>MAPBLOCKSHIFT; + yl = (spot->y - dist - bmaporgy)>>MAPBLOCKSHIFT; + xh = (spot->x + dist - bmaporgx)>>MAPBLOCKSHIFT; + xl = (spot->x - dist - bmaporgx)>>MAPBLOCKSHIFT; + bombspot = spot; + bombsource = source; + bombdamage = damage; + + for (y=yl ; y<=yh ; y++) + for (x=xl ; x<=xh ; x++) + P_BlockThingsIterator (x, y, PIT_RadiusAttack ); +} + + + +// +// SECTOR HEIGHT CHANGING +// After modifying a sectors floor or ceiling height, +// call this routine to adjust the positions +// of all things that touch the sector. +// +// If anything doesn't fit anymore, true will be returned. +// If crunch is true, they will take damage +// as they are being crushed. +// If Crunch is false, you should set the sector height back +// the way it was and call P_ChangeSector again +// to undo the changes. +// + +static boolean crushchange, nofit; + +// +// PIT_ChangeSector +// + +boolean PIT_ChangeSector (mobj_t* thing) +{ + mobj_t* mo; + + if (P_ThingHeightClip (thing)) + return true; // keep checking + + // crunch bodies to giblets + + if (thing->health <= 0) + { + P_SetMobjState (thing, S_GIBS); + + thing->flags &= ~MF_SOLID; + thing->height = 0; + thing->radius = 0; + return true; // keep checking + } + + // crunch dropped items + + if (thing->flags & MF_DROPPED) + { + P_RemoveMobj (thing); + + // keep checking + return true; + } + + /* killough 11/98: kill touchy things immediately */ + if (thing->flags & MF_TOUCHY && + (thing->intflags & MIF_ARMED || sentient(thing))) + { + P_DamageMobj(thing, NULL, NULL, thing->health); // kill object + return true; // keep checking + } + + if (! (thing->flags & MF_SHOOTABLE) ) + { + // assume it is bloody gibs or something + return true; + } + + nofit = true; + + if (crushchange && !(leveltime&3)) { + int t; + P_DamageMobj(thing,NULL,NULL,10); + + // spray blood in a random direction + mo = P_SpawnMobj (thing->x, + thing->y, + thing->z + thing->height/2, MT_BLOOD); + + /* killough 8/10/98: remove dependence on order of evaluation */ + t = P_Random(pr_crush); + mo->momx = (t - P_Random (pr_crush))<<12; + t = P_Random(pr_crush); + mo->momy = (t - P_Random (pr_crush))<<12; + } + + // keep checking (crush other things) + return true; +} + + +// +// P_ChangeSector +// +boolean P_ChangeSector(sector_t* sector,boolean crunch) +{ + int x; + int y; + + nofit = false; + crushchange = crunch; + + // ARRGGHHH!!!! + // This is horrendously slow!!! + // killough 3/14/98 + + // re-check heights for all things near the moving sector + + for (x=sector->blockbox[BOXLEFT] ; x<= sector->blockbox[BOXRIGHT] ; x++) + for (y=sector->blockbox[BOXBOTTOM];y<= sector->blockbox[BOXTOP] ; y++) + P_BlockThingsIterator (x, y, PIT_ChangeSector); + + return nofit; +} + +// +// P_CheckSector +// jff 3/19/98 added to just check monsters on the periphery +// of a moving sector instead of all in bounding box of the +// sector. Both more accurate and faster. +// + +boolean P_CheckSector(sector_t* sector,boolean crunch) +{ + msecnode_t *n; + + if (comp[comp_floors]) /* use the old routine for old demos though */ + return P_ChangeSector(sector,crunch); + + nofit = false; + crushchange = crunch; + + // killough 4/4/98: scan list front-to-back until empty or exhausted, + // restarting from beginning after each thing is processed. Avoids + // crashes, and is sure to examine all things in the sector, and only + // the things which are in the sector, until a steady-state is reached. + // Things can arbitrarily be inserted and removed and it won't mess up. + // + // killough 4/7/98: simplified to avoid using complicated counter + + // Mark all things invalid + + for (n=sector->touching_thinglist; n; n=n->m_snext) + n->visited = false; + + do + for (n=sector->touching_thinglist; n; n=n->m_snext) // go through list + if (!n->visited) // unprocessed thing found + { + n->visited = true; // mark thing as processed + if (!(n->m_thing->flags & MF_NOBLOCKMAP)) //jff 4/7/98 don't do these + PIT_ChangeSector(n->m_thing); // process it + break; // exit and start over + } + while (n); // repeat from scratch until all things left are marked valid + + return nofit; +} + + +// CPhipps - +// Use block memory allocator here + +#include "z_bmalloc.h" + +IMPLEMENT_BLOCK_MEMORY_ALLOC_ZONE(secnodezone, sizeof(msecnode_t), PU_LEVEL, 32, "SecNodes"); + +inline static msecnode_t* P_GetSecnode(void) +{ + return (msecnode_t*)Z_BMalloc(&secnodezone); +} + +// P_PutSecnode() returns a node to the freelist. + +inline static void P_PutSecnode(msecnode_t* node) +{ + Z_BFree(&secnodezone, node); +} + +// phares 3/16/98 +// +// P_AddSecnode() searches the current list to see if this sector is +// already there. If not, it adds a sector node at the head of the list of +// sectors this object appears in. This is called when creating a list of +// nodes that will get linked in later. Returns a pointer to the new node. + +msecnode_t* P_AddSecnode(sector_t* s, mobj_t* thing, msecnode_t* nextnode) +{ + msecnode_t* node; + + node = nextnode; + while (node) + { + if (node->m_sector == s) // Already have a node for this sector? + { + node->m_thing = thing; // Yes. Setting m_thing says 'keep it'. + return(nextnode); + } + node = node->m_tnext; + } + + // Couldn't find an existing node for this sector. Add one at the head + // of the list. + + node = P_GetSecnode(); + + // killough 4/4/98, 4/7/98: mark new nodes unvisited. + node->visited = 0; + + node->m_sector = s; // sector + node->m_thing = thing; // mobj + node->m_tprev = NULL; // prev node on Thing thread + node->m_tnext = nextnode; // next node on Thing thread + if (nextnode) + nextnode->m_tprev = node; // set back link on Thing + + // Add new node at head of sector thread starting at s->touching_thinglist + + node->m_sprev = NULL; // prev node on sector thread + node->m_snext = s->touching_thinglist; // next node on sector thread + if (s->touching_thinglist) + node->m_snext->m_sprev = node; + s->touching_thinglist = node; + return(node); +} + + +// P_DelSecnode() deletes a sector node from the list of +// sectors this object appears in. Returns a pointer to the next node +// on the linked list, or NULL. + +msecnode_t* P_DelSecnode(msecnode_t* node) +{ + msecnode_t* tp; // prev node on thing thread + msecnode_t* tn; // next node on thing thread + msecnode_t* sp; // prev node on sector thread + msecnode_t* sn; // next node on sector thread + + if (node) + { + + // Unlink from the Thing thread. The Thing thread begins at + // sector_list and not from mobj_t->touching_sectorlist. + + tp = node->m_tprev; + tn = node->m_tnext; + if (tp) + tp->m_tnext = tn; + if (tn) + tn->m_tprev = tp; + + // Unlink from the sector thread. This thread begins at + // sector_t->touching_thinglist. + + sp = node->m_sprev; + sn = node->m_snext; + if (sp) + sp->m_snext = sn; + else + node->m_sector->touching_thinglist = sn; + if (sn) + sn->m_sprev = sp; + + // Return this node to the freelist + + P_PutSecnode(node); + return(tn); + } + return(NULL); +} // phares 3/13/98 + +// Delete an entire sector list + +void P_DelSeclist(msecnode_t* node) + +{ + while (node) + node = P_DelSecnode(node); +} + + +// phares 3/14/98 +// +// PIT_GetSectors +// Locates all the sectors the object is in by looking at the lines that +// cross through it. You have already decided that the object is allowed +// at this location, so don't bother with checking impassable or +// blocking lines. + +boolean PIT_GetSectors(line_t* ld) +{ + if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || + tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT] || + tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || + tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP]) + return true; + + if (P_BoxOnLineSide(tmbbox, ld) != -1) + return true; + + // This line crosses through the object. + + // Collect the sector(s) from the line and add to the + // sector_list you're examining. If the Thing ends up being + // allowed to move to this position, then the sector_list + // will be attached to the Thing's mobj_t at touching_sectorlist. + + sector_list = P_AddSecnode(ld->frontsector,tmthing,sector_list); + + /* Don't assume all lines are 2-sided, since some Things + * like MT_TFOG are allowed regardless of whether their radius takes + * them beyond an impassable linedef. + * + * killough 3/27/98, 4/4/98: + * Use sidedefs instead of 2s flag to determine two-sidedness. + * killough 8/1/98: avoid duplicate if same sector on both sides + * cph - DEMOSYNC? */ + + if (ld->backsector && ld->backsector != ld->frontsector) + sector_list = P_AddSecnode(ld->backsector, tmthing, sector_list); + + return true; +} + + +// phares 3/14/98 +// +// P_CreateSecNodeList alters/creates the sector_list that shows what sectors +// the object resides in. + +void P_CreateSecNodeList(mobj_t* thing,fixed_t x,fixed_t y) +{ + int xl; + int xh; + int yl; + int yh; + int bx; + int by; + msecnode_t* node; + mobj_t* saved_tmthing = tmthing; /* cph - see comment at func end */ + fixed_t saved_tmx = tmx, saved_tmy = tmy; /* ditto */ + + // First, clear out the existing m_thing fields. As each node is + // added or verified as needed, m_thing will be set properly. When + // finished, delete all nodes where m_thing is still NULL. These + // represent the sectors the Thing has vacated. + + node = sector_list; + while (node) + { + node->m_thing = NULL; + node = node->m_tnext; + } + + tmthing = thing; + + tmx = x; + tmy = y; + + tmbbox[BOXTOP] = y + tmthing->radius; + tmbbox[BOXBOTTOM] = y - tmthing->radius; + tmbbox[BOXRIGHT] = x + tmthing->radius; + tmbbox[BOXLEFT] = x - tmthing->radius; + + validcount++; // used to make sure we only process a line once + + xl = (tmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT; + xh = (tmbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT; + yl = (tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT; + yh = (tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT; + + for (bx=xl ; bx<=xh ; bx++) + for (by=yl ; by<=yh ; by++) + P_BlockLinesIterator(bx,by,PIT_GetSectors); + + // Add the sector of the (x,y) point to sector_list. + + sector_list = P_AddSecnode(thing->subsector->sector,thing,sector_list); + + // Now delete any nodes that won't be used. These are the ones where + // m_thing is still NULL. + + node = sector_list; + while (node) + { + if (node->m_thing == NULL) + { + if (node == sector_list) + sector_list = node->m_tnext; + node = P_DelSecnode(node); + } + else + node = node->m_tnext; + } + + /* cph - + * This is the strife we get into for using global variables. tmthing + * is being used by several different functions calling + * P_BlockThingIterator, including functions that can be called *from* + * P_BlockThingIterator. Using a global tmthing is not reentrant. + * OTOH for Boom/MBF demos we have to preserve the buggy behavior. + * Fun. We restore its previous value unless we're in a Boom/MBF demo. + */ + if ((compatibility_level < boom_compatibility_compatibility) || + (compatibility_level >= prboom_3_compatibility)) + tmthing = saved_tmthing; + /* And, duh, the same for tmx/y - cph 2002/09/22 + * And for tmbbox - cph 2003/08/10 */ + if ((compatibility_level < boom_compatibility_compatibility) /* || + (compatibility_level >= prboom_4_compatibility) */) { + tmx = saved_tmx, tmy = saved_tmy; + if (tmthing) { + tmbbox[BOXTOP] = tmy + tmthing->radius; + tmbbox[BOXBOTTOM] = tmy - tmthing->radius; + tmbbox[BOXRIGHT] = tmx + tmthing->radius; + tmbbox[BOXLEFT] = tmx - tmthing->radius; + } + } +} + +/* cphipps 2004/08/30 - + * Must clear tmthing at tic end, as it might contain a pointer to a removed thinker, or the level might have ended/been ended and we clear the objects it was pointing too. Hopefully we don't need to carry this between tics for sync. */ +void P_MapStart(void) { + if (tmthing) I_Error("P_MapStart: tmthing set!"); +} +void P_MapEnd(void) { + tmthing = NULL; +} + diff --git a/apps/plugins/doom/p_map.h b/apps/plugins/doom/p_map.h new file mode 100644 index 0000000000..6985cc15c1 --- /dev/null +++ b/apps/plugins/doom/p_map.h @@ -0,0 +1,90 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Map functions + * + *-----------------------------------------------------------------------------*/ + +#ifndef __P_MAP__ +#define __P_MAP__ + +#include "r_defs.h" +#include "d_player.h" + +#define USERANGE (64*FRACUNIT) +#define MELEERANGE (64*FRACUNIT) +#define MISSILERANGE (32*64*FRACUNIT) + +// MAXRADIUS is for precalculated sector block boxes the spider demon +// is larger, but we do not have any moving sectors nearby +#define MAXRADIUS (32*FRACUNIT) + +// killough 3/15/98: add fourth argument to P_TryMove +boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean dropoff); + +// killough 8/9/98: extra argument for telefragging +boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y,boolean boss); +void P_SlideMove(mobj_t *mo); +boolean P_CheckSight(mobj_t *t1, mobj_t *t2); +void P_UseLines(player_t *player); + +// killough 8/2/98: add 'mask' argument to prevent friends autoaiming at others +fixed_t P_AimLineAttack(mobj_t *t1,angle_t angle,fixed_t distance, uint_64_t mask); + +void P_LineAttack(mobj_t *t1, angle_t angle, fixed_t distance, + fixed_t slope, int damage ); +void P_RadiusAttack(mobj_t *spot, mobj_t *source, int damage); +boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y); + +//jff 3/19/98 P_CheckSector(): new routine to replace P_ChangeSector() +boolean P_ChangeSector(sector_t* sector,boolean crunch); +boolean P_CheckSector(sector_t *sector, boolean crunch); +void P_DelSeclist(msecnode_t*); // phares 3/16/98 +void P_CreateSecNodeList(mobj_t*,fixed_t,fixed_t); // phares 3/14/98 +boolean Check_Sides(mobj_t *, int, int); // phares + +int P_GetMoveFactor(const mobj_t *mo, int *friction); // killough 8/28/98 +int P_GetFriction(const mobj_t *mo, int *factor); // killough 8/28/98 +void P_ApplyTorque(mobj_t *mo); // killough 9/12/98 + +/* cphipps 2004/08/30 */ +void P_MapStart(void); +void P_MapEnd(void); + +// If "floatok" true, move would be ok if within "tmfloorz - tmceilingz". +extern boolean floatok; +extern boolean felldown; // killough 11/98: indicates object pushed off ledge +extern fixed_t tmfloorz; +extern fixed_t tmceilingz; +extern line_t *ceilingline; +extern line_t *floorline; // killough 8/23/98 +extern mobj_t *linetarget; // who got hit (or NULL) +extern msecnode_t *sector_list; // phares 3/16/98 +extern fixed_t tmbbox[4]; // phares 3/20/98 +extern line_t *blockline; // killough 8/11/98 + +#endif // __P_MAP__ diff --git a/apps/plugins/doom/p_maputl.c b/apps/plugins/doom/p_maputl.c new file mode 100644 index 0000000000..a2ef132d11 --- /dev/null +++ b/apps/plugins/doom/p_maputl.c @@ -0,0 +1,700 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Movement/collision utility functions, + * as used by function in p_map.c. + * BLOCKMAP Iterator functions, + * and some PIT_* functions to use for iteration. + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "m_bbox.h" +#include "r_main.h" +#include "p_maputl.h" +#include "p_map.h" +#include "p_setup.h" +#include "rockmacros.h" +// +// P_AproxDistance +// Gives an estimation of distance (not exact) +// + +fixed_t CONSTFUNC P_AproxDistance(fixed_t dx, fixed_t dy) +{ + dx = D_abs(dx); + dy = D_abs(dy); + if (dx < dy) + return dx+dy-(dx>>1); + return dx+dy-(dy>>1); +} + +// +// P_PointOnLineSide +// Returns 0 or 1 +// +// killough 5/3/98: reformatted, cleaned up + +int CONSTFUNC P_PointOnLineSide(fixed_t x, fixed_t y, const line_t *line) +{ + return + !line->dx ? x <= line->v1->x ? line->dy > 0 : line->dy < 0 : + !line->dy ? y <= line->v1->y ? line->dx < 0 : line->dx > 0 : + FixedMul(y-line->v1->y, line->dx>>FRACBITS) >= + FixedMul(line->dy>>FRACBITS, x-line->v1->x); +} + +// +// P_BoxOnLineSide +// Considers the line to be infinite +// Returns side 0 or 1, -1 if box crosses the line. +// +// killough 5/3/98: reformatted, cleaned up + +int CONSTFUNC P_BoxOnLineSide(const fixed_t *tmbox, const line_t *ld) +{ + switch (ld->slopetype) + { + int p; + default: // shut up compiler warnings -- killough + case ST_HORIZONTAL: + return + (tmbox[BOXBOTTOM] > ld->v1->y) == (p = tmbox[BOXTOP] > ld->v1->y) ? + p ^ (ld->dx < 0) : -1; + case ST_VERTICAL: + return + (tmbox[BOXLEFT] < ld->v1->x) == (p = tmbox[BOXRIGHT] < ld->v1->x) ? + p ^ (ld->dy < 0) : -1; + case ST_POSITIVE: + return + P_PointOnLineSide(tmbox[BOXRIGHT], tmbox[BOXBOTTOM], ld) == + (p = P_PointOnLineSide(tmbox[BOXLEFT], tmbox[BOXTOP], ld)) ? p : -1; + case ST_NEGATIVE: + return + (P_PointOnLineSide(tmbox[BOXLEFT], tmbox[BOXBOTTOM], ld)) == + (p = P_PointOnLineSide(tmbox[BOXRIGHT], tmbox[BOXTOP], ld)) ? p : -1; + } +} + +// +// P_PointOnDivlineSide +// Returns 0 or 1. +// +// killough 5/3/98: reformatted, cleaned up + +int CONSTFUNC P_PointOnDivlineSide(fixed_t x, fixed_t y, const divline_t *line) +{ + return + !line->dx ? x <= line->x ? line->dy > 0 : line->dy < 0 : + !line->dy ? y <= line->y ? line->dx < 0 : line->dx > 0 : + (line->dy^line->dx^(x -= line->x)^(y -= line->y)) < 0 ? (line->dy^x) < 0 : + FixedMul(y>>8, line->dx>>8) >= FixedMul(line->dy>>8, x>>8); +} + +// +// P_MakeDivline +// + +void P_MakeDivline(const line_t *li, divline_t *dl) +{ + dl->x = li->v1->x; + dl->y = li->v1->y; + dl->dx = li->dx; + dl->dy = li->dy; +} + +// +// P_InterceptVector +// Returns the fractional intercept point +// along the first divline. +// This is only called by the addthings +// and addlines traversers. +// +// killough 5/3/98: reformatted, cleaned up + +fixed_t CONSTFUNC P_InterceptVector(const divline_t *v2, const divline_t *v1) +{ + fixed_t den = FixedMul(v1->dy>>8, v2->dx) - FixedMul(v1->dx>>8, v2->dy); + return den ? FixedDiv((FixedMul((v1->x-v2->x)>>8, v1->dy) + + FixedMul((v2->y-v1->y)>>8, v1->dx)), den) : 0; +} + +// +// P_LineOpening +// Sets opentop and openbottom to the window +// through a two sided line. +// OPTIMIZE: keep this precalculated +// + +fixed_t opentop; +fixed_t openbottom; +fixed_t openrange; +fixed_t lowfloor; + +// moved front and back outside P-LineOpening and changed // phares 3/7/98 +// them to these so we can pick up the new friction value +// in PIT_CheckLine() +sector_t *openfrontsector; // made global // phares +sector_t *openbacksector; // made global + +void P_LineOpening(const line_t *linedef) +{ + if (linedef->sidenum[1] == -1) // single sided line + { + openrange = 0; + return; + } + + openfrontsector = linedef->frontsector; + openbacksector = linedef->backsector; + + if (openfrontsector->ceilingheight < openbacksector->ceilingheight) + opentop = openfrontsector->ceilingheight; + else + opentop = openbacksector->ceilingheight; + + if (openfrontsector->floorheight > openbacksector->floorheight) + { + openbottom = openfrontsector->floorheight; + lowfloor = openbacksector->floorheight; + } + else + { + openbottom = openbacksector->floorheight; + lowfloor = openfrontsector->floorheight; + } + openrange = opentop - openbottom; +} + +// +// THING POSITION SETTING +// + +// +// P_UnsetThingPosition +// Unlinks a thing from block map and sectors. +// On each position change, BLOCKMAP and other +// lookups maintaining lists ot things inside +// these structures need to be updated. +// + +void P_UnsetThingPosition (mobj_t *thing) +{ + if (!(thing->flags & MF_NOSECTOR)) + { + /* invisible things don't need to be in sector list + * unlink from subsector + * + * killough 8/11/98: simpler scheme using pointers-to-pointers for prev + * pointers, allows head node pointers to be treated like everything else + */ + + mobj_t **sprev = thing->sprev; + mobj_t *snext = thing->snext; + if ((*sprev = snext)) // unlink from sector list + snext->sprev = sprev; + + // phares 3/14/98 + // + // Save the sector list pointed to by touching_sectorlist. + // In P_SetThingPosition, we'll keep any nodes that represent + // sectors the Thing still touches. We'll add new ones then, and + // delete any nodes for sectors the Thing has vacated. Then we'll + // put it back into touching_sectorlist. It's done this way to + // avoid a lot of deleting/creating for nodes, when most of the + // time you just get back what you deleted anyway. + // + // If this Thing is being removed entirely, then the calling + // routine will clear out the nodes in sector_list. + + sector_list = thing->touching_sectorlist; + thing->touching_sectorlist = NULL; //to be restored by P_SetThingPosition + } + + if (!(thing->flags & MF_NOBLOCKMAP)) + { + /* inert things don't need to be in blockmap + * + * killough 8/11/98: simpler scheme using pointers-to-pointers for prev + * pointers, allows head node pointers to be treated like everything else + * + * Also more robust, since it doesn't depend on current position for + * unlinking. Old method required computing head node based on position + * at time of unlinking, assuming it was the same position as during + * linking. + */ + + mobj_t *bnext, **bprev = thing->bprev; + if (bprev && (*bprev = bnext = thing->bnext)) // unlink from block map + bnext->bprev = bprev; + } +} + +// +// P_SetThingPosition +// Links a thing into both a block and a subsector +// based on it's x y. +// Sets thing->subsector properly +// +// killough 5/3/98: reformatted, cleaned up + +void P_SetThingPosition(mobj_t *thing) +{ // link into subsector + subsector_t *ss = thing->subsector = R_PointInSubsector(thing->x, thing->y); + if (!(thing->flags & MF_NOSECTOR)) + { + // invisible things don't go into the sector links + + // killough 8/11/98: simpler scheme using pointer-to-pointer prev + // pointers, allows head nodes to be treated like everything else + + mobj_t **link = &ss->sector->thinglist; + mobj_t *snext = *link; + if ((thing->snext = snext)) + snext->sprev = &thing->snext; + thing->sprev = link; + *link = thing; + + // phares 3/16/98 + // + // If sector_list isn't NULL, it has a collection of sector + // nodes that were just removed from this Thing. + + // Collect the sectors the object will live in by looking at + // the existing sector_list and adding new nodes and deleting + // obsolete ones. + + // When a node is deleted, its sector links (the links starting + // at sector_t->touching_thinglist) are broken. When a node is + // added, new sector links are created. + + P_CreateSecNodeList(thing,thing->x,thing->y); + thing->touching_sectorlist = sector_list; // Attach to Thing's mobj_t + sector_list = NULL; // clear for next time + } + + // link into blockmap + if (!(thing->flags & MF_NOBLOCKMAP)) + { + // inert things don't need to be in blockmap + int blockx = (thing->x - bmaporgx)>>MAPBLOCKSHIFT; + int blocky = (thing->y - bmaporgy)>>MAPBLOCKSHIFT; + if (blockx>=0 && blockx < bmapwidth && blocky>=0 && blocky < bmapheight) + { + // killough 8/11/98: simpler scheme using pointer-to-pointer prev + // pointers, allows head nodes to be treated like everything else + + mobj_t **link = &blocklinks[blocky*bmapwidth+blockx]; + mobj_t *bnext = *link; + if ((thing->bnext = bnext)) + bnext->bprev = &thing->bnext; + thing->bprev = link; + *link = thing; + } + else // thing is off the map + thing->bnext = NULL, thing->bprev = NULL; + } +} + +// killough 3/15/98: +// +// A fast function for testing intersections between things and linedefs. + +boolean CONSTFUNC ThingIsOnLine(const mobj_t *t, const line_t *l) +{ + int dx = l->dx >> FRACBITS; // Linedef vector + int dy = l->dy >> FRACBITS; + int a = (l->v1->x >> FRACBITS) - (t->x >> FRACBITS); // Thing-->v1 vector + int b = (l->v1->y >> FRACBITS) - (t->y >> FRACBITS); + int r = t->radius >> FRACBITS; // Thing radius + + // First make sure bounding boxes of linedef and thing intersect. + // Leads to quick rejection using only shifts and adds/subs/compares. + + if (D_abs(a*2+dx)-D_abs(dx) > r*2 || D_abs(b*2+dy)-D_abs(dy) > r*2) + return 0; + + // Next, make sure that at least one thing crosshair intersects linedef's + // extension. Requires only 3-4 multiplications, the rest adds/subs/ + // shifts/xors (writing the steps out this way leads to better codegen). + + a *= dy; + b *= dx; + a -= b; + b = dx + dy; + b *= r; + if (((a-b)^(a+b)) < 0) + return 1; + dy -= dx; + dy *= r; + b = a+dy; + a -= dy; + return (a^b) < 0; +} + +// +// BLOCK MAP ITERATORS +// For each line/thing in the given mapblock, +// call the passed PIT_* function. +// If the function returns false, +// exit with false without checking anything else. +// + +// +// P_BlockLinesIterator +// The validcount flags are used to avoid checking lines +// that are marked in multiple mapblocks, +// so increment validcount before the first call +// to P_BlockLinesIterator, then make one or more calls +// to it. +// +// killough 5/3/98: reformatted, cleaned up + +boolean P_BlockLinesIterator(int x, int y, boolean func(line_t*)) +{ + int offset; + const long *list; // killough 3/1/98: for removal of blockmap limit + + if (x<0 || y<0 || x>=bmapwidth || y>=bmapheight) + return true; + offset = y*bmapwidth+x; + offset = *(blockmap+offset); + list = blockmaplump+offset; // original was reading // phares + // delmiting 0 as linedef 0 // phares + + // killough 1/31/98: for compatibility we need to use the old method. + // Most demos go out of sync, and maybe other problems happen, if we + // don't consider linedef 0. For safety this should be qualified. + + if (!demo_compatibility) // killough 2/22/98: demo_compatibility check + list++; // skip 0 starting delimiter // phares + for ( ; *list != -1 ; list++) // phares + { + line_t *ld = &lines[*list]; + if (ld->validcount == validcount) + continue; // line has already been checked + ld->validcount = validcount; + if (!func(ld)) + return false; + } + return true; // everything was checked +} + +// +// P_BlockThingsIterator +// +// killough 5/3/98: reformatted, cleaned up + +boolean P_BlockThingsIterator(int x, int y, boolean func(mobj_t*)) +{ + mobj_t *mobj; + if (!(x<0 || y<0 || x>=bmapwidth || y>=bmapheight)) + for (mobj = blocklinks[y*bmapwidth+x]; mobj; mobj = mobj->bnext) + if (!func(mobj)) + return false; + return true; +} + +// +// INTERCEPT ROUTINES +// + +// 1/11/98 killough: Intercept limit removed +static intercept_t *intercepts, *intercept_p; + +// Check for limit and double size if necessary -- killough +static void check_intercept(void) +{ + static size_t num_intercepts; + size_t offset = intercept_p - intercepts; + if (offset >= num_intercepts) + { + num_intercepts = num_intercepts ? num_intercepts*2 : 128; + intercepts = realloc(intercepts, sizeof(*intercepts)*num_intercepts); + intercept_p = intercepts + offset; + } +} + +divline_t trace; + +// PIT_AddLineIntercepts. +// Looks for lines in the given block +// that intercept the given trace +// to add to the intercepts list. +// +// A line is crossed if its endpoints +// are on opposite sides of the trace. +// +// killough 5/3/98: reformatted, cleaned up + +boolean PIT_AddLineIntercepts(line_t *ld) +{ + int s1; + int s2; + fixed_t frac; + divline_t dl; + + // avoid precision problems with two routines + if (trace.dx > FRACUNIT*16 || trace.dy > FRACUNIT*16 || + trace.dx < -FRACUNIT*16 || trace.dy < -FRACUNIT*16) + { + s1 = P_PointOnDivlineSide (ld->v1->x, ld->v1->y, &trace); + s2 = P_PointOnDivlineSide (ld->v2->x, ld->v2->y, &trace); + } + else + { + s1 = P_PointOnLineSide (trace.x, trace.y, ld); + s2 = P_PointOnLineSide (trace.x+trace.dx, trace.y+trace.dy, ld); + } + + if (s1 == s2) + return true; // line isn't crossed + + // hit the line + P_MakeDivline(ld, &dl); + frac = P_InterceptVector(&trace, &dl); + + if (frac < 0) + return true; // behind source + + check_intercept(); // killough + + intercept_p->frac = frac; + intercept_p->isaline = true; + intercept_p->d.line = ld; + intercept_p++; + + return true; // continue +} + +// +// PIT_AddThingIntercepts +// +// killough 5/3/98: reformatted, cleaned up + +boolean PIT_AddThingIntercepts(mobj_t *thing) +{ + fixed_t x1, y1; + fixed_t x2, y2; + int s1, s2; + divline_t dl; + fixed_t frac; + + // check a corner to corner crossection for hit + if ((trace.dx ^ trace.dy) > 0) + { + x1 = thing->x - thing->radius; + y1 = thing->y + thing->radius; + x2 = thing->x + thing->radius; + y2 = thing->y - thing->radius; + } + else + { + x1 = thing->x - thing->radius; + y1 = thing->y - thing->radius; + x2 = thing->x + thing->radius; + y2 = thing->y + thing->radius; + } + + s1 = P_PointOnDivlineSide (x1, y1, &trace); + s2 = P_PointOnDivlineSide (x2, y2, &trace); + + if (s1 == s2) + return true; // line isn't crossed + + dl.x = x1; + dl.y = y1; + dl.dx = x2-x1; + dl.dy = y2-y1; + + frac = P_InterceptVector (&trace, &dl); + + if (frac < 0) + return true; // behind source + + check_intercept(); // killough + + intercept_p->frac = frac; + intercept_p->isaline = false; + intercept_p->d.thing = thing; + intercept_p++; + + return true; // keep going +} + +// +// P_TraverseIntercepts +// Returns true if the traverser function returns true +// for all lines. +// +// killough 5/3/98: reformatted, cleaned up + +boolean P_TraverseIntercepts(traverser_t func, fixed_t maxfrac) +{ + intercept_t *in = NULL; + int count = intercept_p - intercepts; + while (count--) + { + fixed_t dist = INT_MAX; + intercept_t *scan; + for (scan = intercepts; scan < intercept_p; scan++) + if (scan->frac < dist) + dist = (in=scan)->frac; + if (dist > maxfrac) + return true; // checked everything in range + if (!func(in)) + return false; // don't bother going farther + in->frac = INT_MAX; + } + return true; // everything was traversed +} + +// +// P_PathTraverse +// Traces a line from x1,y1 to x2,y2, +// calling the traverser function for each. +// Returns true if the traverser function returns true +// for all lines. +// +// killough 5/3/98: reformatted, cleaned up + +boolean P_PathTraverse(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, + int flags, boolean trav(intercept_t *)) +{ + fixed_t xt1, yt1; + fixed_t xt2, yt2; + fixed_t xstep, ystep; + fixed_t partial; + fixed_t xintercept, yintercept; + int mapx, mapy; + int mapxstep, mapystep; + int count; + + validcount++; + intercept_p = intercepts; + + if (!((x1-bmaporgx)&(MAPBLOCKSIZE-1))) + x1 += FRACUNIT; // don't side exactly on a line + + if (!((y1-bmaporgy)&(MAPBLOCKSIZE-1))) + y1 += FRACUNIT; // don't side exactly on a line + + trace.x = x1; + trace.y = y1; + trace.dx = x2 - x1; + trace.dy = y2 - y1; + + x1 -= bmaporgx; + y1 -= bmaporgy; + xt1 = x1>>MAPBLOCKSHIFT; + yt1 = y1>>MAPBLOCKSHIFT; + + x2 -= bmaporgx; + y2 -= bmaporgy; + xt2 = x2>>MAPBLOCKSHIFT; + yt2 = y2>>MAPBLOCKSHIFT; + + if (xt2 > xt1) + { + mapxstep = 1; + partial = FRACUNIT - ((x1>>MAPBTOFRAC)&(FRACUNIT-1)); + ystep = FixedDiv (y2-y1,D_abs(x2-x1)); + } + else + if (xt2 < xt1) + { + mapxstep = -1; + partial = (x1>>MAPBTOFRAC)&(FRACUNIT-1); + ystep = FixedDiv (y2-y1,D_abs(x2-x1)); + } + else + { + mapxstep = 0; + partial = FRACUNIT; + ystep = 256*FRACUNIT; + } + + yintercept = (y1>>MAPBTOFRAC) + FixedMul(partial, ystep); + + if (yt2 > yt1) + { + mapystep = 1; + partial = FRACUNIT - ((y1>>MAPBTOFRAC)&(FRACUNIT-1)); + xstep = FixedDiv (x2-x1,D_abs(y2-y1)); + } + else + if (yt2 < yt1) + { + mapystep = -1; + partial = (y1>>MAPBTOFRAC)&(FRACUNIT-1); + xstep = FixedDiv (x2-x1,D_abs(y2-y1)); + } + else + { + mapystep = 0; + partial = FRACUNIT; + xstep = 256*FRACUNIT; + } + + xintercept = (x1>>MAPBTOFRAC) + FixedMul (partial, xstep); + + // Step through map blocks. + // Count is present to prevent a round off error + // from skipping the break. + + mapx = xt1; + mapy = yt1; + + for (count = 0; count < 64; count++) + { + if (flags & PT_ADDLINES) + if (!P_BlockLinesIterator(mapx, mapy,PIT_AddLineIntercepts)) + return false; // early out + + if (flags & PT_ADDTHINGS) + if (!P_BlockThingsIterator(mapx, mapy,PIT_AddThingIntercepts)) + return false; // early out + + if (mapx == xt2 && mapy == yt2) + break; + + if ((yintercept >> FRACBITS) == mapy) + { + yintercept += ystep; + mapx += mapxstep; + } + else + if ((xintercept >> FRACBITS) == mapx) + { + xintercept += xstep; + mapy += mapystep; + } + } + + // go through the sorted list + return P_TraverseIntercepts(trav, FRACUNIT); +} diff --git a/apps/plugins/doom/p_maputl.h b/apps/plugins/doom/p_maputl.h new file mode 100644 index 0000000000..a000bf0edb --- /dev/null +++ b/apps/plugins/doom/p_maputl.h @@ -0,0 +1,91 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Map utility functions + * + *-----------------------------------------------------------------------------*/ + +#ifndef __P_MAPUTL__ +#define __P_MAPUTL__ + +#include "r_defs.h" + +/* mapblocks are used to check movement against lines and things */ +#define MAPBLOCKUNITS 128 +#define MAPBLOCKSIZE (MAPBLOCKUNITS*FRACUNIT) +#define MAPBLOCKSHIFT (FRACBITS+7) +#define MAPBMASK (MAPBLOCKSIZE-1) +#define MAPBTOFRAC (MAPBLOCKSHIFT-FRACBITS) + +#define PT_ADDLINES 1 +#define PT_ADDTHINGS 2 +#define PT_EARLYOUT 4 + +typedef struct { + fixed_t x; + fixed_t y; + fixed_t dx; + fixed_t dy; +} divline_t; + +typedef struct { + fixed_t frac; /* along trace line */ + boolean isaline; + union { + mobj_t* thing; + line_t* line; + } d; +} intercept_t; + +typedef boolean (*traverser_t)(intercept_t *in); + +#define CONSTFUNC + +fixed_t CONSTFUNC P_AproxDistance (fixed_t dx, fixed_t dy); +int CONSTFUNC P_PointOnLineSide (fixed_t x, fixed_t y, const line_t *line); +int CONSTFUNC P_PointOnDivlineSide (fixed_t x, fixed_t y, + const divline_t *line); +int CONSTFUNC P_BoxOnLineSide (const fixed_t *tmbox, const line_t *ld); +fixed_t CONSTFUNC P_InterceptVector (const divline_t *v2, const divline_t *v1); + +void P_MakeDivline (const line_t *li, divline_t *dl); +void P_LineOpening (const line_t *linedef); +void P_UnsetThingPosition(mobj_t *thing); +void P_SetThingPosition(mobj_t *thing); +boolean P_BlockLinesIterator (int x, int y, boolean func(line_t *)); +boolean P_BlockThingsIterator(int x, int y, boolean func(mobj_t *)); +boolean CONSTFUNC ThingIsOnLine(const mobj_t *t, const line_t *l); /* killough 3/15/98 */ +boolean P_PathTraverse(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, + int flags, boolean trav(intercept_t *)); + +extern fixed_t opentop; +extern fixed_t openbottom; +extern fixed_t openrange; +extern fixed_t lowfloor; +extern divline_t trace; + +#endif /* __P_MAPUTL__ */ diff --git a/apps/plugins/doom/p_mobj.c b/apps/plugins/doom/p_mobj.c new file mode 100644 index 0000000000..3aaaf4510a --- /dev/null +++ b/apps/plugins/doom/p_mobj.c @@ -0,0 +1,1394 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Moving object handling. Spawn functions. + * + *-----------------------------------------------------------------------------*/ + +#include "doomdef.h" +#include "doomstat.h" +#include "m_random.h" +#include "r_main.h" +#include "p_maputl.h" +#include "p_map.h" +#include "p_tick.h" +#include "sounds.h" +#include "st_stuff.h" +#include "hu_stuff.h" +#include "s_sound.h" +#include "info.h" +#include "g_game.h" +#include "p_inter.h" +#include "rockmacros.h" +// +// P_SetMobjState +// Returns true if the mobj is still present. +// + +statenum_t i IBSS_ATTR; // initial state +statenum_t seenstate_tab[NUMSTATES] IBSS_ATTR; // fast transition table + +boolean P_SetMobjState(mobj_t* mobj,statenum_t state) +{ + state_t* st; + // killough 4/9/98: remember states seen, to detect cycles: + statenum_t *seenstate = seenstate_tab; // pointer to table + static int recursion; // detects recursion + i = state; + boolean ret = true; // return value + + if (recursion++) // if recursion detected, + memset(seenstate,0,sizeof(seenstate_tab)); // clear state table + + do + { + if (state == S_NULL) + { + mobj->state = (state_t *) S_NULL; + P_RemoveMobj (mobj); + ret = false; + break; // killough 4/9/98 + } + + st = &states[state]; + mobj->state = st; + mobj->tics = st->tics; + mobj->sprite = st->sprite; + mobj->frame = st->frame; + + // Modified handling. + // Call action functions when the state is set + + if (st->action) + st->action(mobj); + + seenstate[state] = 1 + st->nextstate; // killough 4/9/98 + + state = st->nextstate; + } while (!mobj->tics && !seenstate[state]); // killough 4/9/98 + + if (ret && !mobj->tics) // killough 4/9/98: detect state cycles + doom_printf("Warning: State Cycle Detected"); + + if (!--recursion) + for (;(state=seenstate[i]);i=state-1) + seenstate[i] = 0; // killough 4/9/98: erase memory of states + + return ret; +} + + +// +// P_ExplodeMissile +// + +void P_ExplodeMissile (mobj_t* mo) +{ + mo->momx = mo->momy = mo->momz = 0; + + P_SetMobjState (mo, mobjinfo[mo->type].deathstate); + + mo->tics -= P_Random(pr_explode)&3; + + if (mo->tics < 1) + mo->tics = 1; + + mo->flags &= ~MF_MISSILE; + + if (mo->info->deathsound) + S_StartSound (mo, mo->info->deathsound); +} + + +// +// P_XYMovement +// +// Attempts to move something if it has momentum. +// + +void P_XYMovement (mobj_t* mo) +{ + player_t *player; + fixed_t xmove, ymove; +#if 0 + fixed_t ptryx; + fixed_t ptryy; + fixed_t xmove; + fixed_t ymove; + fixed_t oldx,oldy; // phares 9/10/98: reducing bobbing/momentum on ice + // when up against walls +#endif + if (!(mo->momx | mo->momy)) // Any momentum? + { + if (mo->flags & MF_SKULLFLY) + { + + // the skull slammed into something + + mo->flags &= ~MF_SKULLFLY; + mo->momz = 0; + + P_SetMobjState (mo, mo->info->spawnstate); + } + return; + } + + player = mo->player; + + if (mo->momx > MAXMOVE) + mo->momx = MAXMOVE; + else if (mo->momx < -MAXMOVE) + mo->momx = -MAXMOVE; + + if (mo->momy > MAXMOVE) + mo->momy = MAXMOVE; + else if (mo->momy < -MAXMOVE) + mo->momy = -MAXMOVE; + + xmove = mo->momx; + ymove = mo->momy; + +#if 0 + oldx = mo->x; // phares 9/10/98: new code to reduce bobbing/momentum + oldy = mo->y; // when on ice & up against wall. These will be compared + // to your x,y values later to see if you were able to move +#endif + + do + { + fixed_t ptryx, ptryy; + // killough 8/9/98: fix bug in original Doom source: + // Large negative displacements were never considered. + // This explains the tendency for Mancubus fireballs + // to pass through walls. + // CPhipps - compatibility optioned + + if (xmove > MAXMOVE/2 || ymove > MAXMOVE/2 || + (!comp[comp_moveblock] + && (xmove < -MAXMOVE/2 || ymove < -MAXMOVE/2))) + { + ptryx = mo->x + xmove/2; + ptryy = mo->y + ymove/2; + xmove >>= 1; + ymove >>= 1; + } + else + { + ptryx = mo->x + xmove; + ptryy = mo->y + ymove; + xmove = ymove = 0; + } + + // killough 3/15/98: Allow objects to drop off + + if (!P_TryMove (mo, ptryx, ptryy, true)) + { + // blocked move + + // killough 8/11/98: bouncing off walls + // killough 10/98: + // Add ability for objects other than players to bounce on ice + + if (!(mo->flags & MF_MISSILE) && + mbf_features && + (mo->flags & MF_BOUNCES || + (!player && blockline && + variable_friction && mo->z <= mo->floorz && + P_GetFriction(mo, NULL) > ORIG_FRICTION))) + { + if (blockline) + { + fixed_t r = ((blockline->dx >> FRACBITS) * mo->momx + + (blockline->dy >> FRACBITS) * mo->momy) / + ((blockline->dx >> FRACBITS)*(blockline->dx >> FRACBITS)+ + (blockline->dy >> FRACBITS)*(blockline->dy >> FRACBITS)); + fixed_t x = FixedMul(r, blockline->dx); + fixed_t y = FixedMul(r, blockline->dy); + + // reflect momentum away from wall + + mo->momx = x*2 - mo->momx; + mo->momy = y*2 - mo->momy; + + // if under gravity, slow down in + // direction perpendicular to wall. + + if (!(mo->flags & MF_NOGRAVITY)) + { + mo->momx = (mo->momx + x)/2; + mo->momy = (mo->momy + y)/2; + } + } + else + mo->momx = mo->momy = 0; + } + else + if (player) // try to slide along it + P_SlideMove (mo); + else + if (mo->flags & MF_MISSILE) + { + // explode a missile + + if (ceilingline && + ceilingline->backsector && + ceilingline->backsector->ceilingpic == skyflatnum) + if (demo_compatibility || // killough + mo->z > ceilingline->backsector->ceilingheight) + { + // Hack to prevent missiles exploding + // against the sky. + // Does not handle sky floors. + + P_RemoveMobj (mo); + return; + } + P_ExplodeMissile (mo); + } + else // whatever else it is, it is now standing still in (x,y) + mo->momx = mo->momy = 0; + } + } while (xmove || ymove); + + // slow down + +#if 0 /* killough 10/98: this is unused code (except maybe in .deh files?) */ + if (player && player->cheats & CF_NOMOMENTUM) + { + // debug option for no sliding at all + mo->momx = mo->momy = 0; + player->momx = player->momy = 0; /* killough 10/98 */ + return; + } +#endif + + /* no friction for missiles or skulls ever, no friction when airborne */ + if (mo->flags & (MF_MISSILE | MF_SKULLFLY) || mo->z > mo->floorz) + return; + + /* killough 8/11/98: add bouncers + * killough 9/15/98: add objects falling off ledges + * killough 11/98: only include bouncers hanging off ledges + */ + if (((mo->flags & MF_BOUNCES && mo->z > mo->dropoffz) || + mo->flags & MF_CORPSE || mo->intflags & MIF_FALLING) && + (mo->momx > FRACUNIT/4 || mo->momx < -FRACUNIT/4 || + mo->momy > FRACUNIT/4 || mo->momy < -FRACUNIT/4) && + mo->floorz != mo->subsector->sector->floorheight) + return; // do not stop sliding if halfway off a step with some momentum + + // killough 11/98: + // Stop voodoo dolls that have come to rest, despite any + // moving corresponding player, except in old demos: + + if (mo->momx > -STOPSPEED && mo->momx < STOPSPEED && + mo->momy > -STOPSPEED && mo->momy < STOPSPEED && + (!player || !(player->cmd.forwardmove | player->cmd.sidemove) || + (player->mo != mo && compatibility_level >= lxdoom_1_compatibility))) + { + // if in a walking frame, stop moving + + // killough 10/98: + // Don't affect main player when voodoo dolls stop, except in old demos: + + if (player && (unsigned)(player->mo->state - states - S_PLAY_RUN1) < 4 + && (player->mo == mo || compatibility_level >= lxdoom_1_compatibility)) + P_SetMobjState(player->mo, S_PLAY); + + mo->momx = mo->momy = 0; + + /* killough 10/98: kill any bobbing momentum too (except in voodoo dolls) + * cph - DEMOSYNC - needs compatibility check? + */ + if (player && player->mo == mo) + player->momx = player->momy = 0; + } + else + { + /* phares 3/17/98 + * + * Friction will have been adjusted by friction thinkers for + * icy or muddy floors. Otherwise it was never touched and + * remained set at ORIG_FRICTION + * + * killough 8/28/98: removed inefficient thinker algorithm, + * instead using touching_sectorlist in P_GetFriction() to + * determine friction (and thus only when it is needed). + * + * killough 10/98: changed to work with new bobbing method. + * Reducing player momentum is no longer needed to reduce + * bobbing, so ice works much better now. + * + * cph - DEMOSYNC - need old code for Boom demos? + */ + + fixed_t friction = P_GetFriction(mo, NULL); + + mo->momx = FixedMul(mo->momx, friction); + mo->momy = FixedMul(mo->momy, friction); + + /* killough 10/98: Always decrease player bobbing by ORIG_FRICTION. + * This prevents problems with bobbing on ice, where it was not being + * reduced fast enough, leading to all sorts of kludges being developed. + */ + + if (player && player->mo == mo) /* Not voodoo dolls */ + { + player->momx = FixedMul(player->momx, ORIG_FRICTION); + player->momy = FixedMul(player->momy, ORIG_FRICTION); + } + + } +} + + +// +// P_ZMovement +// +// Attempt vertical movement. + +static void P_ZMovement (mobj_t* mo) +{ + /* killough 7/11/98: + * BFG fireballs bounced on floors and ceilings in Pre-Beta Doom + * killough 8/9/98: added support for non-missile objects bouncing + * (e.g. grenade, mine, pipebomb) + */ + + if (mo->flags & MF_BOUNCES && mo->momz) { + mo->z += mo->momz; + if (mo->z <= mo->floorz) { /* bounce off floors */ + mo->z = mo->floorz; + if (mo->momz < 0) { + mo->momz = -mo->momz; + if (!(mo->flags & MF_NOGRAVITY)) { /* bounce back with decay */ + mo->momz = mo->flags & MF_FLOAT ? // floaters fall slowly + mo->flags & MF_DROPOFF ? // DROPOFF indicates rate + FixedMul(mo->momz, (fixed_t)(FRACUNIT*.85)) : + FixedMul(mo->momz, (fixed_t)(FRACUNIT*.70)) : + FixedMul(mo->momz, (fixed_t)(FRACUNIT*.45)) ; + + /* Bring it to rest below a certain speed */ + if (abs(mo->momz) <= mo->info->mass*(GRAVITY*4/256)) + mo->momz = 0; + } + + /* killough 11/98: touchy objects explode on impact */ + if (mo->flags & MF_TOUCHY && mo->intflags & MIF_ARMED + && mo->health > 0) + P_DamageMobj(mo, NULL, NULL, mo->health); + else if (mo->flags & MF_FLOAT && sentient(mo)) + goto floater; + return; + } +} else if (mo->z >= mo->ceilingz - mo->height) { + /* bounce off ceilings */ + mo->z = mo->ceilingz - mo->height; + if (mo->momz > 0) { + if (mo->subsector->sector->ceilingpic != skyflatnum) + mo->momz = -mo->momz; /* always bounce off non-sky ceiling */ + else if (mo->flags & MF_MISSILE) + P_RemoveMobj(mo); /* missiles don't bounce off skies */ + else if (mo->flags & MF_NOGRAVITY) + mo->momz = -mo->momz; // bounce unless under gravity + + if (mo->flags & MF_FLOAT && sentient(mo)) + goto floater; + + return; + } + } else { + if (!(mo->flags & MF_NOGRAVITY)) /* free-fall under gravity */ + mo->momz -= mo->info->mass*(GRAVITY/256); + + if (mo->flags & MF_FLOAT && sentient(mo)) goto floater; + return; + } + + /* came to a stop */ + mo->momz = 0; + + if (mo->flags & MF_MISSILE) { + if (ceilingline && + ceilingline->backsector && + ceilingline->backsector->ceilingpic == skyflatnum && + mo->z > ceilingline->backsector->ceilingheight) + P_RemoveMobj(mo); /* don't explode on skies */ + else + P_ExplodeMissile(mo); + } + + if (mo->flags & MF_FLOAT && sentient(mo)) goto floater; + return; + } + + /* killough 8/9/98: end bouncing object code */ + + // check for smooth step up + + if (mo->player && + mo->player->mo == mo && // killough 5/12/98: exclude voodoo dolls + mo->z < mo->floorz) + { + mo->player->viewheight -= mo->floorz-mo->z; + mo->player->deltaviewheight = (VIEWHEIGHT - mo->player->viewheight)>>3; + } + + // adjust altitude + + mo->z += mo->momz; + +floater: + if ((mo->flags & MF_FLOAT) && mo->target) + + // float down towards target if too close + + if (!((mo->flags ^ MF_FLOAT) & (MF_FLOAT | MF_SKULLFLY | MF_INFLOAT)) && + mo->target) /* killough 11/98: simplify */ + { + fixed_t delta; + if (P_AproxDistance(mo->x - mo->target->x, mo->y - mo->target->y) < + abs(delta = mo->target->z + (mo->height>>1) - mo->z)*3) + mo->z += delta < 0 ? -FLOATSPEED : FLOATSPEED; + } + + // clip movement + + if (mo->z <= mo->floorz) + { + // hit the floor + + /* Note (id): + * somebody left this after the setting momz to 0, + * kinda useless there. + * cph - This was the a bug in the linuxdoom-1.10 source which + * caused it not to sync Doom 2 v1.9 demos. Someone + * added the above comment and moved up the following code. So + * demos would desync in close lost soul fights. + * Note that this only applies to original Doom 1 or Doom2 demos - + * Final Doom and Ultimate Doom. So we test demo_compatibility *and* + * gamemission. (Note we assume that Doom1 is always Ult Doom, which + * seems to hold for most published demos.) + */ + int correct_lost_soul_bounce = !demo_compatibility || (gamemission != doom2); + + if (correct_lost_soul_bounce && mo->flags & MF_SKULLFLY) + mo->momz = -mo->momz; // the skull slammed into something + + if (mo->momz < 0) + { + /* killough 11/98: touchy objects explode on impact */ + if (mo->flags & MF_TOUCHY && mo->intflags & MIF_ARMED && mo->health > 0) + P_DamageMobj(mo, NULL, NULL, mo->health); + else + if (mo->player && /* killough 5/12/98: exclude voodoo dolls */ + mo->player->mo == mo && mo->momz < -GRAVITY*8) + { + // Squat down. + // Decrease viewheight for a moment + // after hitting the ground (hard), + // and utter appropriate sound. + + mo->player->deltaviewheight = mo->momz>>3; + if (mo->health) /* cph - prevent "oof" when dead */ + S_StartSound (mo, sfx_oof); + } + mo->momz = 0; + } + mo->z = mo->floorz; + + /* cph 2001/05/26 - + * See lost soul bouncing comment above. We need this here for bug + * compatibility with original Doom2 v1.9 - if a soul is charging and + * hit by a raising floor this incorrectly reverses its Y momentum. + */ + if (!correct_lost_soul_bounce && mo->flags & MF_SKULLFLY) + mo->momz = -mo->momz; // the skull slammed into something + + if ( (mo->flags & MF_MISSILE) && !(mo->flags & MF_NOCLIP) ) + { + P_ExplodeMissile (mo); + return; + } + } + else // still above the floor // phares + if (!(mo->flags & MF_NOGRAVITY)) + { + if (!mo->momz) + mo->momz = -GRAVITY; + mo->momz -= GRAVITY; + } + + if (mo->z + mo->height > mo->ceilingz) + { + + // hit the ceiling + + if (mo->momz > 0) + mo->momz = 0; + + mo->z = mo->ceilingz - mo->height; + + if (mo->flags & MF_SKULLFLY) + mo->momz = -mo->momz; // the skull slammed into something + + if ( (mo->flags & MF_MISSILE) && !(mo->flags & MF_NOCLIP) ) + { + P_ExplodeMissile (mo); + return; + } + } +} + +// +// P_NightmareRespawn +// + +void P_NightmareRespawn(mobj_t* mobj) +{ + fixed_t x; + fixed_t y; + fixed_t z; + subsector_t* ss; + mobj_t* mo; + mapthing_t* mthing; + + x = mobj->spawnpoint.x << FRACBITS; + y = mobj->spawnpoint.y << FRACBITS; + + /* haleyjd: stupid nightmare respawning bug fix + * + * 08/09/00: compatibility added, time to ramble :) + * This fixes the notorious nightmare respawning bug that causes monsters + * that didn't spawn at level startup to respawn at the point (0,0) + * regardless of that point's nature. SMMU and Eternity need this for + * script-spawned things like Halif Swordsmythe, as well. + * + * cph - copied from eternity, except comp_respawnfix becomes comp_respawn + * and the logic is reversed (i.e. like the rest of comp_ it *disables* + * the fix) + */ + if(!comp[comp_respawn] && !x && !y) + { + // spawnpoint was zeroed out, so use point of death instead + x = mobj->x; + y = mobj->y; + } + + // something is occupying its position? + + if (!P_CheckPosition (mobj, x, y) ) + return; // no respwan + + // spawn a teleport fog at old spot + // because of removal of the body? + + mo = P_SpawnMobj (mobj->x, + mobj->y, + mobj->subsector->sector->floorheight, + MT_TFOG); + + // initiate teleport sound + + S_StartSound (mo, sfx_telept); + + // spawn a teleport fog at the new spot + + ss = R_PointInSubsector (x,y); + + mo = P_SpawnMobj (x, y, ss->sector->floorheight , MT_TFOG); + + S_StartSound (mo, sfx_telept); + + // spawn the new monster + + mthing = &mobj->spawnpoint; + if (mobj->info->flags & MF_SPAWNCEILING) + z = ONCEILINGZ; + else + z = ONFLOORZ; + + // inherit attributes from deceased one + + mo = P_SpawnMobj (x,y,z, mobj->type); + mo->spawnpoint = mobj->spawnpoint; + mo->angle = ANG45 * (mthing->angle/45); + + if (mthing->options & MTF_AMBUSH) + mo->flags |= MF_AMBUSH; + + /* killough 11/98: transfer friendliness from deceased */ + mo->flags = (mo->flags & ~MF_FRIEND) | (mobj->flags & MF_FRIEND); + + mo->reactiontime = 18; + + // remove the old monster, + + P_RemoveMobj (mobj); +} + + +// +// P_MobjThinker +// + +void P_MobjThinker (mobj_t* mobj) +{ + // killough 11/98: + // removed old code which looked at target references + // (we use pointer reference counting now) + + // momentum movement + if (mobj->momx | mobj->momy || mobj->flags & MF_SKULLFLY) + { + P_XYMovement(mobj); + if (mobj->thinker.function != P_MobjThinker) // cph - Must've been removed + return; // killough - mobj was removed + } + + if (mobj->z != mobj->floorz || mobj->momz) + { + P_ZMovement(mobj); + if (mobj->thinker.function != P_MobjThinker) // cph - Must've been removed + return; // killough - mobj was removed + } + else + if (!(mobj->momx | mobj->momy) && !sentient(mobj)) + { // non-sentient objects at rest + mobj->intflags |= MIF_ARMED; // arm a mine which has come to rest + + // killough 9/12/98: objects fall off ledges if they are hanging off + // slightly push off of ledge if hanging more than halfway off + + if (mobj->z > mobj->dropoffz && // Only objects contacting dropoff + !(mobj->flags & MF_NOGRAVITY) && // Only objects which fall + !comp[comp_falloff]) // Not in old demos + P_ApplyTorque(mobj); // Apply torque + else + mobj->intflags &= ~MIF_FALLING, mobj->gear = 0; // Reset torque + } + + // cycle through states, + // calling action functions at transitions + + if (mobj->tics != -1) + { + mobj->tics--; + + // you can cycle through multiple states in a tic + + if (!mobj->tics) + if (!P_SetMobjState (mobj, mobj->state->nextstate) ) + return; // freed itself + } + else + { + + // check for nightmare respawn + + if (! (mobj->flags & MF_COUNTKILL) ) + return; + + if (!respawnmonsters) + return; + + mobj->movecount++; + + if (mobj->movecount < 12*35) + return; + + if (leveltime & 31) + return; + + if (P_Random (pr_respawn) > 4) + return; + + P_NightmareRespawn (mobj); + } + +} + + +// +// P_SpawnMobj +// +mobj_t* P_SpawnMobj(fixed_t x,fixed_t y,fixed_t z,mobjtype_t type) +{ + mobj_t* mobj; + state_t* st; + mobjinfo_t* info; + + mobj = Z_Malloc (sizeof(*mobj), PU_LEVEL, NULL); + memset (mobj, 0, sizeof (*mobj)); + info = &mobjinfo[type]; + mobj->type = type; + mobj->info = info; + mobj->x = x; + mobj->y = y; + mobj->radius = info->radius; + mobj->height = info->height; // phares + mobj->flags = info->flags; + + /* killough 8/23/98: no friends, bouncers, or touchy things in old demos */ + if (!mbf_features) + mobj->flags &= ~(MF_BOUNCES | MF_FRIEND | MF_TOUCHY); + else + if (type == MT_PLAYER) // Except in old demos, players + mobj->flags |= MF_FRIEND; // are always friends. + + mobj->health = info->spawnhealth; + + if (gameskill != sk_nightmare) + mobj->reactiontime = info->reactiontime; + + mobj->lastlook = P_Random (pr_lastlook) % MAXPLAYERS; + + // do not set the state with P_SetMobjState, + // because action routines can not be called yet + + st = &states[info->spawnstate]; + + mobj->state = st; + mobj->tics = st->tics; + mobj->sprite = st->sprite; + mobj->frame = st->frame; + mobj->touching_sectorlist = NULL; // NULL head of sector list // phares 3/13/98 + + // set subsector and/or block links + + P_SetThingPosition (mobj); + + mobj->dropoffz = /* killough 11/98: for tracking dropoffs */ + mobj->floorz = mobj->subsector->sector->floorheight; + mobj->ceilingz = mobj->subsector->sector->ceilingheight; + + mobj->z = z == ONFLOORZ ? mobj->floorz : z == ONCEILINGZ ? + mobj->ceilingz - mobj->height : z; + + mobj->thinker.function = P_MobjThinker; + mobj->above_thing = 0; // phares + mobj->below_thing = 0; // phares + + mobj->target = mobj->tracer = mobj->lastenemy = NULL; + P_AddThinker (&mobj->thinker); + if (!((mobj->flags ^ MF_COUNTKILL) & (MF_FRIEND | MF_COUNTKILL))) + totallive++; + return mobj; +} + + +mapthing_t itemrespawnque[ITEMQUESIZE]; +int itemrespawntime[ITEMQUESIZE]; +int iquehead; +int iquetail; + + +// +// P_RemoveMobj +// + +void P_RemoveMobj (mobj_t* mobj) +{ + if ((mobj->flags & MF_SPECIAL) + && !(mobj->flags & MF_DROPPED) + && (mobj->type != MT_INV) + && (mobj->type != MT_INS)) + { + itemrespawnque[iquehead] = mobj->spawnpoint; + itemrespawntime[iquehead] = leveltime; + iquehead = (iquehead+1)&(ITEMQUESIZE-1); + + // lose one off the end? + + if (iquehead == iquetail) + iquetail = (iquetail+1)&(ITEMQUESIZE-1); + } + + // unlink from sector and block lists + + P_UnsetThingPosition (mobj); + + // Delete all nodes on the current sector_list phares 3/16/98 + + if (sector_list) + { + P_DelSeclist(sector_list); + sector_list = NULL; + } + + // stop any playing sound + + S_StopSound (mobj); + + // killough 11/98: + // + // Remove any references to other mobjs. + // + // Older demos might depend on the fields being left alone, however, + // if multiple thinkers reference each other indirectly before the + // end of the current tic. + // CPhipps - only leave dead references in old demos; I hope lxdoom_1 level + // demos are rare and don't rely on this. I hope. + + if ((compatibility_level >= lxdoom_1_compatibility) || + (!demorecording && !demoplayback)) { + P_SetTarget(&mobj->target, NULL); + P_SetTarget(&mobj->tracer, NULL); + P_SetTarget(&mobj->lastenemy, NULL); + } + // free block + + // P_RemoveThinker ((thinker_t*)mobj); + P_RemoveThinker (&mobj->thinker); +} + + +/* + * P_FindDoomedNum + * + * Finds a mobj type with a matching doomednum + * + * killough 8/24/98: rewrote to use hashing + */ + +int P_FindDoomedNum(unsigned type) +{ + static struct { int first, next; } *hash; + register int i; + + if (!hash) + { + hash = Z_Malloc(sizeof (*hash) * NUMMOBJTYPES, PU_CACHE, (void*)(void*) &hash); + for (i=0; ix << FRACBITS; + y = mthing->y << FRACBITS; + + // spawn a teleport fog at the new spot + + ss = R_PointInSubsector (x,y); + mo = P_SpawnMobj (x, y, ss->sector->floorheight , MT_IFOG); + S_StartSound (mo, sfx_itmbk); + + // find which type to spawn + + /* killough 8/23/98: use table for faster lookup */ + i = P_FindDoomedNum(mthing->type); + + // spawn it + + if (mobjinfo[i].flags & MF_SPAWNCEILING) + z = ONCEILINGZ; + else + z = ONFLOORZ; + + mo = P_SpawnMobj (x,y,z, i); + mo->spawnpoint = *mthing; + mo->angle = ANG45 * (mthing->angle/45); + + // pull it from the queue + + iquetail = (iquetail+1)&(ITEMQUESIZE-1); +} + +// +// P_SpawnPlayer +// Called when a player is spawned on the level. +// Most of the player structure stays unchanged +// between levels. +// + +extern byte playernumtotrans[MAXPLAYERS]; + +void P_SpawnPlayer (mapthing_t* mthing) +{ + player_t* p; + fixed_t x; + fixed_t y; + fixed_t z; + mobj_t* mobj; + int i; + + // not playing? + + if (!playeringame[mthing->type-1]) + return; + + p = &players[mthing->type-1]; + + if (p->playerstate == PST_REBORN) + G_PlayerReborn (mthing->type-1); + + x = mthing->x << FRACBITS; + y = mthing->y << FRACBITS; + z = ONFLOORZ; + mobj = P_SpawnMobj (x,y,z, MT_PLAYER); + + // set color translations for player sprites + + if (mthing->type > 0) + mobj->flags |= playernumtotrans[mthing->type-1]<angle = ANG45 * (mthing->angle/45); + mobj->player = p; + mobj->health = p->health; + + p->mo = mobj; + p->playerstate = PST_LIVE; + p->refire = 0; + p->message = NULL; + p->damagecount = 0; + p->bonuscount = 0; + p->extralight = 0; + p->fixedcolormap = 0; + p->viewheight = VIEWHEIGHT; + + p->momx = p->momy = 0; // killough 10/98: initialize bobbing to 0. + + // setup gun psprite + + P_SetupPsprites (p); + + // give all cards in death match mode + + if (deathmatch) + for (i = 0 ; i < NUMCARDS ; i++) + p->cards[i] = true; + + if (mthing->type-1 == consoleplayer) + { + ST_Start(); // wake up the status bar + HU_Start(); // wake up the heads up text + } +} + + +// +// P_SpawnMapThing +// The fields of the mapthing should +// already be in host byte order. +// + +void P_SpawnMapThing (mapthing_t* mthing) +{ + int i; + //int bit; + mobj_t* mobj; + fixed_t x; + fixed_t y; + fixed_t z; + + // killough 2/26/98: Ignore type-0 things as NOPs + // phares 5/14/98: Ignore Player 5-8 starts (for now) + + switch(mthing->type) + { + case 0: + case DEN_PLAYER5: + case DEN_PLAYER6: + case DEN_PLAYER7: + case DEN_PLAYER8: + return; + } + + // killough 11/98: clear flags unused by Doom + // + // We clear the flags unused in Doom if we see flag mask 256 set, since + // it is reserved to be 0 under the new scheme. A 1 in this reserved bit + // indicates it's a Doom wad made by a Doom editor which puts 1's in + // bits that weren't used in Doom (such as HellMaker wads). So we should + // then simply ignore all upper bits. + + if (demo_compatibility || + (compatibility_level >= lxdoom_1_compatibility && + mthing->options & MTF_RESERVED)) { + if (!demo_compatibility) // cph - Add warning about bad thing flags + printf("P_SpawnMapThing: correcting bad flags (%u) (thing type %d)\n", + mthing->options, mthing->type); + mthing->options &= MTF_EASY|MTF_NORMAL|MTF_HARD|MTF_AMBUSH|MTF_NOTSINGLE; + } + + // count deathmatch start positions + + // doom2.exe has at most 10 deathmatch starts + if (mthing->type == 11 && (!compatibility || deathmatch_p-deathmatchstarts < 10)) + { + // 1/11/98 killough -- new code removes limit on deathmatch starts: + + size_t offset = deathmatch_p - deathmatchstarts; + + if (offset >= num_deathmatchstarts) + { + num_deathmatchstarts = num_deathmatchstarts ? + num_deathmatchstarts*2 : 16; + deathmatchstarts = realloc(deathmatchstarts, + num_deathmatchstarts * + sizeof(*deathmatchstarts)); + deathmatch_p = deathmatchstarts + offset; + } + memcpy(deathmatch_p++, mthing, sizeof(*mthing)); + return; + } + + // check for players specially + + if (mthing->type <= 4 && mthing->type > 0) // killough 2/26/98 -- fix crashes + { +#ifdef DOGS + // killough 7/19/98: Marine's best friend :) + if (!netgame && mthing->type > 1 && mthing->type <= dogs+1 && + !players[mthing->type-1].secretcount) + { // use secretcount to avoid multiple dogs in case of multiple starts + players[mthing->type-1].secretcount = 1; + + // killough 10/98: force it to be a friend + mthing->options |= MTF_FRIEND; + i = MT_DOGS; + goto spawnit; + } +#endif + + + // save spots for respawning in network games + + playerstarts[mthing->type-1] = *mthing; + if (!deathmatch) + P_SpawnPlayer (mthing); + return; + } + + // check for apropriate skill level + + /* jff "not single" thing flag */ + if (!netgame && mthing->options & MTF_NOTSINGLE) + return; + + //jff 3/30/98 implement "not deathmatch" thing flag + + if (netgame && deathmatch && mthing->options & MTF_NOTDM) + return; + + //jff 3/30/98 implement "not cooperative" thing flag + + if (netgame && !deathmatch && mthing->options & MTF_NOTCOOP) + return; + + // killough 11/98: simplify + if (gameskill == sk_baby || gameskill == sk_easy ? + !(mthing->options & MTF_EASY) : + gameskill == sk_hard || gameskill == sk_nightmare ? + !(mthing->options & MTF_HARD) : !(mthing->options & MTF_NORMAL)) + return; + + // find which type to spawn + + // killough 8/23/98: use table for faster lookup + i = P_FindDoomedNum(mthing->type); + + // phares 5/16/98: + // Do not abort because of an unknown thing. Ignore it, but post a + // warning message for the player. + + if (i == NUMMOBJTYPES) + { + doom_printf("Unknown Thing type %i at (%i, %i)",mthing->type,mthing->x,mthing->y); + return; + } + + // don't spawn keycards and players in deathmatch + + if (deathmatch && mobjinfo[i].flags & MF_NOTDMATCH) + return; + + // don't spawn any monsters if -nomonsters + + if (nomonsters && (i == MT_SKULL || (mobjinfo[i].flags & MF_COUNTKILL))) + return; + + // spawn it +#ifdef DOGS +spawnit: +#endif + + x = mthing->x << FRACBITS; + y = mthing->y << FRACBITS; + + if (mobjinfo[i].flags & MF_SPAWNCEILING) + z = ONCEILINGZ; + else + z = ONFLOORZ; + + mobj = P_SpawnMobj (x,y,z, i); + mobj->spawnpoint = *mthing; + + if (mobj->tics > 0) + mobj->tics = 1 + (P_Random (pr_spawnthing) % mobj->tics); + + if (!(mobj->flags & MF_FRIEND) && + mthing->options & MTF_FRIEND && + mbf_features) + { + mobj->flags |= MF_FRIEND; // killough 10/98: + P_UpdateThinker(&mobj->thinker); // transfer friendliness flag + } + + /* killough 7/20/98: exclude friends */ + if (!((mobj->flags ^ MF_COUNTKILL) & (MF_FRIEND | MF_COUNTKILL))) + totalkills++; + + if (mobj->flags & MF_COUNTITEM) + totalitems++; + + mobj->angle = ANG45 * (mthing->angle/45); + if (mthing->options & MTF_AMBUSH) + mobj->flags |= MF_AMBUSH; +} + + +// +// GAME SPAWN FUNCTIONS +// + +// +// P_SpawnPuff +// + +extern fixed_t attackrange; + +void P_SpawnPuff(fixed_t x,fixed_t y,fixed_t z) +{ + mobj_t* th; + // killough 5/5/98: remove dependence on order of evaluation: + int t = P_Random(pr_spawnpuff); + z += (t - P_Random(pr_spawnpuff))<<10; + + th = P_SpawnMobj (x,y,z, MT_PUFF); + th->momz = FRACUNIT; + th->tics -= P_Random(pr_spawnpuff)&3; + + if (th->tics < 1) + th->tics = 1; + + // don't make punches spark on the wall + + if (attackrange == MELEERANGE) + P_SetMobjState (th, S_PUFF3); +} + + +// +// P_SpawnBlood +// +void P_SpawnBlood(fixed_t x,fixed_t y,fixed_t z,int damage) +{ + mobj_t* th; + // killough 5/5/98: remove dependence on order of evaluation: + int t = P_Random(pr_spawnblood); + z += (t - P_Random(pr_spawnblood))<<10; + th = P_SpawnMobj(x,y,z, MT_BLOOD); + th->momz = FRACUNIT*2; + th->tics -= P_Random(pr_spawnblood)&3; + + if (th->tics < 1) + th->tics = 1; + + if (damage <= 12 && damage >= 9) + P_SetMobjState (th,S_BLOOD2); + else if (damage < 9) + P_SetMobjState (th,S_BLOOD3); +} + + +// +// P_CheckMissileSpawn +// Moves the missile forward a bit +// and possibly explodes it right there. +// + +void P_CheckMissileSpawn (mobj_t* th) +{ + th->tics -= P_Random(pr_missile)&3; + if (th->tics < 1) + th->tics = 1; + + // move a little forward so an angle can + // be computed if it immediately explodes + + th->x += (th->momx>>1); + th->y += (th->momy>>1); + th->z += (th->momz>>1); + + // killough 8/12/98: for non-missile objects (e.g. grenades) + if (!(th->flags & MF_MISSILE) && mbf_features) + return; + + // killough 3/15/98: no dropoff (really = don't care for missiles) + + if (!P_TryMove (th, th->x, th->y, false)) + P_ExplodeMissile (th); +} + + +// +// P_SpawnMissile +// + +mobj_t* P_SpawnMissile(mobj_t* source,mobj_t* dest,mobjtype_t type) +{ + mobj_t* th; + angle_t an; + int dist; + + th = P_SpawnMobj (source->x,source->y,source->z + 4*8*FRACUNIT,type); + + if (th->info->seesound) + S_StartSound (th, th->info->seesound); + + P_SetTarget(&th->target, source); // where it came from + an = R_PointToAngle2 (source->x, source->y, dest->x, dest->y); + + // fuzzy player + + if (dest->flags & MF_SHADOW) + { // killough 5/5/98: remove dependence on order of evaluation: + int t = P_Random(pr_shadow); + an += (t - P_Random(pr_shadow))<<20; + } + + th->angle = an; + an >>= ANGLETOFINESHIFT; + th->momx = FixedMul (th->info->speed, finecosine[an]); + th->momy = FixedMul (th->info->speed, finesine[an]); + + dist = P_AproxDistance (dest->x - source->x, dest->y - source->y); + dist = dist / th->info->speed; + + if (dist < 1) + dist = 1; + + th->momz = (dest->z - source->z) / dist; + P_CheckMissileSpawn (th); + + return th; +} + + +// +// P_SpawnPlayerMissile +// Tries to aim at a nearby monster +// + +void P_SpawnPlayerMissile(mobj_t* source,mobjtype_t type) +{ + mobj_t *th; + fixed_t x, y, z, slope = 0; + + // see which target is to be aimed at + + angle_t an = source->angle; + + // killough 7/19/98: autoaiming was not in original beta + { + // killough 8/2/98: prefer autoaiming at enemies + uint_64_t mask = mbf_features ? MF_FRIEND : 0; + + do + { + slope = P_AimLineAttack(source, an, 16*64*FRACUNIT, mask); + if (!linetarget) + slope = P_AimLineAttack(source, an += 1<<26, 16*64*FRACUNIT, mask); + if (!linetarget) + slope = P_AimLineAttack(source, an -= 2<<26, 16*64*FRACUNIT, mask); + if (!linetarget) + an = source->angle, slope = 0; + } + while (mask && (mask=0, !linetarget)); // killough 8/2/98 + } + + x = source->x; + y = source->y; + z = source->z + 4*8*FRACUNIT; + + th = P_SpawnMobj (x,y,z, type); + + if (th->info->seesound) + S_StartSound (th, th->info->seesound); + + P_SetTarget(&th->target, source); + th->angle = an; + th->momx = FixedMul(th->info->speed,finecosine[an>>ANGLETOFINESHIFT]); + th->momy = FixedMul(th->info->speed,finesine[an>>ANGLETOFINESHIFT]); + th->momz = FixedMul(th->info->speed,slope); + + P_CheckMissileSpawn(th); +} diff --git a/apps/plugins/doom/p_mobj.h b/apps/plugins/doom/p_mobj.h new file mode 100644 index 0000000000..bdd863afd9 --- /dev/null +++ b/apps/plugins/doom/p_mobj.h @@ -0,0 +1,409 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Map Objects, MObj, definition and handling. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __P_MOBJ__ +#define __P_MOBJ__ + +// Basics. +#include "tables.h" +#include "m_fixed.h" + +// We need the thinker_t stuff. +#include "d_think.h" + +// We need the WAD data structure for Map things, +// from the THINGS lump. +#include "doomdata.h" + +// States are tied to finite states are +// tied to animation frames. +// Needs precompiled tables/data structures. +#include "info.h" + +// +// NOTES: mobj_t +// +// mobj_ts are used to tell the refresh where to draw an image, +// tell the world simulation when objects are contacted, +// and tell the sound driver how to position a sound. +// +// The refresh uses the next and prev links to follow +// lists of things in sectors as they are being drawn. +// The sprite, frame, and angle elements determine which patch_t +// is used to draw the sprite if it is visible. +// The sprite and frame values are allmost allways set +// from state_t structures. +// The statescr.exe utility generates the states.h and states.c +// files that contain the sprite/frame numbers from the +// statescr.txt source file. +// The xyz origin point represents a point at the bottom middle +// of the sprite (between the feet of a biped). +// This is the default origin position for patch_ts grabbed +// with lumpy.exe. +// A walking creature will have its z equal to the floor +// it is standing on. +// +// The sound code uses the x,y, and subsector fields +// to do stereo positioning of any sound effited by the mobj_t. +// +// The play simulation uses the blocklinks, x,y,z, radius, height +// to determine when mobj_ts are touching each other, +// touching lines in the map, or hit by trace lines (gunshots, +// lines of sight, etc). +// The mobj_t->flags element has various bit flags +// used by the simulation. +// +// Every mobj_t is linked into a single sector +// based on its origin coordinates. +// The subsector_t is found with R_PointInSubsector(x,y), +// and the sector_t can be found with subsector->sector. +// The sector links are only used by the rendering code, +// the play simulation does not care about them at all. +// +// Any mobj_t that needs to be acted upon by something else +// in the play world (block movement, be shot, etc) will also +// need to be linked into the blockmap. +// If the thing has the MF_NOBLOCK flag set, it will not use +// the block links. It can still interact with other things, +// but only as the instigator (missiles will run into other +// things, but nothing can run into a missile). +// Each block in the grid is 128*128 units, and knows about +// every line_t that it contains a piece of, and every +// interactable mobj_t that has its origin contained. +// +// A valid mobj_t is a mobj_t that has the proper subsector_t +// filled in for its xy coordinates and is linked into the +// sector from which the subsector was made, or has the +// MF_NOSECTOR flag set (the subsector_t needs to be valid +// even if MF_NOSECTOR is set), and is linked into a blockmap +// block or has the MF_NOBLOCKMAP flag set. +// Links should only be modified by the P_[Un]SetThingPosition() +// functions. +// Do not change the MF_NO? flags while a thing is valid. +// +// Any questions? +// + +// +// Misc. mobj flags +// + +// Call P_SpecialThing when touched. +#define MF_SPECIAL (uint_64_t)(0x0000000000000001LL) +// Blocks. +#define MF_SOLID (uint_64_t)(0x0000000000000002LL) +// Can be hit. +#define MF_SHOOTABLE (uint_64_t)(0x0000000000000004LL) +// Don't use the sector links (invisible but touchable). +#define MF_NOSECTOR (uint_64_t)(0x0000000000000008LL) +// Don't use the blocklinks (inert but displayable) +#define MF_NOBLOCKMAP (uint_64_t)(0x0000000000000010LL) + +// Not to be activated by sound, deaf monster. +#define MF_AMBUSH (uint_64_t)(0x0000000000000020LL) +// Will try to attack right back. +#define MF_JUSTHIT (uint_64_t)(0x0000000000000040LL) +// Will take at least one step before attacking. +#define MF_JUSTATTACKED (uint_64_t)(0x0000000000000080LL) +// On level spawning (initial position), +// hang from ceiling instead of stand on floor. +#define MF_SPAWNCEILING (uint_64_t)(0x0000000000000100LL) +// Don't apply gravity (every tic), +// that is, object will float, keeping current height +// or changing it actively. +#define MF_NOGRAVITY (uint_64_t)(0x0000000000000200LL) + +// Movement flags. +// This allows jumps from high places. +#define MF_DROPOFF (uint_64_t)(0x0000000000000400LL) +// For players, will pick up items. +#define MF_PICKUP (uint_64_t)(0x0000000000000800LL) +// Player cheat. ??? +#define MF_NOCLIP (uint_64_t)(0x0000000000001000LL) +// Player: keep info about sliding along walls. +#define MF_SLIDE (uint_64_t)(0x0000000000002000LL) +// Allow moves to any height, no gravity. +// For active floaters, e.g. cacodemons, pain elementals. +#define MF_FLOAT (uint_64_t)(0x0000000000004000LL) +// Don't cross lines +// ??? or look at heights on teleport. +#define MF_TELEPORT (uint_64_t)(0x0000000000008000LL) +// Don't hit same species, explode on block. +// Player missiles as well as fireballs of various kinds. +#define MF_MISSILE (uint_64_t)(0x0000000000010000LL) +// Dropped by a demon, not level spawned. +// E.g. ammo clips dropped by dying former humans. +#define MF_DROPPED (uint_64_t)(0x0000000000020000LL) +// Use fuzzy draw (shadow demons or spectres), +// temporary player invisibility powerup. +#define MF_SHADOW (uint_64_t)(0x0000000000040000LL) +// Flag: don't bleed when shot (use puff), +// barrels and shootable furniture shall not bleed. +#define MF_NOBLOOD (uint_64_t)(0x0000000000080000LL) +// Don't stop moving halfway off a step, +// that is, have dead bodies slide down all the way. +#define MF_CORPSE (uint_64_t)(0x0000000000100000LL) +// Floating to a height for a move, ??? +// don't auto float to target's height. +#define MF_INFLOAT (uint_64_t)(0x0000000000200000LL) + +// On kill, count this enemy object +// towards intermission kill total. +// Happy gathering. +#define MF_COUNTKILL (uint_64_t)(0x0000000000400000LL) + +// On picking up, count this item object +// towards intermission item total. +#define MF_COUNTITEM (uint_64_t)(0x0000000000800000LL) + +// Special handling: skull in flight. +// Neither a cacodemon nor a missile. +#define MF_SKULLFLY (uint_64_t)(0x0000000001000000LL) + +// Don't spawn this object +// in death match mode (e.g. key cards). +#define MF_NOTDMATCH (uint_64_t)(0x0000000002000000LL) + +// Player sprites in multiplayer modes are modified +// using an internal color lookup table for re-indexing. +// If 0x4 0x8 or 0xc, +// use a translation table for player colormaps +#define MF_TRANSLATION (uint_64_t)(0x000000000c000000LL) +#define MF_TRANSLATION1 (uint_64_t)(0x0000000004000000LL) +#define MF_TRANSLATION2 (uint_64_t)(0x0000000008000000LL) +// Hmm ???. +#define MF_TRANSSHIFT 26 + +// proff 11/19/98: Andy Baker's stealth monsters - unused yet +//Stealth Mode - Creatures that dissappear and reappear. + +#define MF_STEALTH (uint_64_t)(0x0000000010000000LL) + +// proff 11/19/98: 3 (4 counting opaque) levels of translucency +// not very good to set the next one in this enum, should be seperate +#define MF_TRANSLUCBITS (uint_64_t)(0x0000000060000000LL) +#define MF_TRANSLUC25 (uint_64_t)(0x0000000020000000LL) +#define MF_TRANSLUC50 (uint_64_t)(0x0000000040000000LL) +#define MF_TRANSLUC75 (uint_64_t)(0x0000000060000000LL) + +// Translucent sprite? // phares +#define MF_TRANSLUCENT (uint_64_t)(0x0000000040000000LL) + +// these are greater than an int. That's why the flags below are now uint_64_t +#define MF_TOUCHY (uint_64_t)(0x0000000100000000LL) +#define MF_BOUNCES (uint_64_t)(0x0000000200000000LL) +#define MF_FRIEND (uint_64_t)(0x0000000400000000LL) + +// killough 9/15/98: Same, but internal flags, not intended for .deh +// (some degree of opaqueness is good, to avoid compatibility woes) + +enum { + MIF_FALLING = 1, // Object is falling + MIF_ARMED = 2, // Object is armed (for MF_TOUCHY objects) +}; + +// Map Object definition. +// +// killough 2/20/98: +// +// WARNING: Special steps must be taken in p_saveg.c if C pointers are added to +// this mobj_s struct, or else savegames will crash when loaded. See p_saveg.c. +// Do not add "struct mobj_s *fooptr" without adding code to p_saveg.c to +// convert the pointers to ordinals and back for savegames. This was the whole +// reason behind monsters going to sleep when loading savegames (the "target" +// pointer was simply nullified after loading, to prevent Doom from crashing), +// and the whole reason behind loadgames crashing on savegames of AV attacks. +// + +// killough 9/8/98: changed some fields to shorts, +// for better memory usage (if only for cache). + +typedef struct mobj_s +{ + // List: thinker links. + thinker_t thinker; + + // Info for drawing: position. + fixed_t x; + fixed_t y; + fixed_t z; + + // More list: links in sector (if needed) + struct mobj_s* snext; + struct mobj_s** sprev; // killough 8/10/98: change to ptr-to-ptr + + //More drawing info: to determine current sprite. + angle_t angle; // orientation + spritenum_t sprite; // used to find patch_t and flip value + int frame; // might be ORed with FF_FULLBRIGHT + + // Interaction info, by BLOCKMAP. + // Links in blocks (if needed). + struct mobj_s* bnext; + struct mobj_s** bprev; // killough 8/11/98: change to ptr-to-ptr + + struct subsector_s* subsector; + + // The closest interval over all contacted Sectors. + fixed_t floorz; + fixed_t ceilingz; + + // killough 11/98: the lowest floor over all contacted Sectors. + fixed_t dropoffz; + + // For movement checking. + fixed_t radius; + fixed_t height; + + // Momentums, used to update position. + fixed_t momx; + fixed_t momy; + fixed_t momz; + + // If == validcount, already checked. + int validcount; + + mobjtype_t type; + mobjinfo_t* info; // &mobjinfo[mobj->type] + + int tics; // state tic counter + state_t* state; + uint_64_t flags; + int intflags; // killough 9/15/98: internal flags + int health; + + // Movement direction, movement generation (zig-zagging). + short movedir; // 0-7 + short movecount; // when 0, select a new dir + short strafecount; // killough 9/8/98: monster strafing + + // Thing being chased/attacked (or NULL), + // also the originator for missiles. + struct mobj_s* target; + + // Reaction time: if non 0, don't attack yet. + // Used by player to freeze a bit after teleporting. + short reactiontime; + + // If >0, the current target will be chased no + // matter what (even if shot by another object) + short threshold; + + // killough 9/9/98: How long a monster pursues a target. + short pursuecount; + + short gear; // killough 11/98: used in torque simulation + + // Additional info record for player avatars only. + // Only valid if type == MT_PLAYER + struct player_s* player; + + // Player number last looked for. + short lastlook; + + // For nightmare respawn. + mapthing_t spawnpoint; + + // Thing being chased/attacked for tracers. + struct mobj_s* tracer; + + //proff 11/22/98: Andy Baker's stealth monsters + boolean invisible; + + // new field: last known enemy -- killough 2/15/98 + struct mobj_s* lastenemy; + + // Are we above a Thing? above_thing points to the Thing // phares + // if so, otherwise it's zero. // | + // V + struct mobj_s* above_thing; + + // Are we below a Thing? below_thing points to the Thing + // if so, otherwise it's zero. + // ^ + struct mobj_s* below_thing; // | + // phares + + // killough 8/2/98: friction properties part of sectors, + // not objects -- removed friction properties from here + + // a linked list of sectors where this object appears + struct msecnode_s* touching_sectorlist; // phares 3/14/98 + + // SEE WARNING ABOVE ABOUT POINTER FIELDS!!! +} mobj_t; + +// External declarations (fomerly in p_local.h) -- killough 5/2/98 + +#define VIEWHEIGHT (41*FRACUNIT) +#define PLAYERRADIUS (16*FRACUNIT) + +#define GRAVITY FRACUNIT +#define MAXMOVE (30*FRACUNIT) + +#define ONFLOORZ INT_MIN +#define ONCEILINGZ INT_MAX + +// Time interval for item respawning. +#define ITEMQUESIZE 128 + +#define FLOATSPEED (FRACUNIT*4) +#define STOPSPEED (FRACUNIT/16) + +// killough 11/98: +// For torque simulation: + +#define OVERDRIVE 6 +#define MAXGEAR (OVERDRIVE+16) + +// killough 11/98: +// Whether an object is "sentient" or not. Used for environmental influences. +#define sentient(mobj) ((mobj)->health > 0 && (mobj)->info->seestate) + +extern mapthing_t itemrespawnque[]; +extern int itemrespawntime[]; +extern int iquehead; +extern int iquetail; + +void P_RespawnSpecials(void); +mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type); +void P_RemoveMobj(mobj_t *th); +boolean P_SetMobjState(mobj_t *mobj, statenum_t state); +void P_MobjThinker(mobj_t *mobj); +void P_SpawnPuff(fixed_t x, fixed_t y, fixed_t z); +void P_SpawnBlood(fixed_t x, fixed_t y, fixed_t z, int damage); +mobj_t *P_SpawnMissile(mobj_t *source, mobj_t *dest, mobjtype_t type); +void P_SpawnPlayerMissile(mobj_t *source, mobjtype_t type); +void P_SpawnMapThing (mapthing_t* mthing); +void P_CheckMissileSpawn(mobj_t*); // killough 8/2/98 +void P_ExplodeMissile(mobj_t*); // killough +#endif + diff --git a/apps/plugins/doom/p_plats.c b/apps/plugins/doom/p_plats.c new file mode 100644 index 0000000000..4a5c28bb88 --- /dev/null +++ b/apps/plugins/doom/p_plats.c @@ -0,0 +1,434 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Plats (i.e. elevator platforms) code, raising/lowering. + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "m_random.h" +#include "r_main.h" +#include "p_spec.h" +#include "p_tick.h" +#include "s_sound.h" +#include "sounds.h" +#include "rockmacros.h" +platlist_t *activeplats; // killough 2/14/98: made global again + +// +// T_PlatRaise() +// +// Action routine to move a plat up and down +// +// Passed a plat structure containing all pertinent information about the move +// No return +// +// jff 02/08/98 all cases with labels beginning with gen added to support +// generalized line type behaviors. + +void T_PlatRaise(plat_t* plat) +{ + result_e res; + + // handle plat moving, up, down, waiting, or in stasis, + switch(plat->status) + { + case up: // plat moving up + res = T_MovePlane(plat->sector,plat->speed,plat->high,plat->crush,0,1); + + // if a pure raise type, make the plat moving sound + if (plat->type == raiseAndChange + || plat->type == raiseToNearestAndChange) + { + if (!(leveltime&7)) + S_StartSound((mobj_t *)&plat->sector->soundorg, sfx_stnmov); + } + + // if encountered an obstacle, and not a crush type, reverse direction + if (res == crushed && (!plat->crush)) + { + plat->count = plat->wait; + plat->status = down; + S_StartSound((mobj_t *)&plat->sector->soundorg, sfx_pstart); + } + else // else handle reaching end of up stroke + { + if (res == pastdest) // end of stroke + { + // if not an instant toggle type, wait, make plat stop sound + if (plat->type!=toggleUpDn) + { + plat->count = plat->wait; + plat->status = waiting; + S_StartSound((mobj_t *)&plat->sector->soundorg, sfx_pstop); + } + else // else go into stasis awaiting next toggle activation + { + plat->oldstatus = plat->status;//jff 3/14/98 after action wait + plat->status = in_stasis; //for reactivation of toggle + } + + // lift types and pure raise types are done at end of up stroke + // only the perpetual type waits then goes back up + switch(plat->type) + { + case blazeDWUS: + case downWaitUpStay: + case raiseAndChange: + case raiseToNearestAndChange: + case genLift: + P_RemoveActivePlat(plat); // killough + default: + break; + } + } + } + break; + + case down: // plat moving down + res = T_MovePlane(plat->sector,plat->speed,plat->low,false,0,-1); + + // handle reaching end of down stroke + if (res == pastdest) + { + // if not an instant toggle, start waiting, make plat stop sound + if (plat->type!=toggleUpDn) //jff 3/14/98 toggle up down + { // is silent, instant, no waiting + plat->count = plat->wait; + plat->status = waiting; + S_StartSound((mobj_t *)&plat->sector->soundorg,sfx_pstop); + } + else // instant toggles go into stasis awaiting next activation + { + plat->oldstatus = plat->status;//jff 3/14/98 after action wait + plat->status = in_stasis; //for reactivation of toggle + } + + //jff 1/26/98 remove the plat if it bounced so it can be tried again + //only affects plats that raise and bounce + //killough 1/31/98: relax compatibility to demo_compatibility + + // remove the plat if its a pure raise type + if (!comp[comp_floors]) + { + switch(plat->type) + { + case raiseAndChange: + case raiseToNearestAndChange: + P_RemoveActivePlat(plat); + default: + break; + } + } + } + break; + + case waiting: // plat is waiting + if (!--plat->count) // downcount and check for delay elapsed + { + if (plat->sector->floorheight == plat->low) + plat->status = up; // if at bottom, start up + else + plat->status = down; // if at top, start down + + // make plat start sound + S_StartSound((mobj_t *)&plat->sector->soundorg,sfx_pstart); + } + break; //jff 1/27/98 don't pickup code added later to in_stasis + + case in_stasis: // do nothing if in stasis + break; + } +} + + +// +// EV_DoPlat +// +// Handle Plat linedef types +// +// Passed the linedef that activated the plat, the type of plat action, +// and for some plat types, an amount to raise +// Returns true if a thinker is started, or restarted from stasis +// +int EV_DoPlat +( line_t* line, + plattype_e type, + int amount ) +{ + plat_t* plat; + int secnum; + int rtn; + sector_t* sec; + + secnum = -1; + rtn = 0; + + + // Activate all plats that are in_stasis + switch(type) + { + case perpetualRaise: + P_ActivateInStasis(line->tag); + break; + + case toggleUpDn: + P_ActivateInStasis(line->tag); + rtn=1; + break; + + default: + break; + } + + // act on all sectors tagged the same as the activating linedef + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; + + // don't start a second floor function if already moving + if (P_SectorActive(floor_special,sec)) //jff 2/23/98 multiple thinkers + continue; + + // Create a thinker + rtn = 1; + plat = Z_Malloc( sizeof(*plat), PU_LEVSPEC, 0); + P_AddThinker(&plat->thinker); + + plat->type = type; + plat->sector = sec; + plat->sector->floordata = plat; //jff 2/23/98 multiple thinkers + plat->thinker.function = T_PlatRaise; + plat->crush = false; + plat->tag = line->tag; + + //jff 1/26/98 Avoid raise plat bouncing a head off a ceiling and then + //going down forever -- default low to plat height when triggered + plat->low = sec->floorheight; + + // set up plat according to type + switch(type) + { + case raiseToNearestAndChange: + plat->speed = PLATSPEED/2; + sec->floorpic = sides[line->sidenum[0]].sector->floorpic; + plat->high = P_FindNextHighestFloor(sec,sec->floorheight); + plat->wait = 0; + plat->status = up; + sec->special = 0; + //jff 3/14/98 clear old field as well + sec->oldspecial = 0; + + S_StartSound((mobj_t *)&sec->soundorg,sfx_stnmov); + break; + + case raiseAndChange: + plat->speed = PLATSPEED/2; + sec->floorpic = sides[line->sidenum[0]].sector->floorpic; + plat->high = sec->floorheight + amount*FRACUNIT; + plat->wait = 0; + plat->status = up; + + S_StartSound((mobj_t *)&sec->soundorg,sfx_stnmov); + break; + + case downWaitUpStay: + plat->speed = PLATSPEED * 4; + plat->low = P_FindLowestFloorSurrounding(sec); + + if (plat->low > sec->floorheight) + plat->low = sec->floorheight; + + plat->high = sec->floorheight; + plat->wait = 35*PLATWAIT; + plat->status = down; + S_StartSound((mobj_t *)&sec->soundorg,sfx_pstart); + break; + + case blazeDWUS: + plat->speed = PLATSPEED * 8; + plat->low = P_FindLowestFloorSurrounding(sec); + + if (plat->low > sec->floorheight) + plat->low = sec->floorheight; + + plat->high = sec->floorheight; + plat->wait = 35*PLATWAIT; + plat->status = down; + S_StartSound((mobj_t *)&sec->soundorg,sfx_pstart); + break; + + case perpetualRaise: + plat->speed = PLATSPEED; + plat->low = P_FindLowestFloorSurrounding(sec); + + if (plat->low > sec->floorheight) + plat->low = sec->floorheight; + + plat->high = P_FindHighestFloorSurrounding(sec); + + if (plat->high < sec->floorheight) + plat->high = sec->floorheight; + + plat->wait = 35*PLATWAIT; + plat->status = P_Random(pr_plats)&1; + + S_StartSound((mobj_t *)&sec->soundorg,sfx_pstart); + break; + + case toggleUpDn: //jff 3/14/98 add new type to support instant toggle + plat->speed = PLATSPEED; //not used + plat->wait = 35*PLATWAIT; //not used + plat->crush = true; //jff 3/14/98 crush anything in the way + + // set up toggling between ceiling, floor inclusive + plat->low = sec->ceilingheight; + plat->high = sec->floorheight; + plat->status = down; + break; + + default: + break; + } + P_AddActivePlat(plat); // add plat to list of active plats + } + return rtn; +} + +// The following were all rewritten by Lee Killough +// to use the new structure which places no limits +// on active plats. It also avoids spending as much +// time searching for active plats. Previously a +// fixed-size array was used, with NULL indicating +// empty entries, while now a doubly-linked list +// is used. + +// +// P_ActivateInStasis() +// +// Activate a plat that has been put in stasis +// (stopped perpetual floor, instant floor/ceil toggle) +// +// Passed the tag of the plat that should be reactivated +// Returns nothing +// +void P_ActivateInStasis(int tag) +{ + platlist_t *pl; + for (pl=activeplats; pl; pl=pl->next) // search the active plats + { + plat_t *plat = pl->plat; // for one in stasis with right tag + if (plat->tag == tag && plat->status == in_stasis) + { + if (plat->type==toggleUpDn) //jff 3/14/98 reactivate toggle type + plat->status = plat->oldstatus==up? down : up; + else + plat->status = plat->oldstatus; + plat->thinker.function = T_PlatRaise; + } + } +} + +// +// EV_StopPlat() +// +// Handler for "stop perpetual floor" linedef type +// +// Passed the linedef that stopped the plat +// Returns true if a plat was put in stasis +// +// jff 2/12/98 added int return value, fixed return +// +int EV_StopPlat(line_t* line) +{ + platlist_t *pl; + for (pl=activeplats; pl; pl=pl->next) // search the active plats + { + plat_t *plat = pl->plat; // for one with the tag not in stasis + if (plat->status != in_stasis && plat->tag == line->tag) + { + plat->oldstatus = plat->status; // put it in stasis + plat->status = in_stasis; + plat->thinker.function = NULL; + } + } + return 1; +} + +// +// P_AddActivePlat() +// +// Add a plat to the head of the active plat list +// +// Passed a pointer to the plat to add +// Returns nothing +// +void P_AddActivePlat(plat_t* plat) +{ + platlist_t *list = malloc(sizeof *list); + list->plat = plat; + plat->list = list; + if ((list->next = activeplats)) + list->next->prev = &list->next; + list->prev = &activeplats; + activeplats = list; +} + +// +// P_RemoveActivePlat() +// +// Remove a plat from the active plat list +// +// Passed a pointer to the plat to remove +// Returns nothing +// +void P_RemoveActivePlat(plat_t* plat) +{ + platlist_t *list = plat->list; + plat->sector->floordata = NULL; //jff 2/23/98 multiple thinkers + P_RemoveThinker(&plat->thinker); + if ((*list->prev = list->next)) + list->next->prev = list->prev; + free(list); +} + +// +// P_RemoveAllActivePlats() +// +// Remove all plats from the active plat list +// +// Passed nothing, returns nothing +// +void P_RemoveAllActivePlats(void) +{ + while (activeplats) + { + platlist_t *next = activeplats->next; + free(activeplats); + activeplats = next; + } +} diff --git a/apps/plugins/doom/p_pspr.c b/apps/plugins/doom/p_pspr.c new file mode 100644 index 0000000000..9ef9e73978 --- /dev/null +++ b/apps/plugins/doom/p_pspr.c @@ -0,0 +1,853 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Weapon sprite animation, weapon objects. + * Action functions for weapons. + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "r_main.h" +#include "p_map.h" +#include "p_inter.h" +#include "p_pspr.h" +#include "p_enemy.h" +#include "m_random.h" +#include "s_sound.h" +#include "sounds.h" +#include "d_event.h" +#include "rockmacros.h" +#define LOWERSPEED (FRACUNIT*6) +#define RAISESPEED (FRACUNIT*6) +#define WEAPONBOTTOM (FRACUNIT*128) +#define WEAPONTOP (FRACUNIT*32) + +// plasma cells for a bfg attack +#define BFGCELLS 40 +//#define BFGCELLS bfgcells /* Ty 03/09/98 externalized in p_inter.c */ + +extern void P_Thrust(player_t *, angle_t, fixed_t); + +// The following array holds the recoil values // phares + +static const int recoil_values[] = { // phares + 10, // wp_fist + 10, // wp_pistol + 30, // wp_shotgun + 10, // wp_chaingun + 100,// wp_missile + 20, // wp_plasma + 100,// wp_bfg + 0, // wp_chainsaw + 80 // wp_supershotgun + }; + +// +// P_SetPsprite +// + +static void P_SetPsprite(player_t *player, int position, statenum_t stnum) +{ + pspdef_t *psp = &player->psprites[position]; + + do + { + state_t *state; + + if (!stnum) + { + // object removed itself + psp->state = NULL; + break; + } + + state = &states[stnum]; + psp->state = state; + psp->tics = state->tics; // could be 0 + + if (state->misc1) + { + // coordinate set + psp->sx = state->misc1 << FRACBITS; + psp->sy = state->misc2 << FRACBITS; + } + + // Call action routine. + // Modified handling. + if (state->action) + { + state->action(player, psp); + if (!psp->state) + break; + } + stnum = psp->state->nextstate; + } + while (!psp->tics); // an initial state of 0 could cycle through +} + +// +// P_BringUpWeapon +// Starts bringing the pending weapon up +// from the bottom of the screen. +// Uses player +// + +static void P_BringUpWeapon(player_t *player) +{ + statenum_t newstate; + + if (player->pendingweapon == wp_nochange) + player->pendingweapon = player->readyweapon; + + if (player->pendingweapon == wp_chainsaw) + S_StartSound (player->mo, sfx_sawup); + + newstate = weaponinfo[player->pendingweapon].upstate; + + player->pendingweapon = wp_nochange; + // killough 12/98: prevent pistol from starting visibly at bottom of screen: + player->psprites[ps_weapon].sy = + mbf_features ? WEAPONBOTTOM+FRACUNIT*2 : WEAPONBOTTOM; + + P_SetPsprite(player, ps_weapon, newstate); +} + +// The first set is where the weapon preferences from // killough, +// default.cfg are stored. These values represent the keys used // phares +// in DOOM2 to bring up the weapon, i.e. 6 = plasma gun. These // | +// are NOT the wp_* constants. // V + +int weapon_preferences[2][NUMWEAPONS+1] = { + {6, 9, 4, 3, 2, 8, 5, 7, 1, 0}, // !compatibility preferences + {6, 9, 4, 3, 2, 8, 5, 7, 1, 0}, // compatibility preferences + }; + +// P_SwitchWeapon checks current ammo levels and gives you the +// most preferred weapon with ammo. It will not pick the currently +// raised weapon. When called from P_CheckAmmo this won't matter, +// because the raised weapon has no ammo anyway. When called from +// G_BuildTiccmd you want to toggle to a different weapon regardless. + +int P_SwitchWeapon(player_t *player) +{ + int *prefer = weapon_preferences[demo_compatibility!=0]; // killough 3/22/98 + int currentweapon = player->readyweapon; + int newweapon = currentweapon; + int i = NUMWEAPONS+1; // killough 5/2/98 + + // killough 2/8/98: follow preferences and fix BFG/SSG bugs + + do + switch (*prefer++) + { + case 1: + if (!player->powers[pw_strength]) // allow chainsaw override + break; + case 0: + newweapon = wp_fist; + break; + case 2: + if (player->ammo[am_clip]) + newweapon = wp_pistol; + break; + case 3: + if (player->weaponowned[wp_shotgun] && player->ammo[am_shell]) + newweapon = wp_shotgun; + break; + case 4: + if (player->weaponowned[wp_chaingun] && player->ammo[am_clip]) + newweapon = wp_chaingun; + break; + case 5: + if (player->weaponowned[wp_missile] && player->ammo[am_misl]) + newweapon = wp_missile; + break; + case 6: + if (player->weaponowned[wp_plasma] && player->ammo[am_cell] && + gamemode != shareware) + newweapon = wp_plasma; + break; + case 7: + if (player->weaponowned[wp_bfg] && gamemode != shareware && + player->ammo[am_cell] >= (demo_compatibility ? 41 : 40)) + newweapon = wp_bfg; + break; + case 8: + if (player->weaponowned[wp_chainsaw]) + newweapon = wp_chainsaw; + break; + case 9: + if (player->weaponowned[wp_supershotgun] && gamemode == commercial && + player->ammo[am_shell] >= (demo_compatibility ? 3 : 2)) + newweapon = wp_supershotgun; + break; + } + while (newweapon==currentweapon && --i); // killough 5/2/98 + return newweapon; +} + +// killough 5/2/98: whether consoleplayer prefers weapon w1 over weapon w2. +int P_WeaponPreferred(int w1, int w2) +{ + return + (weapon_preferences[0][0] != ++w2 && (weapon_preferences[0][0] == ++w1 || + (weapon_preferences[0][1] != w2 && (weapon_preferences[0][1] == w1 || + (weapon_preferences[0][2] != w2 && (weapon_preferences[0][2] == w1 || + (weapon_preferences[0][3] != w2 && (weapon_preferences[0][3] == w1 || + (weapon_preferences[0][4] != w2 && (weapon_preferences[0][4] == w1 || + (weapon_preferences[0][5] != w2 && (weapon_preferences[0][5] == w1 || + (weapon_preferences[0][6] != w2 && (weapon_preferences[0][6] == w1 || + (weapon_preferences[0][7] != w2 && (weapon_preferences[0][7] == w1 + )))))))))))))))); +} + +// +// P_CheckAmmo +// Returns true if there is enough ammo to shoot. +// If not, selects the next weapon to use. +// (only in demo_compatibility mode -- killough 3/22/98) +// + +boolean P_CheckAmmo(player_t *player) +{ + ammotype_t ammo = weaponinfo[player->readyweapon].ammo; + int count = 1; // Regular + + if (player->readyweapon == wp_bfg) // Minimal amount for one shot varies. + count = BFGCELLS; + else + if (player->readyweapon == wp_supershotgun) // Double barrel. + count = 2; + + // Some do not need ammunition anyway. + // Return if current ammunition sufficient. + + if (ammo == am_noammo || player->ammo[ammo] >= count) + return true; + + // Out of ammo, pick a weapon to change to. + // + // killough 3/22/98: for old demos we do the switch here and now; + // for Boom games we cannot do this, and have different player + // preferences across demos or networks, so we have to use the + // G_BuildTiccmd() interface instead of making the switch here. + + if (demo_compatibility) + { + player->pendingweapon = P_SwitchWeapon(player); // phares + // Now set appropriate weapon overlay. + P_SetPsprite(player,ps_weapon,weaponinfo[player->readyweapon].downstate); + } + + return false; +} + +// +// P_FireWeapon. +// + +int lastshottic; // killough 3/22/98 + +static void P_FireWeapon(player_t *player) +{ + statenum_t newstate; + + if (!P_CheckAmmo(player)) + return; + + P_SetMobjState(player->mo, S_PLAY_ATK1); + newstate = weaponinfo[player->readyweapon].atkstate; + P_SetPsprite(player, ps_weapon, newstate); + P_NoiseAlert(player->mo, player->mo); + lastshottic = gametic; // killough 3/22/98 +} + +// +// P_DropWeapon +// Player died, so put the weapon away. +// + +void P_DropWeapon(player_t *player) +{ + P_SetPsprite(player, ps_weapon, weaponinfo[player->readyweapon].downstate); +} + +// +// A_WeaponReady +// The player can fire the weapon +// or change to another weapon at this time. +// Follows after getting weapon up, +// or after previous attack/fire sequence. +// + +void A_WeaponReady(player_t *player, pspdef_t *psp) +{ + // get out of attack state + if (player->mo->state == &states[S_PLAY_ATK1] + || player->mo->state == &states[S_PLAY_ATK2] ) + P_SetMobjState(player->mo, S_PLAY); + + if (player->readyweapon == wp_chainsaw && psp->state == &states[S_SAW]) + S_StartSound(player->mo, sfx_sawidl); + + // check for change + // if player is dead, put the weapon away + + if (player->pendingweapon != wp_nochange || !player->health) + { + // change weapon (pending weapon should already be validated) + statenum_t newstate = weaponinfo[player->readyweapon].downstate; + P_SetPsprite(player, ps_weapon, newstate); + return; + } + + // check for fire + // the missile launcher and bfg do not auto fire + + if (player->cmd.buttons & BT_ATTACK) + { + if (!player->attackdown || (player->readyweapon != wp_missile && + player->readyweapon != wp_bfg)) + { + player->attackdown = true; + P_FireWeapon(player); + return; + } + } + else + player->attackdown = false; + + // bob the weapon based on movement speed + { + int angle = (128*leveltime) & FINEMASK; + psp->sx = FRACUNIT + FixedMul(player->bob, finecosine[angle]); + angle &= FINEANGLES/2-1; + psp->sy = WEAPONTOP + FixedMul(player->bob, finesine[angle]); + } +} + +// +// A_ReFire +// The player can re-fire the weapon +// without lowering it entirely. +// + +void A_ReFire(player_t *player, pspdef_t *psp) +{ + (void)psp; + // check for fire + // (if a weaponchange is pending, let it go through instead) + + if ( (player->cmd.buttons & BT_ATTACK) + && player->pendingweapon == wp_nochange && player->health) + { + player->refire++; + P_FireWeapon(player); + } + else + { + player->refire = 0; + P_CheckAmmo(player); + } +} + +void A_CheckReload(player_t *player, pspdef_t *psp) +{ + (void)psp; + P_CheckAmmo(player); +} + +// +// A_Lower +// Lowers current weapon, +// and changes weapon at bottom. +// + +void A_Lower(player_t *player, pspdef_t *psp) +{ + psp->sy += LOWERSPEED; + + // Is already down. + if (psp->sy < WEAPONBOTTOM) + return; + + // Player is dead. + if (player->playerstate == PST_DEAD) + { + psp->sy = WEAPONBOTTOM; + return; // don't bring weapon back up + } + + // The old weapon has been lowered off the screen, + // so change the weapon and start raising it + + if (!player->health) + { // Player is dead, so keep the weapon off screen. + P_SetPsprite(player, ps_weapon, S_NULL); + return; + } + + player->readyweapon = player->pendingweapon; + + P_BringUpWeapon(player); +} + +// +// A_Raise +// + +void A_Raise(player_t *player, pspdef_t *psp) +{ + statenum_t newstate; + + psp->sy -= RAISESPEED; + + if (psp->sy > WEAPONTOP) + return; + + psp->sy = WEAPONTOP; + + // The weapon has been raised all the way, + // so change to the ready state. + + newstate = weaponinfo[player->readyweapon].readystate; + + P_SetPsprite(player, ps_weapon, newstate); +} + + +// Weapons now recoil, amount depending on the weapon. // phares +// // | +// The P_SetPsprite call in each of the weapon firing routines // V +// was moved here so the recoil could be synched with the +// muzzle flash, rather than the pressing of the trigger. +// The BFG delay caused this to be necessary. + +static void A_FireSomething(player_t* player,int adder) +{ + P_SetPsprite(player, ps_flash, + weaponinfo[player->readyweapon].flashstate+adder); + + // killough 3/27/98: prevent recoil in no-clipping mode + if (!(player->mo->flags & MF_NOCLIP)) + if (!compatibility && weapon_recoil) + P_Thrust(player, + ANG180+player->mo->angle, // ^ + 2048*recoil_values[player->readyweapon]); // | +} // phares + +// +// A_GunFlash +// + +void A_GunFlash(player_t *player, pspdef_t *psp) +{ + (void)psp; + P_SetMobjState(player->mo, S_PLAY_ATK2); + + A_FireSomething(player,0); // phares +} + +// +// WEAPON ATTACKS +// + +// +// A_Punch +// + +void A_Punch(player_t *player, pspdef_t *psp) +{ + (void)psp; + angle_t angle; + int t, slope, damage = (P_Random(pr_punch)%10+1)<<1; + + if (player->powers[pw_strength]) + damage *= 10; + + angle = player->mo->angle; + + // killough 5/5/98: remove dependence on order of evaluation: + t = P_Random(pr_punchangle); + angle += (t - P_Random(pr_punchangle))<<18; + + /* killough 8/2/98: make autoaiming prefer enemies */ + if (!mbf_features || + (slope = P_AimLineAttack(player->mo, angle, MELEERANGE, MF_FRIEND), + !linetarget)) + slope = P_AimLineAttack(player->mo, angle, MELEERANGE, 0); + + P_LineAttack(player->mo, angle, MELEERANGE, slope, damage); + + if (!linetarget) + return; + + S_StartSound(player->mo, sfx_punch); + + // turn to face target + + player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, + linetarget->x, linetarget->y); +} + +// +// A_Saw +// + +void A_Saw(player_t *player, pspdef_t *psp) +{ + (void)psp; + int slope, damage = 2*(P_Random(pr_saw)%10+1); + angle_t angle = player->mo->angle; + // killough 5/5/98: remove dependence on order of evaluation: + int t = P_Random(pr_saw); + angle += (t - P_Random(pr_saw))<<18; + + /* Use meleerange + 1 so that the puff doesn't skip the flash + * killough 8/2/98: make autoaiming prefer enemies */ + if (!mbf_features || + (slope = P_AimLineAttack(player->mo, angle, MELEERANGE+1, MF_FRIEND), + !linetarget)) + slope = P_AimLineAttack(player->mo, angle, MELEERANGE+1, 0); + + P_LineAttack(player->mo, angle, MELEERANGE+1, slope, damage); + + if (!linetarget) + { + S_StartSound(player->mo, sfx_sawful); + return; + } + + S_StartSound(player->mo, sfx_sawhit); + + // turn to face target + angle = R_PointToAngle2(player->mo->x, player->mo->y, + linetarget->x, linetarget->y); + + if (angle - player->mo->angle > ANG180) { + if (angle - player->mo->angle < (unsigned)(-ANG90/20)) + player->mo->angle = angle + ANG90/21; + else + player->mo->angle -= ANG90/20; + } else { + if (angle - player->mo->angle > ANG90/20) + player->mo->angle = angle - ANG90/21; + else + player->mo->angle += ANG90/20; + } + + player->mo->flags |= MF_JUSTATTACKED; +} + +// +// A_FireMissile +// + +void A_FireMissile(player_t *player, pspdef_t *psp) +{ + (void)psp; + player->ammo[weaponinfo[player->readyweapon].ammo]--; + P_SpawnPlayerMissile(player->mo, MT_ROCKET); +} + +// +// A_FireBFG +// + +void A_FireBFG(player_t *player, pspdef_t *psp) +{ + (void)psp; + player->ammo[weaponinfo[player->readyweapon].ammo] -= BFGCELLS; + P_SpawnPlayerMissile(player->mo, MT_BFG); +} + +/* + * A_FireOldBFG + * + * This function emulates Doom's Pre-Beta BFG + * By Lee Killough 6/6/98, 7/11/98, 7/19/98, 8/20/98 + * + * This code may not be used in other mods without appropriate credit given. + * Code leeches will be telefragged. + */ + +void A_FireOldBFG(player_t *player, pspdef_t *psp) +{ + (void)psp; + (void)player; +} + +// +// A_FirePlasma +// + +void A_FirePlasma(player_t *player, pspdef_t *psp) +{ + (void)psp; + player->ammo[weaponinfo[player->readyweapon].ammo]--; + + A_FireSomething(player,P_Random(pr_plasma)&1); // phares + P_SpawnPlayerMissile(player->mo, MT_PLASMA); +} + +// +// P_BulletSlope +// Sets a slope so a near miss is at aproximately +// the height of the intended target +// + +static fixed_t bulletslope; + +static void P_BulletSlope(mobj_t *mo) +{ + angle_t an = mo->angle; // see which target is to be aimed at + + /* killough 8/2/98: make autoaiming prefer enemies */ + uint_64_t mask = mbf_features ? MF_FRIEND : 0; + + do + { + bulletslope = P_AimLineAttack(mo, an, 16*64*FRACUNIT, mask); + if (!linetarget) + bulletslope = P_AimLineAttack(mo, an += 1<<26, 16*64*FRACUNIT, mask); + if (!linetarget) + bulletslope = P_AimLineAttack(mo, an -= 2<<26, 16*64*FRACUNIT, mask); + } + while (mask && (mask=0, !linetarget)); /* killough 8/2/98 */ +} + +// +// P_GunShot +// + +void P_GunShot(mobj_t *mo, boolean accurate) +{ + int damage = 5*(P_Random(pr_gunshot)%3+1); + angle_t angle = mo->angle; + + if (!accurate) + { // killough 5/5/98: remove dependence on order of evaluation: + int t = P_Random(pr_misfire); + angle += (t - P_Random(pr_misfire))<<18; + } + + P_LineAttack(mo, angle, MISSILERANGE, bulletslope, damage); +} + +// +// A_FirePistol +// + +void A_FirePistol(player_t *player, pspdef_t *psp) +{ + (void)psp; + S_StartSound(player->mo, sfx_pistol); + + P_SetMobjState(player->mo, S_PLAY_ATK2); + player->ammo[weaponinfo[player->readyweapon].ammo]--; + + A_FireSomething(player,0); // phares + P_BulletSlope(player->mo); + P_GunShot(player->mo, !player->refire); +} + +// +// A_FireShotgun +// + +void A_FireShotgun(player_t *player, pspdef_t *psp) +{ + (void)psp; + int i; + + S_StartSound(player->mo, sfx_shotgn); + P_SetMobjState(player->mo, S_PLAY_ATK2); + + player->ammo[weaponinfo[player->readyweapon].ammo]--; + + A_FireSomething(player,0); // phares + + P_BulletSlope(player->mo); + + for (i=0; i<7; i++) + P_GunShot(player->mo, false); +} + +// +// A_FireShotgun2 +// + +void A_FireShotgun2(player_t *player, pspdef_t *psp) +{ + (void)psp; + int i; + + S_StartSound(player->mo, sfx_dshtgn); + P_SetMobjState(player->mo, S_PLAY_ATK2); + player->ammo[weaponinfo[player->readyweapon].ammo] -= 2; + + A_FireSomething(player,0); // phares + + P_BulletSlope(player->mo); + + for (i=0; i<20; i++) + { + int damage = 5*(P_Random(pr_shotgun)%3+1); + angle_t angle = player->mo->angle; + // killough 5/5/98: remove dependence on order of evaluation: + int t = P_Random(pr_shotgun); + angle += (t - P_Random(pr_shotgun))<<19; + t = P_Random(pr_shotgun); + P_LineAttack(player->mo, angle, MISSILERANGE, bulletslope + + ((t - P_Random(pr_shotgun))<<5), damage); + } +} + +// +// A_FireCGun +// + +void A_FireCGun(player_t *player, pspdef_t *psp) +{ + if (player->ammo[weaponinfo[player->readyweapon].ammo] || comp[comp_sound]) + S_StartSound(player->mo, sfx_pistol); + + if (!player->ammo[weaponinfo[player->readyweapon].ammo]) + return; + + P_SetMobjState(player->mo, S_PLAY_ATK2); + player->ammo[weaponinfo[player->readyweapon].ammo]--; + + A_FireSomething(player,psp->state - &states[S_CHAIN1]); // phares + + P_BulletSlope(player->mo); + + P_GunShot(player->mo, !player->refire); +} + +void A_Light0(player_t *player, pspdef_t *psp) +{ + (void)psp; + player->extralight = 0; +} + +void A_Light1 (player_t *player, pspdef_t *psp) +{ + (void)psp; + player->extralight = 1; +} + +void A_Light2 (player_t *player, pspdef_t *psp) +{ + (void)psp; + player->extralight = 2; +} + +// +// A_BFGSpray +// Spawn a BFG explosion on every monster in view +// + +void A_BFGSpray(mobj_t *mo) +{ + int i; + + for (i=0 ; i<40 ; i++) // offset angles from its attack angle + { + int j, damage; + angle_t an = mo->angle - ANG90/2 + ANG90/40*i; + + // mo->target is the originator (player) of the missile + + // killough 8/2/98: make autoaiming prefer enemies + if (!mbf_features || + (P_AimLineAttack(mo->target, an, 16*64*FRACUNIT, MF_FRIEND), + !linetarget)) + P_AimLineAttack(mo->target, an, 16*64*FRACUNIT, 0); + + if (!linetarget) + continue; + + P_SpawnMobj(linetarget->x, linetarget->y, + linetarget->z + (linetarget->height>>2), MT_EXTRABFG); + + for (damage=j=0; j<15; j++) + damage += (P_Random(pr_bfg)&7) + 1; + + P_DamageMobj(linetarget, mo->target, mo->target, damage); + } +} + +// +// A_BFGsound +// + +void A_BFGsound(player_t *player, pspdef_t *psp) +{ + (void)psp; + S_StartSound(player->mo, sfx_bfg); +} + +// +// P_SetupPsprites +// Called at start of level for each player. +// + +void P_SetupPsprites(player_t *player) +{ + int i; + + // remove all psprites + for (i=0; ipsprites[i].state = NULL; + + // spawn the gun + player->pendingweapon = player->readyweapon; + P_BringUpWeapon(player); +} + +// +// P_MovePsprites +// Called every tic by player thinking routine. +// + +void P_MovePsprites(player_t *player) +{ + pspdef_t *psp = player->psprites; + int i; + + // a null state means not active + // drop tic count and possibly change state + // a -1 tic count never changes + + for (i=0; istate && psp->tics != -1 && !--psp->tics) + P_SetPsprite(player, i, psp->state->nextstate); + + player->psprites[ps_flash].sx = player->psprites[ps_weapon].sx; + player->psprites[ps_flash].sy = player->psprites[ps_weapon].sy; +} diff --git a/apps/plugins/doom/p_pspr.h b/apps/plugins/doom/p_pspr.h new file mode 100644 index 0000000000..bb6517c4e1 --- /dev/null +++ b/apps/plugins/doom/p_pspr.h @@ -0,0 +1,93 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Sprite animation. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __P_PSPR__ +#define __P_PSPR__ + +/* Basic data types. + * Needs fixed point, and BAM angles. */ + +#include "m_fixed.h" +#include "tables.h" + +/* Needs to include the precompiled sprite animation tables. + * + * Header generated by multigen utility. + * This includes all the data for thing animation, + * i.e. the Thing Atrributes table and the Frame Sequence table. + */ + +#include "info.h" + +#ifdef __GNUG__ +#pragma interface +#endif + +/* + * Frame flags: + * handles maximum brightness (torches, muzzle flare, light sources) + */ + +#define FF_FULLBRIGHT 0x8000 /* flag in thing->frame */ +#define FF_FRAMEMASK 0x7fff + +/* + * Overlay psprites are scaled shapes + * drawn directly on the view screen, + * coordinates are given for a 320*200 view screen. + */ + +typedef enum +{ + ps_weapon, + ps_flash, + NUMPSPRITES +} psprnum_t; + +typedef struct +{ + state_t *state; /* a NULL state means not active */ + int tics; + fixed_t sx; + fixed_t sy; +} pspdef_t; + +extern int weapon_preferences[2][NUMWEAPONS+1]; /* killough 5/2/98 */ +int P_WeaponPreferred(int w1, int w2); + +struct player_s; +int P_SwitchWeapon(struct player_s *player); +boolean P_CheckAmmo(struct player_s *player); +void P_SetupPsprites(struct player_s *curplayer); +void P_MovePsprites(struct player_s *curplayer); +void P_DropWeapon(struct player_s *player); + +#endif diff --git a/apps/plugins/doom/p_saveg.c b/apps/plugins/doom/p_saveg.c new file mode 100644 index 0000000000..bf1a2edc45 --- /dev/null +++ b/apps/plugins/doom/p_saveg.c @@ -0,0 +1,987 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Archiving: SaveGame I/O. + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "r_main.h" +#include "p_maputl.h" +#include "p_spec.h" +#include "p_tick.h" +#include "p_saveg.h" +#include "m_random.h" +#include "am_map.h" +#include "p_enemy.h" +#include "i_system.h" +#include "rockmacros.h" +byte *save_p; + +// Pads save_p to a 4-byte boundary +// so that the load/save works on SGI&Gecko. +#define PADSAVEP() do { save_p += (4 - ((int) save_p & 3)) & 3; } while (0) +// +// P_ArchivePlayers +// +void P_ArchivePlayers (void) +{ + int i; + + CheckSaveGame(sizeof(player_t) * MAXPLAYERS); // killough + for (i=0 ; ipsprites[j].state) + dest->psprites[j].state = + (state_t *)(dest->psprites[j].state-states); + } +} + +// +// P_UnArchivePlayers +// +void P_UnArchivePlayers (void) +{ + int i; + + for (i=0 ; ifloorheight + sizeof sec->ceilingheight) + * numsectors + sizeof(short)*3*numlines + 4; + + for (i=0; itextureoffset + sizeof si->rowoffset; + if (lines[i].sidenum[1] != -1) + size += + sizeof(short)*3 + sizeof si->textureoffset + sizeof si->rowoffset; + } + + CheckSaveGame(size); // killough + + PADSAVEP(); // killough 3/22/98 + + put = (short *)save_p; + + // do sectors + for (i=0, sec = sectors ; ifloorheight, sizeof sec->floorheight); + put = (void *)((char *) put + sizeof sec->floorheight); + memcpy(put, &sec->ceilingheight, sizeof sec->ceilingheight); + put = (void *)((char *) put + sizeof sec->ceilingheight); + + *put++ = sec->floorpic; + *put++ = sec->ceilingpic; + *put++ = sec->lightlevel; + *put++ = sec->special; // needed? yes -- transfer types + *put++ = sec->tag; // needed? need them -- killough + } + + // do lines + for (i=0, li = lines ; iflags; + *put++ = li->special; + *put++ = li->tag; + + for (j=0; j<2; j++) + if (li->sidenum[j] != -1) + { + si = &sides[li->sidenum[j]]; + + // killough 10/98: save full sidedef offsets, + // preserving fractional scroll offsets + + memcpy(put, &si->textureoffset, sizeof si->textureoffset); + put = (void *)((char *) put + sizeof si->textureoffset); + memcpy(put, &si->rowoffset, sizeof si->rowoffset); + put = (void *)((char *) put + sizeof si->rowoffset); + + *put++ = si->toptexture; + *put++ = si->bottomtexture; + *put++ = si->midtexture; + } + } + save_p = (byte *) put; +} + + + +// +// P_UnArchiveWorld +// +void P_UnArchiveWorld (void) +{ + int i; + sector_t *sec; + line_t *li; + const short *get; + + PADSAVEP(); // killough 3/22/98 + + get = (short *) save_p; + + // do sectors + for (i=0, sec = sectors ; ifloorheight, get, sizeof sec->floorheight); + get = (void *)((char *) get + sizeof sec->floorheight); + memcpy(&sec->ceilingheight, get, sizeof sec->ceilingheight); + get = (void *)((char *) get + sizeof sec->ceilingheight); + + sec->floorpic = *get++; + sec->ceilingpic = *get++; + sec->lightlevel = *get++; + sec->special = *get++; + sec->tag = *get++; + sec->ceilingdata = 0; //jff 2/22/98 now three thinker fields, not two + sec->floordata = 0; + sec->lightingdata = 0; + sec->soundtarget = 0; + } + + // do lines + for (i=0, li = lines ; iflags = *get++; + li->special = *get++; + li->tag = *get++; + for (j=0 ; j<2 ; j++) + if (li->sidenum[j] != -1) + { + side_t *si = &sides[li->sidenum[j]]; + + // killough 10/98: load full sidedef offsets, including fractions + + memcpy(&si->textureoffset, get, sizeof si->textureoffset); + get = (void *)((char *) get + sizeof si->textureoffset); + memcpy(&si->rowoffset, get, sizeof si->rowoffset); + get = (void *)((char *) get + sizeof si->rowoffset); + + si->toptexture = *get++; + si->bottomtexture = *get++; + si->midtexture = *get++; + } + } + save_p = (byte *) get; +} + +// +// Thinkers +// + +typedef enum { + tc_end, + tc_mobj +} thinkerclass_t; + +// phares 9/13/98: Moved this code outside of P_ArchiveThinkers so the +// thinker indices could be used by the code that saves sector info. + +static int number_of_thinkers; + +void P_ThinkerToIndex(void) +{ + thinker_t *th; + + // killough 2/14/98: + // count the number of thinkers, and mark each one with its index, using + // the prev field as a placeholder, since it can be restored later. + + number_of_thinkers = 0; + for (th = thinkercap.next ; th != &thinkercap ; th=th->next) + if (th->function == P_MobjThinker) + th->prev = (thinker_t *) ++number_of_thinkers; +} + +// phares 9/13/98: Moved this code outside of P_ArchiveThinkers so the +// thinker indices could be used by the code that saves sector info. + +void P_IndexToThinker(void) +{ + // killough 2/14/98: restore prev pointers + thinker_t *th; + thinker_t *prev = &thinkercap; + + for (th = thinkercap.next ; th != &thinkercap ; prev=th, th=th->next) + th->prev = prev; +} + +// +// P_ArchiveThinkers +// +// 2/14/98 killough: substantially modified to fix savegame bugs + +void P_ArchiveThinkers (void) +{ + thinker_t *th; + + CheckSaveGame(sizeof brain); // killough 3/26/98: Save boss brain state + memcpy(save_p, &brain, sizeof brain); + save_p += sizeof brain; + + /* check that enough room is available in savegame buffer + * - killough 2/14/98 + * cph - use number_of_thinkers saved by P_ThinkerToIndex above + */ + CheckSaveGame(number_of_thinkers*(sizeof(mobj_t)+4)); + + // save off the current thinkers + for (th = thinkercap.next ; th != &thinkercap ; th=th->next) + if (th->function == P_MobjThinker) + { + mobj_t *mobj; + + *save_p++ = tc_mobj; + PADSAVEP(); + mobj = (mobj_t *)save_p; + memcpy (mobj, th, sizeof(*mobj)); + save_p += sizeof(*mobj); + mobj->state = (state_t *)(mobj->state - states); + + // killough 2/14/98: convert pointers into indices. + // Fixes many savegame problems, by properly saving + // target and tracer fields. Note: we store NULL if + // the thinker pointed to by these fields is not a + // mobj thinker. + + if (mobj->target) + mobj->target = mobj->target->thinker.function == + P_MobjThinker ? + (mobj_t *) mobj->target->thinker.prev : NULL; + + if (mobj->tracer) + mobj->tracer = mobj->tracer->thinker.function == + P_MobjThinker ? + (mobj_t *) mobj->tracer->thinker.prev : NULL; + + // killough 2/14/98: new field: save last known enemy. Prevents + // monsters from going to sleep after killing monsters and not + // seeing player anymore. + + if (mobj->lastenemy) + mobj->lastenemy = mobj->lastenemy->thinker.function == + P_MobjThinker ? + (mobj_t *) mobj->lastenemy->thinker.prev : NULL; + + // killough 2/14/98: end changes + + if (mobj->above_thing) // phares + mobj->above_thing = mobj->above_thing->thinker.function == + P_MobjThinker ? + (mobj_t *) mobj->above_thing->thinker.prev : NULL; + + if (mobj->below_thing) + mobj->below_thing = mobj->below_thing->thinker.function == + P_MobjThinker ? + (mobj_t *) mobj->below_thing->thinker.prev : NULL; // phares + + if (mobj->player) + mobj->player = (player_t *)((mobj->player-players) + 1); + } + + // add a terminating marker + *save_p++ = tc_end; + + // killough 9/14/98: save soundtargets + { + int i; + CheckSaveGame(numsectors * sizeof(mobj_t *)); // killough 9/14/98 + for (i = 0; i < numsectors; i++) + { + mobj_t *target = sectors[i].soundtarget; + if (target) + target = (mobj_t *) target->thinker.prev; + memcpy(save_p, &target, sizeof target); + save_p += sizeof target; + } + } +} + +/* + * killough 11/98 + * + * Same as P_SetTarget() in p_tick.c, except that the target is nullified + * first, so that no old target's reference count is decreased (when loading + * savegames, old targets are indices, not really pointers to targets). + */ + +static void P_SetNewTarget(mobj_t **mop, mobj_t *targ) +{ + *mop = NULL; + P_SetTarget(mop, targ); +} + +// +// P_UnArchiveThinkers +// +// 2/14/98 killough: substantially modified to fix savegame bugs +// + +void P_UnArchiveThinkers (void) +{ + thinker_t *th; + mobj_t **mobj_p; // killough 2/14/98: Translation table + size_t size; // killough 2/14/98: size of or index into table + + totallive = 0; + // killough 3/26/98: Load boss brain state + memcpy(&brain, save_p, sizeof brain); + save_p += sizeof brain; + + // remove all the current thinkers + for (th = thinkercap.next; th != &thinkercap; ) + { + thinker_t *next = th->next; + if (th->function == P_MobjThinker) + P_RemoveMobj ((mobj_t *) th); + else + Z_Free (th); + th = next; + } + P_InitThinkers (); + + // killough 2/14/98: count number of thinkers by skipping through them + { + byte *sp = save_p; // save pointer and skip header + for (size = 1; *save_p++ == tc_mobj; size++) // killough 2/14/98 + { // skip all entries, adding up count + PADSAVEP(); + save_p += sizeof(mobj_t); + } + + if (*--save_p != tc_end) + I_Error ("P_UnArchiveThinkers: Unknown tclass %i in savegame", *save_p); + + // first table entry special: 0 maps to NULL + *(mobj_p = malloc(size * sizeof *mobj_p)) = 0; // table of pointers + save_p = sp; // restore save pointer + } + + // read in saved thinkers + for (size = 1; *save_p++ == tc_mobj; size++) // killough 2/14/98 + { + mobj_t *mobj = Z_Malloc(sizeof(mobj_t), PU_LEVEL, NULL); + + // killough 2/14/98 -- insert pointers to thinkers into table, in order: + mobj_p[size] = mobj; + + PADSAVEP(); + memcpy (mobj, save_p, sizeof(mobj_t)); + save_p += sizeof(mobj_t); + mobj->state = states + (int) mobj->state; + + if (mobj->player) + (mobj->player = &players[(int) mobj->player - 1]) -> mo = mobj; + + P_SetThingPosition (mobj); + mobj->info = &mobjinfo[mobj->type]; + + // killough 2/28/98: + // Fix for falling down into a wall after savegame loaded: + // mobj->floorz = mobj->subsector->sector->floorheight; + // mobj->ceilingz = mobj->subsector->sector->ceilingheight; + + mobj->thinker.function = P_MobjThinker; + P_AddThinker (&mobj->thinker); + + if (!((mobj->flags ^ MF_COUNTKILL) & (MF_FRIEND | MF_COUNTKILL | MF_CORPSE))) + totallive++; + } + + // killough 2/14/98: adjust target and tracer fields, plus + // lastenemy field, to correctly point to mobj thinkers. + // NULL entries automatically handled by first table entry. + // + // killough 11/98: use P_SetNewTarget() to set fields + + for (th = thinkercap.next ; th != &thinkercap ; th=th->next) + { + P_SetNewTarget(&((mobj_t *) th)->target, + mobj_p[(size_t)((mobj_t *)th)->target]); + + P_SetNewTarget(&((mobj_t *) th)->tracer, + mobj_p[(size_t)((mobj_t *)th)->tracer]); + + P_SetNewTarget(&((mobj_t *) th)->lastenemy, + mobj_p[(size_t)((mobj_t *)th)->lastenemy]); + + // phares: added two new fields for Sprite Height problem + + P_SetNewTarget(&((mobj_t *) th)->above_thing, + mobj_p[(size_t)((mobj_t *)th)->above_thing]); + + P_SetNewTarget(&((mobj_t *) th)->below_thing, + mobj_p[(size_t)((mobj_t *)th)->below_thing]); + } + + { // killough 9/14/98: restore soundtargets + int i; + for (i = 0; i < numsectors; i++) + { + mobj_t *target; + memcpy(&target, save_p, sizeof target); + save_p += sizeof target; + P_SetNewTarget(§ors[i].soundtarget, mobj_p[(size_t) target]); + } + } + + free(mobj_p); // free translation table + + // killough 3/26/98: Spawn icon landings: + if (gamemode == commercial) + P_SpawnBrainTargets(); +} + +// +// P_ArchiveSpecials +// +enum { + tc_ceiling, + tc_door, + tc_floor, + tc_plat, + tc_flash, + tc_strobe, + tc_glow, + tc_elevator, //jff 2/22/98 new elevator type thinker + tc_scroll, // killough 3/7/98: new scroll effect thinker + tc_pusher, // phares 3/22/98: new push/pull effect thinker + tc_flicker, // killough 10/4/98 + tc_endspecials +} specials_e; + +// +// Things to handle: +// +// T_MoveCeiling, (ceiling_t: sector_t * swizzle), - active list +// T_VerticalDoor, (vldoor_t: sector_t * swizzle), +// T_MoveFloor, (floormove_t: sector_t * swizzle), +// T_LightFlash, (lightflash_t: sector_t * swizzle), +// T_StrobeFlash, (strobe_t: sector_t *), +// T_Glow, (glow_t: sector_t *), +// T_PlatRaise, (plat_t: sector_t *), - active list +// T_MoveElevator, (plat_t: sector_t *), - active list // jff 2/22/98 +// T_Scroll // killough 3/7/98 +// T_Pusher // phares 3/22/98 +// T_FireFlicker // killough 10/4/98 +// + +void P_ArchiveSpecials (void) +{ + thinker_t *th; + size_t size = 0; // killough + + // save off the current thinkers (memory size calculation -- killough) + + for (th = thinkercap.next ; th != &thinkercap ; th=th->next) + if (!th->function) + { + platlist_t *pl; + ceilinglist_t *cl; //jff 2/22/98 need this for ceilings too now + for (pl=activeplats; pl; pl=pl->next) + if (pl->plat == (plat_t *) th) // killough 2/14/98 + { + size += 4+sizeof(plat_t); + goto end; + } + for (cl=activeceilings; cl; cl=cl->next) // search for activeceiling + if (cl->ceiling == (ceiling_t *) th) //jff 2/22/98 + { + size += 4+sizeof(ceiling_t); + goto end; + } +end:; + } + else + size += + th->function==T_MoveCeiling ? 4+sizeof(ceiling_t) : + th->function==T_VerticalDoor ? 4+sizeof(vldoor_t) : + th->function==T_MoveFloor ? 4+sizeof(floormove_t): + th->function==T_PlatRaise ? 4+sizeof(plat_t) : + th->function==T_LightFlash ? 4+sizeof(lightflash_t): + th->function==T_StrobeFlash ? 4+sizeof(strobe_t) : + th->function==T_Glow ? 4+sizeof(glow_t) : + th->function==T_MoveElevator ? 4+sizeof(elevator_t): + th->function==T_Scroll ? 4+sizeof(scroll_t) : + th->function==T_Pusher ? 4+sizeof(pusher_t) : + th->function==T_FireFlicker? 4+sizeof(fireflicker_t) : + 0; + + CheckSaveGame(size); // killough + + // save off the current thinkers + for (th=thinkercap.next; th!=&thinkercap; th=th->next) + { + if (!th->function) + { + platlist_t *pl; + ceilinglist_t *cl; //jff 2/22/98 add iter variable for ceilings + + // killough 2/8/98: fix plat original height bug. + // Since acv==NULL, this could be a plat in stasis. + // so check the active plats list, and save this + // plat (jff: or ceiling) even if it is in stasis. + + for (pl=activeplats; pl; pl=pl->next) + if (pl->plat == (plat_t *) th) // killough 2/14/98 + goto plat; + + for (cl=activeceilings; cl; cl=cl->next) + if (cl->ceiling == (ceiling_t *) th) //jff 2/22/98 + goto ceiling; + + continue; + } + + if (th->function == T_MoveCeiling) + { + ceiling_t *ceiling; +ceiling: // killough 2/14/98 + *save_p++ = tc_ceiling; + PADSAVEP(); + ceiling = (ceiling_t *)save_p; + memcpy (ceiling, th, sizeof(*ceiling)); + save_p += sizeof(*ceiling); + ceiling->sector = (sector_t *)(ceiling->sector - sectors); + continue; + } + + if (th->function == T_VerticalDoor) + { + vldoor_t *door; + *save_p++ = tc_door; + PADSAVEP(); + door = (vldoor_t *) save_p; + memcpy (door, th, sizeof *door); + save_p += sizeof(*door); + door->sector = (sector_t *)(door->sector - sectors); + //jff 1/31/98 archive line remembered by door as well + door->line = (line_t *) (door->line ? door->line-lines : -1); + continue; + } + + if (th->function == T_MoveFloor) + { + floormove_t *floor; + *save_p++ = tc_floor; + PADSAVEP(); + floor = (floormove_t *)save_p; + memcpy (floor, th, sizeof(*floor)); + save_p += sizeof(*floor); + floor->sector = (sector_t *)(floor->sector - sectors); + continue; + } + + if (th->function == T_PlatRaise) + { + plat_t *plat; +plat: // killough 2/14/98: added fix for original plat height above + *save_p++ = tc_plat; + PADSAVEP(); + plat = (plat_t *)save_p; + memcpy (plat, th, sizeof(*plat)); + save_p += sizeof(*plat); + plat->sector = (sector_t *)(plat->sector - sectors); + continue; + } + + if (th->function == T_LightFlash) + { + lightflash_t *flash; + *save_p++ = tc_flash; + PADSAVEP(); + flash = (lightflash_t *)save_p; + memcpy (flash, th, sizeof(*flash)); + save_p += sizeof(*flash); + flash->sector = (sector_t *)(flash->sector - sectors); + continue; + } + + if (th->function == T_StrobeFlash) + { + strobe_t *strobe; + *save_p++ = tc_strobe; + PADSAVEP(); + strobe = (strobe_t *)save_p; + memcpy (strobe, th, sizeof(*strobe)); + save_p += sizeof(*strobe); + strobe->sector = (sector_t *)(strobe->sector - sectors); + continue; + } + + if (th->function == T_Glow) + { + glow_t *glow; + *save_p++ = tc_glow; + PADSAVEP(); + glow = (glow_t *)save_p; + memcpy (glow, th, sizeof(*glow)); + save_p += sizeof(*glow); + glow->sector = (sector_t *)(glow->sector - sectors); + continue; + } + + // killough 10/4/98: save flickers + if (th->function == T_FireFlicker) + { + fireflicker_t *flicker; + *save_p++ = tc_flicker; + PADSAVEP(); + flicker = (fireflicker_t *)save_p; + memcpy (flicker, th, sizeof(*flicker)); + save_p += sizeof(*flicker); + flicker->sector = (sector_t *)(flicker->sector - sectors); + continue; + } + + //jff 2/22/98 new case for elevators + if (th->function == T_MoveElevator) + { + elevator_t *elevator; //jff 2/22/98 + *save_p++ = tc_elevator; + PADSAVEP(); + elevator = (elevator_t *)save_p; + memcpy (elevator, th, sizeof(*elevator)); + save_p += sizeof(*elevator); + elevator->sector = (sector_t *)(elevator->sector - sectors); + continue; + } + + // killough 3/7/98: Scroll effect thinkers + if (th->function == T_Scroll) + { + *save_p++ = tc_scroll; + memcpy (save_p, th, sizeof(scroll_t)); + save_p += sizeof(scroll_t); + continue; + } + + // phares 3/22/98: Push/Pull effect thinkers + + if (th->function == T_Pusher) + { + *save_p++ = tc_pusher; + memcpy (save_p, th, sizeof(pusher_t)); + save_p += sizeof(pusher_t); + continue; + } + } + + // add a terminating marker + *save_p++ = tc_endspecials; +} + + +// +// P_UnArchiveSpecials +// +void P_UnArchiveSpecials (void) +{ + byte tclass; + + // read in saved thinkers + while ((tclass = *save_p++) != tc_endspecials) // killough 2/14/98 + switch (tclass) + { + case tc_ceiling: + PADSAVEP(); + { + ceiling_t *ceiling = Z_Malloc (sizeof(*ceiling), PU_LEVEL, NULL); + memcpy (ceiling, save_p, sizeof(*ceiling)); + save_p += sizeof(*ceiling); + ceiling->sector = §ors[(int)ceiling->sector]; + ceiling->sector->ceilingdata = ceiling; //jff 2/22/98 + + if (ceiling->thinker.function) + ceiling->thinker.function = T_MoveCeiling; + + P_AddThinker (&ceiling->thinker); + P_AddActiveCeiling(ceiling); + break; + } + + case tc_door: + PADSAVEP(); + { + vldoor_t *door = Z_Malloc (sizeof(*door), PU_LEVEL, NULL); + memcpy (door, save_p, sizeof(*door)); + save_p += sizeof(*door); + door->sector = §ors[(int)door->sector]; + + //jff 1/31/98 unarchive line remembered by door as well + door->line = (int)door->line!=-1? &lines[(int)door->line] : NULL; + + door->sector->ceilingdata = door; //jff 2/22/98 + door->thinker.function = T_VerticalDoor; + P_AddThinker (&door->thinker); + break; + } + + case tc_floor: + PADSAVEP(); + { + floormove_t *floor = Z_Malloc (sizeof(*floor), PU_LEVEL, NULL); + memcpy (floor, save_p, sizeof(*floor)); + save_p += sizeof(*floor); + floor->sector = §ors[(int)floor->sector]; + floor->sector->floordata = floor; //jff 2/22/98 + floor->thinker.function = T_MoveFloor; + P_AddThinker (&floor->thinker); + break; + } + + case tc_plat: + PADSAVEP(); + { + plat_t *plat = Z_Malloc (sizeof(*plat), PU_LEVEL, NULL); + memcpy (plat, save_p, sizeof(*plat)); + save_p += sizeof(*plat); + plat->sector = §ors[(int)plat->sector]; + plat->sector->floordata = plat; //jff 2/22/98 + + if (plat->thinker.function) + plat->thinker.function = T_PlatRaise; + + P_AddThinker (&plat->thinker); + P_AddActivePlat(plat); + break; + } + + case tc_flash: + PADSAVEP(); + { + lightflash_t *flash = Z_Malloc (sizeof(*flash), PU_LEVEL, NULL); + memcpy (flash, save_p, sizeof(*flash)); + save_p += sizeof(*flash); + flash->sector = §ors[(int)flash->sector]; + flash->thinker.function = T_LightFlash; + P_AddThinker (&flash->thinker); + break; + } + + case tc_strobe: + PADSAVEP(); + { + strobe_t *strobe = Z_Malloc (sizeof(*strobe), PU_LEVEL, NULL); + memcpy (strobe, save_p, sizeof(*strobe)); + save_p += sizeof(*strobe); + strobe->sector = §ors[(int)strobe->sector]; + strobe->thinker.function = T_StrobeFlash; + P_AddThinker (&strobe->thinker); + break; + } + + case tc_glow: + PADSAVEP(); + { + glow_t *glow = Z_Malloc (sizeof(*glow), PU_LEVEL, NULL); + memcpy (glow, save_p, sizeof(*glow)); + save_p += sizeof(*glow); + glow->sector = §ors[(int)glow->sector]; + glow->thinker.function = T_Glow; + P_AddThinker (&glow->thinker); + break; + } + + case tc_flicker: // killough 10/4/98 + PADSAVEP(); + { + fireflicker_t *flicker = Z_Malloc (sizeof(*flicker), PU_LEVEL, NULL); + memcpy (flicker, save_p, sizeof(*flicker)); + save_p += sizeof(*flicker); + flicker->sector = §ors[(int)flicker->sector]; + flicker->thinker.function = T_FireFlicker; + P_AddThinker (&flicker->thinker); + break; + } + + //jff 2/22/98 new case for elevators + case tc_elevator: + PADSAVEP(); + { + elevator_t *elevator = Z_Malloc (sizeof(*elevator), PU_LEVEL, NULL); + memcpy (elevator, save_p, sizeof(*elevator)); + save_p += sizeof(*elevator); + elevator->sector = §ors[(int)elevator->sector]; + elevator->sector->floordata = elevator; //jff 2/22/98 + elevator->sector->ceilingdata = elevator; //jff 2/22/98 + elevator->thinker.function = T_MoveElevator; + P_AddThinker (&elevator->thinker); + break; + } + + case tc_scroll: // killough 3/7/98: scroll effect thinkers + { + scroll_t *scroll = Z_Malloc (sizeof(scroll_t), PU_LEVEL, NULL); + memcpy (scroll, save_p, sizeof(scroll_t)); + save_p += sizeof(scroll_t); + scroll->thinker.function = T_Scroll; + P_AddThinker(&scroll->thinker); + break; + } + + case tc_pusher: // phares 3/22/98: new Push/Pull effect thinkers + { + pusher_t *pusher = Z_Malloc (sizeof(pusher_t), PU_LEVEL, NULL); + memcpy (pusher, save_p, sizeof(pusher_t)); + save_p += sizeof(pusher_t); + pusher->thinker.function = T_Pusher; + pusher->source = P_GetPushThing(pusher->affectee); + P_AddThinker(&pusher->thinker); + break; + } + + default: + I_Error("P_UnarchiveSpecials: Unknown tclass %i in savegame", tclass); + } +} + +// killough 2/16/98: save/restore random number generator state information + +void P_ArchiveRNG(void) +{ + CheckSaveGame(sizeof rng); + memcpy(save_p, &rng, sizeof rng); + save_p += sizeof rng; +} + +void P_UnArchiveRNG(void) +{ + memcpy(&rng, save_p, sizeof rng); + save_p += sizeof rng; +} + +// killough 2/22/98: Save/restore automap state +// killough 2/22/98: Save/restore automap state +void P_ArchiveMap(void) +{ + int zero = 0, one = 1; + CheckSaveGame(2 * sizeof zero + sizeof markpointnum + + markpointnum * sizeof *markpoints + + sizeof automapmode + sizeof one); + + memcpy(save_p, &automapmode, sizeof automapmode); + save_p += sizeof automapmode; + memcpy(save_p, &one, sizeof one); // CPhipps - used to be viewactive, now + save_p += sizeof one; // that's worked out locally by D_Display + memcpy(save_p, &zero, sizeof zero); // CPhipps - used to be followplayer + save_p += sizeof zero; // that is now part of automapmode + memcpy(save_p, &zero, sizeof zero); // CPhipps - used to be automap_grid, ditto + save_p += sizeof zero; + memcpy(save_p, &markpointnum, sizeof markpointnum); + save_p += sizeof markpointnum; + + if (markpointnum) + { + memcpy(save_p, markpoints, sizeof *markpoints * markpointnum); + save_p += markpointnum * sizeof *markpoints; + } +} + +void P_UnArchiveMap(void) +{ + int unused; + memcpy(&automapmode, save_p, sizeof automapmode); + save_p += sizeof automapmode; + memcpy(&unused, save_p, sizeof unused); + save_p += sizeof unused; + memcpy(&unused, save_p, sizeof unused); + save_p += sizeof unused; + memcpy(&unused, save_p, sizeof unused); + save_p += sizeof unused; + + if (automapmode & am_active) + AM_Start(); + + memcpy(&markpointnum, save_p, sizeof markpointnum); + save_p += sizeof markpointnum; + + if (markpointnum) + { + while (markpointnum >= markpointnum_max) + markpoints = realloc(markpoints, sizeof *markpoints * + (markpointnum_max = markpointnum_max ? markpointnum_max*2 : 16)); + memcpy(markpoints, save_p, markpointnum * sizeof *markpoints); + save_p += markpointnum * sizeof *markpoints; + } +} + diff --git a/apps/plugins/doom/p_saveg.h b/apps/plugins/doom/p_saveg.h new file mode 100644 index 0000000000..1bfe1d4291 --- /dev/null +++ b/apps/plugins/doom/p_saveg.h @@ -0,0 +1,63 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Savegame I/O, archiving, persistence. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __P_SAVEG__ +#define __P_SAVEG__ + +#ifdef __GNUG__ +#pragma interface +#endif + +/* Persistent storage/archiving. + * These are the load / save game routines. */ +void P_ArchivePlayers(void); +void P_UnArchivePlayers(void); +void P_ArchiveWorld(void); +void P_UnArchiveWorld(void); +void P_ArchiveThinkers(void); +void P_UnArchiveThinkers(void); +void P_ArchiveSpecials(void); +void P_UnArchiveSpecials(void); +void P_ThinkerToIndex(void); /* phares 9/13/98: save soundtarget in savegame */ +void P_IndexToThinker(void); /* phares 9/13/98: save soundtarget in savegame */ + +/* 1/18/98 killough: add RNG info to savegame */ +void P_ArchiveRNG(void); +void P_UnArchiveRNG(void); + +/* 2/21/98 killough: add automap info to savegame */ +void P_ArchiveMap(void); +void P_UnArchiveMap(void); + +extern byte *save_p; +void CheckSaveGame(size_t); /* killough */ + +#endif diff --git a/apps/plugins/doom/p_setup.c b/apps/plugins/doom/p_setup.c new file mode 100644 index 0000000000..d40372d6da --- /dev/null +++ b/apps/plugins/doom/p_setup.c @@ -0,0 +1,1255 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Do all the WAD I/O, get map description, + * set up initial state and misc. LUTs. + * + *-----------------------------------------------------------------------------*/ + +#include + +#include "doomstat.h" +#include "m_bbox.h" +#include "m_argv.h" +#include "g_game.h" +#include "w_wad.h" +#include "r_main.h" +#include "r_things.h" +#include "p_maputl.h" +#include "p_map.h" +#include "p_setup.h" +#include "p_spec.h" +#include "p_tick.h" +#include "p_enemy.h" +#include "s_sound.h" +#include "i_system.h" +#include "m_swap.h" + +#include "rockmacros.h" +// +// MAP related Lookup tables. +// Store VERTEXES, LINEDEFS, SIDEDEFS, etc. +// + +int numvertexes; +vertex_t *vertexes; + +int numsegs; +seg_t *segs; + +int numsectors; +sector_t *sectors; + +int numsubsectors; +subsector_t *subsectors; + +int numnodes; +node_t *nodes; + +int numlines; +line_t *lines; + +int numsides; +side_t *sides; + + +//////////////////////////////////////////////////////////////////////////////////////////// +// figgi 08/21/00 -- constants and globals for glBsp support +#define gNd2 0x32644E67 // figgi -- suppport for new GL_VERT format v2.0 +#define GL_VERT_OFFSET 4 + +int firstglvertex = 0; +boolean usingGLNodes = false; +boolean forceOldBsp = false; + +enum +{ + ML_GL_LABEL=0, // A separator name, GL_ExMx or GL_MAPxx + ML_GL_VERTS, // Extra Vertices + ML_GL_SEGS, // Segs, from linedefs & minisegs + ML_GL_SSECT, // SubSectors, list of segs + ML_GL_NODES // GL BSP nodes +}; +//////////////////////////////////////////////////////////////////////////////////////////// + + +// BLOCKMAP +// Created from axis aligned bounding box +// of the map, a rectangular array of +// blocks of size ... +// Used to speed up collision detection +// by spatial subdivision in 2D. +// +// Blockmap size. + +int bmapwidth, bmapheight; // size in mapblocks + +// killough 3/1/98: remove blockmap limit internally: +long *blockmap; // was short -- killough + +// offsets in blockmap are from here +long *blockmaplump; // was short -- killough + +fixed_t bmaporgx, bmaporgy; // origin of block map + +mobj_t **blocklinks; // for thing chains + +// +// REJECT +// For fast sight rejection. +// Speeds up enemy AI by skipping detailed +// LineOf Sight calculation. +// Without the special effect, this could +// be used as a PVS lookup as well. +// + +static int rejectlump = -1;// cph - store reject lump num if cached +const byte *rejectmatrix; // cph - const* + +// Maintain single and multi player starting spots. + +// 1/11/98 killough: Remove limit on deathmatch starts +mapthing_t *deathmatchstarts; // killough +size_t num_deathmatchstarts; // killough + +mapthing_t *deathmatch_p; +mapthing_t playerstarts[MAXPLAYERS]; + +// +// P_LoadVertexes +// +// killough 5/3/98: reformatted, cleaned up +// +static void P_LoadVertexes (int lump) +{ + const byte *data; // cph - const + int i; + + // Determine number of lumps: + // total lump length / vertex record length. + numvertexes = W_LumpLength(lump) / sizeof(mapvertex_t); + + // Allocate zone memory for buffer. + vertexes = Z_Malloc(numvertexes*sizeof(vertex_t),PU_LEVEL,0); + + // Load data into cache. + data = W_CacheLumpNum(lump); // cph - wad handling updated + + // Copy and convert vertex coordinates, + // internal representation as fixed. + for (i=0; iv1 = &vertexes[SHORT(ml->v1)]; + li->v2 = &vertexes[SHORT(ml->v2)]; + + li->miniseg = false; // figgi -- there are no minisegs in classic BSP nodes + + li->angle = (SHORT(ml->angle))<<16; + li->offset =(SHORT(ml->offset))<<16; + linedef = SHORT(ml->linedef); + ldef = &lines[linedef]; + li->linedef = ldef; + side = SHORT(ml->side); + li->sidedef = &sides[ldef->sidenum[side]]; + li->frontsector = sides[ldef->sidenum[side]].sector; + + // killough 5/3/98: ignore 2s flag if second sidedef missing: + if (ldef->flags & ML_TWOSIDED && ldef->sidenum[side^1]!=-1) + li->backsector = sides[ldef->sidenum[side^1]].sector; + else + li->backsector = 0; + } + + W_UnlockLumpNum(lump); // cph - release the data +} + + +// +// P_LoadSubsectors +// +// killough 5/3/98: reformatted, cleaned up + +static void P_LoadSubsectors (int lump) +{ + const byte *data; // cph - const* + int i; + + numsubsectors = W_LumpLength (lump) / sizeof(mapsubsector_t); + subsectors = Z_Calloc(numsubsectors,sizeof(subsector_t),PU_LEVEL,0); + data = W_CacheLumpNum(lump); // cph - wad lump handling updated + + for (i=0; ifloorheight = SHORT(ms->floorheight)<ceilingheight = SHORT(ms->ceilingheight)<floorpic = R_FlatNumForName(ms->floorpic); + ss->ceilingpic = R_FlatNumForName(ms->ceilingpic); + ss->lightlevel = SHORT(ms->lightlevel); + ss->special = SHORT(ms->special); + ss->oldspecial = SHORT(ms->special); + ss->tag = SHORT(ms->tag); + ss->thinglist = NULL; + ss->touching_thinglist = NULL; // phares 3/14/98 + + ss->nextsec = -1; //jff 2/26/98 add fields to support locking out + ss->prevsec = -1; // stair retriggering until build completes + + // killough 3/7/98: + ss->floor_xoffs = 0; + ss->floor_yoffs = 0; // floor and ceiling flats offsets + ss->ceiling_xoffs = 0; + ss->ceiling_yoffs = 0; + ss->heightsec = -1; // sector used to get floor and ceiling height + ss->floorlightsec = -1; // sector used to get floor lighting + // killough 3/7/98: end changes + + // killough 4/11/98 sector used to get ceiling lighting: + ss->ceilinglightsec = -1; + + // killough 4/4/98: colormaps: + ss->bottommap = ss->midmap = ss->topmap = 0; + + // killough 10/98: sky textures coming from sidedefs: + ss->sky = 0; + } + + W_UnlockLumpNum(lump); // cph - release the data +} + + +// +// P_LoadNodes +// +// killough 5/3/98: reformatted, cleaned up + +static void P_LoadNodes (int lump) +{ + const byte *data; // cph - const* + int i; + + numnodes = W_LumpLength (lump) / sizeof(mapnode_t); + nodes = Z_Malloc (numnodes*sizeof(node_t),PU_LEVEL,0); + data = W_CacheLumpNum (lump); // cph - wad lump handling updated + + for (i=0; ix = SHORT(mn->x)<y = SHORT(mn->y)<dx = SHORT(mn->dx)<dy = SHORT(mn->dy)<children[j] = SHORT(mn->children[j]); + for (k=0 ; k<4 ; k++) + no->bbox[j][k] = SHORT(mn->bbox[j][k])<type) + { + case 68: // Arachnotron + case 64: // Archvile + case 88: // Boss Brain + case 89: // Boss Shooter + case 69: // Hell Knight + case 67: // Mancubus + case 71: // Pain Elemental + case 65: // Former Human Commando + case 66: // Revenant + case 84: // Wolf SS + continue; + } + + // Do spawn all other stuff. + tempthing.x = SHORT(mt->x); + tempthing.y = SHORT(mt->y); + tempthing.angle = SHORT(mt->angle); + tempthing.type = SHORT(mt->type); + tempthing.options = SHORT(mt->options); + + P_SpawnMapThing (&tempthing); + } + + W_UnlockLumpNum(lump); // cph - release the data +} + +// +// P_LoadLineDefs +// Also counts secret lines for intermissions. +// ^^^ +// ??? killough ??? +// Does this mean secrets used to be linedef-based, rather than sector-based? +// +// killough 4/4/98: split into two functions, to allow sidedef overloading +// +// killough 5/3/98: reformatted, cleaned up + +static void P_LoadLineDefs (int lump) +{ + const byte *data; // cph - const* + int i; + + numlines = W_LumpLength (lump) / sizeof(maplinedef_t); + lines = Z_Calloc (numlines,sizeof(line_t),PU_LEVEL,0); + data = W_CacheLumpNum (lump); // cph - wad lump handling updated + + for (i=0; iflags = SHORT(mld->flags); + ld->special = SHORT(mld->special); + ld->tag = SHORT(mld->tag); + v1 = ld->v1 = &vertexes[SHORT(mld->v1)]; + v2 = ld->v2 = &vertexes[SHORT(mld->v2)]; + ld->dx = v2->x - v1->x; + ld->dy = v2->y - v1->y; + + ld->tranlump = -1; // killough 4/11/98: no translucency by default + + ld->slopetype = !ld->dx ? ST_VERTICAL : !ld->dy ? ST_HORIZONTAL : + FixedDiv(ld->dy, ld->dx) > 0 ? ST_POSITIVE : ST_NEGATIVE; + + if (v1->x < v2->x) + { + ld->bbox[BOXLEFT] = v1->x; + ld->bbox[BOXRIGHT] = v2->x; + } + else + { + ld->bbox[BOXLEFT] = v2->x; + ld->bbox[BOXRIGHT] = v1->x; + } + + if (v1->y < v2->y) + { + ld->bbox[BOXBOTTOM] = v1->y; + ld->bbox[BOXTOP] = v2->y; + } + else + { + ld->bbox[BOXBOTTOM] = v2->y; + ld->bbox[BOXTOP] = v1->y; + } + + ld->sidenum[0] = SHORT(mld->sidenum[0]); + ld->sidenum[1] = SHORT(mld->sidenum[1]); + + // killough 4/4/98: support special sidedef interpretation below + if (ld->sidenum[0] != -1 && ld->special) + sides[*ld->sidenum].special = ld->special; + } + + W_UnlockLumpNum(lump); // cph - release the lump +} + +// killough 4/4/98: delay using sidedefs until they are loaded +// killough 5/3/98: reformatted, cleaned up + +static void P_LoadLineDefs2(int lump) +{ + (void)lump; + int i = numlines; + register line_t *ld = lines; + for (;i--;ld++) + { + { // cph 2002/07/20 - these errors are fatal if not fixed, so apply them in compatibility mode - a desync is better than a crash! + // killough 11/98: fix common wad errors (missing sidedefs): + + if (ld->sidenum[0] == -1) { + ld->sidenum[0] = 0; // Substitute dummy sidedef for missing right side + // cph - print a warning about the bug + printf("P_LoadSegs: linedef %d missing first sidedef\n",numlines-i); + } + + if ((ld->sidenum[1] == -1) && (ld->flags & ML_TWOSIDED)) { + ld->flags &= ~ML_TWOSIDED; // Clear 2s flag for missing left side + // cph - print a warning about the bug + printf("P_LoadSegs: linedef %d has two-sided flag set, but no second sidedef\n",numlines-i); + } + } + + ld->frontsector = ld->sidenum[0]!=-1 ? sides[ld->sidenum[0]].sector : 0; + ld->backsector = ld->sidenum[1]!=-1 ? sides[ld->sidenum[1]].sector : 0; + switch (ld->special) + { // killough 4/11/98: handle special types + int lump, j; + + case 260: // killough 4/11/98: translucent 2s textures + lump = sides[*ld->sidenum].special; // translucency from sidedef + if (!ld->tag) // if tag==0, + ld->tranlump = lump; // affect this linedef only + else + for (j=0;jtag) // affect all matching linedefs + lines[j].tranlump = lump; + break; + } + } +} + +// +// P_LoadSideDefs +// +// killough 4/4/98: split into two functions + +static void P_LoadSideDefs (int lump) +{ + numsides = W_LumpLength(lump) / sizeof(mapsidedef_t); + sides = Z_Calloc(numsides,sizeof(side_t),PU_LEVEL,0); +} + +// killough 4/4/98: delay using texture names until +// after linedefs are loaded, to allow overloading. +// killough 5/3/98: reformatted, cleaned up + +static void P_LoadSideDefs2(int lump) +{ + const byte *data = W_CacheLumpNum(lump); // cph - const*, wad lump handling updated + int i; + + for (i=0; itextureoffset = SHORT(msd->textureoffset)<rowoffset = SHORT(msd->rowoffset)<sector = sec = §ors[SHORT(msd->sector)]; + switch (sd->special) + { + case 242: // variable colormap via 242 linedef + sd->bottomtexture = + (sec->bottommap = R_ColormapNumForName(msd->bottomtexture)) < 0 ? + sec->bottommap = 0, R_TextureNumForName(msd->bottomtexture): 0 ; + sd->midtexture = + (sec->midmap = R_ColormapNumForName(msd->midtexture)) < 0 ? + sec->midmap = 0, R_TextureNumForName(msd->midtexture) : 0 ; + sd->toptexture = + (sec->topmap = R_ColormapNumForName(msd->toptexture)) < 0 ? + sec->topmap = 0, R_TextureNumForName(msd->toptexture) : 0 ; + break; + + case 260: // killough 4/11/98: apply translucency to 2s normal texture + sd->midtexture = strncasecmp("TRANMAP", msd->midtexture, 8) ? + (sd->special = W_CheckNumForName(msd->midtexture)) < 0 || + W_LumpLength(sd->special) != 65536 ? + sd->special=0, R_TextureNumForName(msd->midtexture) : + (sd->special++, 0) : (sd->special=0); + sd->toptexture = R_TextureNumForName(msd->toptexture); + sd->bottomtexture = R_TextureNumForName(msd->bottomtexture); + break; + + default: // normal cases + sd->midtexture = R_TextureNumForName(msd->midtexture); + sd->toptexture = R_TextureNumForName(msd->toptexture); + sd->bottomtexture = R_TextureNumForName(msd->bottomtexture); + break; + } + } + + W_UnlockLumpNum(lump); // cph - release the lump +} + +// +// jff 10/6/98 +// New code added to speed up calculation of internal blockmap +// Algorithm is order of nlines*(ncols+nrows) not nlines*ncols*nrows +// + +#define blkshift 7 /* places to shift rel position for cell num */ +#define blkmask ((1<0 +// jff 10/12/98 0 ok with + 1 in rows,cols + +typedef struct linelist_t // type used to list lines in each block +{ + long num; + struct linelist_t *next; +} linelist_t; + +// +// Subroutine to add a line number to a block list +// It simply returns if the line is already in the block +// + +static void AddBlockLine +( + linelist_t **lists, + int *count, + int *done, + int blockno, + long lineno +) +{ + linelist_t *l; + + if (done[blockno]) + return; + + l = malloc(sizeof(linelist_t)); + l->num = lineno; + l->next = lists[blockno]; + lists[blockno] = l; + count[blockno]++; + done[blockno] = 1; +} + +// +// Actually construct the blockmap lump from the level data +// +// This finds the intersection of each linedef with the column and +// row lines at the left and bottom of each blockmap cell. It then +// adds the line to all block lists touching the intersection. +// + +void P_CreateBlockMap() +{ + int xorg,yorg; // blockmap origin (lower left) + int nrows,ncols; // blockmap dimensions + linelist_t **blocklists=NULL; // array of pointers to lists of lines + int *blockcount=NULL; // array of counters of line lists + int *blockdone=NULL; // array keeping track of blocks/line + int NBlocks; // number of cells = nrows*ncols + long linetotal=0; // total length of all blocklists + int i,j; + int map_minx=INT_MAX; // init for map limits search + int map_miny=INT_MAX; + int map_maxx=INT_MIN; + int map_maxy=INT_MIN; + + // scan for map limits, which the blockmap must enclose + + for (i=0;i map_maxx) + map_maxx = t; + if ((t=vertexes[i].y) < map_miny) + map_miny = t; + else if (t > map_maxy) + map_maxy = t; + } + map_minx >>= FRACBITS; // work in map coords, not fixed_t + map_maxx >>= FRACBITS; + map_miny >>= FRACBITS; + map_maxy >>= FRACBITS; + + // set up blockmap area to enclose level plus margin + + xorg = map_minx-blkmargin; + yorg = map_miny-blkmargin; + ncols = (map_maxx+blkmargin-xorg+1+blkmask)>>blkshift; //jff 10/12/98 + nrows = (map_maxy+blkmargin-yorg+1+blkmask)>>blkshift; //+1 needed for + NBlocks = ncols*nrows; //map exactly 1 cell + + // create the array of pointers on NBlocks to blocklists + // also create an array of linelist counts on NBlocks + // finally make an array in which we can mark blocks done per line + + // CPhipps - calloc's + blocklists = calloc(NBlocks,sizeof(linelist_t *)); + blockcount = calloc(NBlocks,sizeof(int)); + blockdone = malloc(NBlocks*sizeof(int)); + + // initialize each blocklist, and enter the trailing -1 in all blocklists + // note the linked list of lines grows backwards + + for (i=0;inum = -1; + blocklists[i]->next = NULL; + blockcount[i]++; + } + + // For each linedef in the wad, determine all blockmap blocks it touches, + // and add the linedef number to the blocklists for those blocks + + for (i=0;ix>>FRACBITS; // lines[i] map coords + int y1 = lines[i].v1->y>>FRACBITS; + int x2 = lines[i].v2->x>>FRACBITS; + int y2 = lines[i].v2->y>>FRACBITS; + int dx = x2-x1; + int dy = y2-y1; + int vert = !dx; // lines[i] slopetype + int horiz = !dy; + int spos = (dx^dy) > 0; + int sneg = (dx^dy) < 0; + int bx,by; // block cell coords + int minx = x1>x2? x2 : x1; // extremal lines[i] coords + int maxx = x1>x2? x1 : x2; + int miny = y1>y2? y2 : y1; + int maxy = y1>y2? y1 : y2; + + // no blocks done for this linedef yet + + memset(blockdone,0,NBlocks*sizeof(int)); + + // The line always belongs to the blocks containing its endpoints + + bx = (x1-xorg)>>blkshift; + by = (y1-yorg)>>blkshift; + AddBlockLine(blocklists,blockcount,blockdone,by*ncols+bx,i); + bx = (x2-xorg)>>blkshift; + by = (y2-yorg)>>blkshift; + AddBlockLine(blocklists,blockcount,blockdone,by*ncols+bx,i); + + + // For each column, see where the line along its left edge, which + // it contains, intersects the Linedef i. Add i to each corresponding + // blocklist. + + if (!vert) // don't interesect vertical lines with columns + { + for (j=0;j>blkshift; // block row number + int yp = (y-yorg)&blkmask; // y position within block + + if (yb<0 || yb>nrows-1) // outside blockmap, continue + continue; + + if (xmaxx) // line doesn't touch column + continue; + + // The cell that contains the intersection point is always added + + AddBlockLine(blocklists,blockcount,blockdone,ncols*yb+j,i); + + // if the intersection is at a corner it depends on the slope + // (and whether the line extends past the intersection) which + // blocks are hit + + if (yp==0) // intersection at a corner + { + if (sneg) // \ - blocks x,y-, x-,y + { + if (yb>0 && miny0 && minx0 && j>0 && minx0 && minx0 && minx>blkshift; // block column number + int xp = (x-xorg)&blkmask; // x position within block + + if (xb<0 || xb>ncols-1) // outside blockmap, continue + continue; + + if (ymaxy) // line doesn't touch row + continue; + + // The cell that contains the intersection point is always added + + AddBlockLine(blocklists,blockcount,blockdone,ncols*j+xb,i); + + // if the intersection is at a corner it depends on the slope + // (and whether the line extends past the intersection) which + // blocks are hit + + if (xp==0) // intersection at a corner + { + if (sneg) // \ - blocks x,y-, x-,y + { + if (j>0 && miny0 && minx0 && miny0 && j>0 && miny0 && minynext; + blockmaplump[offs++] = bl->num; + free(bl); + bl = tmp; + } + } + + // free all temporary storage + + free (blocklists); + free (blockcount); + free (blockdone); +} + +// jff 10/6/98 +// End new code added to speed up calculation of internal blockmap + +// +// P_LoadBlockMap +// +// killough 3/1/98: substantially modified to work +// towards removing blockmap limit (a wad limitation) +// +// killough 3/30/98: Rewritten to remove blockmap limit, +// though current algorithm is brute-force and unoptimal. +// + +static void P_LoadBlockMap (int lump) +{ + long count; + + if (M_CheckParm("-blockmap") || (count = W_LumpLength(lump)/2) >= 0x10000) + P_CreateBlockMap(); + else + { + long i; + // cph - const*, wad lump handling updated + const short *wadblockmaplump = W_CacheLumpNum(lump); + blockmaplump = Z_Malloc(sizeof(*blockmaplump) * count, PU_LEVEL, 0); + + // killough 3/1/98: Expand wad blockmap into larger internal one, + // by treating all offsets except -1 as unsigned and zero-extending + // them. This potentially doubles the size of blockmaps allowed, + // because Doom originally considered the offsets as always signed. + + blockmaplump[0] = SHORT(wadblockmaplump[0]); + blockmaplump[1] = SHORT(wadblockmaplump[1]); + blockmaplump[2] = (long)(SHORT(wadblockmaplump[2])) & 0xffff; + blockmaplump[3] = (long)(SHORT(wadblockmaplump[3])) & 0xffff; + + for (i=4 ; iblockbox; + + sector->lines[sector->linecount++] = li; + M_AddToBox (bbox, li->v1->x, li->v1->y); + M_AddToBox (bbox, li->v2->x, li->v2->y); +} + +void P_GroupLines (void) +{ + register line_t *li; + register sector_t *sector; + int i,j, total = numlines; + + // figgi + for (i=0 ; isidedef) + { + subsectors[i].sector = seg->sidedef->sector; + break; + } + seg++; + } + if(subsectors[i].sector == NULL) + I_Error("P_GroupLines: Subsector a part of no sector!\n"); + } + + // count number of lines in each sector + for (i=0,li=lines; ifrontsector->linecount++; + if (li->backsector && li->backsector != li->frontsector) + { + li->backsector->linecount++; + total++; + } + } + + { // allocate line tables for each sector + line_t **linebuffer = Z_Malloc(total*sizeof(line_t *), PU_LEVEL, 0); + + for (i=0, sector = sectors; ilines = linebuffer; + linebuffer += sector->linecount; + sector->linecount = 0; + M_ClearBox(sector->blockbox); + } + } + + // Enter those lines + for (i=0,li=lines; ifrontsector); + if (li->backsector && li->backsector != li->frontsector) + P_AddLineToSector(li, li->backsector); + } + + for (i=0, sector = sectors; iblockbox; // cph - For convenience, so + // I can sue the old code unchanged + int block; + + // set the degenmobj_t to the middle of the bounding box + sector->soundorg.x = (bbox[BOXRIGHT]+bbox[BOXLEFT])/2; + sector->soundorg.y = (bbox[BOXTOP]+bbox[BOXBOTTOM])/2; + + // adjust bounding box to map blocks + block = (bbox[BOXTOP]-bmaporgy+MAXRADIUS)>>MAPBLOCKSHIFT; + block = block >= bmapheight ? bmapheight-1 : block; + sector->blockbox[BOXTOP]=block; + + block = (bbox[BOXBOTTOM]-bmaporgy-MAXRADIUS)>>MAPBLOCKSHIFT; + block = block < 0 ? 0 : block; + sector->blockbox[BOXBOTTOM]=block; + + block = (bbox[BOXRIGHT]-bmaporgx+MAXRADIUS)>>MAPBLOCKSHIFT; + block = block >= bmapwidth ? bmapwidth-1 : block; + sector->blockbox[BOXRIGHT]=block; + + block = (bbox[BOXLEFT]-bmaporgx-MAXRADIUS)>>MAPBLOCKSHIFT; + block = block < 0 ? 0 : block; + sector->blockbox[BOXLEFT]=block; + } + +} + +// +// killough 10/98 +// +// Remove slime trails. +// +// Slime trails are inherent to Doom's coordinate system -- i.e. there is +// nothing that a node builder can do to prevent slime trails ALL of the time, +// because it's a product of the integer coodinate system, and just because +// two lines pass through exact integer coordinates, doesn't necessarily mean +// that they will intersect at integer coordinates. Thus we must allow for +// fractional coordinates if we are to be able to split segs with node lines, +// as a node builder must do when creating a BSP tree. +// +// A wad file does not allow fractional coordinates, so node builders are out +// of luck except that they can try to limit the number of splits (they might +// also be able to detect the degree of roundoff error and try to avoid splits +// with a high degree of roundoff error). But we can use fractional coordinates +// here, inside the engine. It's like the difference between square inches and +// square miles, in terms of granularity. +// +// For each vertex of every seg, check to see whether it's also a vertex of +// the linedef associated with the seg (i.e, it's an endpoint). If it's not +// an endpoint, and it wasn't already moved, move the vertex towards the +// linedef by projecting it using the law of cosines. Formula: +// +// 2 2 2 2 +// dx x0 + dy x1 + dx dy (y0 - y1) dy y0 + dx y1 + dx dy (x0 - x1) +// {---------------------------------, ---------------------------------} +// 2 2 2 2 +// dx + dy dx + dy +// +// (x0,y0) is the vertex being moved, and (x1,y1)-(x1+dx,y1+dy) is the +// reference linedef. +// +// Segs corresponding to orthogonal linedefs (exactly vertical or horizontal +// linedefs), which comprise at least half of all linedefs in most wads, don't +// need to be considered, because they almost never contribute to slime trails +// (because then any roundoff error is parallel to the linedef, which doesn't +// cause slime). Skipping simple orthogonal lines lets the code finish quicker. +// +// Please note: This section of code is not interchangable with TeamTNT's +// code which attempts to fix the same problem. +// +// Firelines (TM) is a Rezistered Trademark of MBF Productions +// + +void P_RemoveSlimeTrails(void) // killough 10/98 +{ + byte *hit = calloc(1, numvertexes); // Hitlist for vertices + int i; + for (i=0; idx && l->dy) // We can ignore orthogonal lines + { + vertex_t *v = segs[i].v1; + do + if (!hit[v - vertexes]) // If we haven't processed vertex + { + hit[v - vertexes] = 1; // Mark this vertex as processed + if (v != l->v1 && v != l->v2) // Exclude endpoints of linedefs + { // Project the vertex back onto the parent linedef + int_64_t dx2 = (l->dx >> FRACBITS) * (l->dx >> FRACBITS); + int_64_t dy2 = (l->dy >> FRACBITS) * (l->dy >> FRACBITS); + int_64_t dxy = (l->dx >> FRACBITS) * (l->dy >> FRACBITS); + int_64_t s = dx2 + dy2; + int x0 = v->x, y0 = v->y, x1 = l->v1->x, y1 = l->v1->y; + v->x = (int)((dx2 * x0 + dy2 * x1 + dxy * (y0 - y1)) / s); + v->y = (int)((dy2 * y0 + dx2 * y1 + dxy * (x0 - x1)) / s); + } + } // Obsfucated C contest entry: :) + while ((v != segs[i].v2) && (v = segs[i].v2)); + } + } + free(hit); +} + +// +// P_SetupLevel +// +// killough 5/3/98: reformatted, cleaned up + +void P_SetupLevel(int episode, int map, int playermask, skill_t skill) +{ + (void)playermask; + (void)skill; + int i; + char lumpname[9]; + int lumpnum; + + + totalkills = totalitems = totalsecret = wminfo.maxfrags = 0; + wminfo.partime = 180; + + for (i=0; idx ? x == node->x ? 2 : x <= node->x ? node->dy > 0 : node->dy < 0 : + !node->dy ? x == node->y ? 2 : y <= node->y ? node->dx < 0 : node->dx > 0 : + (right = ((y - node->y) >> FRACBITS) * (node->dx >> FRACBITS)) < + (left = ((x - node->x) >> FRACBITS) * (node->dy >> FRACBITS)) ? 0 : + right == left ? 2 : 1; +} + +// +// P_InterceptVector2 +// Returns the fractional intercept point +// along the first divline. +// +// killough 4/19/98: made static, cleaned up + +static fixed_t P_InterceptVector2(const divline_t *v2, const divline_t *v1) +{ + fixed_t den; + return (den = FixedMul(v1->dy>>8, v2->dx) - FixedMul(v1->dx>>8, v2->dy)) ? + FixedDiv(FixedMul((v1->x - v2->x)>>8, v1->dy) + + FixedMul((v2->y - v1->y)>>8, v1->dx), den) : 0; +} + +// +// P_CrossSubsector +// Returns true +// if strace crosses the given subsector successfully. +// +// killough 4/19/98: made static and cleaned up + +static boolean P_CrossSubsector(int num) +{ + seg_t *seg = segs + subsectors[num].firstline; + int count; + fixed_t opentop = 0, openbottom = 0; + const sector_t *front = NULL, *back = NULL; + +#ifdef RANGECHECK + if (num >= numsubsectors) + I_Error("P_CrossSubsector: ss %i with numss = %i", num, numsubsectors); +#endif + + for (count = subsectors[num].numlines; --count >= 0; seg++) { // check lines + line_t *line = seg->linedef; + divline_t divl; + + if(!line) // figgi -- skip minisegs + continue; + + // allready checked other side? + if (line->validcount == validcount) + continue; + + line->validcount = validcount; + + /* OPTIMIZE: killough 4/20/98: Added quick bounding-box rejection test + * cph - this is causing demo desyncs on original Doom demos. + * Who knows why. Exclude test for those. + */ + if (!demo_compatibility) + if (line->bbox[BOXLEFT ] > los.bbox[BOXRIGHT ] || + line->bbox[BOXRIGHT ] < los.bbox[BOXLEFT ] || + line->bbox[BOXBOTTOM] > los.bbox[BOXTOP ] || + line->bbox[BOXTOP] < los.bbox[BOXBOTTOM]) + continue; + + // cph - do what we can before forced to check intersection + if (line->flags & ML_TWOSIDED) { + + // no wall to block sight with? + if ((front = seg->frontsector)->floorheight == + (back = seg->backsector)->floorheight && + front->ceilingheight == back->ceilingheight) + continue; + + // possible occluder + // because of ceiling height differences + opentop = front->ceilingheight < back->ceilingheight ? + front->ceilingheight : back->ceilingheight ; + + // because of floor height differences + openbottom = front->floorheight > back->floorheight ? + front->floorheight : back->floorheight ; + + // cph - reject if does not intrude in the z-space of the possible LOS + if ((opentop >= los.maxz) && (openbottom <= los.minz)) + continue; + } + + { // Forget this line if it doesn't cross the line of sight + const vertex_t *v1,*v2; + + v1 = line->v1; + v2 = line->v2; + + if (P_DivlineSide(v1->x, v1->y, &los.strace) == + P_DivlineSide(v2->x, v2->y, &los.strace)) + continue; + + divl.dx = v2->x - (divl.x = v1->x); + divl.dy = v2->y - (divl.y = v1->y); + + // line isn't crossed? + if (P_DivlineSide(los.strace.x, los.strace.y, &divl) == + P_DivlineSide(los.t2x, los.t2y, &divl)) + continue; + } + + // cph - if bottom >= top or top < minz or bottom > maxz then it must be + // solid wrt this LOS + if (!(line->flags & ML_TWOSIDED) || (openbottom >= opentop) || + (opentop < los.minz) || (openbottom > los.maxz)) + return false; + + { // crosses a two sided line + fixed_t frac = P_InterceptVector2(&los.strace, &divl); + + if (front->floorheight != back->floorheight) + { + fixed_t slope = FixedDiv(openbottom - los.sightzstart , frac); + if (slope > los.bottomslope) + los.bottomslope = slope; + } + + if (front->ceilingheight != back->ceilingheight) + { + fixed_t slope = FixedDiv(opentop - los.sightzstart , frac); + if (slope < los.topslope) + los.topslope = slope; + } + + if (los.topslope <= los.bottomslope) + return false; // stop + } + } + // passed the subsector ok + return true; +} + +// +// P_CrossBSPNode +// Returns true +// if strace crosses the given node successfully. +// +// killough 4/20/98: rewritten to remove tail recursion, clean up, and optimize +// cph - Made to use R_PointOnSide instead of P_DivlineSide, since the latter +// could return 2 which was ambigous, and the former is +// better optimised; also removes two casts :-) + +static boolean P_CrossBSPNode_LxDoom(int bspnum) +{ + while (!(bspnum & NF_SUBSECTOR)) + { + register const node_t *bsp = nodes + bspnum; + int side,side2; + side = R_PointOnSide(los.strace.x, los.strace.y, bsp); + side2 = R_PointOnSide(los.t2x, los.t2y, bsp); + if (side == side2) + bspnum = bsp->children[side]; // doesn't touch the other side + else // the partition plane is crossed here + if (!P_CrossBSPNode_LxDoom(bsp->children[side])) + return 0; // cross the starting side + else + bspnum = bsp->children[side^1]; // cross the ending side + } + return P_CrossSubsector(bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR); +} + +static boolean P_CrossBSPNode_PrBoom(int bspnum) +{ + while (!(bspnum & NF_SUBSECTOR)) + { + register const node_t *bsp = nodes + bspnum; + int side,side2; + side = P_DivlineSide(los.strace.x,los.strace.y,(divline_t *)bsp)&1; + side2= P_DivlineSide(los.t2x, los.t2y, (divline_t *) bsp); + if (side == side2) + bspnum = bsp->children[side]; // doesn't touch the other side + else // the partition plane is crossed here + if (!P_CrossBSPNode_PrBoom(bsp->children[side])) + return 0; // cross the starting side + else + bspnum = bsp->children[side^1]; // cross the ending side + } + return P_CrossSubsector(bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR); +} + +/* proff - Moved the compatibility check outside the functions + * this gives a slight speedup + */ +static boolean P_CrossBSPNode(int bspnum) +{ + /* cph - LxDoom used some R_* funcs here */ + if (compatibility_level == lxdoom_1_compatibility) + return P_CrossBSPNode_LxDoom(bspnum); + else + return P_CrossBSPNode_PrBoom(bspnum); +} + +// +// P_CheckSight +// Returns true +// if a straight line between t1 and t2 is unobstructed. +// Uses REJECT. +// +// killough 4/20/98: cleaned up, made to use new LOS struct + +boolean P_CheckSight(mobj_t *t1, mobj_t *t2) +{ + const sector_t *s1 = t1->subsector->sector; + const sector_t *s2 = t2->subsector->sector; + int pnum = (s1-sectors)*numsectors + (s2-sectors); + + // First check for trivial rejection. + // Determine subsector entries in REJECT table. + // + // Check in REJECT table. + + if (rejectmatrix[pnum>>3] & (1 << (pnum&7))) // can't possibly be connected + return false; + + // killough 4/19/98: make fake floors and ceilings block monster view + + if ((s1->heightsec != -1 && + ((t1->z + t1->height <= sectors[s1->heightsec].floorheight && + t2->z >= sectors[s1->heightsec].floorheight) || + (t1->z >= sectors[s1->heightsec].ceilingheight && + t2->z + t1->height <= sectors[s1->heightsec].ceilingheight))) + || + (s2->heightsec != -1 && + ((t2->z + t2->height <= sectors[s2->heightsec].floorheight && + t1->z >= sectors[s2->heightsec].floorheight) || + (t2->z >= sectors[s2->heightsec].ceilingheight && + t1->z + t2->height <= sectors[s2->heightsec].ceilingheight)))) + return false; + + /* killough 11/98: shortcut for melee situations + * same subsector? obviously visible + * cph - compatibility optioned for demo sync, cf HR06-UV.LMP */ + if ((t1->subsector == t2->subsector) && + (compatibility_level >= mbf_compatibility)) + return true; + + // An unobstructed LOS is possible. + // Now look from eyes of t1 to any part of t2. + + validcount++; + + los.topslope = (los.bottomslope = t2->z - (los.sightzstart = + t1->z + t1->height - + (t1->height>>2))) + t2->height; + los.strace.dx = (los.t2x = t2->x) - (los.strace.x = t1->x); + los.strace.dy = (los.t2y = t2->y) - (los.strace.y = t1->y); + + if (t1->x > t2->x) + los.bbox[BOXRIGHT] = t1->x, los.bbox[BOXLEFT] = t2->x; + else + los.bbox[BOXRIGHT] = t2->x, los.bbox[BOXLEFT] = t1->x; + + if (t1->y > t2->y) + los.bbox[BOXTOP] = t1->y, los.bbox[BOXBOTTOM] = t2->y; + else + los.bbox[BOXTOP] = t2->y, los.bbox[BOXBOTTOM] = t1->y; + + /* cph - calculate min and max z of the potential line of sight + * For old demos, we disable this optimisation by setting them to + * the extremes */ + switch (compatibility_level) { + case lxdoom_1_compatibility: + if (los.sightzstart < t2->z) { + los.maxz = t2->z + t2->height; los.minz = los.sightzstart; + } else if (los.sightzstart > t2->z + t2->height) { + los.maxz = los.sightzstart; los.minz = t2->z; + } else { + los.maxz = t2->z + t2->height; los.minz = t2->z; + } + break; + default: + los.maxz = INT_MAX; los.minz = INT_MIN; + } + + // the head node is the last node output + return P_CrossBSPNode(numnodes-1); +} diff --git a/apps/plugins/doom/p_spec.c b/apps/plugins/doom/p_spec.c new file mode 100644 index 0000000000..2876b7f4e5 --- /dev/null +++ b/apps/plugins/doom/p_spec.c @@ -0,0 +1,3255 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * -Loads and initializes texture and flat animation sequences + * -Implements utility functions for all linedef/sector special handlers + * -Dispatches walkover and gun line triggers + * -Initializes and implements special sector types + * -Implements donut linedef triggers + * -Initializes and implements BOOM linedef triggers for + * Scrollers/Conveyors + * Friction + * Wind/Current + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "p_spec.h" +#include "p_tick.h" +#include "p_setup.h" +#include "m_random.h" +#include "d_englsh.h" +#include "m_argv.h" +#include "w_wad.h" +#include "r_main.h" +#include "p_maputl.h" +#include "p_map.h" +#include "g_game.h" +#include "p_inter.h" +#include "m_swap.h" +#include "s_sound.h" +#include "sounds.h" +#include "m_bbox.h" // phares 3/20/98 +//#include "d_deh.h" +#include "r_plane.h" +#include "i_system.h" +#include "rockmacros.h" +// +// Animating textures and planes +// There is another anim_t used in wi_stuff, unrelated. +// +typedef struct +{ + boolean istexture; + int picnum; + int basepic; + int numpics; + int speed; + +} anim_t; + +// +// source animation definition +// +// +#ifdef _MSC_VER // proff: This is the same as __attribute__ ((packed)) in GNUC +#pragma pack(push) +#pragma pack(1) +#endif //_MSC_VER + +#if defined(__MWERKS__) +#pragma options align=packed +#endif + +typedef struct +{ + signed char istexture; //jff 3/23/98 make char for comparison // cph - make signed + char endname[9]; // if false, it is a flat + char startname[9]; + int speed; +} PACKEDATTR animdef_t; //jff 3/23/98 pack to read from memory + +#define MAXANIMS 32 // no longer a strict limit -- killough + +static anim_t* lastanim; +static anim_t* anims; // new structure w/o limits -- killough +static size_t maxanims; + +// killough 3/7/98: Initialize generalized scrolling +static void P_SpawnScrollers(void); + +static void P_SpawnFriction(void); // phares 3/16/98 +static void P_SpawnPushers(void); // phares 3/20/98 + +extern int allow_pushers; +extern int variable_friction; // phares 3/20/98 + +// +// P_InitPicAnims +// +// Load the table of animation definitions, checking for existence of +// the start and end of each frame. If the start doesn't exist the sequence +// is skipped, if the last doesn't exist, BOOM exits. +// +// Wall/Flat animation sequences, defined by name of first and last frame, +// The full animation sequence is given using all lumps between the start +// and end entry, in the order found in the WAD file. +// +// This routine modified to read its data from a predefined lump or +// PWAD lump called ANIMATED rather than a static table in this module to +// allow wad designers to insert or modify animation sequences. +// +// Lump format is an array of byte packed animdef_t structures, terminated +// by a structure with istexture == -1. The lump can be generated from a +// text source file using SWANTBLS.EXE, distributed with the BOOM utils. +// The standard list of switches and animations is contained in the example +// source text file DEFSWANI.DAT also in the BOOM util distribution. +// +// +void P_InitPicAnims (void) +{ + int i; + const animdef_t *animdefs; //jff 3/23/98 pointer to animation lump + int lump = W_GetNumForName("ANIMATED"); // cph - new wad lump handling + // Init animation + + //jff 3/23/98 read from predefined or wad lump instead of table + animdefs = (const animdef_t *)W_CacheLumpNum(lump); + + lastanim = anims; + for (i=0 ; animdefs[i].istexture != -1 ; i++) + { + // 1/11/98 killough -- removed limit by array-doubling + if (lastanim >= anims + maxanims) + { + size_t newmax = maxanims ? maxanims*2 : MAXANIMS; + anims = realloc(anims, newmax*sizeof(*anims)); // killough + lastanim = anims + maxanims; + maxanims = newmax; + } + + if (animdefs[i].istexture) + { + // different episode ? + if (R_CheckTextureNumForName(animdefs[i].startname) == -1) + continue; + + lastanim->picnum = R_TextureNumForName (animdefs[i].endname); + lastanim->basepic = R_TextureNumForName (animdefs[i].startname); + } + else + { + if ((W_CheckNumForName)(animdefs[i].startname, ns_flats) == -1) // killough 4/17/98 + continue; + + lastanim->picnum = R_FlatNumForName (animdefs[i].endname); + lastanim->basepic = R_FlatNumForName (animdefs[i].startname); + } + + lastanim->istexture = animdefs[i].istexture; + lastanim->numpics = lastanim->picnum - lastanim->basepic + 1; + + if (lastanim->numpics < 2) + I_Error ("P_InitPicAnims: bad cycle from %s to %s", + animdefs[i].startname, + animdefs[i].endname); + + lastanim->speed = LONG(animdefs[i].speed); // killough 5/5/98: add LONG() + lastanim++; + } + W_UnlockLumpNum(lump); +} + +/////////////////////////////////////////////////////////////// +// +// Linedef and Sector Special Implementation Utility Functions +// +/////////////////////////////////////////////////////////////// + +// +// getSide() +// +// Will return a side_t* +// given the number of the current sector, +// the line number, and the side (0/1) that you want. +// +// Note: if side=1 is specified, it must exist or results undefined +// +side_t* getSide +( int currentSector, + int line, + int side ) +{ + return &sides[ (sectors[currentSector].lines[line])->sidenum[side] ]; +} + + +// +// getSector() +// +// Will return a sector_t* +// given the number of the current sector, +// the line number and the side (0/1) that you want. +// +// Note: if side=1 is specified, it must exist or results undefined +// +sector_t* getSector +( int currentSector, + int line, + int side ) +{ + return sides[ (sectors[currentSector].lines[line])->sidenum[side] ].sector; +} + + +// +// twoSided() +// +// Given the sector number and the line number, +// it will tell you whether the line is two-sided or not. +// +// modified to return actual two-sidedness rather than presence +// of 2S flag unless compatibility optioned +// +int twoSided +( int sector, + int line ) +{ + //jff 1/26/98 return what is actually needed, whether the line + //has two sidedefs, rather than whether the 2S flag is set + + return comp[comp_model] ? + (sectors[sector].lines[line])->flags & ML_TWOSIDED + : + (sectors[sector].lines[line])->sidenum[1] != -1; +} + + +// +// getNextSector() +// +// Return sector_t * of sector next to current across line. +// +// Note: returns NULL if not two-sided line, or both sides refer to sector +// +sector_t* getNextSector +( line_t* line, + sector_t* sec ) +{ + //jff 1/26/98 check unneeded since line->backsector already + //returns NULL if the line is not two sided, and does so from + //the actual two-sidedness of the line, rather than its 2S flag + + if (comp[comp_model]) + { + if (!(line->flags & ML_TWOSIDED)) + return NULL; + } + + if (line->frontsector == sec) { + if (comp[comp_model] || line->backsector!=sec) + return line->backsector; //jff 5/3/98 don't retn sec unless compatibility + else // fixes an intra-sector line breaking functions + return NULL; // like floor->highest floor + } + return line->frontsector; +} + + +// +// P_FindLowestFloorSurrounding() +// +// Returns the fixed point value of the lowest floor height +// in the sector passed or its surrounding sectors. +// +fixed_t P_FindLowestFloorSurrounding(sector_t* sec) +{ + int i; + line_t* check; + sector_t* other; + fixed_t floor = sec->floorheight; + + for (i=0 ;i < sec->linecount ; i++) + { + check = sec->lines[i]; + other = getNextSector(check,sec); + + if (!other) + continue; + + if (other->floorheight < floor) + floor = other->floorheight; + } + return floor; +} + + +// +// P_FindHighestFloorSurrounding() +// +// Passed a sector, returns the fixed point value of the largest +// floor height in the surrounding sectors, not including that passed +// +// NOTE: if no surrounding sector exists -32000*FRACUINT is returned +// if compatibility then -500*FRACUNIT is the smallest return possible +// +fixed_t P_FindHighestFloorSurrounding(sector_t *sec) +{ + int i; + line_t* check; + sector_t* other; + fixed_t floor = -500*FRACUNIT; + + //jff 1/26/98 Fix initial value for floor to not act differently + //in sections of wad that are below -500 units + if (!comp[comp_model]) /* jff 3/12/98 avoid ovf */ + floor = -32000*FRACUNIT; // in height calculations + + for (i=0 ;i < sec->linecount ; i++) + { + check = sec->lines[i]; + other = getNextSector(check,sec); + + if (!other) + continue; + + if (other->floorheight > floor) + floor = other->floorheight; + } + return floor; +} + + +// +// P_FindNextHighestFloor() +// +// Passed a sector and a floor height, returns the fixed point value +// of the smallest floor height in a surrounding sector larger than +// the floor height passed. If no such height exists the floorheight +// passed is returned. +// +// Rewritten by Lee Killough to avoid fixed array and to be faster +// +fixed_t P_FindNextHighestFloor(sector_t *sec, int currentheight) +{ + sector_t *other; + int i; + + for (i=0 ;i < sec->linecount ; i++) + if ((other = getNextSector(sec->lines[i],sec)) && + other->floorheight > currentheight) + { + int height = other->floorheight; + while (++i < sec->linecount) + if ((other = getNextSector(sec->lines[i],sec)) && + other->floorheight < height && + other->floorheight > currentheight) + height = other->floorheight; + return height; + } + return currentheight; +} + + +// +// P_FindNextLowestFloor() +// +// Passed a sector and a floor height, returns the fixed point value +// of the largest floor height in a surrounding sector smaller than +// the floor height passed. If no such height exists the floorheight +// passed is returned. +// +// jff 02/03/98 Twiddled Lee's P_FindNextHighestFloor to make this +// +fixed_t P_FindNextLowestFloor(sector_t *sec, int currentheight) +{ + sector_t *other; + int i; + + for (i=0 ;i < sec->linecount ; i++) + if ((other = getNextSector(sec->lines[i],sec)) && + other->floorheight < currentheight) + { + int height = other->floorheight; + while (++i < sec->linecount) + if ((other = getNextSector(sec->lines[i],sec)) && + other->floorheight > height && + other->floorheight < currentheight) + height = other->floorheight; + return height; + } + return currentheight; +} + + +// +// P_FindNextLowestCeiling() +// +// Passed a sector and a ceiling height, returns the fixed point value +// of the largest ceiling height in a surrounding sector smaller than +// the ceiling height passed. If no such height exists the ceiling height +// passed is returned. +// +// jff 02/03/98 Twiddled Lee's P_FindNextHighestFloor to make this +// +fixed_t P_FindNextLowestCeiling(sector_t *sec, int currentheight) +{ + sector_t *other; + int i; + + for (i=0 ;i < sec->linecount ; i++) + if ((other = getNextSector(sec->lines[i],sec)) && + other->ceilingheight < currentheight) + { + int height = other->ceilingheight; + while (++i < sec->linecount) + if ((other = getNextSector(sec->lines[i],sec)) && + other->ceilingheight > height && + other->ceilingheight < currentheight) + height = other->ceilingheight; + return height; + } + return currentheight; +} + + +// +// P_FindNextHighestCeiling() +// +// Passed a sector and a ceiling height, returns the fixed point value +// of the smallest ceiling height in a surrounding sector larger than +// the ceiling height passed. If no such height exists the ceiling height +// passed is returned. +// +// jff 02/03/98 Twiddled Lee's P_FindNextHighestFloor to make this +// +fixed_t P_FindNextHighestCeiling(sector_t *sec, int currentheight) +{ + sector_t *other; + int i; + + for (i=0 ;i < sec->linecount ; i++) + if ((other = getNextSector(sec->lines[i],sec)) && + other->ceilingheight > currentheight) + { + int height = other->ceilingheight; + while (++i < sec->linecount) + if ((other = getNextSector(sec->lines[i],sec)) && + other->ceilingheight < height && + other->ceilingheight > currentheight) + height = other->ceilingheight; + return height; + } + return currentheight; +} + + +// +// P_FindLowestCeilingSurrounding() +// +// Passed a sector, returns the fixed point value of the smallest +// ceiling height in the surrounding sectors, not including that passed +// +// NOTE: if no surrounding sector exists 32000*FRACUINT is returned +// but if compatibility then INT_MAX is the return +// +fixed_t P_FindLowestCeilingSurrounding(sector_t* sec) +{ + int i; + line_t* check; + sector_t* other; + fixed_t height = INT_MAX; + + /* jff 3/12/98 avoid ovf in height calculations */ + if (!comp[comp_model]) height = 32000*FRACUNIT; + + for (i=0 ;i < sec->linecount ; i++) + { + check = sec->lines[i]; + other = getNextSector(check,sec); + + if (!other) + continue; + + if (other->ceilingheight < height) + height = other->ceilingheight; + } + return height; +} + + +// +// P_FindHighestCeilingSurrounding() +// +// Passed a sector, returns the fixed point value of the largest +// ceiling height in the surrounding sectors, not including that passed +// +// NOTE: if no surrounding sector exists -32000*FRACUINT is returned +// but if compatibility then 0 is the smallest return possible +// +fixed_t P_FindHighestCeilingSurrounding(sector_t* sec) +{ + int i; + line_t* check; + sector_t* other; + fixed_t height = 0; + + /* jff 1/26/98 Fix initial value for floor to not act differently + * in sections of wad that are below 0 units + * jff 3/12/98 avoid ovf in height calculations */ + if (!comp[comp_model]) height = -32000*FRACUNIT; + + for (i=0 ;i < sec->linecount ; i++) + { + check = sec->lines[i]; + other = getNextSector(check,sec); + + if (!other) + continue; + + if (other->ceilingheight > height) + height = other->ceilingheight; + } + return height; +} + + +// +// P_FindShortestTextureAround() +// +// Passed a sector number, returns the shortest lower texture on a +// linedef bounding the sector. +// +// Note: If no lower texture exists 32000*FRACUNIT is returned. +// but if compatibility then INT_MAX is returned +// +// jff 02/03/98 Add routine to find shortest lower texture +// +fixed_t P_FindShortestTextureAround(int secnum) +{ + int minsize = INT_MAX; + side_t* side; + int i; + sector_t *sec = §ors[secnum]; + + if (!comp[comp_model]) + minsize = 32000<linecount; i++) + { + if (twoSided(secnum, i)) + { + side = getSide(secnum,i,0); + if (side->bottomtexture > 0) //jff 8/14/98 texture 0 is a placeholder + if (textureheight[side->bottomtexture] < minsize) + minsize = textureheight[side->bottomtexture]; + side = getSide(secnum,i,1); + if (side->bottomtexture > 0) //jff 8/14/98 texture 0 is a placeholder + if (textureheight[side->bottomtexture] < minsize) + minsize = textureheight[side->bottomtexture]; + } + } + return minsize; +} + + +// +// P_FindShortestUpperAround() +// +// Passed a sector number, returns the shortest upper texture on a +// linedef bounding the sector. +// +// Note: If no upper texture exists 32000*FRACUNIT is returned. +// but if compatibility then INT_MAX is returned +// +// jff 03/20/98 Add routine to find shortest upper texture +// +fixed_t P_FindShortestUpperAround(int secnum) +{ + int minsize = INT_MAX; + side_t* side; + int i; + sector_t *sec = §ors[secnum]; + + if (!comp[comp_model]) + minsize = 32000<linecount; i++) + { + if (twoSided(secnum, i)) + { + side = getSide(secnum,i,0); + if (side->toptexture > 0) //jff 8/14/98 texture 0 is a placeholder + if (textureheight[side->toptexture] < minsize) + minsize = textureheight[side->toptexture]; + side = getSide(secnum,i,1); + if (side->toptexture > 0) //jff 8/14/98 texture 0 is a placeholder + if (textureheight[side->toptexture] < minsize) + minsize = textureheight[side->toptexture]; + } + } + return minsize; +} + + +// +// P_FindModelFloorSector() +// +// Passed a floor height and a sector number, return a pointer to a +// a sector with that floor height across the lowest numbered two sided +// line surrounding the sector. +// +// Note: If no sector at that height bounds the sector passed, return NULL +// +// jff 02/03/98 Add routine to find numeric model floor +// around a sector specified by sector number +// jff 3/14/98 change first parameter to plain height to allow call +// from routine not using floormove_t +// +sector_t *P_FindModelFloorSector(fixed_t floordestheight,int secnum) +{ + int i; + sector_t *sec=NULL; + int linecount; + + sec = §ors[secnum]; //jff 3/2/98 woops! better do this + //jff 5/23/98 don't disturb sec->linecount while searching + // but allow early exit in old demos + linecount = sec->linecount; + for (i = 0; i < (demo_compatibility && sec->linecountlinecount : linecount); i++) + { + if ( twoSided(secnum, i) ) + { + if (getSide(secnum,i,0)->sector-sectors == secnum) + sec = getSector(secnum,i,1); + else + sec = getSector(secnum,i,0); + + if (sec->floorheight == floordestheight) + return sec; + } + } + return NULL; +} + + +// +// P_FindModelCeilingSector() +// +// Passed a ceiling height and a sector number, return a pointer to a +// a sector with that ceiling height across the lowest numbered two sided +// line surrounding the sector. +// +// Note: If no sector at that height bounds the sector passed, return NULL +// +// jff 02/03/98 Add routine to find numeric model ceiling +// around a sector specified by sector number +// used only from generalized ceiling types +// jff 3/14/98 change first parameter to plain height to allow call +// from routine not using ceiling_t +// +sector_t *P_FindModelCeilingSector(fixed_t ceildestheight,int secnum) +{ + int i; + sector_t *sec=NULL; + int linecount; + + sec = §ors[secnum]; //jff 3/2/98 woops! better do this + //jff 5/23/98 don't disturb sec->linecount while searching + // but allow early exit in old demos + linecount = sec->linecount; + for (i = 0; i < (demo_compatibility && sec->linecountlinecount : linecount); i++) + { + if ( twoSided(secnum, i) ) + { + if (getSide(secnum,i,0)->sector-sectors == secnum) + sec = getSector(secnum,i,1); + else + sec = getSector(secnum,i,0); + + if (sec->ceilingheight == ceildestheight) + return sec; + } + } + return NULL; +} + +// +// RETURN NEXT SECTOR # THAT LINE TAG REFERS TO +// + +// Find the next sector with the same tag as a linedef. +// Rewritten by Lee Killough to use chained hashing to improve speed + +int P_FindSectorFromLineTag(const line_t *line, int start) +{ + start = start >= 0 ? sectors[start].nexttag : + sectors[(unsigned) line->tag % (unsigned) numsectors].firsttag; + while (start >= 0 && sectors[start].tag != line->tag) + start = sectors[start].nexttag; + return start; +} + +// killough 4/16/98: Same thing, only for linedefs + +int P_FindLineFromLineTag(const line_t *line, int start) +{ + start = start >= 0 ? lines[start].nexttag : + lines[(unsigned) line->tag % (unsigned) numlines].firsttag; + while (start >= 0 && lines[start].tag != line->tag) + start = lines[start].nexttag; + return start; +} + +// Hash the sector tags across the sectors and linedefs. +static void P_InitTagLists(void) +{ + register int i; + + for (i=numsectors; --i>=0; ) // Initially make all slots empty. + sectors[i].firsttag = -1; + for (i=numsectors; --i>=0; ) // Proceed from last to first sector + { // so that lower sectors appear first + int j = (unsigned) sectors[i].tag % (unsigned) numsectors; // Hash func + sectors[i].nexttag = sectors[j].firsttag; // Prepend sector to chain + sectors[j].firsttag = i; + } + + // killough 4/17/98: same thing, only for linedefs + + for (i=numlines; --i>=0; ) // Initially make all slots empty. + lines[i].firsttag = -1; + for (i=numlines; --i>=0; ) // Proceed from last to first linedef + { // so that lower linedefs appear first + int j = (unsigned) lines[i].tag % (unsigned) numlines; // Hash func + lines[i].nexttag = lines[j].firsttag; // Prepend linedef to chain + lines[j].firsttag = i; + } +} + +// +// P_FindMinSurroundingLight() +// +// Passed a sector and a light level, returns the smallest light level +// in a surrounding sector less than that passed. If no smaller light +// level exists, the light level passed is returned. +// +int P_FindMinSurroundingLight +( sector_t* sector, + int max ) +{ + int i; + int min; + line_t* line; + sector_t* check; + + min = max; + for (i=0 ; i < sector->linecount ; i++) + { + line = sector->lines[i]; + check = getNextSector(line,sector); + + if (!check) + continue; + + if (check->lightlevel < min) + min = check->lightlevel; + } + return min; +} + + +// +// P_CanUnlockGenDoor() +// +// Passed a generalized locked door linedef and a player, returns whether +// the player has the keys necessary to unlock that door. +// +// Note: The linedef passed MUST be a generalized locked door type +// or results are undefined. +// +// jff 02/05/98 routine added to test for unlockability of +// generalized locked doors +// +boolean P_CanUnlockGenDoor +( line_t* line, + player_t* player) +{ + // does this line special distinguish between skulls and keys? + int skulliscard = (line->special & LockedNKeys)>>LockedNKeysShift; + + // determine for each case of lock type if player's keys are adequate + switch((line->special & LockedKey)>>LockedKeyShift) + { + case AnyKey: + if + ( + !player->cards[it_redcard] && + !player->cards[it_redskull] && + !player->cards[it_bluecard] && + !player->cards[it_blueskull] && + !player->cards[it_yellowcard] && + !player->cards[it_yellowskull] + ) + { + player->message = PD_ANY; // Ty 03/27/98 - externalized + S_StartSound(player->mo,sfx_oof); // killough 3/20/98 + return false; + } + break; + case RCard: + if + ( + !player->cards[it_redcard] && + (!skulliscard || !player->cards[it_redskull]) + ) + { + player->message = skulliscard? PD_REDK : PD_REDC; // Ty 03/27/98 - externalized + S_StartSound(player->mo,sfx_oof); // killough 3/20/98 + return false; + } + break; + case BCard: + if + ( + !player->cards[it_bluecard] && + (!skulliscard || !player->cards[it_blueskull]) + ) + { + player->message = skulliscard? PD_BLUEK : PD_BLUEC; // Ty 03/27/98 - externalized + S_StartSound(player->mo,sfx_oof); // killough 3/20/98 + return false; + } + break; + case YCard: + if + ( + !player->cards[it_yellowcard] && + (!skulliscard || !player->cards[it_yellowskull]) + ) + { + player->message = skulliscard? PD_YELLOWK : PD_YELLOWC; // Ty 03/27/98 - externalized + S_StartSound(player->mo,sfx_oof); // killough 3/20/98 + return false; + } + break; + case RSkull: + if + ( + !player->cards[it_redskull] && + (!skulliscard || !player->cards[it_redcard]) + ) + { + player->message = skulliscard? PD_REDK : PD_REDS; // Ty 03/27/98 - externalized + S_StartSound(player->mo,sfx_oof); // killough 3/20/98 + return false; + } + break; + case BSkull: + if + ( + !player->cards[it_blueskull] && + (!skulliscard || !player->cards[it_bluecard]) + ) + { + player->message = skulliscard? PD_BLUEK : PD_BLUES; // Ty 03/27/98 - externalized + S_StartSound(player->mo,sfx_oof); // killough 3/20/98 + return false; + } + break; + case YSkull: + if + ( + !player->cards[it_yellowskull] && + (!skulliscard || !player->cards[it_yellowcard]) + ) + { + player->message = skulliscard? PD_YELLOWK : PD_YELLOWS; // Ty 03/27/98 - externalized + S_StartSound(player->mo,sfx_oof); // killough 3/20/98 + return false; + } + break; + case AllKeys: + if + ( + !skulliscard && + ( + !player->cards[it_redcard] || + !player->cards[it_redskull] || + !player->cards[it_bluecard] || + !player->cards[it_blueskull] || + !player->cards[it_yellowcard] || + !player->cards[it_yellowskull] + ) + ) + { + player->message = PD_ALL6; // Ty 03/27/98 - externalized + S_StartSound(player->mo,sfx_oof); // killough 3/20/98 + return false; + } + if + ( + skulliscard && + ( + (!player->cards[it_redcard] && + !player->cards[it_redskull]) || + (!player->cards[it_bluecard] && + !player->cards[it_blueskull]) || + (!player->cards[it_yellowcard] && + !player->cards[it_yellowskull]) + ) + ) + { + player->message = PD_ALL3; // Ty 03/27/98 - externalized + S_StartSound(player->mo,sfx_oof); // killough 3/20/98 + return false; + } + break; + } + return true; +} + + +// +// P_SectorActive() +// +// Passed a linedef special class (floor, ceiling, lighting) and a sector +// returns whether the sector is already busy with a linedef special of the +// same class. If old demo compatibility true, all linedef special classes +// are the same. +// +// jff 2/23/98 added to prevent old demos from +// succeeding in starting multiple specials on one sector +// +int P_SectorActive(special_e t,sector_t *sec) +{ + if (demo_compatibility) // return whether any thinker is active + return sec->floordata || sec->ceilingdata || sec->lightingdata; + else + switch (t) // return whether thinker of same type is active + { + case floor_special: + return (int)sec->floordata; + case ceiling_special: + return (int)sec->ceilingdata; + case lighting_special: + return (int)sec->lightingdata; + } + return 1; // don't know which special, must be active, shouldn't be here +} + + +// +// P_CheckTag() +// +// Passed a line, returns true if the tag is non-zero or the line special +// allows no tag without harm. If compatibility, all linedef specials are +// allowed to have zero tag. +// +// Note: Only line specials activated by walkover, pushing, or shooting are +// checked by this routine. +// +// jff 2/27/98 Added to check for zero tag allowed for regular special types +// +int P_CheckTag(line_t *line) +{ + /* tag not zero, allowed, or + * killough 11/98: compatibility option */ + if (comp[comp_zerotags] || line->tag) + return 1; + + switch(line->special) + { + case 1: // Manual door specials + case 26: + case 27: + case 28: + case 31: + case 32: + case 33: + case 34: + case 117: + case 118: + + case 139: // Lighting specials + case 170: + case 79: + case 35: + case 138: + case 171: + case 81: + case 13: + case 192: + case 169: + case 80: + case 12: + case 194: + case 173: + case 157: + case 104: + case 193: + case 172: + case 156: + case 17: + + case 195: // Thing teleporters + case 174: + case 97: + case 39: + case 126: + case 125: + case 210: + case 209: + case 208: + case 207: + + case 11: // Exits + case 52: + case 197: + case 51: + case 124: + case 198: + + case 48: // Scrolling walls + case 85: + return 1; // zero tag allowed + + default: + break; + } + return 0; // zero tag not allowed +} + + +// +// P_IsSecret() +// +// Passed a sector, returns if the sector secret type is still active, i.e. +// secret type is set and the secret has not yet been obtained. +// +// jff 3/14/98 added to simplify checks for whether sector is secret +// in automap and other places +// +boolean P_IsSecret(sector_t *sec) +{ + return (sec->special==9 || (sec->special&SECRET_MASK)); +} + + +// +// P_WasSecret() +// +// Passed a sector, returns if the sector secret type is was active, i.e. +// secret type was set and the secret has been obtained already. +// +// jff 3/14/98 added to simplify checks for whether sector is secret +// in automap and other places +// +boolean P_WasSecret(sector_t *sec) +{ + return (sec->oldspecial==9 || (sec->oldspecial&SECRET_MASK)); +} + + +////////////////////////////////////////////////////////////////////////// +// +// Events +// +// Events are operations triggered by using, crossing, +// or shooting special lines, or by timed thinkers. +// +///////////////////////////////////////////////////////////////////////// + +// +// P_CrossSpecialLine - Walkover Trigger Dispatcher +// +// Called every time a thing origin is about +// to cross a line with a non 0 special, whether a walkover type or not. +// +// jff 02/12/98 all W1 lines were fixed to check the result from the EV_ +// function before clearing the special. This avoids losing the function +// of the line, should the sector already be active when the line is +// crossed. Change is qualified by demo_compatibility. +// +// CPhipps - take a line_t pointer instead of a line number, as in MBF +void P_CrossSpecialLine(line_t *line, int side, mobj_t *thing) +{ + int ok; + + // Things that should never trigger lines + if (!thing->player) + { + // Things that should NOT trigger specials... + switch(thing->type) + { + case MT_ROCKET: + case MT_PLASMA: + case MT_BFG: + case MT_TROOPSHOT: + case MT_HEADSHOT: + case MT_BRUISERSHOT: + return; + break; + + default: break; + } + } + + //jff 02/04/98 add check here for generalized lindef types + if (!demo_compatibility) // generalized types not recognized if old demo + { + // pointer to line function is NULL by default, set non-null if + // line special is walkover generalized linedef type + int (*linefunc)(line_t *line)=NULL; + + // check each range of generalized linedefs + if ((unsigned)line->special >= GenEnd) + { + // Out of range for GenFloors + } + else if ((unsigned)line->special >= GenFloorBase) + { + if (!thing->player) + if ((line->special & FloorChange) || !(line->special & FloorModel)) + return; // FloorModel is "Allow Monsters" if FloorChange is 0 + if (!line->tag) //jff 2/27/98 all walk generalized types require tag + return; + linefunc = EV_DoGenFloor; + } + else if ((unsigned)line->special >= GenCeilingBase) + { + if (!thing->player) + if ((line->special & CeilingChange) || !(line->special & CeilingModel)) + return; // CeilingModel is "Allow Monsters" if CeilingChange is 0 + if (!line->tag) //jff 2/27/98 all walk generalized types require tag + return; + linefunc = EV_DoGenCeiling; + } + else if ((unsigned)line->special >= GenDoorBase) + { + if (!thing->player) + { + if (!(line->special & DoorMonster)) + return; // monsters disallowed from this door + if (line->flags & ML_SECRET) // they can't open secret doors either + return; + } + if (!line->tag) //3/2/98 move outside the monster check + return; + linefunc = EV_DoGenDoor; + } + else if ((unsigned)line->special >= GenLockedBase) + { + if (!thing->player) + return; // monsters disallowed from unlocking doors + if (((line->special&TriggerType)==WalkOnce) || ((line->special&TriggerType)==WalkMany)) + { //jff 4/1/98 check for being a walk type before reporting door type + if (!P_CanUnlockGenDoor(line,thing->player)) + return; + } + else + return; + linefunc = EV_DoGenLockedDoor; + } + else if ((unsigned)line->special >= GenLiftBase) + { + if (!thing->player) + if (!(line->special & LiftMonster)) + return; // monsters disallowed + if (!line->tag) //jff 2/27/98 all walk generalized types require tag + return; + linefunc = EV_DoGenLift; + } + else if ((unsigned)line->special >= GenStairsBase) + { + if (!thing->player) + if (!(line->special & StairMonster)) + return; // monsters disallowed + if (!line->tag) //jff 2/27/98 all walk generalized types require tag + return; + linefunc = EV_DoGenStairs; + } + + if (linefunc) // if it was a valid generalized type + switch((line->special & TriggerType) >> TriggerTypeShift) + { + case WalkOnce: + if (linefunc(line)) + line->special = 0; // clear special if a walk once type + return; + case WalkMany: + linefunc(line); + return; + default: // if not a walk type, do nothing here + return; + } + } + + if (!thing->player) + { + ok = 0; + switch(line->special) + { + case 39: // teleport trigger + case 97: // teleport retrigger + case 125: // teleport monsteronly trigger + case 126: // teleport monsteronly retrigger + case 4: // raise door + case 10: // plat down-wait-up-stay trigger + case 88: // plat down-wait-up-stay retrigger + //jff 3/5/98 add ability of monsters etc. to use teleporters + case 208: //silent thing teleporters + case 207: + case 243: //silent line-line teleporter + case 244: //jff 3/6/98 make fit within DCK's 256 linedef types + case 262: //jff 4/14/98 add monster only + case 263: //jff 4/14/98 silent thing,line,line rev types + case 264: //jff 4/14/98 plus player/monster silent line + case 265: // reversed types + case 266: + case 267: + case 268: + case 269: + ok = 1; + break; + } + if (!ok) + return; + } + + if (!P_CheckTag(line)) //jff 2/27/98 disallow zero tag on some types + return; + + // Dispatch on the line special value to the line's action routine + // If a once only function, and successful, clear the line special + + switch (line->special) + { + // Regular walk once triggers + + case 2: + // Open Door + if (EV_DoDoor(line,p_open) || demo_compatibility) + line->special = 0; + break; + + case 3: + // Close Door + if (EV_DoDoor(line,p_close) || demo_compatibility) + line->special = 0; + break; + + case 4: + // Raise Door + if (EV_DoDoor(line,normal) || demo_compatibility) + line->special = 0; + break; + + case 5: + // Raise Floor + if (EV_DoFloor(line,raiseFloor) || demo_compatibility) + line->special = 0; + break; + + case 6: + // Fast Ceiling Crush & Raise + if (EV_DoCeiling(line,fastCrushAndRaise) || demo_compatibility) + line->special = 0; + break; + + case 8: + // Build Stairs + if (EV_BuildStairs(line,build8) || demo_compatibility) + line->special = 0; + break; + + case 10: + // PlatDownWaitUp + if (EV_DoPlat(line,downWaitUpStay,0) || demo_compatibility) + line->special = 0; + break; + + case 12: + // Light Turn On - brightest near + if (EV_LightTurnOn(line,0) || demo_compatibility) + line->special = 0; + break; + + case 13: + // Light Turn On 255 + if (EV_LightTurnOn(line,255) || demo_compatibility) + line->special = 0; + break; + + case 16: + // Close Door 30 + if (EV_DoDoor(line,close30ThenOpen) || demo_compatibility) + line->special = 0; + break; + + case 17: + // Start Light Strobing + if (EV_StartLightStrobing(line) || demo_compatibility) + line->special = 0; + break; + + case 19: + // Lower Floor + if (EV_DoFloor(line,lowerFloor) || demo_compatibility) + line->special = 0; + break; + + case 22: + // Raise floor to nearest height and change texture + if (EV_DoPlat(line,raiseToNearestAndChange,0) || demo_compatibility) + line->special = 0; + break; + + case 25: + // Ceiling Crush and Raise + if (EV_DoCeiling(line,crushAndRaise) || demo_compatibility) + line->special = 0; + break; + + case 30: + // Raise floor to shortest texture height + // on either side of lines. + if (EV_DoFloor(line,raiseToTexture) || demo_compatibility) + line->special = 0; + break; + + case 35: + // Lights Very Dark + if (EV_LightTurnOn(line,35) || demo_compatibility) + line->special = 0; + break; + + case 36: + // Lower Floor (TURBO) + if (EV_DoFloor(line,turboLower) || demo_compatibility) + line->special = 0; + break; + + case 37: + // LowerAndChange + if (EV_DoFloor(line,lowerAndChange) || demo_compatibility) + line->special = 0; + break; + + case 38: + // Lower Floor To Lowest + if (EV_DoFloor(line, lowerFloorToLowest) || demo_compatibility) + line->special = 0; + break; + + case 39: + // TELEPORT! //jff 02/09/98 fix using up with wrong side crossing + if (EV_Teleport(line, side, thing) || demo_compatibility) + line->special = 0; + break; + + case 40: + // RaiseCeilingLowerFloor + if (demo_compatibility) + { + EV_DoCeiling( line, raiseToHighest ); + EV_DoFloor( line, lowerFloorToLowest ); //jff 02/12/98 doesn't work + line->special = 0; + } + else + if (EV_DoCeiling(line, raiseToHighest)) + line->special = 0; + break; + + case 44: + // Ceiling Crush + if (EV_DoCeiling(line, lowerAndCrush) || demo_compatibility) + line->special = 0; + break; + + case 52: + // EXIT! + // killough 10/98: prevent zombies from exiting levels + if (!(thing->player && thing->player->health <= 0 && !comp[comp_zombie])) + G_ExitLevel (); + break; + + case 53: + // Perpetual Platform Raise + if (EV_DoPlat(line,perpetualRaise,0) || demo_compatibility) + line->special = 0; + break; + + case 54: + // Platform Stop + if (EV_StopPlat(line) || demo_compatibility) + line->special = 0; + break; + + case 56: + // Raise Floor Crush + if (EV_DoFloor(line,raiseFloorCrush) || demo_compatibility) + line->special = 0; + break; + + case 57: + // Ceiling Crush Stop + if (EV_CeilingCrushStop(line) || demo_compatibility) + line->special = 0; + break; + + case 58: + // Raise Floor 24 + if (EV_DoFloor(line,raiseFloor24) || demo_compatibility) + line->special = 0; + break; + + case 59: + // Raise Floor 24 And Change + if (EV_DoFloor(line,raiseFloor24AndChange) || demo_compatibility) + line->special = 0; + break; + + case 100: + // Build Stairs Turbo 16 + if (EV_BuildStairs(line,turbo16) || demo_compatibility) + line->special = 0; + break; + + case 104: + // Turn lights off in sector(tag) + if (EV_TurnTagLightsOff(line) || demo_compatibility) + line->special = 0; + break; + + case 108: + // Blazing Door Raise (faster than TURBO!) + if (EV_DoDoor(line,blazeRaise) || demo_compatibility) + line->special = 0; + break; + + case 109: + // Blazing Door Open (faster than TURBO!) + if (EV_DoDoor (line,blazeOpen) || demo_compatibility) + line->special = 0; + break; + + case 110: + // Blazing Door Close (faster than TURBO!) + if (EV_DoDoor (line,blazeClose) || demo_compatibility) + line->special = 0; + break; + + case 119: + // Raise floor to nearest surr. floor + if (EV_DoFloor(line,raiseFloorToNearest) || demo_compatibility) + line->special = 0; + break; + + case 121: + // Blazing PlatDownWaitUpStay + if (EV_DoPlat(line,blazeDWUS,0) || demo_compatibility) + line->special = 0; + break; + + case 124: + // Secret EXIT + // killough 10/98: prevent zombies from exiting levels + // CPhipps - change for lxdoom's compatibility handling + if (!(thing->player && thing->player->health <= 0 && !comp[comp_zombie])) + G_SecretExitLevel (); + break; + + case 125: + // TELEPORT MonsterONLY + if (!thing->player && + (EV_Teleport(line, side, thing) || demo_compatibility)) + line->special = 0; + break; + + case 130: + // Raise Floor Turbo + if (EV_DoFloor(line,raiseFloorTurbo) || demo_compatibility) + line->special = 0; + break; + + case 141: + // Silent Ceiling Crush & Raise + if (EV_DoCeiling(line,silentCrushAndRaise) || demo_compatibility) + line->special = 0; + break; + + // Regular walk many retriggerable + + case 72: + // Ceiling Crush + EV_DoCeiling( line, lowerAndCrush ); + break; + + case 73: + // Ceiling Crush and Raise + EV_DoCeiling(line,crushAndRaise); + break; + + case 74: + // Ceiling Crush Stop + EV_CeilingCrushStop(line); + break; + + case 75: + // Close Door + EV_DoDoor(line,p_close); + break; + + case 76: + // Close Door 30 + EV_DoDoor(line,close30ThenOpen); + break; + + case 77: + // Fast Ceiling Crush & Raise + EV_DoCeiling(line,fastCrushAndRaise); + break; + + case 79: + // Lights Very Dark + EV_LightTurnOn(line,35); + break; + + case 80: + // Light Turn On - brightest near + EV_LightTurnOn(line,0); + break; + + case 81: + // Light Turn On 255 + EV_LightTurnOn(line,255); + break; + + case 82: + // Lower Floor To Lowest + EV_DoFloor( line, lowerFloorToLowest ); + break; + + case 83: + // Lower Floor + EV_DoFloor(line,lowerFloor); + break; + + case 84: + // LowerAndChange + EV_DoFloor(line,lowerAndChange); + break; + + case 86: + // Open Door + EV_DoDoor(line,p_open); + break; + + case 87: + // Perpetual Platform Raise + EV_DoPlat(line,perpetualRaise,0); + break; + + case 88: + // PlatDownWaitUp + EV_DoPlat(line,downWaitUpStay,0); + break; + + case 89: + // Platform Stop + EV_StopPlat(line); + break; + + case 90: + // Raise Door + EV_DoDoor(line,normal); + break; + + case 91: + // Raise Floor + EV_DoFloor(line,raiseFloor); + break; + + case 92: + // Raise Floor 24 + EV_DoFloor(line,raiseFloor24); + break; + + case 93: + // Raise Floor 24 And Change + EV_DoFloor(line,raiseFloor24AndChange); + break; + + case 94: + // Raise Floor Crush + EV_DoFloor(line,raiseFloorCrush); + break; + + case 95: + // Raise floor to nearest height + // and change texture. + EV_DoPlat(line,raiseToNearestAndChange,0); + break; + + case 96: + // Raise floor to shortest texture height + // on either side of lines. + EV_DoFloor(line,raiseToTexture); + break; + + case 97: + // TELEPORT! + EV_Teleport( line, side, thing ); + break; + + case 98: + // Lower Floor (TURBO) + EV_DoFloor(line,turboLower); + break; + + case 105: + // Blazing Door Raise (faster than TURBO!) + EV_DoDoor (line,blazeRaise); + break; + + case 106: + // Blazing Door Open (faster than TURBO!) + EV_DoDoor (line,blazeOpen); + break; + + case 107: + // Blazing Door Close (faster than TURBO!) + EV_DoDoor (line,blazeClose); + break; + + case 120: + // Blazing PlatDownWaitUpStay. + EV_DoPlat(line,blazeDWUS,0); + break; + + case 126: + // TELEPORT MonsterONLY. + if (!thing->player) + EV_Teleport( line, side, thing ); + break; + + case 128: + // Raise To Nearest Floor + EV_DoFloor(line,raiseFloorToNearest); + break; + + case 129: + // Raise Floor Turbo + EV_DoFloor(line,raiseFloorTurbo); + break; + + // Extended walk triggers + + // jff 1/29/98 added new linedef types to fill all functions out so that + // all have varieties SR, S1, WR, W1 + + // killough 1/31/98: "factor out" compatibility test, by + // adding inner switch qualified by compatibility flag. + // relax test to demo_compatibility + + // killough 2/16/98: Fix problems with W1 types being cleared too early + + default: + if (!demo_compatibility) + switch (line->special) + { + // Extended walk once triggers + + case 142: + // Raise Floor 512 + // 142 W1 EV_DoFloor(raiseFloor512) + if (EV_DoFloor(line,raiseFloor512)) + line->special = 0; + break; + + case 143: + // Raise Floor 24 and change + // 143 W1 EV_DoPlat(raiseAndChange,24) + if (EV_DoPlat(line,raiseAndChange,24)) + line->special = 0; + break; + + case 144: + // Raise Floor 32 and change + // 144 W1 EV_DoPlat(raiseAndChange,32) + if (EV_DoPlat(line,raiseAndChange,32)) + line->special = 0; + break; + + case 145: + // Lower Ceiling to Floor + // 145 W1 EV_DoCeiling(lowerToFloor) + if (EV_DoCeiling( line, lowerToFloor )) + line->special = 0; + break; + + case 146: + // Lower Pillar, Raise Donut + // 146 W1 EV_DoDonut() + if (EV_DoDonut(line)) + line->special = 0; + break; + + case 199: + // Lower ceiling to lowest surrounding ceiling + // 199 W1 EV_DoCeiling(lowerToLowest) + if (EV_DoCeiling(line,lowerToLowest)) + line->special = 0; + break; + + case 200: + // Lower ceiling to highest surrounding floor + // 200 W1 EV_DoCeiling(lowerToMaxFloor) + if (EV_DoCeiling(line,lowerToMaxFloor)) + line->special = 0; + break; + + case 207: + // killough 2/16/98: W1 silent teleporter (normal kind) + if (EV_SilentTeleport(line, side, thing)) + line->special = 0; + break; + + //jff 3/16/98 renumber 215->153 + case 153: //jff 3/15/98 create texture change no motion type + // Texture/Type Change Only (Trig) + // 153 W1 Change Texture/Type Only + if (EV_DoChange(line,trigChangeOnly)) + line->special = 0; + break; + + case 239: //jff 3/15/98 create texture change no motion type + // Texture/Type Change Only (Numeric) + // 239 W1 Change Texture/Type Only + if (EV_DoChange(line,numChangeOnly)) + line->special = 0; + break; + + case 219: + // Lower floor to next lower neighbor + // 219 W1 Lower Floor Next Lower Neighbor + if (EV_DoFloor(line,lowerFloorToNearest)) + line->special = 0; + break; + + case 227: + // Raise elevator next floor + // 227 W1 Raise Elevator next floor + if (EV_DoElevator(line,elevateUp)) + line->special = 0; + break; + + case 231: + // Lower elevator next floor + // 231 W1 Lower Elevator next floor + if (EV_DoElevator(line,elevateDown)) + line->special = 0; + break; + + case 235: + // Elevator to current floor + // 235 W1 Elevator to current floor + if (EV_DoElevator(line,elevateCurrent)) + line->special = 0; + break; + + case 243: //jff 3/6/98 make fit within DCK's 256 linedef types + // killough 2/16/98: W1 silent teleporter (linedef-linedef kind) + if (EV_SilentLineTeleport(line, side, thing, false)) + line->special = 0; + break; + + case 262: //jff 4/14/98 add silent line-line reversed + if (EV_SilentLineTeleport(line, side, thing, true)) + line->special = 0; + break; + + case 264: //jff 4/14/98 add monster-only silent line-line reversed + if (!thing->player && + EV_SilentLineTeleport(line, side, thing, true)) + line->special = 0; + break; + + case 266: //jff 4/14/98 add monster-only silent line-line + if (!thing->player && + EV_SilentLineTeleport(line, side, thing, false)) + line->special = 0; + break; + + case 268: //jff 4/14/98 add monster-only silent + if (!thing->player && EV_SilentTeleport(line, side, thing)) + line->special = 0; + break; + + //jff 1/29/98 end of added W1 linedef types + + // Extended walk many retriggerable + + //jff 1/29/98 added new linedef types to fill all functions + //out so that all have varieties SR, S1, WR, W1 + + case 147: + // Raise Floor 512 + // 147 WR EV_DoFloor(raiseFloor512) + EV_DoFloor(line,raiseFloor512); + break; + + case 148: + // Raise Floor 24 and Change + // 148 WR EV_DoPlat(raiseAndChange,24) + EV_DoPlat(line,raiseAndChange,24); + break; + + case 149: + // Raise Floor 32 and Change + // 149 WR EV_DoPlat(raiseAndChange,32) + EV_DoPlat(line,raiseAndChange,32); + break; + + case 150: + // Start slow silent crusher + // 150 WR EV_DoCeiling(silentCrushAndRaise) + EV_DoCeiling(line,silentCrushAndRaise); + break; + + case 151: + // RaiseCeilingLowerFloor + // 151 WR EV_DoCeiling(raiseToHighest), + // EV_DoFloor(lowerFloortoLowest) + EV_DoCeiling( line, raiseToHighest ); + EV_DoFloor( line, lowerFloorToLowest ); + break; + + case 152: + // Lower Ceiling to Floor + // 152 WR EV_DoCeiling(lowerToFloor) + EV_DoCeiling( line, lowerToFloor ); + break; + + //jff 3/16/98 renumber 153->256 + case 256: + // Build stairs, step 8 + // 256 WR EV_BuildStairs(build8) + EV_BuildStairs(line,build8); + break; + + //jff 3/16/98 renumber 154->257 + case 257: + // Build stairs, step 16 + // 257 WR EV_BuildStairs(turbo16) + EV_BuildStairs(line,turbo16); + break; + + case 155: + // Lower Pillar, Raise Donut + // 155 WR EV_DoDonut() + EV_DoDonut(line); + break; + + case 156: + // Start lights strobing + // 156 WR Lights EV_StartLightStrobing() + EV_StartLightStrobing(line); + break; + + case 157: + // Lights to dimmest near + // 157 WR Lights EV_TurnTagLightsOff() + EV_TurnTagLightsOff(line); + break; + + case 201: + // Lower ceiling to lowest surrounding ceiling + // 201 WR EV_DoCeiling(lowerToLowest) + EV_DoCeiling(line,lowerToLowest); + break; + + case 202: + // Lower ceiling to highest surrounding floor + // 202 WR EV_DoCeiling(lowerToMaxFloor) + EV_DoCeiling(line,lowerToMaxFloor); + break; + + case 208: + // killough 2/16/98: WR silent teleporter (normal kind) + EV_SilentTeleport(line, side, thing); + break; + + case 212: //jff 3/14/98 create instant toggle floor type + // Toggle floor between C and F instantly + // 212 WR Instant Toggle Floor + EV_DoPlat(line,toggleUpDn,0); + break; + + //jff 3/16/98 renumber 216->154 + case 154: //jff 3/15/98 create texture change no motion type + // Texture/Type Change Only (Trigger) + // 154 WR Change Texture/Type Only + EV_DoChange(line,trigChangeOnly); + break; + + case 240: //jff 3/15/98 create texture change no motion type + // Texture/Type Change Only (Numeric) + // 240 WR Change Texture/Type Only + EV_DoChange(line,numChangeOnly); + break; + + case 220: + // Lower floor to next lower neighbor + // 220 WR Lower Floor Next Lower Neighbor + EV_DoFloor(line,lowerFloorToNearest); + break; + + case 228: + // Raise elevator next floor + // 228 WR Raise Elevator next floor + EV_DoElevator(line,elevateUp); + break; + + case 232: + // Lower elevator next floor + // 232 WR Lower Elevator next floor + EV_DoElevator(line,elevateDown); + break; + + case 236: + // Elevator to current floor + // 236 WR Elevator to current floor + EV_DoElevator(line,elevateCurrent); + break; + + case 244: //jff 3/6/98 make fit within DCK's 256 linedef types + // killough 2/16/98: WR silent teleporter (linedef-linedef kind) + EV_SilentLineTeleport(line, side, thing, false); + break; + + case 263: //jff 4/14/98 add silent line-line reversed + EV_SilentLineTeleport(line, side, thing, true); + break; + + case 265: //jff 4/14/98 add monster-only silent line-line reversed + if (!thing->player) + EV_SilentLineTeleport(line, side, thing, true); + break; + + case 267: //jff 4/14/98 add monster-only silent line-line + if (!thing->player) + EV_SilentLineTeleport(line, side, thing, false); + break; + + case 269: //jff 4/14/98 add monster-only silent + if (!thing->player) + EV_SilentTeleport(line, side, thing); + break; + + //jff 1/29/98 end of added WR linedef types + } + break; + } +} + +// +// P_ShootSpecialLine - Gun trigger special dispatcher +// +// Called when a thing shoots a special line with bullet, shell, saw, or fist. +// +// jff 02/12/98 all G1 lines were fixed to check the result from the EV_ +// function before clearing the special. This avoids losing the function +// of the line, should the sector already be in motion when the line is +// impacted. Change is qualified by demo_compatibility. +// +void P_ShootSpecialLine +( mobj_t* thing, + line_t* line ) +{ + //jff 02/04/98 add check here for generalized linedef + if (!demo_compatibility) + { + // pointer to line function is NULL by default, set non-null if + // line special is gun triggered generalized linedef type + int (*linefunc)(line_t *line)=NULL; + + // check each range of generalized linedefs + if ((unsigned)line->special >= GenEnd) + { + // Out of range for GenFloors + } + else if ((unsigned)line->special >= GenFloorBase) + { + if (!thing->player) + if ((line->special & FloorChange) || !(line->special & FloorModel)) + return; // FloorModel is "Allow Monsters" if FloorChange is 0 + if (!line->tag) //jff 2/27/98 all gun generalized types require tag + return; + + linefunc = EV_DoGenFloor; + } + else if ((unsigned)line->special >= GenCeilingBase) + { + if (!thing->player) + if ((line->special & CeilingChange) || !(line->special & CeilingModel)) + return; // CeilingModel is "Allow Monsters" if CeilingChange is 0 + if (!line->tag) //jff 2/27/98 all gun generalized types require tag + return; + linefunc = EV_DoGenCeiling; + } + else if ((unsigned)line->special >= GenDoorBase) + { + if (!thing->player) + { + if (!(line->special & DoorMonster)) + return; // monsters disallowed from this door + if (line->flags & ML_SECRET) // they can't open secret doors either + return; + } + if (!line->tag) //jff 3/2/98 all gun generalized types require tag + return; + linefunc = EV_DoGenDoor; + } + else if ((unsigned)line->special >= GenLockedBase) + { + if (!thing->player) + return; // monsters disallowed from unlocking doors + if (((line->special&TriggerType)==GunOnce) || ((line->special&TriggerType)==GunMany)) + { //jff 4/1/98 check for being a gun type before reporting door type + if (!P_CanUnlockGenDoor(line,thing->player)) + return; + } + else + return; + if (!line->tag) //jff 2/27/98 all gun generalized types require tag + return; + + linefunc = EV_DoGenLockedDoor; + } + else if ((unsigned)line->special >= GenLiftBase) + { + if (!thing->player) + if (!(line->special & LiftMonster)) + return; // monsters disallowed + linefunc = EV_DoGenLift; + } + else if ((unsigned)line->special >= GenStairsBase) + { + if (!thing->player) + if (!(line->special & StairMonster)) + return; // monsters disallowed + if (!line->tag) //jff 2/27/98 all gun generalized types require tag + return; + linefunc = EV_DoGenStairs; + } + else if ((unsigned)line->special >= GenCrusherBase) + { + if (!thing->player) + if (!(line->special & StairMonster)) + return; // monsters disallowed + if (!line->tag) //jff 2/27/98 all gun generalized types require tag + return; + linefunc = EV_DoGenCrusher; + } + + if (linefunc) + switch((line->special & TriggerType) >> TriggerTypeShift) + { + case GunOnce: + if (linefunc(line)) + P_ChangeSwitchTexture(line,0); + return; + case GunMany: + if (linefunc(line)) + P_ChangeSwitchTexture(line,1); + return; + default: // if not a gun type, do nothing here + return; + } + } + + // Impacts that other things can activate. + if (!thing->player) + { + int ok = 0; + switch(line->special) + { + case 46: + // 46 GR Open door on impact weapon is monster activatable + ok = 1; + break; + } + if (!ok) + return; + } + + if (!P_CheckTag(line)) //jff 2/27/98 disallow zero tag on some types + return; + + switch(line->special) + { + case 24: + // 24 G1 raise floor to highest adjacent + if (EV_DoFloor(line,raiseFloor) || demo_compatibility) + P_ChangeSwitchTexture(line,0); + break; + + case 46: + // 46 GR open door, stay open + EV_DoDoor(line,p_open); + P_ChangeSwitchTexture(line,1); + break; + + case 47: + // 47 G1 raise floor to nearest and change texture and type + if (EV_DoPlat(line,raiseToNearestAndChange,0) || demo_compatibility) + P_ChangeSwitchTexture(line,0); + break; + + //jff 1/30/98 added new gun linedefs here + // killough 1/31/98: added demo_compatibility check, added inner switch + + default: + if (!demo_compatibility) + switch (line->special) + { + case 197: + // Exit to next level + // killough 10/98: prevent zombies from exiting levels + if(thing->player && thing->player->health<=0 && !comp[comp_zombie]) + break; + P_ChangeSwitchTexture(line,0); + G_ExitLevel(); + break; + + case 198: + // Exit to secret level + // killough 10/98: prevent zombies from exiting levels + if(thing->player && thing->player->health<=0 && !comp[comp_zombie]) + break; + P_ChangeSwitchTexture(line,0); + G_SecretExitLevel(); + break; + //jff end addition of new gun linedefs + } + break; + } +} + + +// +// P_PlayerInSpecialSector() +// +// Called every tick frame +// that the player origin is in a special sector +// +// Changed to ignore sector types the engine does not recognize +// +void P_PlayerInSpecialSector (player_t* player) +{ + sector_t* sector; + + sector = player->mo->subsector->sector; + + // Falling, not all the way down yet? + // Sector specials don't apply in mid-air + if (player->mo->z != sector->floorheight) + return; + + // Has hit ground. + //jff add if to handle old vs generalized types + if (sector->special<32) // regular sector specials + { + switch (sector->special) + { + case 5: + // 5/10 unit damage per 31 ticks + if (!player->powers[pw_ironfeet]) + if (!(leveltime&0x1f)) + P_DamageMobj (player->mo, NULL, NULL, 10); + break; + + case 7: + // 2/5 unit damage per 31 ticks + if (!player->powers[pw_ironfeet]) + if (!(leveltime&0x1f)) + P_DamageMobj (player->mo, NULL, NULL, 5); + break; + + case 16: + // 10/20 unit damage per 31 ticks + case 4: + // 10/20 unit damage plus blinking light (light already spawned) + if (!player->powers[pw_ironfeet] + || (P_Random(pr_slimehurt)<5) ) // even with suit, take damage + { + if (!(leveltime&0x1f)) + P_DamageMobj (player->mo, NULL, NULL, 20); + } + break; + + case 9: + // Tally player in secret sector, clear secret special + player->secretcount++; + sector->special = 0; + break; + + case 11: + // Exit on health < 11, take 10/20 damage per 31 ticks + if (comp[comp_god]) /* killough 2/21/98: add compatibility switch */ + player->cheats &= ~CF_GODMODE; // on godmode cheat clearing + // does not affect invulnerability + if (!(leveltime&0x1f)) + P_DamageMobj (player->mo, NULL, NULL, 20); + + if (player->health <= 10) + G_ExitLevel(); + break; + + default: + //jff 1/24/98 Don't exit as DOOM2 did, just ignore + break; + }; + } + else //jff 3/14/98 handle extended sector types for secrets and damage + { + switch ((sector->special&DAMAGE_MASK)>>DAMAGE_SHIFT) + { + case 0: // no damage + break; + case 1: // 2/5 damage per 31 ticks + if (!player->powers[pw_ironfeet]) + if (!(leveltime&0x1f)) + P_DamageMobj (player->mo, NULL, NULL, 5); + break; + case 2: // 5/10 damage per 31 ticks + if (!player->powers[pw_ironfeet]) + if (!(leveltime&0x1f)) + P_DamageMobj (player->mo, NULL, NULL, 10); + break; + case 3: // 10/20 damage per 31 ticks + if (!player->powers[pw_ironfeet] + || (P_Random(pr_slimehurt)<5)) // take damage even with suit + { + if (!(leveltime&0x1f)) + P_DamageMobj (player->mo, NULL, NULL, 20); + } + break; + } + if (sector->special&SECRET_MASK) + { + player->secretcount++; + sector->special &= ~SECRET_MASK; + if (sector->special<32) // if all extended bits clear, + sector->special=0; // sector is not special anymore + } + + // phares 3/19/98: + // + // If FRICTION_MASK or PUSH_MASK is set, we don't care at this + // point, since the code to deal with those situations is + // handled by Thinkers. + + } +} + +// +// P_UpdateSpecials() +// +// Check level timer, frag counter, +// animate flats, scroll walls, +// change button textures +// +// Reads and modifies globals: +// levelTimer, levelTimeCount, +// levelFragLimit, levelFragLimitCount +// + +boolean levelTimer; +int levelTimeCount; +boolean levelFragLimit; // Ty 03/18/98 Added -frags support +int levelFragLimitCount; // Ty 03/18/98 Added -frags support + +void P_UpdateSpecials (void) +{ + anim_t* anim; + int pic; + int i; + + // Downcount level timer, exit level if elapsed + if (levelTimer == true) + { + levelTimeCount--; + if (!levelTimeCount) + G_ExitLevel(); + } + + // Check frag counters, if frag limit reached, exit level // Ty 03/18/98 + // Seems like the total frags should be kept in a simple + // array somewhere, but until they are... + if (levelFragLimit == true) // we used -frags so compare count + { + int k,m,fragcount,exitflag=false; + for (k=0;k= levelFragLimitCount) exitflag = true; + if (exitflag == true) break; // skip out of the loop--we're done + } + if (exitflag == true) + G_ExitLevel(); + } + + // Animate flats and textures globally + for (anim = anims ; anim < lastanim ; anim++) + { + for (i=anim->basepic ; ibasepic+anim->numpics ; i++) + { + pic = anim->basepic + ( (leveltime/anim->speed + i)%anim->numpics ); + if (anim->istexture) + texturetranslation[i] = pic; + else + flattranslation[i] = pic; + } + } + + // Check buttons (retriggerable switches) and change texture on timeout + for (i = 0; i < MAXBUTTONS; i++) + if (buttonlist[i].btimer) + { + buttonlist[i].btimer--; + if (!buttonlist[i].btimer) + { + switch(buttonlist[i].where) + { + case top: + sides[buttonlist[i].line->sidenum[0]].toptexture = + buttonlist[i].btexture; + break; + + case middle: + sides[buttonlist[i].line->sidenum[0]].midtexture = + buttonlist[i].btexture; + break; + + case bottom: + sides[buttonlist[i].line->sidenum[0]].bottomtexture = + buttonlist[i].btexture; + break; + } + S_StartSound((mobj_t *)&buttonlist[i].soundorg,sfx_swtchn); + memset(&buttonlist[i],0,sizeof(button_t)); + } + } +} + +////////////////////////////////////////////////////////////////////// +// +// Sector and Line special thinker spawning at level startup +// +////////////////////////////////////////////////////////////////////// + +// +// P_SpawnSpecials +// After the map has been loaded, +// scan for specials that spawn thinkers +// + +// Parses command line parameters. +void P_SpawnSpecials (void) +{ + sector_t* sector; + int i; + int episode; + + episode = 1; + if (W_CheckNumForName("texture2") >= 0) + episode = 2; + + // See if -timer needs to be used. + levelTimer = false; + + i = M_CheckParm("-avg"); // Austin Virtual Gaming 20 min timer on DM play + if (i && deathmatch) + { + levelTimer = true; + levelTimeCount = 20 * 60 * TICRATE; + } + + i = M_CheckParm("-timer"); // user defined timer on game play + if (i && deathmatch) + { + int time; + time = atoi(myargv[i+1]) * 60 * TICRATE; + levelTimer = true; + levelTimeCount = time; + } + + // See if -frags has been used + levelFragLimit = false; + i = M_CheckParm("-frags"); // Ty 03/18/98 Added -frags support + if (i && deathmatch) + { + int frags; + frags = atoi(myargv[i+1]); + if (frags <= 0) frags = 10; // default 10 if no count provided + levelFragLimit = true; + levelFragLimitCount = frags; + } + + + // Init special sectors. + sector = sectors; + for (i=0 ; ispecial) + continue; + + if (sector->special&SECRET_MASK) //jff 3/15/98 count extended + totalsecret++; // secret sectors too + + switch (sector->special&31) + { + case 1: + // random off + P_SpawnLightFlash (sector); + break; + + case 2: + // strobe fast + P_SpawnStrobeFlash(sector,FASTDARK,0); + break; + + case 3: + // strobe slow + P_SpawnStrobeFlash(sector,SLOWDARK,0); + break; + + case 4: + // strobe fast/death slime + P_SpawnStrobeFlash(sector,FASTDARK,0); + sector->special |= 3<special<32) //jff 3/14/98 bits don't count unless not + totalsecret++; // a generalized sector type + break; + + case 10: + // door close in 30 seconds + P_SpawnDoorCloseIn30 (sector); + break; + + case 12: + // sync strobe slow + P_SpawnStrobeFlash (sector, SLOWDARK, 1); + break; + + case 13: + // sync strobe fast + P_SpawnStrobeFlash (sector, FASTDARK, 1); + break; + + case 14: + // door raise in 5 minutes + P_SpawnDoorRaiseIn5Mins (sector, i); + break; + + case 17: + // fire flickering + P_SpawnFireFlicker(sector); + break; + } + } + + P_RemoveAllActiveCeilings(); // jff 2/22/98 use killough's scheme + + P_RemoveAllActivePlats(); // killough + + for (i = 0;i < MAXBUTTONS;i++) + memset(&buttonlist[i],0,sizeof(button_t)); + + // P_InitTagLists() must be called before P_FindSectorFromLineTag() + // or P_FindLineFromLineTag() can be called. + + P_InitTagLists(); // killough 1/30/98: Create xref tables for tags + + P_SpawnScrollers(); // killough 3/7/98: Add generalized scrollers + + P_SpawnFriction(); // phares 3/12/98: New friction model using linedefs + + P_SpawnPushers(); // phares 3/20/98: New pusher model using linedefs + + for (i=0; i= 0;) + sectors[s].heightsec = sec; + break; + + // killough 3/16/98: Add support for setting + // floor lighting independently (e.g. lava) + case 213: + sec = sides[*lines[i].sidenum].sector-sectors; + for (s = -1; (s = P_FindSectorFromLineTag(lines+i,s)) >= 0;) + sectors[s].floorlightsec = sec; + break; + + // killough 4/11/98: Add support for setting + // ceiling lighting independently + case 261: + sec = sides[*lines[i].sidenum].sector-sectors; + for (s = -1; (s = P_FindSectorFromLineTag(lines+i,s)) >= 0;) + sectors[s].ceilinglightsec = sec; + break; + + // killough 10/98: + // + // Support for sky textures being transferred from sidedefs. + // Allows scrolling and other effects (but if scrolling is + // used, then the same sector tag needs to be used for the + // sky sector, the sky-transfer linedef, and the scroll-effect + // linedef). Still requires user to use F_SKY1 for the floor + // or ceiling texture, to distinguish floor and ceiling sky. + + case 271: // Regular sky + case 272: // Same, only flipped + for (s = -1; (s = P_FindSectorFromLineTag(lines+i,s)) >= 0;) + sectors[s].sky = i | PL_SKYFLAT; + break; + } +} + +// killough 2/28/98: +// +// This function, with the help of r_plane.c and r_bsp.c, supports generalized +// scrolling floors and walls, with optional mobj-carrying properties, e.g. +// conveyor belts, rivers, etc. A linedef with a special type affects all +// tagged sectors the same way, by creating scrolling and/or object-carrying +// properties. Multiple linedefs may be used on the same sector and are +// cumulative, although the special case of scrolling a floor and carrying +// things on it, requires only one linedef. The linedef's direction determines +// the scrolling direction, and the linedef's length determines the scrolling +// speed. This was designed so that an edge around the sector could be used to +// control the direction of the sector's scrolling, which is usually what is +// desired. +// +// Process the active scrollers. +// +// This is the main scrolling code +// killough 3/7/98 + +void T_Scroll(scroll_t *s) +{ + fixed_t dx = s->dx, dy = s->dy; + + if (s->control != -1) + { // compute scroll amounts based on a sector's height changes + fixed_t height = sectors[s->control].floorheight + + sectors[s->control].ceilingheight; + fixed_t delta = height - s->last_height; + s->last_height = height; + dx = FixedMul(dx, delta); + dy = FixedMul(dy, delta); + } + + // killough 3/14/98: Add acceleration + if (s->accel) + { + s->vdx = dx += s->vdx; + s->vdy = dy += s->vdy; + } + + if (!(dx | dy)) // no-op if both (x,y) offsets 0 + return; + + switch (s->type) + { + side_t *side; + sector_t *sec; + fixed_t height, waterheight; // killough 4/4/98: add waterheight + msecnode_t *node; + mobj_t *thing; + + case sc_side: // killough 3/7/98: Scroll wall texture + side = sides + s->affectee; + side->textureoffset += dx; + side->rowoffset += dy; + break; + + case sc_floor: // killough 3/7/98: Scroll floor texture + sec = sectors + s->affectee; + sec->floor_xoffs += dx; + sec->floor_yoffs += dy; + break; + + case sc_ceiling: // killough 3/7/98: Scroll ceiling texture + sec = sectors + s->affectee; + sec->ceiling_xoffs += dx; + sec->ceiling_yoffs += dy; + break; + + case sc_carry: + + // killough 3/7/98: Carry things on floor + // killough 3/20/98: use new sector list which reflects true members + // killough 3/27/98: fix carrier bug + // killough 4/4/98: Underwater, carry things even w/o gravity + + sec = sectors + s->affectee; + height = sec->floorheight; + waterheight = sec->heightsec != -1 && + sectors[sec->heightsec].floorheight > height ? + sectors[sec->heightsec].floorheight : INT_MIN; + + for (node = sec->touching_thinglist; node; node = node->m_snext) + if (!((thing = node->m_thing)->flags & MF_NOCLIP) && + (!(thing->flags & MF_NOGRAVITY || thing->z > height) || + thing->z < waterheight)) + { + // Move objects only if on floor or underwater, + // non-floating, and clipped. + thing->momx += dx; + thing->momy += dy; + } + break; + + case sc_carry_ceiling: // to be added later + break; + } +} + +// +// Add_Scroller() +// +// Add a generalized scroller to the thinker list. +// +// type: the enumerated type of scrolling: floor, ceiling, floor carrier, +// wall, floor carrier & scroller +// +// (dx,dy): the direction and speed of the scrolling or its acceleration +// +// control: the sector whose heights control this scroller's effect +// remotely, or -1 if no control sector +// +// affectee: the index of the affected object (sector or sidedef) +// +// accel: non-zero if this is an accelerative effect +// + +static void Add_Scroller(int type, fixed_t dx, fixed_t dy, + int control, int affectee, int accel) +{ + scroll_t *s = Z_Malloc(sizeof *s, PU_LEVSPEC, 0); + s->thinker.function = T_Scroll; + s->type = type; + s->dx = dx; + s->dy = dy; + s->accel = accel; + s->vdx = s->vdy = 0; + if ((s->control = control) != -1) + s->last_height = + sectors[control].floorheight + sectors[control].ceilingheight; + s->affectee = affectee; + P_AddThinker(&s->thinker); +} + +// Adds wall scroller. Scroll amount is rotated with respect to wall's +// linedef first, so that scrolling towards the wall in a perpendicular +// direction is translated into vertical motion, while scrolling along +// the wall in a parallel direction is translated into horizontal motion. +// +// killough 5/25/98: cleaned up arithmetic to avoid drift due to roundoff +// +// killough 10/98: +// fix scrolling aliasing problems, caused by long linedefs causing overflowing + +static void Add_WallScroller(fixed_t dx, fixed_t dy, const line_t *l, + int control, int accel) +{ + fixed_t x = D_abs(l->dx), y = D_abs(l->dy), d; + if (y > x) + d = x, x = y, y = d; + d = FixedDiv(x, finesine[(tantoangle[FixedDiv(y,x) >> DBITS] + ANG90) + >> ANGLETOFINESHIFT]); + + // CPhipps - Import scroller calc overflow fix, compatibility optioned + if (compatibility_level >= lxdoom_1_compatibility) { + x = (fixed_t)(((int_64_t)dy * -(int_64_t)l->dy - (int_64_t)dx * (int_64_t)l->dx) / (int_64_t)d); // killough 10/98: + y = (fixed_t)(((int_64_t)dy * (int_64_t)l->dx - (int_64_t)dx * (int_64_t)l->dy) / (int_64_t)d); // Use long long arithmetic + } else { + x = -FixedDiv(FixedMul(dy, l->dy) + FixedMul(dx, l->dx), d); + y = -FixedDiv(FixedMul(dx, l->dy) - FixedMul(dy, l->dx), d); + } + Add_Scroller(sc_side, x, y, control, *l->sidenum, accel); +} + +// Amount (dx,dy) vector linedef is shifted right to get scroll amount +#define SCROLL_SHIFT 5 + +// Factor to scale scrolling effect into mobj-carrying properties = 3/32. +// (This is so scrolling floors and objects on them can move at same speed.) +#define CARRYFACTOR ((fixed_t)(FRACUNIT*.09375)) + +// Initialize the scrollers +static void P_SpawnScrollers(void) +{ + int i; + line_t *l = lines; + + for (i=0;idx >> SCROLL_SHIFT; // direction and speed of scrolling + fixed_t dy = l->dy >> SCROLL_SHIFT; + int control = -1, accel = 0; // no control sector or acceleration + int special = l->special; + + // killough 3/7/98: Types 245-249 are same as 250-254 except that the + // first side's sector's heights cause scrolling when they change, and + // this linedef controls the direction and speed of the scrolling. The + // most complicated linedef since donuts, but powerful :) + // + // killough 3/15/98: Add acceleration. Types 214-218 are the same but + // are accelerative. + + if (special >= 245 && special <= 249) // displacement scrollers + { + special += 250-245; + control = sides[*l->sidenum].sector - sectors; + } + else + if (special >= 214 && special <= 218) // accelerative scrollers + { + accel = 1; + special += 250-214; + control = sides[*l->sidenum].sector - sectors; + } + + switch (special) + { + register int s; + + case 250: // scroll effect ceiling + for (s=-1; (s = P_FindSectorFromLineTag(l,s)) >= 0;) + Add_Scroller(sc_ceiling, -dx, dy, control, s, accel); + break; + + case 251: // scroll effect floor + case 253: // scroll and carry objects on floor + for (s=-1; (s = P_FindSectorFromLineTag(l,s)) >= 0;) + Add_Scroller(sc_floor, -dx, dy, control, s, accel); + if (special != 253) + break; + + case 252: // carry objects on floor + dx = FixedMul(dx,CARRYFACTOR); + dy = FixedMul(dy,CARRYFACTOR); + for (s=-1; (s = P_FindSectorFromLineTag(l,s)) >= 0;) + Add_Scroller(sc_carry, dx, dy, control, s, accel); + break; + + // killough 3/1/98: scroll wall according to linedef + // (same direction and speed as scrolling floors) + case 254: + for (s=-1; (s = P_FindLineFromLineTag(l,s)) >= 0;) + if (s != i) + Add_WallScroller(dx, dy, lines+s, control, accel); + break; + + case 255: // killough 3/2/98: scroll according to sidedef offsets + s = lines[i].sidenum[0]; + Add_Scroller(sc_side, -sides[s].textureoffset, + sides[s].rowoffset, -1, s, accel); + break; + + case 48: // scroll first side + Add_Scroller(sc_side, FRACUNIT, 0, -1, lines[i].sidenum[0], accel); + break; + + case 85: // jff 1/30/98 2-way scroll + Add_Scroller(sc_side, -FRACUNIT, 0, -1, lines[i].sidenum[0], accel); + break; + } + } +} + +// killough 3/7/98 -- end generalized scroll effects + +//////////////////////////////////////////////////////////////////////////// +// +// FRICTION EFFECTS +// +// phares 3/12/98: Start of friction effects +// +// As the player moves, friction is applied by decreasing the x and y +// momentum values on each tic. By varying the percentage of decrease, +// we can simulate muddy or icy conditions. In mud, the player slows +// down faster. In ice, the player slows down more slowly. +// +// The amount of friction change is controlled by the length of a linedef +// with type 223. A length < 100 gives you mud. A length > 100 gives you ice. +// +// Also, each sector where these effects are to take place is given a +// new special type _______. Changing the type value at runtime allows +// these effects to be turned on or off. +// +// Sector boundaries present problems. The player should experience these +// friction changes only when his feet are touching the sector floor. At +// sector boundaries where floor height changes, the player can find +// himself still 'in' one sector, but with his feet at the floor level +// of the next sector (steps up or down). To handle this, Thinkers are used +// in icy/muddy sectors. These thinkers examine each object that is touching +// their sectors, looking for players whose feet are at the same level as +// their floors. Players satisfying this condition are given new friction +// values that are applied by the player movement code later. +// +// killough 8/28/98: +// +// Completely redid code, which did not need thinkers, and which put a heavy +// drag on CPU. Friction is now a property of sectors, NOT objects inside +// them. All objects, not just players, are affected by it, if they touch +// the sector's floor. Code simpler and faster, only calling on friction +// calculations when an object needs friction considered, instead of doing +// friction calculations on every sector during every tic. +// +// Although this -might- ruin Boom demo sync involving friction, it's the only +// way, short of code explosion, to fix the original design bug. Fixing the +// design bug in Boom's original friction code, while maintaining demo sync +// under every conceivable circumstance, would double or triple code size, and +// would require maintenance of buggy legacy code which is only useful for old +// demos. Doom demos, which are more important IMO, are not affected by this +// change. +// +///////////////////////////// +// +// Initialize the sectors where friction is increased or decreased + +static void P_SpawnFriction(void) +{ + int i; + line_t *l = lines; + + // killough 8/28/98: initialize all sectors to normal friction first + for (i = 0; i < numsectors; i++) + { + sectors[i].friction = ORIG_FRICTION; + sectors[i].movefactor = ORIG_FRICTION_FACTOR; + } + + for (i = 0 ; i < numlines ; i++,l++) + if (l->special == 223) + { + int length = P_AproxDistance(l->dx,l->dy)>>FRACBITS; + int friction = (0x1EB8*length)/0x80 + 0xD000; + int movefactor, s; + + // The following check might seem odd. At the time of movement, + // the move distance is multiplied by 'friction/0x10000', so a + // higher friction value actually means 'less friction'. + + if (friction > ORIG_FRICTION) // ice + movefactor = ((0x10092 - friction)*(0x70))/0x158; + else + movefactor = ((friction - 0xDB34)*(0xA))/0x80; + + if (mbf_features) + { // killough 8/28/98: prevent odd situations + if (friction > FRACUNIT) + friction = FRACUNIT; + if (friction < 0) + friction = 0; + if (movefactor < 32) + movefactor = 32; + } + + for (s = -1; (s = P_FindSectorFromLineTag(l,s)) >= 0 ; ) + { + // killough 8/28/98: + // + // Instead of spawning thinkers, which are slow and expensive, + // modify the sector's own friction values. Friction should be + // a property of sectors, not objects which reside inside them. + // Original code scanned every object in every friction sector + // on every tic, adjusting its friction, putting unnecessary + // drag on CPU. New code adjusts friction of sector only once + // at level startup, and then uses this friction value. + + sectors[s].friction = friction; + sectors[s].movefactor = movefactor; + } + } +} + +// +// phares 3/12/98: End of friction effects +// +//////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////// +// +// PUSH/PULL EFFECT +// +// phares 3/20/98: Start of push/pull effects +// +// This is where push/pull effects are applied to objects in the sectors. +// +// There are four kinds of push effects +// +// 1) Pushing Away +// +// Pushes you away from a point source defined by the location of an +// MT_PUSH Thing. The force decreases linearly with distance from the +// source. This force crosses sector boundaries and is felt w/in a circle +// whose center is at the MT_PUSH. The force is felt only if the point +// MT_PUSH can see the target object. +// +// 2) Pulling toward +// +// Same as Pushing Away except you're pulled toward an MT_PULL point +// source. This force crosses sector boundaries and is felt w/in a circle +// whose center is at the MT_PULL. The force is felt only if the point +// MT_PULL can see the target object. +// +// 3) Wind +// +// Pushes you in a constant direction. Full force above ground, half +// force on the ground, nothing if you're below it (water). +// +// 4) Current +// +// Pushes you in a constant direction. No force above ground, full +// force if on the ground or below it (water). +// +// The magnitude of the force is controlled by the length of a controlling +// linedef. The force vector for types 3 & 4 is determined by the angle +// of the linedef, and is constant. +// +// For each sector where these effects occur, the sector special type has +// to have the PUSH_MASK bit set. If this bit is turned off by a switch +// at run-time, the effect will not occur. The controlling sector for +// types 1 & 2 is the sector containing the MT_PUSH/MT_PULL Thing. + + +#define PUSH_FACTOR 7 + +///////////////////////////// +// +// Add a push thinker to the thinker list + +static void Add_Pusher(int type, int x_mag, int y_mag, mobj_t* source, int affectee) +{ + pusher_t *p = Z_Malloc(sizeof *p, PU_LEVSPEC, 0); + + p->thinker.function = T_Pusher; + p->source = source; + p->type = type; + p->x_mag = x_mag>>FRACBITS; + p->y_mag = y_mag>>FRACBITS; + p->magnitude = P_AproxDistance(p->x_mag,p->y_mag); + if (source) // point source exist? + { + p->radius = (p->magnitude)<<(FRACBITS+1); // where force goes to zero + p->x = p->source->x; + p->y = p->source->y; + } + p->affectee = affectee; + P_AddThinker(&p->thinker); +} + +///////////////////////////// +// +// PIT_PushThing determines the angle and magnitude of the effect. +// The object's x and y momentum values are changed. +// +// tmpusher belongs to the point source (MT_PUSH/MT_PULL). +// +// killough 10/98: allow to affect things besides players + +pusher_t* tmpusher; // pusher structure for blockmap searches + +boolean PIT_PushThing(mobj_t* thing) +{ + /* killough 10/98: made more general */ + if (!mbf_features ? + thing->player && !(thing->flags & (MF_NOCLIP | MF_NOGRAVITY)) : + (sentient(thing) || thing->flags & MF_SHOOTABLE) && + !(thing->flags & MF_NOCLIP)) + { + angle_t pushangle; + fixed_t speed; + fixed_t sx = tmpusher->x; + fixed_t sy = tmpusher->y; + + speed = (tmpusher->magnitude - + ((P_AproxDistance(thing->x - sx,thing->y - sy) + >>FRACBITS)>>1))<<(FRACBITS-PUSH_FACTOR-1); + + // killough 10/98: make magnitude decrease with square + // of distance, making it more in line with real nature, + // so long as it's still in range with original formula. + // + // Removes angular distortion, and makes effort required + // to stay close to source, grow increasingly hard as you + // get closer, as expected. Still, it doesn't consider z :( + + if (speed > 0 && mbf_features) + { + int x = (thing->x-sx) >> FRACBITS; + int y = (thing->y-sy) >> FRACBITS; + speed = (int)(((uint_64_t) tmpusher->magnitude << 23) / (x*x+y*y+1)); + } + + // If speed <= 0, you're outside the effective radius. You also have + // to be able to see the push/pull source point. + + if (speed > 0 && P_CheckSight(thing,tmpusher->source)) + { + pushangle = R_PointToAngle2(thing->x,thing->y,sx,sy); + if (tmpusher->source->type == MT_PUSH) + pushangle += ANG180; // away + pushangle >>= ANGLETOFINESHIFT; + thing->momx += FixedMul(speed,finecosine[pushangle]); + thing->momy += FixedMul(speed,finesine[pushangle]); + } + } + return true; +} + +///////////////////////////// +// +// T_Pusher looks for all objects that are inside the radius of +// the effect. +// + +void T_Pusher(pusher_t *p) +{ + sector_t *sec; + mobj_t *thing; + msecnode_t* node; + int xspeed,yspeed; + int xl,xh,yl,yh,bx,by; + int radius; + int ht = 0; + + if (!allow_pushers) + return; + + sec = sectors + p->affectee; + + // Be sure the special sector type is still turned on. If so, proceed. + // Else, bail out; the sector type has been changed on us. + + if (!(sec->special & PUSH_MASK)) + return; + + // For constant pushers (wind/current) there are 3 situations: + // + // 1) Affected Thing is above the floor. + // + // Apply the full force if wind, no force if current. + // + // 2) Affected Thing is on the ground. + // + // Apply half force if wind, full force if current. + // + // 3) Affected Thing is below the ground (underwater effect). + // + // Apply no force if wind, full force if current. + + if (p->type == p_push) + { + + // Seek out all pushable things within the force radius of this + // point pusher. Crosses sectors, so use blockmap. + + tmpusher = p; // MT_PUSH/MT_PULL point source + radius = p->radius; // where force goes to zero + tmbbox[BOXTOP] = p->y + radius; + tmbbox[BOXBOTTOM] = p->y - radius; + tmbbox[BOXRIGHT] = p->x + radius; + tmbbox[BOXLEFT] = p->x - radius; + + xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT; + xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT; + yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT; + yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT; + for (bx=xl ; bx<=xh ; bx++) + for (by=yl ; by<=yh ; by++) + P_BlockThingsIterator(bx,by,PIT_PushThing); + return; + } + + // constant pushers p_wind and p_current + + if (sec->heightsec != -1) // special water sector? + ht = sectors[sec->heightsec].floorheight; + node = sec->touching_thinglist; // things touching this sector + for ( ; node ; node = node->m_snext) + { + thing = node->m_thing; + if (!thing->player || (thing->flags & (MF_NOGRAVITY | MF_NOCLIP))) + continue; + if (p->type == p_wind) + { + if (sec->heightsec == -1) // NOT special water sector + if (thing->z > thing->floorz) // above ground + { + xspeed = p->x_mag; // full force + yspeed = p->y_mag; + } + else // on ground + { + xspeed = (p->x_mag)>>1; // half force + yspeed = (p->y_mag)>>1; + } + else // special water sector + { + if (thing->z > ht) // above ground + { + xspeed = p->x_mag; // full force + yspeed = p->y_mag; + } + else if (thing->player->viewz < ht) // underwater + xspeed = yspeed = 0; // no force + else // wading in water + { + xspeed = (p->x_mag)>>1; // half force + yspeed = (p->y_mag)>>1; + } + } + } + else // p_current + { + if (sec->heightsec == -1) // NOT special water sector + if (thing->z > sec->floorheight) // above ground + xspeed = yspeed = 0; // no force + else // on ground + { + xspeed = p->x_mag; // full force + yspeed = p->y_mag; + } + else // special water sector + if (thing->z > ht) // above ground + xspeed = yspeed = 0; // no force + else // underwater + { + xspeed = p->x_mag; // full force + yspeed = p->y_mag; + } + } + thing->momx += xspeed<<(FRACBITS-PUSH_FACTOR); + thing->momy += yspeed<<(FRACBITS-PUSH_FACTOR); + } +} + +///////////////////////////// +// +// P_GetPushThing() returns a pointer to an MT_PUSH or MT_PULL thing, +// NULL otherwise. + +mobj_t* P_GetPushThing(int s) +{ + mobj_t* thing; + sector_t* sec; + + sec = sectors + s; + thing = sec->thinglist; + while (thing) + { + switch(thing->type) + { + case MT_PUSH: + case MT_PULL: + return thing; + default: + break; + } + thing = thing->snext; + } + return NULL; +} + +///////////////////////////// +// +// Initialize the sectors where pushers are present +// + +static void P_SpawnPushers(void) +{ + int i; + line_t *l = lines; + register int s; + mobj_t* thing; + + for (i = 0 ; i < numlines ; i++,l++) + switch(l->special) + { + case 224: // wind + for (s = -1; (s = P_FindSectorFromLineTag(l,s)) >= 0 ; ) + Add_Pusher(p_wind,l->dx,l->dy,NULL,s); + break; + case 225: // current + for (s = -1; (s = P_FindSectorFromLineTag(l,s)) >= 0 ; ) + Add_Pusher(p_current,l->dx,l->dy,NULL,s); + break; + case 226: // push/pull + for (s = -1; (s = P_FindSectorFromLineTag(l,s)) >= 0 ; ) + { + thing = P_GetPushThing(s); + if (thing) // No MT_P* means no effect + Add_Pusher(p_push,l->dx,l->dy,thing,s); + } + break; + } +} + +// +// phares 3/20/98: End of Pusher effects +// +//////////////////////////////////////////////////////////////////////////// diff --git a/apps/plugins/doom/p_spec.h b/apps/plugins/doom/p_spec.h new file mode 100644 index 0000000000..7a13ad8aa0 --- /dev/null +++ b/apps/plugins/doom/p_spec.h @@ -0,0 +1,1148 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: definitions, declarations and prototypes for specials + * + *-----------------------------------------------------------------------------*/ + +#ifndef __P_SPEC__ +#define __P_SPEC__ + +#include "r_defs.h" +#include "d_player.h" + +// Define values for map objects +#define MO_TELEPORTMAN 14 + +// p_floor + +#define ELEVATORSPEED (FRACUNIT*4) +#define FLOORSPEED FRACUNIT + +// p_ceilng + +#define CEILSPEED FRACUNIT +#define CEILWAIT 150 + +// p_doors + +#define VDOORSPEED (FRACUNIT*2) +#define VDOORWAIT 150 + +// p_plats + +#define PLATWAIT 3 +#define PLATSPEED FRACUNIT + +// p_switch + +// 4 players, 4 buttons each at once, max. +// killough 2/14/98: redefine in terms of MAXPLAYERS +#define MAXBUTTONS (MAXPLAYERS*4) + +// 1 second, in ticks. +#define BUTTONTIME TICRATE + +// p_lights + +#define GLOWSPEED 8 +#define STROBEBRIGHT 5 +#define FASTDARK 15 +#define SLOWDARK 35 + +//jff 3/14/98 add bits and shifts for generalized sector types + +#define DAMAGE_MASK 0x60 +#define DAMAGE_SHIFT 5 +#define SECRET_MASK 0x80 +#define SECRET_SHIFT 7 +#define FRICTION_MASK 0x100 +#define FRICTION_SHIFT 8 +#define PUSH_MASK 0x200 +#define PUSH_SHIFT 9 + +//jff 02/04/98 Define masks, shifts, for fields in +// generalized linedef types + +#define GenEnd 0x8000 +#define GenFloorBase 0x6000 +#define GenCeilingBase 0x4000 +#define GenDoorBase 0x3c00 +#define GenLockedBase 0x3800 +#define GenLiftBase 0x3400 +#define GenStairsBase 0x3000 +#define GenCrusherBase 0x2F80 + +#define TriggerType 0x0007 +#define TriggerTypeShift 0 + +// define masks and shifts for the floor type fields + +#define FloorCrush 0x1000 +#define FloorChange 0x0c00 +#define FloorTarget 0x0380 +#define FloorDirection 0x0040 +#define FloorModel 0x0020 +#define FloorSpeed 0x0018 + +#define FloorCrushShift 12 +#define FloorChangeShift 10 +#define FloorTargetShift 7 +#define FloorDirectionShift 6 +#define FloorModelShift 5 +#define FloorSpeedShift 3 + +// define masks and shifts for the ceiling type fields + +#define CeilingCrush 0x1000 +#define CeilingChange 0x0c00 +#define CeilingTarget 0x0380 +#define CeilingDirection 0x0040 +#define CeilingModel 0x0020 +#define CeilingSpeed 0x0018 + +#define CeilingCrushShift 12 +#define CeilingChangeShift 10 +#define CeilingTargetShift 7 +#define CeilingDirectionShift 6 +#define CeilingModelShift 5 +#define CeilingSpeedShift 3 + +// define masks and shifts for the lift type fields + +#define LiftTarget 0x0300 +#define LiftDelay 0x00c0 +#define LiftMonster 0x0020 +#define LiftSpeed 0x0018 + +#define LiftTargetShift 8 +#define LiftDelayShift 6 +#define LiftMonsterShift 5 +#define LiftSpeedShift 3 + +// define masks and shifts for the stairs type fields + +#define StairIgnore 0x0200 +#define StairDirection 0x0100 +#define StairStep 0x00c0 +#define StairMonster 0x0020 +#define StairSpeed 0x0018 + +#define StairIgnoreShift 9 +#define StairDirectionShift 8 +#define StairStepShift 6 +#define StairMonsterShift 5 +#define StairSpeedShift 3 + +// define masks and shifts for the crusher type fields + +#define CrusherSilent 0x0040 +#define CrusherMonster 0x0020 +#define CrusherSpeed 0x0018 + +#define CrusherSilentShift 6 +#define CrusherMonsterShift 5 +#define CrusherSpeedShift 3 + +// define masks and shifts for the door type fields + +#define DoorDelay 0x0300 +#define DoorMonster 0x0080 +#define DoorKind 0x0060 +#define DoorSpeed 0x0018 + +#define DoorDelayShift 8 +#define DoorMonsterShift 7 +#define DoorKindShift 5 +#define DoorSpeedShift 3 + +// define masks and shifts for the locked door type fields + +#define LockedNKeys 0x0200 +#define LockedKey 0x01c0 +#define LockedKind 0x0020 +#define LockedSpeed 0x0018 + +#define LockedNKeysShift 9 +#define LockedKeyShift 6 +#define LockedKindShift 5 +#define LockedSpeedShift 3 + +// define names for the TriggerType field of the general linedefs + +typedef enum +{ + WalkOnce, + WalkMany, + SwitchOnce, + SwitchMany, + GunOnce, + GunMany, + PushOnce, + PushMany, +} triggertype_e; + +// define names for the Speed field of the general linedefs + +typedef enum +{ + SpeedSlow, + SpeedNormal, + SpeedFast, + SpeedTurbo, +} motionspeed_e; + +// define names for the Target field of the general floor + +typedef enum +{ + FtoHnF, + FtoLnF, + FtoNnF, + FtoLnC, + FtoC, + FbyST, + Fby24, + Fby32, +} floortarget_e; + +// define names for the Changer Type field of the general floor + +typedef enum +{ + FNoChg, + FChgZero, + FChgTxt, + FChgTyp, +} floorchange_e; + +// define names for the Change Model field of the general floor + +typedef enum +{ + FTriggerModel, + FNumericModel, +} floormodel_t; + +// define names for the Target field of the general ceiling + +typedef enum +{ + CtoHnC, + CtoLnC, + CtoNnC, + CtoHnF, + CtoF, + CbyST, + Cby24, + Cby32, +} ceilingtarget_e; + +// define names for the Changer Type field of the general ceiling + +typedef enum +{ + CNoChg, + CChgZero, + CChgTxt, + CChgTyp, +} ceilingchange_e; + +// define names for the Change Model field of the general ceiling + +typedef enum +{ + CTriggerModel, + CNumericModel, +} ceilingmodel_t; + +// define names for the Target field of the general lift + +typedef enum +{ + F2LnF, + F2NnF, + F2LnC, + LnF2HnF, +} lifttarget_e; + +// define names for the door Kind field of the general ceiling + +typedef enum +{ + OdCDoor, + ODoor, + CdODoor, + CDoor, +} doorkind_e; + +// define names for the locked door Kind field of the general ceiling + +typedef enum +{ + AnyKey, + RCard, + BCard, + YCard, + RSkull, + BSkull, + YSkull, + AllKeys, +} keykind_e; + +////////////////////////////////////////////////////////////////// +// +// enums for classes of linedef triggers +// +////////////////////////////////////////////////////////////////// + +//jff 2/23/98 identify the special classes that can share sectors + +typedef enum +{ + floor_special, + ceiling_special, + lighting_special, +} special_e; + +//jff 3/15/98 pure texture/type change for better generalized support +typedef enum +{ + trigChangeOnly, + numChangeOnly, +} change_e; + +// p_plats + +typedef enum +{ + up, + down, + waiting, + in_stasis +} plat_e; + +typedef enum +{ + perpetualRaise, + downWaitUpStay, + raiseAndChange, + raiseToNearestAndChange, + blazeDWUS, + genLift, //jff added to support generalized Plat types + genPerpetual, + toggleUpDn, //jff 3/14/98 added to support instant toggle type + +} plattype_e; + +// p_doors + +typedef enum +{ + normal, + close30ThenOpen, + p_close, + p_open, + raiseIn5Mins, + blazeRaise, + blazeOpen, + blazeClose, + + //jff 02/05/98 add generalize door types + genRaise, + genBlazeRaise, + genOpen, + genBlazeOpen, + genClose, + genBlazeClose, + genCdO, + genBlazeCdO, +} vldoor_e; + +// p_ceilng + +typedef enum +{ + lowerToFloor, + raiseToHighest, + lowerToLowest, + lowerToMaxFloor, + lowerAndCrush, + crushAndRaise, + fastCrushAndRaise, + silentCrushAndRaise, + + //jff 02/04/98 add types for generalized ceiling mover + genCeiling, + genCeilingChg, + genCeilingChg0, + genCeilingChgT, + + //jff 02/05/98 add types for generalized ceiling mover + genCrusher, + genSilentCrusher, + +} ceiling_e; + +// p_floor + +typedef enum +{ + // lower floor to highest surrounding floor + lowerFloor, + + // lower floor to lowest surrounding floor + lowerFloorToLowest, + + // lower floor to highest surrounding floor VERY FAST + turboLower, + + // raise floor to lowest surrounding CEILING + raiseFloor, + + // raise floor to next highest surrounding floor + raiseFloorToNearest, + + //jff 02/03/98 lower floor to next lowest neighbor + lowerFloorToNearest, + + //jff 02/03/98 lower floor 24 absolute + lowerFloor24, + + //jff 02/03/98 lower floor 32 absolute + lowerFloor32Turbo, + + // raise floor to shortest height texture around it + raiseToTexture, + + // lower floor to lowest surrounding floor + // and change floorpic + lowerAndChange, + + raiseFloor24, + + //jff 02/03/98 raise floor 32 absolute + raiseFloor32Turbo, + + raiseFloor24AndChange, + raiseFloorCrush, + + // raise to next highest floor, turbo-speed + raiseFloorTurbo, + donutRaise, + raiseFloor512, + + //jff 02/04/98 add types for generalized floor mover + genFloor, + genFloorChg, + genFloorChg0, + genFloorChgT, + + //new types for stair builders + buildStair, + genBuildStair, +} floor_e; + +typedef enum +{ + build8, // slowly build by 8 + turbo16 // quickly build by 16 + +} stair_e; + +typedef enum +{ + elevateUp, + elevateDown, + elevateCurrent, +} elevator_e; + +////////////////////////////////////////////////////////////////// +// +// general enums +// +////////////////////////////////////////////////////////////////// + +// texture type enum +typedef enum +{ + top, + middle, + bottom + +} bwhere_e; + +// crush check returns +typedef enum +{ + ok, + crushed, + pastdest +} result_e; + +////////////////////////////////////////////////////////////////// +// +// linedef and sector special data types +// +////////////////////////////////////////////////////////////////// + +// p_switch + +// switch animation structure type + +#if defined(__MWERKS__) +#pragma options align=packed +#endif + +typedef struct +{ + char name1[9]; + char name2[9]; + short episode; +} PACKEDATTR switchlist_t; //jff 3/23/98 pack to read from memory + +#if defined(__MWERKS__) +#pragma options align=reset +#endif + +typedef struct +{ + line_t* line; + bwhere_e where; + int btexture; + int btimer; + mobj_t* soundorg; + +} button_t; + +// p_lights + +typedef struct +{ + thinker_t thinker; + sector_t* sector; + int count; + int maxlight; + int minlight; + +} fireflicker_t; + +typedef struct +{ + thinker_t thinker; + sector_t* sector; + int count; + int maxlight; + int minlight; + int maxtime; + int mintime; + +} lightflash_t; + +typedef struct +{ + thinker_t thinker; + sector_t* sector; + int count; + int minlight; + int maxlight; + int darktime; + int brighttime; + +} strobe_t; + +typedef struct +{ + thinker_t thinker; + sector_t* sector; + int minlight; + int maxlight; + int direction; + +} glow_t; + +// p_plats + +typedef struct +{ + thinker_t thinker; + sector_t* sector; + fixed_t speed; + fixed_t low; + fixed_t high; + int wait; + int count; + plat_e status; + plat_e oldstatus; + boolean crush; + int tag; + plattype_e type; + + struct platlist *list; // killough +} plat_t; + +// New limit-free plat structure -- killough + +typedef struct platlist { + plat_t *plat; + struct platlist *next,**prev; +} platlist_t; + +// p_ceilng + +typedef struct +{ + thinker_t thinker; + vldoor_e type; + sector_t* sector; + fixed_t topheight; + fixed_t speed; + + // 1 = up, 0 = waiting at top, -1 = down + int direction; + + // tics to wait at the top + int topwait; + // (keep in case a door going down is reset) + // when it reaches 0, start going down + int topcountdown; + + //jff 1/31/98 keep track of line door is triggered by + line_t *line; + + /* killough 10/98: sector tag for gradual lighting effects */ + int lighttag; +} vldoor_t; + +// p_doors + +typedef struct +{ + thinker_t thinker; + ceiling_e type; + sector_t* sector; + fixed_t bottomheight; + fixed_t topheight; + fixed_t speed; + fixed_t oldspeed; + boolean crush; + + //jff 02/04/98 add these to support ceiling changers + int newspecial; + int oldspecial; //jff 3/14/98 add to fix bug in change transfers + short texture; + + // 1 = up, 0 = waiting, -1 = down + int direction; + + // ID + int tag; + int olddirection; + struct ceilinglist *list; // jff 2/22/98 copied from killough's plats +} ceiling_t; + +typedef struct ceilinglist { + ceiling_t *ceiling; + struct ceilinglist *next,**prev; +} ceilinglist_t; + +// p_floor + +typedef struct +{ + thinker_t thinker; + floor_e type; + boolean crush; + sector_t* sector; + int direction; + int newspecial; + int oldspecial; //jff 3/14/98 add to fix bug in change transfers + short texture; + fixed_t floordestheight; + fixed_t speed; + +} floormove_t; + +typedef struct +{ + thinker_t thinker; + elevator_e type; + sector_t* sector; + int direction; + fixed_t floordestheight; + fixed_t ceilingdestheight; + fixed_t speed; +} elevator_t; + +// p_spec + +// killough 3/7/98: Add generalized scroll effects + +typedef struct { + thinker_t thinker; // Thinker structure for scrolling + fixed_t dx, dy; // (dx,dy) scroll speeds + int affectee; // Number of affected sidedef, sector, tag, or whatever + int control; // Control sector (-1 if none) used to control scrolling + fixed_t last_height; // Last known height of control sector + fixed_t vdx, vdy; // Accumulated velocity if accelerative + int accel; // Whether it's accelerative + enum + { + sc_side, + sc_floor, + sc_ceiling, + sc_carry, + sc_carry_ceiling, // killough 4/11/98: carry objects hanging on ceilings + } type; // Type of scroll effect +} scroll_t; + +// phares 3/12/98: added new model of friction for ice/sludge effects + +typedef struct { + thinker_t thinker; // Thinker structure for friction + int friction; // friction value (E800 = normal) + int movefactor; // inertia factor when adding to momentum + int affectee; // Number of affected sector +} friction_t; + +// phares 3/20/98: added new model of Pushers for push/pull effects + +typedef struct { + thinker_t thinker; // Thinker structure for Pusher + enum + { + p_push, + p_pull, + p_wind, + p_current, + } type; + mobj_t* source; // Point source if point pusher + int x_mag; // X Strength + int y_mag; // Y Strength + int magnitude; // Vector strength for point pusher + int radius; // Effective radius for point pusher + int x; // X of point source if point pusher + int y; // Y of point source if point pusher + int affectee; // Number of affected sector +} pusher_t; + +////////////////////////////////////////////////////////////////// +// +// external data declarations +// +////////////////////////////////////////////////////////////////// + +// +// End-level timer (-TIMER option) +// +extern boolean levelTimer; +extern int levelTimeCount; + +// list of retriggerable buttons active +extern button_t buttonlist[MAXBUTTONS]; + +extern platlist_t *activeplats; // killough 2/14/98 + +extern ceilinglist_t *activeceilings; // jff 2/22/98 + +//////////////////////////////////////////////////////////////// +// +// Linedef and sector special utility function prototypes +// +//////////////////////////////////////////////////////////////// + +int twoSided +( int sector, + int line ); + +sector_t* getSector +( int currentSector, + int line, + int side ); + +side_t* getSide +( int currentSector, + int line, + int side ); + +fixed_t P_FindLowestFloorSurrounding +( sector_t* sec ); + +fixed_t P_FindHighestFloorSurrounding +( sector_t* sec ); + +fixed_t P_FindNextHighestFloor +( sector_t* sec, + int currentheight ); + +fixed_t P_FindNextLowestFloor +( sector_t* sec, + int currentheight ); + +fixed_t P_FindLowestCeilingSurrounding +( sector_t* sec ); // jff 2/04/98 + +fixed_t P_FindHighestCeilingSurrounding +( sector_t* sec ); // jff 2/04/98 + +fixed_t P_FindNextLowestCeiling +( sector_t *sec, + int currentheight ); // jff 2/04/98 + +fixed_t P_FindNextHighestCeiling +( sector_t *sec, + int currentheight ); // jff 2/04/98 + +fixed_t P_FindShortestTextureAround +( int secnum ); // jff 2/04/98 + +fixed_t P_FindShortestUpperAround +( int secnum ); // jff 2/04/98 + +sector_t* P_FindModelFloorSector +( fixed_t floordestheight, + int secnum ); //jff 02/04/98 + +sector_t* P_FindModelCeilingSector +( fixed_t ceildestheight, + int secnum ); //jff 02/04/98 + +int P_FindSectorFromLineTag +( const line_t *line, + int start ); // killough 4/17/98 + +int P_FindLineFromLineTag +( const line_t *line, + int start ); // killough 4/17/98 + +int P_FindMinSurroundingLight +( sector_t* sector, + int max ); + +sector_t* getNextSector +( line_t* line, + sector_t* sec ); + +int P_CheckTag +(line_t *line); // jff 2/27/98 + +boolean P_CanUnlockGenDoor +( line_t* line, + player_t* player); + +int P_SectorActive +( special_e t, + sector_t* s ); + +boolean P_IsSecret +( sector_t *sec ); + +boolean P_WasSecret +( sector_t *sec ); + +void P_ChangeSwitchTexture +( line_t* line, + int useAgain ); + +//////////////////////////////////////////////////////////////// +// +// Linedef and sector special action function prototypes +// +//////////////////////////////////////////////////////////////// + +// p_lights + +void T_LightFlash +( lightflash_t* flash ); + +void T_StrobeFlash +( strobe_t* flash ); + +// jff 8/8/98 add missing thinker for flicker +void T_FireFlicker +( fireflicker_t* flick ); + +void T_Glow +( glow_t* g ); + +// p_plats + +void T_PlatRaise +( plat_t* plat ); + +// p_doors + +void T_VerticalDoor +( vldoor_t* door ); + +// p_ceilng + +void T_MoveCeiling +( ceiling_t* ceiling ); + +// p_floor + +result_e T_MovePlane +( sector_t* sector, + fixed_t speed, + fixed_t dest, + boolean crush, + int floorOrCeiling, + int direction ); + +void T_MoveFloor +( floormove_t* floor ); + +void T_MoveElevator +( elevator_t* elevator ); + +// p_spec + +void T_Scroll +( scroll_t * ); // killough 3/7/98: scroll effect thinker + +void T_Friction +( friction_t * ); // phares 3/12/98: friction thinker + +void T_Pusher +( pusher_t * ); // phares 3/20/98: Push thinker + +//////////////////////////////////////////////////////////////// +// +// Linedef and sector special handler prototypes +// +//////////////////////////////////////////////////////////////// + +// p_telept + +int EV_Teleport +( line_t* line, + int side, + mobj_t* thing ); + +// killough 2/14/98: Add silent teleporter +int EV_SilentTeleport +( line_t* line, + int side, + mobj_t* thing ); + +// killough 1/31/98: Add silent line teleporter +int EV_SilentLineTeleport +( line_t* line, + int side, + mobj_t* thing, + boolean reverse); + +// p_floor + +int +EV_DoElevator +( line_t* line, + elevator_e type ); + +int EV_BuildStairs +( line_t* line, + stair_e type ); + +int EV_DoFloor +( line_t* line, + floor_e floortype ); + +// p_ceilng + +int EV_DoCeiling +( line_t* line, + ceiling_e type ); + +int EV_CeilingCrushStop +( line_t* line ); + +// p_doors + +int EV_VerticalDoor +( line_t* line, + mobj_t* thing ); + +int EV_DoDoor +( line_t* line, + vldoor_e type ); + +int EV_DoLockedDoor +( line_t* line, + vldoor_e type, + mobj_t* thing ); + +// p_lights + +int EV_StartLightStrobing +( line_t* line ); + +int EV_TurnTagLightsOff +( line_t* line ); + +int EV_LightTurnOn +( line_t* line, + int bright ); + +int EV_LightTurnOnPartway(line_t* line, fixed_t level); // killough 10/10/98 + +// p_floor + +int EV_DoChange +( line_t* line, + change_e changetype ); + +int EV_DoDonut +( line_t* line ); + +// p_plats + +int EV_DoPlat +( line_t* line, + plattype_e type, + int amount ); + +int EV_StopPlat +( line_t* line ); + +// p_genlin + +int EV_DoGenFloor +( line_t* line ); + +int EV_DoGenCeiling +( line_t* line ); + +int EV_DoGenLift +( line_t* line ); + +int EV_DoGenStairs +( line_t* line ); + +int EV_DoGenCrusher +( line_t* line ); + +int EV_DoGenDoor +( line_t* line ); + +int EV_DoGenLockedDoor +( line_t* line ); + +//////////////////////////////////////////////////////////////// +// +// Linedef and sector special thinker spawning +// +//////////////////////////////////////////////////////////////// + +// at game start +void P_InitPicAnims +( void ); + +void P_InitSwitchList +( void ); + +// at map load +void P_SpawnSpecials +( void ); + +// every tic +void P_UpdateSpecials +( void ); + +// when needed +boolean P_UseSpecialLine +( mobj_t* thing, + line_t* line, + int side ); + +void P_ShootSpecialLine +( mobj_t* thing, + line_t* line ); + +void P_CrossSpecialLine(line_t *line, int side, mobj_t *thing); + +void P_PlayerInSpecialSector +( player_t* player ); + +// p_lights + +void P_SpawnFireFlicker +( sector_t* sector ); + +void P_SpawnLightFlash +( sector_t* sector ); + +void P_SpawnStrobeFlash +( sector_t* sector, + int fastOrSlow, + int inSync ); + +void P_SpawnGlowingLight +( sector_t* sector ); + +// p_plats + +void P_AddActivePlat +( plat_t* plat ); + +void P_RemoveActivePlat +( plat_t* plat ); + +void P_RemoveAllActivePlats +( void ); // killough + +void P_ActivateInStasis +( int tag ); + +// p_doors + +void P_SpawnDoorCloseIn30 +( sector_t* sec ); + +void P_SpawnDoorRaiseIn5Mins +( sector_t* sec, + int secnum ); + +// p_ceilng + +void P_RemoveActiveCeiling +( ceiling_t* ceiling ); //jff 2/22/98 + +void P_RemoveAllActiveCeilings +( void ); //jff 2/22/98 + +void P_AddActiveCeiling +( ceiling_t* c ); + +void P_RemoveActiveCeiling +( ceiling_t* c ); + +int P_ActivateInStasisCeiling +( line_t* line ); + +mobj_t* P_GetPushThing(int); // phares 3/23/98 + +#endif diff --git a/apps/plugins/doom/p_switch.c b/apps/plugins/doom/p_switch.c new file mode 100644 index 0000000000..698c4c8ee3 --- /dev/null +++ b/apps/plugins/doom/p_switch.c @@ -0,0 +1,1138 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Switches, buttons. Two-state animation. Exits. + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "w_wad.h" +#include "r_main.h" +#include "p_spec.h" +#include "g_game.h" +#include "s_sound.h" +#include "sounds.h" +#include "m_swap.h" +#include "i_system.h" +#include "rockmacros.h" +// killough 2/8/98: Remove switch limit + +static int *switchlist; // killough +static int max_numswitches; // killough +static int numswitches; // killough + +button_t buttonlist[MAXBUTTONS]; + +// +// P_InitSwitchList() +// +// Only called at game initialization in order to list the set of switches +// and buttons known to the engine. This enables their texture to change +// when activated, and in the case of buttons, change back after a timeout. +// +// This routine modified to read its data from a predefined lump or +// PWAD lump called SWITCHES rather than a static table in this module to +// allow wad designers to insert or modify switches. +// +// Lump format is an array of byte packed switchlist_t structures, terminated +// by a structure with episode == -0. The lump can be generated from a +// text source file using SWANTBLS.EXE, distributed with the BOOM utils. +// The standard list of switches and animations is contained in the example +// source text file DEFSWANI.DAT also in the BOOM util distribution. +// +// Rewritten by Lee Killough to remove limit 2/8/98 +// +void P_InitSwitchList(void) +{ + int i, index = 0; + int episode = (gamemode == registered || gamemode==retail) ? + 2 : gamemode == commercial ? 3 : 1; + const switchlist_t *alphSwitchList; //jff 3/23/98 pointer to switch table + int lump = W_GetNumForName("SWITCHES"); // cph - new wad lump handling + + //jff 3/23/98 read the switch table from a predefined lump + alphSwitchList = (const switchlist_t *)W_CacheLumpNum(lump); + + for (i=0;;i++) + { + if (index+1 >= max_numswitches) + switchlist = realloc(switchlist, sizeof *switchlist * + (max_numswitches = max_numswitches ? max_numswitches*2 : 8)); + if (SHORT(alphSwitchList[i].episode) <= episode) //jff 5/11/98 endianess + { + if (!SHORT(alphSwitchList[i].episode)) + break; + switchlist[index++] = R_TextureNumForName(alphSwitchList[i].name1); + switchlist[index++] = R_TextureNumForName(alphSwitchList[i].name2); + } + } + + numswitches = index/2; + switchlist[index] = -1; + W_UnlockLumpNum(lump); +} + +// +// P_StartButton() +// +// Start a button (retriggerable switch) counting down till it turns off. +// +// Passed the linedef the button is on, which texture on the sidedef contains +// the button, the texture number of the button, and the time the button is +// to remain active in gametics. +// No return. +// +void P_StartButton +( line_t* line, + bwhere_e w, + int texture, + int time ) +{ + int i; + + // See if button is already pressed + for (i = 0;i < MAXBUTTONS;i++) + if (buttonlist[i].btimer && buttonlist[i].line == line) + return; + + for (i = 0;i < MAXBUTTONS;i++) + if (!buttonlist[i].btimer) // use first unused element of list + { + buttonlist[i].line = line; + buttonlist[i].where = w; + buttonlist[i].btexture = texture; + buttonlist[i].btimer = time; + buttonlist[i].soundorg = (mobj_t *)&line->frontsector->soundorg; + return; + } + + I_Error("P_StartButton: no button slots left!"); +} + +// +// P_ChangeSwitchTexture() +// +// Function that changes switch wall texture on activation. +// +// Passed the line which the switch is on, and whether its retriggerable. +// If not retriggerable, this function clears the line special to insure that +// +// No return +// +void P_ChangeSwitchTexture +( line_t* line, + int useAgain ) +{ + int texTop; + int texMid; + int texBot; + int i; + int sound; + + if (!useAgain) + line->special = 0; + + texTop = sides[line->sidenum[0]].toptexture; + texMid = sides[line->sidenum[0]].midtexture; + texBot = sides[line->sidenum[0]].bottomtexture; + + sound = sfx_swtchn; + + // EXIT SWITCH? + if (line->special == 11) + sound = sfx_swtchx; + + for (i = 0;i < numswitches*2;i++) + { + if (switchlist[i] == texTop) // if an upper texture + { + S_StartSound(buttonlist->soundorg,sound); // switch activation sound + sides[line->sidenum[0]].toptexture = switchlist[i^1]; //chg texture + + if (useAgain) + P_StartButton(line,top,switchlist[i],BUTTONTIME); //start timer + + return; + } + else + { + if (switchlist[i] == texMid) // if a normal texture + { + S_StartSound(buttonlist->soundorg,sound); // switch activation sound + sides[line->sidenum[0]].midtexture = switchlist[i^1]; //chg texture + + if (useAgain) + P_StartButton(line, middle,switchlist[i],BUTTONTIME); //start timer + + return; + } + else + { + if (switchlist[i] == texBot) // if a lower texture + { + S_StartSound(buttonlist->soundorg,sound); // switch activation sound + sides[line->sidenum[0]].bottomtexture = switchlist[i^1];//chg texture + + if (useAgain) + P_StartButton(line, bottom,switchlist[i],BUTTONTIME); //start timer + + return; + } + } + } + } +} + + +// +// P_UseSpecialLine +// +// +// Called when a thing uses (pushes) a special line. +// Only the front sides of lines are usable. +// Dispatches to the appropriate linedef function handler. +// +// Passed the thing using the line, the line being used, and the side used +// Returns true if a thinker was created +// +boolean +P_UseSpecialLine +( mobj_t* thing, + line_t* line, + int side ) +{ + + if (side) //jff 6/1/98 fix inadvertent deletion of side test + return false; + + //jff 02/04/98 add check here for generalized floor/ceil mover + if (!demo_compatibility) + { + // pointer to line function is NULL by default, set non-null if + // line special is push or switch generalized linedef type + int (*linefunc)(line_t *line)=NULL; + + // check each range of generalized linedefs + if ((unsigned)line->special >= GenEnd) + { + // Out of range for GenFloors + } + else if ((unsigned)line->special >= GenFloorBase) + { + if (!thing->player) + if ((line->special & FloorChange) || !(line->special & FloorModel)) + return false; // FloorModel is "Allow Monsters" if FloorChange is 0 + if (!line->tag && ((line->special&6)!=6)) //jff 2/27/98 all non-manual + return false; // generalized types require tag + linefunc = EV_DoGenFloor; + } + else if ((unsigned)line->special >= GenCeilingBase) + { + if (!thing->player) + if ((line->special & CeilingChange) || !(line->special & CeilingModel)) + return false; // CeilingModel is "Allow Monsters" if CeilingChange is 0 + if (!line->tag && ((line->special&6)!=6)) //jff 2/27/98 all non-manual + return false; // generalized types require tag + linefunc = EV_DoGenCeiling; + } + else if ((unsigned)line->special >= GenDoorBase) + { + if (!thing->player) + { + if (!(line->special & DoorMonster)) + return false; // monsters disallowed from this door + if (line->flags & ML_SECRET) // they can't open secret doors either + return false; + } + if (!line->tag && ((line->special&6)!=6)) //jff 3/2/98 all non-manual + return false; // generalized types require tag + linefunc = EV_DoGenDoor; + } + else if ((unsigned)line->special >= GenLockedBase) + { + if (!thing->player) + return false; // monsters disallowed from unlocking doors + if (!P_CanUnlockGenDoor(line,thing->player)) + return false; + if (!line->tag && ((line->special&6)!=6)) //jff 2/27/98 all non-manual + return false; // generalized types require tag + + linefunc = EV_DoGenLockedDoor; + } + else if ((unsigned)line->special >= GenLiftBase) + { + if (!thing->player) + if (!(line->special & LiftMonster)) + return false; // monsters disallowed + if (!line->tag && ((line->special&6)!=6)) //jff 2/27/98 all non-manual + return false; // generalized types require tag + linefunc = EV_DoGenLift; + } + else if ((unsigned)line->special >= GenStairsBase) + { + if (!thing->player) + if (!(line->special & StairMonster)) + return false; // monsters disallowed + if (!line->tag && ((line->special&6)!=6)) //jff 2/27/98 all non-manual + return false; // generalized types require tag + linefunc = EV_DoGenStairs; + } + else if ((unsigned)line->special >= GenCrusherBase) + { + if (!thing->player) + if (!(line->special & CrusherMonster)) + return false; // monsters disallowed + if (!line->tag && ((line->special&6)!=6)) //jff 2/27/98 all non-manual + return false; // generalized types require tag + linefunc = EV_DoGenCrusher; + } + + if (linefunc) + switch((line->special & TriggerType) >> TriggerTypeShift) + { + case PushOnce: + if (!side) + if (linefunc(line)) + line->special = 0; + return true; + case PushMany: + if (!side) + linefunc(line); + return true; + case SwitchOnce: + if (linefunc(line)) + P_ChangeSwitchTexture(line,0); + return true; + case SwitchMany: + if (linefunc(line)) + P_ChangeSwitchTexture(line,1); + return true; + default: // if not a switch/push type, do nothing here + return false; + } + } + + // Switches that other things can activate. + if (!thing->player) + { + // never open secret doors + if (line->flags & ML_SECRET) + return false; + + switch(line->special) + { + case 1: // MANUAL DOOR RAISE + case 32: // MANUAL BLUE + case 33: // MANUAL RED + case 34: // MANUAL YELLOW + //jff 3/5/98 add ability to use teleporters for monsters + case 195: // switch teleporters + case 174: + case 210: // silent switch teleporters + case 209: + break; + + default: + return false; + break; + } + } + + if (!P_CheckTag(line)) //jff 2/27/98 disallow zero tag on some types + return false; + + // Dispatch to handler according to linedef type + switch (line->special) + { + // Manual doors, push type with no tag + case 1: // Vertical Door + case 26: // Blue Door/Locked + case 27: // Yellow Door /Locked + case 28: // Red Door /Locked + + case 31: // Manual door open + case 32: // Blue locked door open + case 33: // Red locked door open + case 34: // Yellow locked door open + + case 117: // Blazing door raise + case 118: // Blazing door open + EV_VerticalDoor (line, thing); + break; + + // Switches (non-retriggerable) + case 7: + // Build Stairs + if (EV_BuildStairs(line,build8)) + P_ChangeSwitchTexture(line,0); + break; + + case 9: + // Change Donut + if (EV_DoDonut(line)) + P_ChangeSwitchTexture(line,0); + break; + + case 11: + /* Exit level + * killough 10/98: prevent zombies from exiting levels + */ + if (thing->player && thing->player->health <= 0 && !comp[comp_zombie]) + { + S_StartSound(thing, sfx_noway); + return false; + } + + P_ChangeSwitchTexture(line,0); + G_ExitLevel (); + break; + + case 14: + // Raise Floor 32 and change texture + if (EV_DoPlat(line,raiseAndChange,32)) + P_ChangeSwitchTexture(line,0); + break; + + case 15: + // Raise Floor 24 and change texture + if (EV_DoPlat(line,raiseAndChange,24)) + P_ChangeSwitchTexture(line,0); + break; + + case 18: + // Raise Floor to next highest floor + if (EV_DoFloor(line, raiseFloorToNearest)) + P_ChangeSwitchTexture(line,0); + break; + + case 20: + // Raise Plat next highest floor and change texture + if (EV_DoPlat(line,raiseToNearestAndChange,0)) + P_ChangeSwitchTexture(line,0); + break; + + case 21: + // PlatDownWaitUpStay + if (EV_DoPlat(line,downWaitUpStay,0)) + P_ChangeSwitchTexture(line,0); + break; + + case 23: + // Lower Floor to Lowest + if (EV_DoFloor(line,lowerFloorToLowest)) + P_ChangeSwitchTexture(line,0); + break; + + case 29: + // Raise Door + if (EV_DoDoor(line,normal)) + P_ChangeSwitchTexture(line,0); + break; + + case 41: + // Lower Ceiling to Floor + if (EV_DoCeiling(line,lowerToFloor)) + P_ChangeSwitchTexture(line,0); + break; + + case 71: + // Turbo Lower Floor + if (EV_DoFloor(line,turboLower)) + P_ChangeSwitchTexture(line,0); + break; + + case 49: + // Ceiling Crush And Raise + if (EV_DoCeiling(line,crushAndRaise)) + P_ChangeSwitchTexture(line,0); + break; + + case 50: + // Close Door + if (EV_DoDoor(line,p_close)) + P_ChangeSwitchTexture(line,0); + break; + + case 51: + /* Secret EXIT + * killough 10/98: prevent zombies from exiting levels + */ + if (thing->player && thing->player->health <= 0 && !comp[comp_zombie]) + { + S_StartSound(thing, sfx_noway); + return false; + } + + P_ChangeSwitchTexture(line,0); + G_SecretExitLevel (); + break; + + case 55: + // Raise Floor Crush + if (EV_DoFloor(line,raiseFloorCrush)) + P_ChangeSwitchTexture(line,0); + break; + + case 101: + // Raise Floor + if (EV_DoFloor(line,raiseFloor)) + P_ChangeSwitchTexture(line,0); + break; + + case 102: + // Lower Floor to Surrounding floor height + if (EV_DoFloor(line,lowerFloor)) + P_ChangeSwitchTexture(line,0); + break; + + case 103: + // Open Door + if (EV_DoDoor(line,p_open)) + P_ChangeSwitchTexture(line,0); + break; + + case 111: + // Blazing Door Raise (faster than TURBO!) + if (EV_DoDoor (line,blazeRaise)) + P_ChangeSwitchTexture(line,0); + break; + + case 112: + // Blazing Door Open (faster than TURBO!) + if (EV_DoDoor (line,blazeOpen)) + P_ChangeSwitchTexture(line,0); + break; + + case 113: + // Blazing Door Close (faster than TURBO!) + if (EV_DoDoor (line,blazeClose)) + P_ChangeSwitchTexture(line,0); + break; + + case 122: + // Blazing PlatDownWaitUpStay + if (EV_DoPlat(line,blazeDWUS,0)) + P_ChangeSwitchTexture(line,0); + break; + + case 127: + // Build Stairs Turbo 16 + if (EV_BuildStairs(line,turbo16)) + P_ChangeSwitchTexture(line,0); + break; + + case 131: + // Raise Floor Turbo + if (EV_DoFloor(line,raiseFloorTurbo)) + P_ChangeSwitchTexture(line,0); + break; + + case 133: + // BlzOpenDoor BLUE + case 135: + // BlzOpenDoor RED + case 137: + // BlzOpenDoor YELLOW + if (EV_DoLockedDoor (line,blazeOpen,thing)) + P_ChangeSwitchTexture(line,0); + break; + + case 140: + // Raise Floor 512 + if (EV_DoFloor(line,raiseFloor512)) + P_ChangeSwitchTexture(line,0); + break; + + // killough 1/31/98: factored out compatibility check; + // added inner switch, relaxed check to demo_compatibility + + default: + if (!demo_compatibility) + switch (line->special) + { + //jff 1/29/98 added linedef types to fill all functions out so that + // all possess SR, S1, WR, W1 types + + case 158: + // Raise Floor to shortest lower texture + // 158 S1 EV_DoFloor(raiseToTexture), CSW(0) + if (EV_DoFloor(line,raiseToTexture)) + P_ChangeSwitchTexture(line,0); + break; + + case 159: + // Raise Floor to shortest lower texture + // 159 S1 EV_DoFloor(lowerAndChange) + if (EV_DoFloor(line,lowerAndChange)) + P_ChangeSwitchTexture(line,0); + break; + + case 160: + // Raise Floor 24 and change + // 160 S1 EV_DoFloor(raiseFloor24AndChange) + if (EV_DoFloor(line,raiseFloor24AndChange)) + P_ChangeSwitchTexture(line,0); + break; + + case 161: + // Raise Floor 24 + // 161 S1 EV_DoFloor(raiseFloor24) + if (EV_DoFloor(line,raiseFloor24)) + P_ChangeSwitchTexture(line,0); + break; + + case 162: + // Moving floor min n to max n + // 162 S1 EV_DoPlat(perpetualRaise,0) + if (EV_DoPlat(line,perpetualRaise,0)) + P_ChangeSwitchTexture(line,0); + break; + + case 163: + // Stop Moving floor + // 163 S1 EV_DoPlat(perpetualRaise,0) + EV_StopPlat(line); + P_ChangeSwitchTexture(line,0); + break; + + case 164: + // Start fast crusher + // 164 S1 EV_DoCeiling(fastCrushAndRaise) + if (EV_DoCeiling(line,fastCrushAndRaise)) + P_ChangeSwitchTexture(line,0); + break; + + case 165: + // Start slow silent crusher + // 165 S1 EV_DoCeiling(silentCrushAndRaise) + if (EV_DoCeiling(line,silentCrushAndRaise)) + P_ChangeSwitchTexture(line,0); + break; + + case 166: + // Raise ceiling, Lower floor + // 166 S1 EV_DoCeiling(raiseToHighest), EV_DoFloor(lowerFloortoLowest) + if (EV_DoCeiling(line, raiseToHighest) || + EV_DoFloor(line, lowerFloorToLowest)) + P_ChangeSwitchTexture(line,0); + break; + + case 167: + // Lower floor and Crush + // 167 S1 EV_DoCeiling(lowerAndCrush) + if (EV_DoCeiling(line, lowerAndCrush)) + P_ChangeSwitchTexture(line,0); + break; + + case 168: + // Stop crusher + // 168 S1 EV_CeilingCrushStop() + if (EV_CeilingCrushStop(line)) + P_ChangeSwitchTexture(line,0); + break; + + case 169: + // Lights to brightest neighbor sector + // 169 S1 EV_LightTurnOn(0) + EV_LightTurnOn(line,0); + P_ChangeSwitchTexture(line,0); + break; + + case 170: + // Lights to near dark + // 170 S1 EV_LightTurnOn(35) + EV_LightTurnOn(line,35); + P_ChangeSwitchTexture(line,0); + break; + + case 171: + // Lights on full + // 171 S1 EV_LightTurnOn(255) + EV_LightTurnOn(line,255); + P_ChangeSwitchTexture(line,0); + break; + + case 172: + // Start Lights Strobing + // 172 S1 EV_StartLightStrobing() + EV_StartLightStrobing(line); + P_ChangeSwitchTexture(line,0); + break; + + case 173: + // Lights to Dimmest Near + // 173 S1 EV_TurnTagLightsOff() + EV_TurnTagLightsOff(line); + P_ChangeSwitchTexture(line,0); + break; + + case 174: + // Teleport + // 174 S1 EV_Teleport(side,thing) + if (EV_Teleport(line,side,thing)) + P_ChangeSwitchTexture(line,0); + break; + + case 175: + // Close Door, Open in 30 secs + // 175 S1 EV_DoDoor(close30ThenOpen) + if (EV_DoDoor(line,close30ThenOpen)) + P_ChangeSwitchTexture(line,0); + break; + + case 189: //jff 3/15/98 create texture change no motion type + // Texture Change Only (Trigger) + // 189 S1 Change Texture/Type Only + if (EV_DoChange(line,trigChangeOnly)) + P_ChangeSwitchTexture(line,0); + break; + + case 203: + // Lower ceiling to lowest surrounding ceiling + // 203 S1 EV_DoCeiling(lowerToLowest) + if (EV_DoCeiling(line,lowerToLowest)) + P_ChangeSwitchTexture(line,0); + break; + + case 204: + // Lower ceiling to highest surrounding floor + // 204 S1 EV_DoCeiling(lowerToMaxFloor) + if (EV_DoCeiling(line,lowerToMaxFloor)) + P_ChangeSwitchTexture(line,0); + break; + + case 209: + // killough 1/31/98: silent teleporter + //jff 209 S1 SilentTeleport + if (EV_SilentTeleport(line, side, thing)) + P_ChangeSwitchTexture(line,0); + break; + + case 241: //jff 3/15/98 create texture change no motion type + // Texture Change Only (Numeric) + // 241 S1 Change Texture/Type Only + if (EV_DoChange(line,numChangeOnly)) + P_ChangeSwitchTexture(line,0); + break; + + case 221: + // Lower floor to next lowest floor + // 221 S1 Lower Floor To Nearest Floor + if (EV_DoFloor(line,lowerFloorToNearest)) + P_ChangeSwitchTexture(line,0); + break; + + case 229: + // Raise elevator next floor + // 229 S1 Raise Elevator next floor + if (EV_DoElevator(line,elevateUp)) + P_ChangeSwitchTexture(line,0); + break; + + case 233: + // Lower elevator next floor + // 233 S1 Lower Elevator next floor + if (EV_DoElevator(line,elevateDown)) + P_ChangeSwitchTexture(line,0); + break; + + case 237: + // Elevator to current floor + // 237 S1 Elevator to current floor + if (EV_DoElevator(line,elevateCurrent)) + P_ChangeSwitchTexture(line,0); + break; + + + // jff 1/29/98 end of added S1 linedef types + + //jff 1/29/98 added linedef types to fill all functions out so that + // all possess SR, S1, WR, W1 types + + case 78: //jff 3/15/98 create texture change no motion type + // Texture Change Only (Numeric) + // 78 SR Change Texture/Type Only + if (EV_DoChange(line,numChangeOnly)) + P_ChangeSwitchTexture(line,1); + break; + + case 176: + // Raise Floor to shortest lower texture + // 176 SR EV_DoFloor(raiseToTexture), CSW(1) + if (EV_DoFloor(line,raiseToTexture)) + P_ChangeSwitchTexture(line,1); + break; + + case 177: + // Raise Floor to shortest lower texture + // 177 SR EV_DoFloor(lowerAndChange) + if (EV_DoFloor(line,lowerAndChange)) + P_ChangeSwitchTexture(line,1); + break; + + case 178: + // Raise Floor 512 + // 178 SR EV_DoFloor(raiseFloor512) + if (EV_DoFloor(line,raiseFloor512)) + P_ChangeSwitchTexture(line,1); + break; + + case 179: + // Raise Floor 24 and change + // 179 SR EV_DoFloor(raiseFloor24AndChange) + if (EV_DoFloor(line,raiseFloor24AndChange)) + P_ChangeSwitchTexture(line,1); + break; + + case 180: + // Raise Floor 24 + // 180 SR EV_DoFloor(raiseFloor24) + if (EV_DoFloor(line,raiseFloor24)) + P_ChangeSwitchTexture(line,1); + break; + + case 181: + // Moving floor min n to max n + // 181 SR EV_DoPlat(perpetualRaise,0) + + EV_DoPlat(line,perpetualRaise,0); + P_ChangeSwitchTexture(line,1); + break; + + case 182: + // Stop Moving floor + // 182 SR EV_DoPlat(perpetualRaise,0) + EV_StopPlat(line); + P_ChangeSwitchTexture(line,1); + break; + + case 183: + // Start fast crusher + // 183 SR EV_DoCeiling(fastCrushAndRaise) + if (EV_DoCeiling(line,fastCrushAndRaise)) + P_ChangeSwitchTexture(line,1); + break; + + case 184: + // Start slow crusher + // 184 SR EV_DoCeiling(crushAndRaise) + if (EV_DoCeiling(line,crushAndRaise)) + P_ChangeSwitchTexture(line,1); + break; + + case 185: + // Start slow silent crusher + // 185 SR EV_DoCeiling(silentCrushAndRaise) + if (EV_DoCeiling(line,silentCrushAndRaise)) + P_ChangeSwitchTexture(line,1); + break; + + case 186: + // Raise ceiling, Lower floor + // 186 SR EV_DoCeiling(raiseToHighest), EV_DoFloor(lowerFloortoLowest) + if (EV_DoCeiling(line, raiseToHighest) || + EV_DoFloor(line, lowerFloorToLowest)) + P_ChangeSwitchTexture(line,1); + break; + + case 187: + // Lower floor and Crush + // 187 SR EV_DoCeiling(lowerAndCrush) + if (EV_DoCeiling(line, lowerAndCrush)) + P_ChangeSwitchTexture(line,1); + break; + + case 188: + // Stop crusher + // 188 SR EV_CeilingCrushStop() + if (EV_CeilingCrushStop(line)) + P_ChangeSwitchTexture(line,1); + break; + + case 190: //jff 3/15/98 create texture change no motion type + // Texture Change Only (Trigger) + // 190 SR Change Texture/Type Only + if (EV_DoChange(line,trigChangeOnly)) + P_ChangeSwitchTexture(line,1); + break; + + case 191: + // Lower Pillar, Raise Donut + // 191 SR EV_DoDonut() + if (EV_DoDonut(line)) + P_ChangeSwitchTexture(line,1); + break; + + case 192: + // Lights to brightest neighbor sector + // 192 SR EV_LightTurnOn(0) + EV_LightTurnOn(line,0); + P_ChangeSwitchTexture(line,1); + break; + + case 193: + // Start Lights Strobing + // 193 SR EV_StartLightStrobing() + EV_StartLightStrobing(line); + P_ChangeSwitchTexture(line,1); + break; + + case 194: + // Lights to Dimmest Near + // 194 SR EV_TurnTagLightsOff() + EV_TurnTagLightsOff(line); + P_ChangeSwitchTexture(line,1); + break; + + case 195: + // Teleport + // 195 SR EV_Teleport(side,thing) + if (EV_Teleport(line,side,thing)) + P_ChangeSwitchTexture(line,1); + break; + + case 196: + // Close Door, Open in 30 secs + // 196 SR EV_DoDoor(close30ThenOpen) + if (EV_DoDoor(line,close30ThenOpen)) + P_ChangeSwitchTexture(line,1); + break; + + case 205: + // Lower ceiling to lowest surrounding ceiling + // 205 SR EV_DoCeiling(lowerToLowest) + if (EV_DoCeiling(line,lowerToLowest)) + P_ChangeSwitchTexture(line,1); + break; + + case 206: + // Lower ceiling to highest surrounding floor + // 206 SR EV_DoCeiling(lowerToMaxFloor) + if (EV_DoCeiling(line,lowerToMaxFloor)) + P_ChangeSwitchTexture(line,1); + break; + + case 210: + // killough 1/31/98: silent teleporter + //jff 210 SR SilentTeleport + if (EV_SilentTeleport(line, side, thing)) + P_ChangeSwitchTexture(line,1); + break; + + case 211: //jff 3/14/98 create instant toggle floor type + // Toggle Floor Between C and F Instantly + // 211 SR Toggle Floor Instant + if (EV_DoPlat(line,toggleUpDn,0)) + P_ChangeSwitchTexture(line,1); + break; + + case 222: + // Lower floor to next lowest floor + // 222 SR Lower Floor To Nearest Floor + if (EV_DoFloor(line,lowerFloorToNearest)) + P_ChangeSwitchTexture(line,1); + break; + + case 230: + // Raise elevator next floor + // 230 SR Raise Elevator next floor + if (EV_DoElevator(line,elevateUp)) + P_ChangeSwitchTexture(line,1); + break; + + case 234: + // Lower elevator next floor + // 234 SR Lower Elevator next floor + if (EV_DoElevator(line,elevateDown)) + P_ChangeSwitchTexture(line,1); + break; + + case 238: + // Elevator to current floor + // 238 SR Elevator to current floor + if (EV_DoElevator(line,elevateCurrent)) + P_ChangeSwitchTexture(line,1); + break; + + case 258: + // Build stairs, step 8 + // 258 SR EV_BuildStairs(build8) + if (EV_BuildStairs(line,build8)) + P_ChangeSwitchTexture(line,1); + break; + + case 259: + // Build stairs, step 16 + // 259 SR EV_BuildStairs(turbo16) + if (EV_BuildStairs(line,turbo16)) + P_ChangeSwitchTexture(line,1); + break; + + // 1/29/98 jff end of added SR linedef types + + } + break; + + // Buttons (retriggerable switches) + case 42: + // Close Door + if (EV_DoDoor(line,p_close)) + P_ChangeSwitchTexture(line,1); + break; + + case 43: + // Lower Ceiling to Floor + if (EV_DoCeiling(line,lowerToFloor)) + P_ChangeSwitchTexture(line,1); + break; + + case 45: + // Lower Floor to Surrounding floor height + if (EV_DoFloor(line,lowerFloor)) + P_ChangeSwitchTexture(line,1); + break; + + case 60: + // Lower Floor to Lowest + if (EV_DoFloor(line,lowerFloorToLowest)) + P_ChangeSwitchTexture(line,1); + break; + + case 61: + // Open Door + if (EV_DoDoor(line,p_open)) + P_ChangeSwitchTexture(line,1); + break; + + case 62: + // PlatDownWaitUpStay + if (EV_DoPlat(line,downWaitUpStay,1)) + P_ChangeSwitchTexture(line,1); + break; + + case 63: + // Raise Door + if (EV_DoDoor(line,normal)) + P_ChangeSwitchTexture(line,1); + break; + + case 64: + // Raise Floor to ceiling + if (EV_DoFloor(line,raiseFloor)) + P_ChangeSwitchTexture(line,1); + break; + + case 66: + // Raise Floor 24 and change texture + if (EV_DoPlat(line,raiseAndChange,24)) + P_ChangeSwitchTexture(line,1); + break; + + case 67: + // Raise Floor 32 and change texture + if (EV_DoPlat(line,raiseAndChange,32)) + P_ChangeSwitchTexture(line,1); + break; + + case 65: + // Raise Floor Crush + if (EV_DoFloor(line,raiseFloorCrush)) + P_ChangeSwitchTexture(line,1); + break; + + case 68: + // Raise Plat to next highest floor and change texture + if (EV_DoPlat(line,raiseToNearestAndChange,0)) + P_ChangeSwitchTexture(line,1); + break; + + case 69: + // Raise Floor to next highest floor + if (EV_DoFloor(line, raiseFloorToNearest)) + P_ChangeSwitchTexture(line,1); + break; + + case 70: + // Turbo Lower Floor + if (EV_DoFloor(line,turboLower)) + P_ChangeSwitchTexture(line,1); + break; + + case 114: + // Blazing Door Raise (faster than TURBO!) + if (EV_DoDoor (line,blazeRaise)) + P_ChangeSwitchTexture(line,1); + break; + + case 115: + // Blazing Door Open (faster than TURBO!) + if (EV_DoDoor (line,blazeOpen)) + P_ChangeSwitchTexture(line,1); + break; + + case 116: + // Blazing Door Close (faster than TURBO!) + if (EV_DoDoor (line,blazeClose)) + P_ChangeSwitchTexture(line,1); + break; + + case 123: + // Blazing PlatDownWaitUpStay + if (EV_DoPlat(line,blazeDWUS,0)) + P_ChangeSwitchTexture(line,1); + break; + + case 132: + // Raise Floor Turbo + if (EV_DoFloor(line,raiseFloorTurbo)) + P_ChangeSwitchTexture(line,1); + break; + + case 99: + // BlzOpenDoor BLUE + case 134: + // BlzOpenDoor RED + case 136: + // BlzOpenDoor YELLOW + if (EV_DoLockedDoor (line,blazeOpen,thing)) + P_ChangeSwitchTexture(line,1); + break; + + case 138: + // Light Turn On + EV_LightTurnOn(line,255); + P_ChangeSwitchTexture(line,1); + break; + + case 139: + // Light Turn Off + EV_LightTurnOn(line,35); + P_ChangeSwitchTexture(line,1); + break; + } + return true; +} diff --git a/apps/plugins/doom/p_telept.c b/apps/plugins/doom/p_telept.c new file mode 100644 index 0000000000..9282e9f42e --- /dev/null +++ b/apps/plugins/doom/p_telept.c @@ -0,0 +1,322 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Teleportation. + * + *-----------------------------------------------------------------------------*/ + +#include "doomdef.h" +#include "doomstat.h" +#include "p_spec.h" +#include "p_maputl.h" +#include "p_map.h" +#include "r_main.h" +#include "p_tick.h" +#include "s_sound.h" +#include "sounds.h" +#include "p_user.h" +#include "rockmacros.h" +// +// TELEPORTATION +// +// killough 5/3/98: reformatted, cleaned up + +int EV_Teleport(line_t *line, int side, mobj_t *thing) +{ + thinker_t *thinker; + mobj_t *m; + int i; + + // don't teleport missiles + // Don't teleport if hit back of line, + // so you can get out of teleporter. + if (side || thing->flags & MF_MISSILE) + return 0; + + // killough 1/31/98: improve performance by using + // P_FindSectorFromLineTag instead of simple linear search. + + for (i = -1; (i = P_FindSectorFromLineTag(line, i)) >= 0;) + for (thinker=thinkercap.next; thinker!=&thinkercap; thinker=thinker->next) + if (thinker->function == P_MobjThinker && + (m = (mobj_t *) thinker)->type == MT_TELEPORTMAN && + m->subsector->sector-sectors == i) + { + fixed_t oldx = thing->x, oldy = thing->y, oldz = thing->z; + player_t *player = thing->player; + + // killough 5/12/98: exclude voodoo dolls: + if (player && player->mo != thing) + player = NULL; + + if (!P_TeleportMove(thing, m->x, m->y, false)) /* killough 8/9/98 */ + return 0; + + if (!(demo_compatibility && gamemission >= pack_tnt)) + thing->z = thing->floorz; + + if (player) + player->viewz = thing->z + player->viewheight; + + // spawn teleport fog and emit sound at source + S_StartSound(P_SpawnMobj(oldx, oldy, oldz, MT_TFOG), sfx_telept); + + // spawn teleport fog and emit sound at destination + S_StartSound(P_SpawnMobj(m->x + + 20*finecosine[m->angle>>ANGLETOFINESHIFT], + m->y + + 20*finesine[m->angle>>ANGLETOFINESHIFT], + thing->z, MT_TFOG), + sfx_telept); + + /* don't move for a bit + * cph - DEMOSYNC - BOOM had (player) here? */ + if (thing->player) + thing->reactiontime = 18; + + thing->angle = m->angle; + + thing->momx = thing->momy = thing->momz = 0; + + /* killough 10/98: kill all bobbing momentum too */ + if (player) + player->momx = player->momy = 0; + + return 1; + } + return 0; +} + +// +// Silent TELEPORTATION, by Lee Killough +// Primarily for rooms-over-rooms etc. +// + +int EV_SilentTeleport(line_t *line, int side, mobj_t *thing) +{ + int i; + mobj_t *m; + thinker_t *th; + + // don't teleport missiles + // Don't teleport if hit back of line, + // so you can get out of teleporter. + + if (side || thing->flags & MF_MISSILE) + return 0; + + for (i = -1; (i = P_FindSectorFromLineTag(line, i)) >= 0;) + for (th = thinkercap.next; th != &thinkercap; th = th->next) + if (th->function == P_MobjThinker && + (m = (mobj_t *) th)->type == MT_TELEPORTMAN && + m->subsector->sector-sectors == i) + { + // Height of thing above ground, in case of mid-air teleports: + fixed_t z = thing->z - thing->floorz; + + // Get the angle between the exit thing and source linedef. + // Rotate 90 degrees, so that walking perpendicularly across + // teleporter linedef causes thing to exit in the direction + // indicated by the exit thing. + angle_t angle = + R_PointToAngle2(0, 0, line->dx, line->dy) - m->angle + ANG90; + + // Sine, cosine of angle adjustment + fixed_t s = finesine[angle>>ANGLETOFINESHIFT]; + fixed_t c = finecosine[angle>>ANGLETOFINESHIFT]; + + // Momentum of thing crossing teleporter linedef + fixed_t momx = thing->momx; + fixed_t momy = thing->momy; + + // Whether this is a player, and if so, a pointer to its player_t + player_t *player = thing->player; + + // Attempt to teleport, aborting if blocked + if (!P_TeleportMove(thing, m->x, m->y, false)) /* killough 8/9/98 */ + return 0; + + // Rotate thing according to difference in angles + thing->angle += angle; + + // Adjust z position to be same height above ground as before + thing->z = z + thing->floorz; + + // Rotate thing's momentum to come out of exit just like it entered + thing->momx = FixedMul(momx, c) - FixedMul(momy, s); + thing->momy = FixedMul(momy, c) + FixedMul(momx, s); + + // Adjust player's view, in case there has been a height change + // Voodoo dolls are excluded by making sure player->mo == thing. + if (player && player->mo == thing) + { + // Save the current deltaviewheight, used in stepping + fixed_t deltaviewheight = player->deltaviewheight; + + // Clear deltaviewheight, since we don't want any changes + player->deltaviewheight = 0; + + // Set player's view according to the newly set parameters + P_CalcHeight(player); + + // Reset the delta to have the same dynamics as before + player->deltaviewheight = deltaviewheight; + } + return 1; + } + return 0; +} + +// +// Silent linedef-based TELEPORTATION, by Lee Killough +// Primarily for rooms-over-rooms etc. +// This is the complete player-preserving kind of teleporter. +// It has advantages over the teleporter with thing exits. +// + +// maximum fixed_t units to move object to avoid hiccups +#define FUDGEFACTOR 10 + +int EV_SilentLineTeleport(line_t *line, int side, mobj_t *thing, + boolean reverse) +{ + int i; + line_t *l; + + if (side || thing->flags & MF_MISSILE) + return 0; + + for (i = -1; (i = P_FindLineFromLineTag(line, i)) >= 0;) + if ((l=lines+i) != line && l->backsector) + { + // Get the thing's position along the source linedef + fixed_t pos = D_abs(line->dx) > D_abs(line->dy) ? + FixedDiv(thing->x - line->v1->x, line->dx) : + FixedDiv(thing->y - line->v1->y, line->dy) ; + + // Get the angle between the two linedefs, for rotating + // orientation and momentum. Rotate 180 degrees, and flip + // the position across the exit linedef, if reversed. + angle_t angle = (reverse ? pos = FRACUNIT-pos, 0 : ANG180) + + R_PointToAngle2(0, 0, l->dx, l->dy) - + R_PointToAngle2(0, 0, line->dx, line->dy); + + // Interpolate position across the exit linedef + fixed_t x = l->v2->x - FixedMul(pos, l->dx); + fixed_t y = l->v2->y - FixedMul(pos, l->dy); + + // Sine, cosine of angle adjustment + fixed_t s = finesine[angle>>ANGLETOFINESHIFT]; + fixed_t c = finecosine[angle>>ANGLETOFINESHIFT]; + + // Maximum distance thing can be moved away from interpolated + // exit, to ensure that it is on the correct side of exit linedef + int fudge = FUDGEFACTOR; + + // Whether this is a player, and if so, a pointer to its player_t. + // Voodoo dolls are excluded by making sure thing->player->mo==thing. + player_t *player = thing->player && thing->player->mo == thing ? + thing->player : NULL; + + // Whether walking towards first side of exit linedef steps down + int stepdown = + l->frontsector->floorheight < l->backsector->floorheight; + + // Height of thing above ground + fixed_t z = thing->z - thing->floorz; + + // Side to exit the linedef on positionally. + // + // Notes: + // + // This flag concerns exit position, not momentum. Due to + // roundoff error, the thing can land on either the left or + // the right side of the exit linedef, and steps must be + // taken to make sure it does not end up on the wrong side. + // + // Exit momentum is always towards side 1 in a reversed + // teleporter, and always towards side 0 otherwise. + // + // Exiting positionally on side 1 is always safe, as far + // as avoiding oscillations and stuck-in-wall problems, + // but may not be optimum for non-reversed teleporters. + // + // Exiting on side 0 can cause oscillations if momentum + // is towards side 1, as it is with reversed teleporters. + // + // Exiting on side 1 slightly improves player viewing + // when going down a step on a non-reversed teleporter. + + int side = reverse || (player && stepdown); + + // Make sure we are on correct side of exit linedef. + while (P_PointOnLineSide(x, y, l) != side && --fudge>=0) + if (D_abs(l->dx) > D_abs(l->dy)) + y -= (l->dx < 0) != side ? -1 : 1; + else + x += (l->dy < 0) != side ? -1 : 1; + + // Attempt to teleport, aborting if blocked + if (!P_TeleportMove(thing, x, y, false)) /* killough 8/9/98 */ + return 0; + + // Adjust z position to be same height above ground as before. + // Ground level at the exit is measured as the higher of the + // two floor heights at the exit linedef. + thing->z = z + sides[l->sidenum[stepdown]].sector->floorheight; + + // Rotate thing's orientation according to difference in linedef angles + thing->angle += angle; + + // Momentum of thing crossing teleporter linedef + x = thing->momx; + y = thing->momy; + + // Rotate thing's momentum to come out of exit just like it entered + thing->momx = FixedMul(x, c) - FixedMul(y, s); + thing->momy = FixedMul(y, c) + FixedMul(x, s); + + // Adjust a player's view, in case there has been a height change + if (player) + { + // Save the current deltaviewheight, used in stepping + fixed_t deltaviewheight = player->deltaviewheight; + + // Clear deltaviewheight, since we don't want any changes now + player->deltaviewheight = 0; + + // Set player's view according to the newly set parameters + P_CalcHeight(player); + + // Reset the delta to have the same dynamics as before + player->deltaviewheight = deltaviewheight; + } + + return 1; + } + return 0; +} diff --git a/apps/plugins/doom/p_tick.c b/apps/plugins/doom/p_tick.c new file mode 100644 index 0000000000..4bf8feaf7e --- /dev/null +++ b/apps/plugins/doom/p_tick.c @@ -0,0 +1,255 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Thinker, Ticker. + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "p_user.h" +#include "p_spec.h" +#include "p_tick.h" +#include "p_map.h" +#include "rockmacros.h" +int leveltime; + +// +// THINKERS +// All thinkers should be allocated by Z_Malloc +// so they can be operated on uniformly. +// The actual structures will vary in size, +// but the first element must be thinker_t. +// + +// Both the head and tail of the thinker list. +thinker_t thinkercap; + +// killough 8/29/98: we maintain several separate threads, each containing +// a special class of thinkers, to allow more efficient searches. + +thinker_t thinkerclasscap[NUMTHCLASS]; + +// +// P_InitThinkers +// + +void P_InitThinkers(void) +{ + int i; + + for (i=0; ifunction == P_MobjThinker && + ((mobj_t *) thinker)->health > 0 && + (((mobj_t *) thinker)->flags & MF_COUNTKILL || + ((mobj_t *) thinker)->type == MT_SKULL) ? + ((mobj_t *) thinker)->flags & MF_FRIEND ? + th_friends : th_enemies : th_misc; + + // Remove from current thread + thinker_t *th = thinker->cnext; + (th->cprev = thinker->cprev)->cnext = th; + + // Add to appropriate thread + th = &thinkerclasscap[class]; + th->cprev->cnext = thinker; + thinker->cnext = th; + thinker->cprev = th->cprev; + th->cprev = thinker; +} + +// +// P_AddThinker +// Adds a new thinker at the end of the list. +// + +void P_AddThinker(thinker_t* thinker) +{ + thinkercap.prev->next = thinker; + thinker->next = &thinkercap; + thinker->prev = thinkercap.prev; + thinkercap.prev = thinker; + + thinker->references = 0; // killough 11/98: init reference counter to 0 + + // killough 8/29/98: set sentinel pointers, and then add to appropriate list + thinker->cnext = thinker->cprev = thinker; + P_UpdateThinker(thinker); +} + +// +// killough 11/98: +// +// Make currentthinker external, so that P_RemoveThinkerDelayed +// can adjust currentthinker when thinkers self-remove. + +static thinker_t *currentthinker; + +// +// P_RemoveThinkerDelayed() +// +// Called automatically as part of the thinker loop in P_RunThinkers(), +// on nodes which are pending deletion. +// +// If this thinker has no more pointers referencing it indirectly, +// remove it, and set currentthinker to one node preceeding it, so +// that the next step in P_RunThinkers() will get its successor. +// + +void P_RemoveThinkerDelayed(thinker_t *thinker) +{ + if (!thinker->references) + { + thinker_t *next = thinker->next; + (next->prev = currentthinker = thinker->prev)->next = next; + Z_Free(thinker); + } +} + +// +// P_RemoveThinker +// +// Deallocation is lazy -- it will not actually be freed +// until its thinking turn comes up. +// +// killough 4/25/98: +// +// Instead of marking the function with -1 value cast to a function pointer, +// set the function to P_RemoveThinkerDelayed(), so that later, it will be +// removed automatically as part of the thinker process. +// + +void P_RemoveThinker(thinker_t *thinker) +{ + thinker->function = P_RemoveThinkerDelayed; + + // killough 8/29/98: remove immediately from threaded list + (thinker->cnext->cprev = thinker->cprev)->cnext = thinker->cnext; +} + +/* + * P_SetTarget + * + * This function is used to keep track of pointer references to mobj thinkers. + * In Doom, objects such as lost souls could sometimes be removed despite + * their still being referenced. In Boom, 'target' mobj fields were tested + * during each gametic, and any objects pointed to by them would be prevented + * from being removed. But this was incomplete, and was slow (every mobj was + * checked during every gametic). Now, we keep a count of the number of + * references, and delay removal until the count is 0. + */ + +void P_SetTarget(mobj_t **mop, mobj_t *targ) +{ + if (*mop) // If there was a target already, decrease its refcount + (*mop)->thinker.references--; + if ((*mop = targ)) // Set new target and if non-NULL, increase its counter + targ->thinker.references++; +} + +// +// P_RunThinkers +// +// killough 4/25/98: +// +// Fix deallocator to stop using "next" pointer after node has been freed +// (a Doom bug). +// +// Process each thinker. For thinkers which are marked deleted, we must +// load the "next" pointer prior to freeing the node. In Doom, the "next" +// pointer was loaded AFTER the thinker was freed, which could have caused +// crashes. +// +// But if we are not deleting the thinker, we should reload the "next" +// pointer after calling the function, in case additional thinkers are +// added at the end of the list. +// +// killough 11/98: +// +// Rewritten to delete nodes implicitly, by making currentthinker +// external and using P_RemoveThinkerDelayed() implicitly. +// + +static void P_RunThinkers (void) +{ + for (currentthinker = thinkercap.next; + currentthinker != &thinkercap; + currentthinker = currentthinker->next) + if (currentthinker->function) + currentthinker->function(currentthinker); +} + +// +// P_Ticker +// + +void P_Ticker (void) +{ + int i; + + /* pause if in menu and at least one tic has been run + * + * killough 9/29/98: note that this ties in with basetic, + * since G_Ticker does the pausing during recording or + * playback, and compenates by incrementing basetic. + * + * All of this complicated mess is used to preserve demo sync. + */ + + if (paused || (menuactive && !demoplayback && !netgame && + players[consoleplayer].viewz != 1)) + return; + + P_MapStart(); + // not if this is an intermission screen + if(gamestate==GS_LEVEL) + for (i=0; i>= ANGLETOFINESHIFT; + player->mo->momx += FixedMul(move,finecosine[angle]); + player->mo->momy += FixedMul(move,finesine[angle]); +} + + +/* + * P_Bob + * Same as P_Thrust, but only affects bobbing. + * + * killough 10/98: We apply thrust separately between the real physical player + * and the part which affects bobbing. This way, bobbing only comes from player + * motion, nothing external, avoiding many problems, e.g. bobbing should not + * occur on conveyors, unless the player walks on one, and bobbing should be + * reduced at a regular rate, even on ice (where the player coasts). + */ + +void P_Bob(player_t *player, angle_t angle, fixed_t move) +{ + player->momx += FixedMul(move,finecosine[angle >>= ANGLETOFINESHIFT]); + player->momy += FixedMul(move,finesine[angle]); +} + +// +// P_CalcHeight +// Calculate the walking / running height adjustment +// + +void P_CalcHeight (player_t* player) +{ + int angle; + fixed_t bob; + + // Regular movement bobbing + // (needs to be calculated for gun swing + // even if not on ground) + // OPTIMIZE: tablify angle + // Note: a LUT allows for effects + // like a ramp with low health. + + + /* killough 10/98: Make bobbing depend only on player-applied motion. + * + * Note: don't reduce bobbing here if on ice: if you reduce bobbing here, + * it causes bobbing jerkiness when the player moves from ice to non-ice, + * and vice-versa. + */ + player->bob = !mbf_features ? + (FixedMul (player->mo->momx, player->mo->momx) + + FixedMul (player->mo->momy,player->mo->momy))>>2 : + player_bobbing ? (FixedMul(player->momx,player->momx) + + FixedMul(player->momy,player->momy))>>2 : 0; + + if (player->bob > MAXBOB) + player->bob = MAXBOB; + + if (!onground || player->cheats & CF_NOMOMENTUM) + { + player->viewz = player->mo->z + VIEWHEIGHT; + + if (player->viewz > player->mo->ceilingz-4*FRACUNIT) + player->viewz = player->mo->ceilingz-4*FRACUNIT; + + // The following line was in the Id source and appears // phares 2/25/98 + // to be a bug. player->viewz is checked in a similar + // manner at a different exit below. + + // player->viewz = player->mo->z + player->viewheight; + return; + } + + angle = (FINEANGLES/20*leveltime)&FINEMASK; + bob = FixedMul(player->bob/2,finesine[angle]); + + // move viewheight + + if (player->playerstate == PST_LIVE) + { + player->viewheight += player->deltaviewheight; + + if (player->viewheight > VIEWHEIGHT) + { + player->viewheight = VIEWHEIGHT; + player->deltaviewheight = 0; + } + + if (player->viewheight < VIEWHEIGHT/2) + { + player->viewheight = VIEWHEIGHT/2; + if (player->deltaviewheight <= 0) + player->deltaviewheight = 1; + } + + if (player->deltaviewheight) + { + player->deltaviewheight += FRACUNIT/4; + if (!player->deltaviewheight) + player->deltaviewheight = 1; + } + } + + player->viewz = player->mo->z + player->viewheight + bob; + + if (player->viewz > player->mo->ceilingz-4*FRACUNIT) + player->viewz = player->mo->ceilingz-4*FRACUNIT; +} + + +// +// P_MovePlayer +// +// Adds momentum if the player is not in the air +// +// killough 10/98: simplified + +void P_MovePlayer (player_t* player) +{ + ticcmd_t *cmd = &player->cmd; + mobj_t *mo = player->mo; + + mo->angle += cmd->angleturn << 16; + onground = mo->z <= mo->floorz; + + // killough 10/98: + // + // We must apply thrust to the player and bobbing separately, to avoid + // anomalies. The thrust applied to bobbing is always the same strength on + // ice, because the player still "works just as hard" to move, while the + // thrust applied to the movement varies with 'movefactor'. + + if (cmd->forwardmove | cmd->sidemove) // killough 10/98 + { + if (onground || mo->flags & MF_BOUNCES) // killough 8/9/98 + { + int friction, movefactor = P_GetMoveFactor(mo, &friction); + + // killough 11/98: + // On sludge, make bobbing depend on efficiency. + // On ice, make it depend on effort. + + int bobfactor = + friction < ORIG_FRICTION ? movefactor : ORIG_FRICTION_FACTOR; + + if (cmd->forwardmove) + { + P_Bob(player,mo->angle,cmd->forwardmove*bobfactor); + P_Thrust(player,mo->angle,cmd->forwardmove*movefactor); + } + + if (cmd->sidemove) + { + P_Bob(player,mo->angle-ANG90,cmd->sidemove*bobfactor); + P_Thrust(player,mo->angle-ANG90,cmd->sidemove*movefactor); + } + } + if (mo->state == states+S_PLAY) + P_SetMobjState(mo,S_PLAY_RUN1); + } +} + +#define ANG5 (ANG90/18) + +// +// P_DeathThink +// Fall on your face when dying. +// Decrease POV height to floor height. +// + +void P_DeathThink (player_t* player) +{ + angle_t angle; + angle_t delta; + + P_MovePsprites (player); + + // fall to the ground + + if (player->viewheight > 6*FRACUNIT) + player->viewheight -= FRACUNIT; + + if (player->viewheight < 6*FRACUNIT) + player->viewheight = 6*FRACUNIT; + + player->deltaviewheight = 0; + onground = (player->mo->z <= player->mo->floorz); + P_CalcHeight (player); + + if (player->attacker && player->attacker != player->mo) + { + angle = R_PointToAngle2 (player->mo->x, + player->mo->y, + player->attacker->x, + player->attacker->y); + + delta = angle - player->mo->angle; + + if (delta < ANG5 || delta > (unsigned)-ANG5) + { + // Looking at killer, + // so fade damage flash down. + + player->mo->angle = angle; + + if (player->damagecount) + player->damagecount--; + } + else if (delta < ANG180) + player->mo->angle += ANG5; + else + player->mo->angle -= ANG5; + } + else if (player->damagecount) + player->damagecount--; + + if (player->cmd.buttons & BT_USE) + player->playerstate = PST_REBORN; +} + + +// +// P_PlayerThink +// + +void P_PlayerThink (player_t* player) +{ + ticcmd_t* cmd; + weapontype_t newweapon; + + // killough 2/8/98, 3/21/98: + if (player->cheats & CF_NOCLIP) + player->mo->flags |= MF_NOCLIP; + else + player->mo->flags &= ~MF_NOCLIP; + + // chain saw run forward + + cmd = &player->cmd; + if (player->mo->flags & MF_JUSTATTACKED) + { + cmd->angleturn = 0; + cmd->forwardmove = 0xc800/512; + cmd->sidemove = 0; + player->mo->flags &= ~MF_JUSTATTACKED; + } + + if (player->playerstate == PST_DEAD) + { + P_DeathThink (player); + return; + } + + // Move around. + // Reactiontime is used to prevent movement + // for a bit after a teleport. + + if (player->mo->reactiontime) + player->mo->reactiontime--; + else + P_MovePlayer (player); + + P_CalcHeight (player); // Determines view height and bobbing + + // Determine if there's anything about the sector you're in that's + // going to affect you, like painful floors. + + if (player->mo->subsector->sector->special) + P_PlayerInSpecialSector (player); + + // Check for weapon change. + + if (cmd->buttons & BT_CHANGE) + { + // The actual changing of the weapon is done + // when the weapon psprite can do it + // (read: not in the middle of an attack). + + newweapon = (cmd->buttons & BT_WEAPONMASK)>>BT_WEAPONSHIFT; + + // killough 3/22/98: For demo compatibility we must perform the fist + // and SSG weapons switches here, rather than in G_BuildTiccmd(). For + // other games which rely on user preferences, we must use the latter. + + if (demo_compatibility) + { // compatibility mode -- required for old demos -- killough + if (newweapon == wp_fist && player->weaponowned[wp_chainsaw] && + (player->readyweapon != wp_chainsaw || + !player->powers[pw_strength])) + newweapon = wp_chainsaw; + if (gamemode == commercial && + newweapon == wp_shotgun && + player->weaponowned[wp_supershotgun] && + player->readyweapon != wp_supershotgun) + newweapon = wp_supershotgun; + } + + // killough 2/8/98, 3/22/98 -- end of weapon selection changes + + if (player->weaponowned[newweapon] && newweapon != player->readyweapon) + + // Do not go to plasma or BFG in shareware, + // even if cheated. + + if ((newweapon != wp_plasma && newweapon != wp_bfg) + || (gamemode != shareware) ) + player->pendingweapon = newweapon; + } + + // check for use + + if (cmd->buttons & BT_USE) + { + if (!player->usedown) + { + P_UseLines (player); + player->usedown = true; + } + } + else + player->usedown = false; + + // cycle psprites + + P_MovePsprites (player); + + // Counters, time dependent power ups. + + // Strength counts up to diminish fade. + + if (player->powers[pw_strength]) + player->powers[pw_strength]++; + + // killough 1/98: Make idbeholdx toggle: + + if (player->powers[pw_invulnerability] > 0) // killough + player->powers[pw_invulnerability]--; + + if (player->powers[pw_invisibility] > 0) // killough + if (! --player->powers[pw_invisibility] ) + player->mo->flags &= ~MF_SHADOW; + + if (player->powers[pw_infrared] > 0) // killough + player->powers[pw_infrared]--; + + if (player->powers[pw_ironfeet] > 0) // killough + player->powers[pw_ironfeet]--; + + if (player->damagecount) + player->damagecount--; + + if (player->bonuscount) + player->bonuscount--; + + // Handling colormaps. + // killough 3/20/98: reformat to terse C syntax + + player->fixedcolormap = player->powers[pw_invulnerability] > 4*32 || + player->powers[pw_invulnerability] & 8 ? INVERSECOLORMAP : + player->powers[pw_infrared] > 4*32 || player->powers[pw_infrared] & 8; +} diff --git a/apps/plugins/doom/p_user.h b/apps/plugins/doom/p_user.h new file mode 100644 index 0000000000..a236b2a03c --- /dev/null +++ b/apps/plugins/doom/p_user.h @@ -0,0 +1,45 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Player related stuff. + * Bobbing POV/weapon, movement. + * Pending weapon. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __P_USER__ +#define __P_USER__ + +#include "d_player.h" + +void P_PlayerThink(player_t *player); +void P_CalcHeight(player_t *player); +void P_DeathThink(player_t *player); +void P_MovePlayer(player_t *player); +void P_Thrust(player_t *player, angle_t angle, fixed_t move); + +#endif /* __P_USER__ */ diff --git a/apps/plugins/doom/r_bsp.c b/apps/plugins/doom/r_bsp.c new file mode 100644 index 0000000000..358787dc58 --- /dev/null +++ b/apps/plugins/doom/r_bsp.c @@ -0,0 +1,576 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * BSP traversal, handling of LineSegs for rendering. + * + *-----------------------------------------------------------------------------*/ + +#include "doomdef.h" + +#include "m_bbox.h" + +#include "i_system.h" + +#include "r_main.h" +#include "r_plane.h" +#include "r_things.h" + +// State. +#include "doomstat.h" +#include "r_state.h" +#include "r_segs.h" +#include "rockmacros.h" + +seg_t *curline; +side_t *sidedef; +line_t *linedef; +sector_t *frontsector; +sector_t *backsector; +drawseg_t *ds_p; + + +drawseg_t *drawsegs; +unsigned maxdrawsegs; + +// +// R_ClearDrawSegs +// +void R_ClearDrawSegs (void) +{ + ds_p = drawsegs; +} + +// CPhipps - +// Instead of clipsegs, let's try using an array with one entry for each column, +// indicating whether it's blocked by a solid wall yet or not. + +byte solidcol[SCREENWIDTH] IBSS_ATTR; + +// CPhipps - +// R_ClipWallSegment +// +// Replaces the old R_Clip*WallSegment functions. It draws bits of walls in those +// columns which aren't solid, and updates the solidcol[] array appropriately + +void R_ClipWallSegment(int first, int last, boolean solid) +{ + byte *p; + while (first < last) { + if (solidcol[first]) { + if (!(p = memchr(solidcol+first, 0, last-first))) return; // All solid + first = p - solidcol; + } else { + int to; + if (!(p = memchr(solidcol+first, 1, last-first))) to = last; + else to = p - solidcol; + R_StoreWallRange(first, to-1); + if (solid) { + memset(solidcol+first,1,to-first); + } + first = to; + } + } +} + +// +// R_ClearClipSegs +// + +void R_ClearClipSegs (void) +{ + memset(solidcol, 0, SCREENWIDTH); +} + +// killough 1/18/98 -- This function is used to fix the automap bug which +// showed lines behind closed doors simply because the door had a dropoff. +// +// cph - converted to R_RecalcLineFlags. This recalculates all the flags for +// a line, including closure and texture tiling. + +static void R_RecalcLineFlags(void) +{ + linedef->r_validcount = gametic; + + /* First decide if the line is closed, normal, or invisible */ + if (!(linedef->flags & ML_TWOSIDED) + || backsector->ceilingheight <= frontsector->floorheight + || backsector->floorheight >= frontsector->ceilingheight + || ( + // if door is closed because back is shut: + backsector->ceilingheight <= backsector->floorheight + + // preserve a kind of transparent door/lift special effect: + && (backsector->ceilingheight >= frontsector->ceilingheight || + curline->sidedef->toptexture) + + && (backsector->floorheight <= frontsector->floorheight || + curline->sidedef->bottomtexture) + + // properly render skies (consider door "open" if both ceilings are sky): + && (backsector->ceilingpic !=skyflatnum || + frontsector->ceilingpic!=skyflatnum) + ) + ) + linedef->r_flags = RF_CLOSED; + else { + // Reject empty lines used for triggers + // and special events. + // Identical floor and ceiling on both sides, + // identical light levels on both sides, + // and no middle texture. + // CPhipps - recode for speed, not certain if this is portable though + if (backsector->ceilingheight != frontsector->ceilingheight + || backsector->floorheight != frontsector->floorheight + || curline->sidedef->midtexture + || memcmp(&backsector->floor_xoffs, &frontsector->floor_xoffs, + sizeof(frontsector->floor_xoffs) + sizeof(frontsector->floor_yoffs) + + sizeof(frontsector->ceiling_xoffs) + sizeof(frontsector->ceiling_yoffs) + + sizeof(frontsector->ceilingpic) + sizeof(frontsector->floorpic) + + sizeof(frontsector->lightlevel) + sizeof(frontsector->floorlightsec) + + sizeof(frontsector->ceilinglightsec))) { + linedef->r_flags = 0; return; + } else + linedef->r_flags = RF_IGNORE; + } + + /* cph - I'm too lazy to try and work with offsets in this */ + if (curline->sidedef->rowoffset) return; + + /* Now decide on texture tiling */ + if (linedef->flags & ML_TWOSIDED) { + int c; + + /* Does top texture need tiling */ + if ((c = frontsector->ceilingheight - backsector->ceilingheight) > 0 && + (textureheight[texturetranslation[curline->sidedef->toptexture]] > c)) + linedef->r_flags |= RF_TOP_TILE; + + /* Does bottom texture need tiling */ + if ((c = frontsector->floorheight - backsector->floorheight) > 0 && + (textureheight[texturetranslation[curline->sidedef->bottomtexture]] > c)) + linedef->r_flags |= RF_BOT_TILE; + } else { + int c; + /* Does middle texture need tiling */ + if ((c = frontsector->ceilingheight - frontsector->floorheight) > 0 && + (textureheight[texturetranslation[curline->sidedef->midtexture]] > c)) + linedef->r_flags |= RF_MID_TILE; + } +} + +// +// killough 3/7/98: Hack floor/ceiling heights for deep water etc. +// +// If player's view height is underneath fake floor, lower the +// drawn ceiling to be just under the floor height, and replace +// the drawn floor and ceiling textures, and light level, with +// the control sector's. +// +// Similar for ceiling, only reflected. +// +// killough 4/11/98, 4/13/98: fix bugs, add 'back' parameter +// + +sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec, + int *floorlightlevel, int *ceilinglightlevel, + boolean back) +{ + if (floorlightlevel) + *floorlightlevel = sec->floorlightsec == -1 ? + sec->lightlevel : sectors[sec->floorlightsec].lightlevel; + + if (ceilinglightlevel) + *ceilinglightlevel = sec->ceilinglightsec == -1 ? // killough 4/11/98 + sec->lightlevel : sectors[sec->ceilinglightsec].lightlevel; + + if (sec->heightsec != -1) + { + const sector_t *s = §ors[sec->heightsec]; + int heightsec = viewplayer->mo->subsector->sector->heightsec; + int underwater = heightsec!=-1 && viewz<=sectors[heightsec].floorheight; + + // Replace sector being drawn, with a copy to be hacked + *tempsec = *sec; + + // Replace floor and ceiling height with other sector's heights. + tempsec->floorheight = s->floorheight; + tempsec->ceilingheight = s->ceilingheight; + + // killough 11/98: prevent sudden light changes from non-water sectors: + if (underwater && (tempsec-> floorheight = sec->floorheight, + tempsec->ceilingheight = s->floorheight-1, !back)) + { // head-below-floor hack + tempsec->floorpic = s->floorpic; + tempsec->floor_xoffs = s->floor_xoffs; + tempsec->floor_yoffs = s->floor_yoffs; + + if (underwater) { + if (s->ceilingpic == skyflatnum) { + tempsec->floorheight = tempsec->ceilingheight+1; + tempsec->ceilingpic = tempsec->floorpic; + tempsec->ceiling_xoffs = tempsec->floor_xoffs; + tempsec->ceiling_yoffs = tempsec->floor_yoffs; + } else { + tempsec->ceilingpic = s->ceilingpic; + tempsec->ceiling_xoffs = s->ceiling_xoffs; + tempsec->ceiling_yoffs = s->ceiling_yoffs; + } + } + + tempsec->lightlevel = s->lightlevel; + + if (floorlightlevel) + *floorlightlevel = s->floorlightsec == -1 ? s->lightlevel : + sectors[s->floorlightsec].lightlevel; // killough 3/16/98 + + if (ceilinglightlevel) + *ceilinglightlevel = s->ceilinglightsec == -1 ? s->lightlevel : + sectors[s->ceilinglightsec].lightlevel; // killough 4/11/98 + } + else + if (heightsec != -1 && viewz >= sectors[heightsec].ceilingheight && + sec->ceilingheight > s->ceilingheight) + { // Above-ceiling hack + tempsec->ceilingheight = s->ceilingheight; + tempsec->floorheight = s->ceilingheight + 1; + + tempsec->floorpic = tempsec->ceilingpic = s->ceilingpic; + tempsec->floor_xoffs = tempsec->ceiling_xoffs = s->ceiling_xoffs; + tempsec->floor_yoffs = tempsec->ceiling_yoffs = s->ceiling_yoffs; + + if (s->floorpic != skyflatnum) + { + tempsec->ceilingheight = sec->ceilingheight; + tempsec->floorpic = s->floorpic; + tempsec->floor_xoffs = s->floor_xoffs; + tempsec->floor_yoffs = s->floor_yoffs; + } + + tempsec->lightlevel = s->lightlevel; + + if (floorlightlevel) + *floorlightlevel = s->floorlightsec == -1 ? s->lightlevel : + sectors[s->floorlightsec].lightlevel; // killough 3/16/98 + + if (ceilinglightlevel) + *ceilinglightlevel = s->ceilinglightsec == -1 ? s->lightlevel : + sectors[s->ceilinglightsec].lightlevel; // killough 4/11/98 + } + sec = tempsec; // Use other sector + } + return sec; +} + +// +// R_AddLine +// Clips the given segment +// and adds any visible pieces to the line list. +// + +static void R_AddLine (seg_t *line) +{ + int x1; + int x2; + angle_t angle1; + angle_t angle2; + angle_t span; + angle_t tspan; + static sector_t tempsec; // killough 3/8/98: ceiling/water hack + // boolean solid = true; + + curline = line; + + angle1 = R_PointToAngle (line->v1->x, line->v1->y); + angle2 = R_PointToAngle (line->v2->x, line->v2->y); + + // Clip to view edges. + span = angle1 - angle2; + + // Back side, i.e. backface culling + if (span >= ANG180) + return; + + // Global angle needed by segcalc. + rw_angle1 = angle1; + angle1 -= viewangle; + angle2 -= viewangle; + + tspan = angle1 + clipangle; + if (tspan > 2*clipangle) + { + tspan -= 2*clipangle; + + // Totally off the left edge? + if (tspan >= span) + return; + + angle1 = clipangle; + } + + tspan = clipangle - angle2; + if (tspan > 2*clipangle) + { + tspan -= 2*clipangle; + + // Totally off the left edge? + if (tspan >= span) + return; + angle2 = 0-clipangle; + } + + // The seg is in the view range, + // but not necessarily visible. + + angle1 = (angle1+ANG90)>>ANGLETOFINESHIFT; + angle2 = (angle2+ANG90)>>ANGLETOFINESHIFT; + + // killough 1/31/98: Here is where "slime trails" can SOMETIMES occur: + x1 = viewangletox[angle1]; + x2 = viewangletox[angle2]; + + // Does not cross a pixel? + if (x1 >= x2) // killough 1/31/98 -- change == to >= for robustness + return; + + backsector = line->backsector; + + // Single sided line? + if (backsector) + // killough 3/8/98, 4/4/98: hack for invisible ceilings / deep water + backsector = R_FakeFlat(backsector, &tempsec, NULL, NULL, true); + + /* cph - roll up linedef properties in flags */ + if ((linedef = curline->linedef)->r_validcount != gametic) + R_RecalcLineFlags(); + + if (linedef->r_flags & RF_IGNORE) + { + return; + } + else + R_ClipWallSegment (x1, x2, linedef->r_flags & RF_CLOSED); +} + +// +// R_CheckBBox +// Checks BSP node/subtree bounding box. +// Returns true +// if some part of the bbox might be visible. +// + +static const int checkcoord[12][4] = // killough -- static const + { + {3,0,2,1}, + {3,0,2,0}, + {3,1,2,0}, + {0}, + {2,0,2,1}, + {0,0,0,0}, + {3,1,3,0}, + {0}, + {2,0,3,1}, + {2,1,3,1}, + {2,1,3,0} + }; + +// killough 1/28/98: static // CPhipps - const parameter, reformatted +static boolean R_CheckBBox(const fixed_t *bspcoord) +{ + angle_t angle1, angle2; + + { + int boxpos; + const int* check; + + // Find the corners of the box + // that define the edges from current viewpoint. + boxpos = (viewx <= bspcoord[BOXLEFT] ? 0 : viewx < bspcoord[BOXRIGHT ] ? 1 : 2) + + (viewy >= bspcoord[BOXTOP ] ? 0 : viewy > bspcoord[BOXBOTTOM] ? 4 : 8); + + if (boxpos == 5) + return true; + + check = checkcoord[boxpos]; + angle1 = R_PointToAngle (bspcoord[check[0]], bspcoord[check[1]]) - viewangle; + angle2 = R_PointToAngle (bspcoord[check[2]], bspcoord[check[3]]) - viewangle; + } + + // cph - replaced old code, which was unclear and badly commented + // Much more efficient code now + if ((signed)angle1 < (signed)angle2) { /* it's "behind" us */ + /* Either angle1 or angle2 is behind us, so it doesn't matter if we + * change it to the corect sign + */ + if ((angle1 >= ANG180) && (angle1 < ANG270)) + angle1 = INT_MAX; /* which is ANG180-1 */ + else + angle2 = INT_MIN; + } + + if ((signed)angle2 >= (signed)clipangle) return false; // Both off left edge + if ((signed)angle1 <= -(signed)clipangle) return false; // Both off right edge + if ((signed)angle1 >= (signed)clipangle) angle1 = clipangle; // Clip at left edge + if ((signed)angle2 <= -(signed)clipangle) angle2 = 0-clipangle; // Clip at right edge + + // Find the first clippost + // that touches the source post + // (adjacent pixels are touching). + angle1 = (angle1+ANG90)>>ANGLETOFINESHIFT; + angle2 = (angle2+ANG90)>>ANGLETOFINESHIFT; + { + int sx1 = viewangletox[angle1]; + int sx2 = viewangletox[angle2]; + // const cliprange_t *start; + + // Does not cross a pixel. + if (sx1 == sx2) + return false; + + if (!memchr(solidcol+sx1, 0, sx2-sx1)) return false; + // All columns it covers are already solidly covered + } + + return true; +} + +// +// R_Subsector +// Determine floor/ceiling planes. +// Add sprites of things in sector. +// Draw one or more line segments. +// +// killough 1/31/98 -- made static, polished + +// Had to move this out of the function - causes stack overflows in RockBox +sector_t tempsec IBSS_ATTR; // killough 3/7/98: deep water hack +static void R_Subsector(int num) +{ + int count; + seg_t *line; + subsector_t *sub; + + int floorlightlevel; // killough 3/16/98: set floor lightlevel + int ceilinglightlevel; // killough 4/11/98 + +#ifdef RANGECHECK + if (num>=numsubsectors) + I_Error ("R_Subsector: ss %i with numss = %i", num, numsubsectors); +#endif + + sub = &subsectors[num]; + frontsector = sub->sector; + count = sub->numlines; + line = &segs[sub->firstline]; +// sscount++; + + // killough 3/8/98, 4/4/98: Deep water / fake ceiling effect + frontsector = R_FakeFlat(frontsector, &tempsec, &floorlightlevel, + &ceilinglightlevel, false); // killough 4/11/98 + + // killough 3/7/98: Add (x,y) offsets to flats, add deep water check + // killough 3/16/98: add floorlightlevel + // killough 10/98: add support for skies transferred from sidedefs + + floorplane = frontsector->floorheight < viewz || // killough 3/7/98 + (frontsector->heightsec != -1 && + sectors[frontsector->heightsec].ceilingpic == skyflatnum) + ? + R_FindPlane(frontsector->floorheight, + frontsector->floorpic == skyflatnum && // kilough 10/98 + frontsector->sky & PL_SKYFLAT ? frontsector->sky : + frontsector->floorpic, + floorlightlevel, // killough 3/16/98 + frontsector->floor_xoffs, // killough 3/7/98 + frontsector->floor_yoffs + ) : NULL; + + ceilingplane = frontsector->ceilingheight > viewz || + frontsector->ceilingpic == skyflatnum || + (frontsector->heightsec != -1 && + sectors[frontsector->heightsec].floorpic == skyflatnum) + ? + R_FindPlane(frontsector->ceilingheight, // killough 3/8/98 + frontsector->ceilingpic == skyflatnum && // kilough 10/98 + frontsector->sky & PL_SKYFLAT ? frontsector->sky : + frontsector->ceilingpic, + ceilinglightlevel, // killough 4/11/98 + frontsector->ceiling_xoffs, // killough 3/7/98 + frontsector->ceiling_yoffs + ) : NULL; + + // killough 9/18/98: Fix underwater slowdown, by passing real sector + // instead of fake one. Improve sprite lighting by basing sprite + // lightlevels on floor & ceiling lightlevels in the surrounding area. + // + // 10/98 killough: + // + // NOTE: TeamTNT fixed this bug incorrectly, messing up sprite lighting!!! + // That is part of the 242 effect!!! If you simply pass sub->sector to + // the old code you will not get correct lighting for underwater sprites!!! + // Either you must pass the fake sector and handle validcount here, on the + // real sector, or you must account for the lighting in some other way, + // like passing it as an argument. + + R_AddSprites(sub, (floorlightlevel+ceilinglightlevel)/2); + + while (count--) + { + if (line->miniseg == false) + R_AddLine (line); + line++; + } + +} + +// +// RenderBSPNode +// Renders all subsectors below a given node, +// traversing subtree recursively. +// Just call with BSP root. +// +// killough 5/2/98: reformatted, removed tail recursion + +void R_RenderBSPNode(int bspnum) +{ + while (!(bspnum & NF_SUBSECTOR)) // Found a subsector? + { + const node_t *bsp = &nodes[bspnum]; + + // Decide which side the view point is on. + int side = R_PointOnSide(viewx, viewy, bsp); + // Recursively divide front space. + R_RenderBSPNode(bsp->children[side]); + + // Possibly divide back space. + + if (!R_CheckBBox(bsp->bbox[side^1])) + return; + + bspnum = bsp->children[side^1]; + } + R_Subsector(bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR); +} diff --git a/apps/plugins/doom/r_bsp.h b/apps/plugins/doom/r_bsp.h new file mode 100644 index 0000000000..2ea653833d --- /dev/null +++ b/apps/plugins/doom/r_bsp.h @@ -0,0 +1,78 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Refresh module, BSP traversal and handling. + * + *-----------------------------------------------------------------------------*/ + + +#ifndef __R_BSP__ +#define __R_BSP__ + +#ifdef __GNUG__ +#pragma interface +#endif + +extern seg_t *curline; +extern side_t *sidedef; +extern line_t *linedef; +extern sector_t *frontsector; +extern sector_t *backsector; +extern int rw_x; +extern int rw_stopx; +extern boolean segtextured; +extern boolean markfloor; /* false if the back side is the same plane */ +extern boolean markceiling; + +//extern boolean skymap; + +/* old code -- killough: + * extern drawseg_t drawsegs[MAXDRAWSEGS]; + * new code -- killough: */ +extern drawseg_t *drawsegs; +extern unsigned maxdrawsegs; + +extern drawseg_t* ds_p; + +/*extern lighttable_t** hscalelight; +extern lighttable_t** vscalelight; +extern lighttable_t** dscalelight; +*/ + +//typedef void (*drawfunc_t) (int start, int stop); + + +// BSP? +void R_ClearClipSegs (void); +void R_ClearDrawSegs (void); +void R_RenderBSPNode (int bspnum); +int R_DoorClosed(void); /* killough 1/17/98 */ + +/* killough 4/13/98: fake floors/ceilings for deep water / fake ceilings: */ +sector_t *R_FakeFlat(sector_t *, sector_t *, int *, int *, boolean); + +#endif diff --git a/apps/plugins/doom/r_data.c b/apps/plugins/doom/r_data.c new file mode 100644 index 0000000000..aad16e4d95 --- /dev/null +++ b/apps/plugins/doom/r_data.c @@ -0,0 +1,975 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Preparation of data for rendering, + * generation of lookups, caching, retrieval by name. + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "w_wad.h" +#include "r_main.h" +#include "r_sky.h" +#include "i_system.h" +#include "m_swap.h" +#include "p_tick.h" +//#include "lprintf.h" // jff 08/03/98 - declaration of lprintf +#include "rockmacros.h" +// +// Graphics. +// DOOM graphics for walls and sprites +// is stored in vertical runs of opaque pixels (posts). +// A column is composed of zero or more posts, +// a patch or sprite is composed of zero or more columns. +// + +// +// Texture definition. +// Each texture is composed of one or more patches, +// with patches being lumps stored in the WAD. +// The lumps are referenced by number, and patched +// into the rectangular texture space using origin +// and possibly other attributes. +// + +typedef struct +{ + short originx; + short originy; + short patch; + short stepdir; // unused in Doom but might be used in Phase 2 Boom + short colormap; // unused in Doom but might be used in Phase 2 Boom +} PACKEDATTR mappatch_t; + +typedef struct +{ + char name[8]; + boolean masked; + short width; + short height; + char pad[4]; // unused in Doom but might be used in Boom Phase 2 + short patchcount; + mappatch_t patches[1]; +} PACKEDATTR maptexture_t; + +// A maptexturedef_t describes a rectangular texture, which is composed +// of one or more mappatch_t structures that arrange graphic patches. + +// killough 4/17/98: make firstcolormaplump,lastcolormaplump external +int firstcolormaplump, lastcolormaplump; // killough 4/17/98 + +int firstflat, lastflat, numflats; +int firstspritelump, lastspritelump, numspritelumps; +int numtextures; +static texture_t **textures; +fixed_t *textureheight; //needed for texture pegging (and TFE fix - killough) +int *flattranslation; // for global animation +int *texturetranslation; +// needed for pre-rendering +fixed_t *spritewidth, *spriteoffset, *spritetopoffset; + +// +// MAPTEXTURE_T CACHING +// When a texture is first needed, +// it counts the number of composite columns +// required in the texture and allocates space +// for a column directory and any new columns. +// The directory will simply point inside other patches +// if there is only one patch in a given column, +// but any columns with multiple patches +// will have new column_ts generated. +// + +// +// R_DrawColumnInCache +// Clip and draw a column +// from a patch into a cached post. +// +// Rewritten by Lee Killough for performance and to fix Medusa bug +// + +void R_DrawColumnInCache(const column_t *patch, byte *cache, + int originy, int cacheheight, byte *marks) +{ + while (patch->topdelta != 0xff) + { + int count = patch->length; + int position = originy + patch->topdelta; + + if (position < 0) + { + count += position; + position = 0; + } + + if (position + count > cacheheight) + count = cacheheight - position; + + if (count > 0) + { + memcpy (cache + position, (byte *)patch + 3, count); + + // killough 4/9/98: remember which cells in column have been drawn, + // so that column can later be converted into a series of posts, to + // fix the Medusa bug. + + memset (marks + position, 0xff, count); + } + + patch = (column_t *)((byte *) patch + patch->length + 4); + } +} + +// +// R_GenerateComposite +// Using the texture definition, +// the composite texture is created from the patches, +// and each column is cached. +// +// Rewritten by Lee Killough for performance and to fix Medusa bug + +void R_GenerateComposite(int texnum) +{ + texture_t *texture = textures[texnum]; + byte *block = Z_Malloc(texture->compositesize, PU_STATIC, + (void **)&texture->composite); + // Composite the columns together. + texpatch_t *patch = texture->patches; + short *collump = texture->columnlump; + unsigned *colofs = texture->columnofs; // killough 4/9/98: make 32-bit + int i = texture->patchcount; + // killough 4/9/98: marks to identify transparent regions in merged textures + byte *marks = calloc(texture->width, texture->height), *source; + + for (; --i >=0; patch++) + { + const patch_t *realpatch = W_CacheLumpNum(patch->patch); // cph + int x1 = patch->originx, x2 = x1 + SHORT(realpatch->width); + const int *cofs = realpatch->columnofs-x1; + if (x1<0) + x1 = 0; + if (x2 > texture->width) + x2 = texture->width; + for (; x1originy,texture->height, + marks + x1 * texture->height); + + W_UnlockLumpNum(patch->patch); // cph - unlock the patch lump + } + + // killough 4/9/98: Next, convert multipatched columns into true columns, + // to fix Medusa bug while still allowing for transparent regions. + + source = malloc(texture->height); // temporary column + for (i=0; i < texture->width; i++) + if (collump[i] == -1) // process only multipatched columns + { + column_t *col = (column_t *)(block + colofs[i] - 3); // cached column + const byte *mark = marks + i * texture->height; + int j = 0; + + // save column in temporary so we can shuffle it around + memcpy(source, (byte *) col + 3, texture->height); + + for (;;) // reconstruct the column by scanning transparency marks + { + while (j < texture->height && !mark[j]) // skip transparent cells + j++; + if (j >= texture->height) // if at end of column + { + col->topdelta = -1; // end-of-column marker + break; + } + col->topdelta = j; // starting offset of post + for (col->length=0; j < texture->height && mark[j]; j++) + col->length++; // count opaque cells + // copy opaque cells from the temporary back into the column + memcpy((byte *) col + 3, source + col->topdelta, col->length); + col = (column_t *)((byte *) col + col->length + 4); // next post + } + } + free(source); // free temporary column + free(marks); // free transparency marks + + // Now that the texture has been built in column cache, + // it is purgable from zone memory. + + Z_ChangeTag(block, PU_CACHE); +} + +// +// R_GenerateLookup +// +// Rewritten by Lee Killough for performance and to fix Medusa bug +// + +static void R_GenerateLookup(int texnum, int *const errors) +{ + texture_t *texture = textures[texnum]; + + // killough 4/9/98: make column offsets 32-bit; + // clean up malloc-ing to use sizeof + // CPhipps - moved allocing here + short *collump = texture->columnlump = + Z_Malloc(texture->width*sizeof(*texture->columnlump), PU_STATIC,0); + unsigned *colofs = texture->columnofs = + Z_Malloc(texture->width*sizeof(*texture->columnofs), PU_STATIC,0); + + // killough 4/9/98: keep count of posts in addition to patches. + // Part of fix for medusa bug for multipatched 2s normals. + + struct { + unsigned short patches, posts; + } *count = calloc(sizeof *count, texture->width); + + { + int i = texture->patchcount; + const texpatch_t *patch = texture->patches; + + while (--i >= 0) + { + int pat = patch->patch; + const patch_t *realpatch = W_CacheLumpNum(pat); + int x1 = patch++->originx, x2 = x1 + SHORT(realpatch->width), x = x1; + const int *cofs = realpatch->columnofs-x1; + + if (x2 > texture->width) + x2 = texture->width; + if (x1 < 0) + x = 0; + for ( ; xtopdelta != 0xff; count[x].posts++) + col = (column_t *)((byte *) col + col->length + 4); + count[x].patches++; + collump[x] = pat; + colofs[x] = LONG(cofs[x])+3; + } + + W_UnlockLumpNum(pat); + } + } + + // Composited texture not created yet. + texture->composite = NULL; + + // Now count the number of columns + // that are covered by more than one patch. + // Fill in the lump / offset, so columns + // with only a single patch are all done. + + { + int x = texture->width; + int height = texture->height; + int csize = 0; + + while (--x >= 0) + { + if (!count[x].patches) // killough 4/9/98 + { + //jff 8/3/98 use logical output routine + printf("\nR_GenerateLookup: Column %d is without a patch in texture %s", + x, texture->name); + if (errors) ++*errors; + else I_Error("R_GenerateLookup: Failed"); + } + if (count[x].patches > 1) // killough 4/9/98 + { + // killough 1/25/98, 4/9/98: + // + // Fix Medusa bug, by adding room for column header + // and trailer bytes for each post in merged column. + // For now, just allocate conservatively 4 bytes + // per post per patch per column, since we don't + // yet know how many posts the merged column will + // require, and it's bounded above by this limit. + + collump[x] = -1; // mark lump as multipatched + colofs[x] = csize + 3; // three header bytes in a column + csize += 4*count[x].posts+1; // 1 stop byte plus 4 bytes per post + } + csize += height; // height bytes of texture data + } + texture->compositesize = csize; + } + free(count); // killough 4/9/98 +} + +// +// R_GetColumn +// + +const byte *R_GetColumn(int tex, int col) +{ + const texture_t *texture = textures[tex]; + if (!texture->columnlump) R_GenerateLookup(tex, NULL); + { + int lump = texture->columnlump[col &= texture->widthmask]; + int ofs = texture->columnofs[col]; // cph - WARNING: must be after the above line + // cph - remember the last lump, so we can unlock it if no longer needed, + // or reuse it if possible to reduce lump locking/unlocking + static int lastlump = -1; + static const byte* lastlumpdata; + + if ((lump<=0) && (lastlump<=0)) + lump = lastlump; // cph - force equal + + if (lump != lastlump) { + // cph - must change the cached lump + if (lastlump>0) + W_UnlockLumpNum(lastlump); + + if ((lastlump = lump) > 0) + lastlumpdata = W_CacheLumpNum(lump); +#ifdef RANGECHECK + else + lastlumpdata = NULL; +#endif + } + + if (lump > 0) + return lastlumpdata + ofs; + + if (!texture->composite) + R_GenerateComposite(tex); + + return texture->composite + ofs; + } +} + +// +// R_InitTextures +// Initializes the texture list +// with the textures from the world map. +// + +void R_InitTextures (void) +{ + maptexture_t *mtexture; + texture_t *texture; + mappatch_t *mpatch; + texpatch_t *patch; + int i, j; + int maptex_lump[2] = {-1, -1}; + const int *maptex; + const int *maptex1, *maptex2; + char name[9]; + int names_lump; // cph - new wad lump handling + const char *names; // cph - + const char *name_p;// const*'s + int *patchlookup; + int totalwidth; + int nummappatches; + int offset; + int maxoff, maxoff2; + int numtextures1, numtextures2; + const int *directory; + int errors = 0; + + // Load the patch names from pnames.lmp. + name[8] = 0; + names = W_CacheLumpNum(names_lump = W_GetNumForName("PNAMES")); + nummappatches = LONG(*((const int *)names)); + name_p = names+4; + patchlookup = malloc(nummappatches*sizeof(*patchlookup)); // killough + + for (i=0 ; i maxoff) + I_Error("R_InitTextures: Bad texture directory"); + + mtexture = (maptexture_t *) ( (byte *)maptex + offset); + + texture = textures[i] = + Z_Malloc(sizeof(texture_t) + + sizeof(texpatch_t)*(SHORT(mtexture->patchcount)-1), + PU_STATIC, 0); + + texture->width = SHORT(mtexture->width); + texture->height = SHORT(mtexture->height); + texture->patchcount = SHORT(mtexture->patchcount); + + /* Mattias EngdegÃ¥rd emailed me of the following explenation of + * why memcpy doesnt work on some systems: + * "I suppose it is the mad unaligned allocation + * going on (and which gcc in some way manages to cope with + * through the __attribute__ ((packed))), and which it forgets + * when optimizing memcpy (to a single word move) since it appears + * to be aligned. Technically a gcc bug, but I can't blame it when + * it's stressed with that amount of + * non-standard nonsense." + * So in short the unaligned struct confuses gcc's optimizer so + * i took the memcpy out alltogether to avoid future problems-Jess + */ + /* The above was #ifndef SPARC, but i got a mail from + * Putera Joseph F NPRI containing: + * I had to use the memcpy function on a sparc machine. The + * other one would give me a core dump. + * cph - I find it hard to believe that sparc memcpy is broken, + * but I don't believe the pointers to memcpy have to be aligned + * either. Use fast memcpy on other machines anyway. + */ + /* + proff - I took this out, because Oli Kraus (olikraus@yahoo.com) told + me the memcpy produced a buserror. Since this function isn't time- + critical I'm using the for loop now. + */ + /* + #ifndef GCC + memcpy(texture->name, mtexture->name, sizeof(texture->name)); + #else + */ + { + unsigned int j; + for(j=0;jname);j++) + texture->name[j]=mtexture->name[j]; + } + /* #endif */ + + mpatch = mtexture->patches; + patch = texture->patches; + + for (j=0 ; jpatchcount ; j++, mpatch++, patch++) + { + patch->originx = SHORT(mpatch->originx); + patch->originy = SHORT(mpatch->originy); + patch->patch = patchlookup[SHORT(mpatch->patch)]; + if (patch->patch == -1) + { + //jff 8/3/98 use logical output routine + printf("\nR_InitTextures: Missing patch %d in texture %s", + SHORT(mpatch->patch), texture->name); // killough 4/17/98 + ++errors; + } + } + + texture->columnofs = NULL; texture->columnlump = NULL; + + for (j=1; j*2 <= texture->width; j<<=1) + ; + texture->widthmask = j-1; + textureheight[i] = texture->height<width; + } + + free(patchlookup); // killough + + for (i=0; i<2; i++) // cph - release the TEXTUREx lumps + if (maptex_lump[i] != -1) + W_UnlockLumpNum(maptex_lump[i]); + + if (errors) + I_Error("R_InitTextures: %d errors", errors); + + // Precalculate whatever possible. + if (devparm) // cph - If in development mode, generate now so all errors are found at once + for (i=0 ; iindex = -1; + while (--i >= 0) + { + int j = W_LumpNameHash(textures[i]->name) % (unsigned) numtextures; + textures[i]->next = textures[j]->index; // Prepend to chain + textures[j]->index = i; + } +} + +// +// R_InitFlats +// +void R_InitFlats(void) +{ + int i; + + firstflat = W_GetNumForName("F_START") + 1; + lastflat = W_GetNumForName("F_END") - 1; + numflats = lastflat - firstflat + 1; + + // Create translation table for global animation. + // killough 4/9/98: make column offsets 32-bit; + // clean up malloc-ing to use sizeof + + flattranslation = + Z_Malloc((numflats+1)*sizeof(*flattranslation), PU_STATIC, 0); + + for (i=0 ; iwidth)<leftoffset)<topoffset)<=0); + } + + // Next, compute all entries using minimum arithmetic. + + { + int i,j; + byte *tp = my_tranmap; + for (i=0;i<256;i++) + { + long r1 = pal[0][i] * w2; + long g1 = pal[1][i] * w2; + long b1 = pal[2][i] * w2; + if (!(i & 31) && progress) + //jff 8/3/98 use logical output routine + printf(" Computing: %d", 256/32-i/32); + for (j=0;j<256;j++,tp++) + { + register int color = 255; + register long err; + long r = pal_w1[0][j] + r1; + long g = pal_w1[1][j] + g1; + long b = pal_w1[2][j] + b1; + long best = LONG_MAX; + do + if ((err = tot[color] - pal[0][color]*r + - pal[1][color]*g - pal[2][color]*b) < best) + best = err, *tp = color; + while (--color >= 0); + } + } + } + + free(stackdeath); // Free this beast + + if (cachefd) // write out the cached translucency map + { + cache.pct = tran_filter_pct; + memcpy(cache.playpal, playpal, 256); + lseek(cachefd, 0, SEEK_SET); + write(cachefd, &cache, sizeof cache); + write(cachefd,main_tranmap, 256*256); + // CPhipps - leave close for a few lines... + } + + } + + if (cachefd) // killough 11/98: fix filehandle leak + close(cachefd); + + W_UnlockLumpName("PLAYPAL"); + } +} + +// +// R_InitData +// Locates all the lumps +// that will be used by all views +// Must be called after W_Init. +// +void R_InitData (void) +{ + R_InitTextures (); + printf ("\nInitTextures"); + R_InitFlats (); + printf ("\nInitFlats"); + R_InitSpriteLumps (); + printf ("\nInitSprites"); + if (general_translucency) // killough 3/1/98 + R_InitTranMap(1); + R_InitColormaps (); + printf ("\nInitColormaps"); +} + +// +// R_FlatNumForName +// Retrieval, get a flat number for a flat name. +// +// killough 4/17/98: changed to use ns_flats namespace +// + +int R_FlatNumForName(const char *name) // killough -- const added +{ + int i = (W_CheckNumForName)(name, ns_flats); + if (i == -1) + I_Error("R_FlatNumForName: %s not found", name); + return i - firstflat; +} + +// +// R_CheckTextureNumForName +// Check whether texture is available. +// Filter out NoTexture indicator. +// +// Rewritten by Lee Killough to use hash table for fast lookup. Considerably +// reduces the time needed to start new levels. See w_wad.c for comments on +// the hashing algorithm, which is also used for lump searches. +// +// killough 1/21/98, 1/31/98 +// + +int R_CheckTextureNumForName(const char *name) +{ + int i = 0; + if (*name != '-') // "NoTexture" marker. + { + i = textures[W_LumpNameHash(name) % (unsigned) numtextures]->index; + while (i >= 0 && strncasecmp(textures[i]->name,name,8)) + i = textures[i]->next; + } + return i; +} + +// +// R_TextureNumForName +// Calls R_CheckTextureNumForName, +// aborts with error message. +// + +int R_TextureNumForName(const char *name) // const added -- killough +{ + int i = R_CheckTextureNumForName(name); + if (i == -1) + I_Error("R_TextureNumForName: %s not found", name); + return i; +} + +// +// R_PrecacheLevel +// Preloads all relevant graphics for the level. +// +// Totally rewritten by Lee Killough to use less memory, +// to avoid using alloca(), and to improve performance. +// cph - new wad lump handling, calls cache functions but acquires no locks + +void R_PrecacheLevel(void) +{ + register int i; + register byte *hitlist; + + if (demoplayback) + return; + + { + size_t size = numflats > numsprites ? numflats : numsprites; + hitlist = malloc((size_t)numtextures > size ? (unsigned)numtextures : size); + } + // Precache flats. + + memset(hitlist, 0, numflats); + + for (i = numsectors; --i >= 0; ) + hitlist[sectors[i].floorpic] = hitlist[sectors[i].ceilingpic] = 1; + + for (i = numflats; --i >= 0; ) + if (hitlist[i]) + (W_CacheLumpNum)(firstflat + i, 0); + + // Precache textures. + + memset(hitlist, 0, numtextures); + + for (i = numsides; --i >= 0;) + hitlist[sides[i].bottomtexture] = + hitlist[sides[i].toptexture] = + hitlist[sides[i].midtexture] = 1; + + // Sky texture is always present. + // Note that F_SKY1 is the name used to + // indicate a sky floor/ceiling as a flat, + // while the sky texture is stored like + // a wall texture, with an episode dependend + // name. + + hitlist[skytexture] = 1; + + for (i = numtextures; --i >= 0; ) + if (hitlist[i]) + { + texture_t *texture = textures[i]; + int j = texture->patchcount; + while (--j >= 0) + (W_CacheLumpNum)(texture->patches[j].patch, 0); + } + + // Precache sprites. + memset(hitlist, 0, numsprites); + + { + thinker_t *th; + for (th = thinkercap.next ; th != &thinkercap ; th=th->next) + if (th->function == P_MobjThinker) + hitlist[((mobj_t *)th)->sprite] = 1; + } + + for (i=numsprites; --i >= 0;) + if (hitlist[i]) + { + int j = sprites[i].numframes; + while (--j >= 0) + { + short *sflump = sprites[i].spriteframes[j].lump; + int k = 7; + do + (W_CacheLumpNum)(firstspritelump + sflump[k], 0); + while (--k >= 0); + } + } + free(hitlist); +} + +// Proff - Added for OpenGL +void R_SetPatchNum(patchnum_t *patchnum, const char *name) +{ + patch_t *patch; + + patch = (patch_t *) W_CacheLumpName(name); + patchnum->width = patch->width; + patchnum->height = patch->height; + patchnum->leftoffset = patch->leftoffset; + patchnum->topoffset = patch->topoffset; + patchnum->lumpnum = W_GetNumForName(name); + W_UnlockLumpName(name); +} diff --git a/apps/plugins/doom/r_data.h b/apps/plugins/doom/r_data.h new file mode 100644 index 0000000000..12c9eb74af --- /dev/null +++ b/apps/plugins/doom/r_data.h @@ -0,0 +1,105 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Refresh module, data I/O, caching, retrieval of graphics + * by name. + * + *-----------------------------------------------------------------------------*/ + + +#ifndef __R_DATA__ +#define __R_DATA__ + +#include "r_defs.h" +#include "r_state.h" + +#ifdef __GNUG__ +#pragma interface +#endif + +// A single patch from a texture definition, basically +// a rectangular area within the texture rectangle. +typedef struct +{ + int originx, originy; // Block origin, which has already accounted + int patch; // for the internal origin of the patch. +} texpatch_t; + +// +// Texture definition. +// A DOOM wall texture is a list of patches +// which are to be combined in a predefined order. +// + +typedef struct +{ + char name[8]; // Keep name for switch changing, etc. + int next, index; // killough 1/31/98: used in hashing algorithm + // CPhipps - moved arrays with per-texture entries to elements here + unsigned widthmask; + size_t compositesize; + byte *composite; + short *columnlump; + unsigned *columnofs; + // CPhipps - end of additions + short width, height; + short patchcount; // All the patches[patchcount] are drawn + texpatch_t patches[1]; // back-to-front into the cached texture. +} texture_t; + +// Retrieve column data for span blitting. +const byte* +R_GetColumn +( int tex, + int col ); + + +// I/O, setting up the stuff. +void R_InitData (void); +void R_PrecacheLevel (void); + + +// Retrieval. +// Floor/ceiling opaque texture tiles, +// lookup by name. For animation? +int R_FlatNumForName (const char* name); // killough -- const added + + +// Called by P_Ticker for switches and animations, +// returns the texture number for the texture name. +int R_TextureNumForName (const char *name); // killough -- const added +int R_CheckTextureNumForName (const char *name); + +void R_InitTranMap(int); // killough 3/6/98: translucency initialization +int R_ColormapNumForName(const char *name); // killough 4/4/98 + +extern const byte *main_tranmap, *tranmap; + +/* Proff - Added for OpenGL - cph - const char* param */ +void R_SetPatchNum(patchnum_t *patchnum, const char *name); + +#endif diff --git a/apps/plugins/doom/r_defs.h b/apps/plugins/doom/r_defs.h new file mode 100644 index 0000000000..a3bd5cdf33 --- /dev/null +++ b/apps/plugins/doom/r_defs.h @@ -0,0 +1,422 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// $Id$ +// +// Copyright (C) 1993-1996 by id Software, Inc. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// Refresh/rendering module, shared data struct definitions. +// +//----------------------------------------------------------------------------- + +#ifndef __R_DEFS__ +#define __R_DEFS__ + +// Screenwidth. +#include "doomdef.h" + +// Some more or less basic data types +// we depend on. +#include "m_fixed.h" + +// We rely on the thinker data struct +// to handle sound origins in sectors. +#include "d_think.h" +// SECTORS do store MObjs anyway. +#include "p_mobj.h" + +#ifdef __GNUG__ +#pragma interface +#endif + +// Silhouette, needed for clipping Segs (mainly) +// and sprites representing things. +#define SIL_NONE 0 +#define SIL_BOTTOM 1 +#define SIL_TOP 2 +#define SIL_BOTH 3 + +#define MAXDRAWSEGS 256 + +// +// INTERNAL MAP TYPES +// used by play and refresh +// + +// +// Your plain vanilla vertex. +// Note: transformed values not buffered locally, +// like some DOOM-alikes ("wt", "WebView") do. +// +typedef struct +{ + fixed_t x, y; +} vertex_t; + + +// Forward of LineDefs, for Sectors. +struct line_s; + +// Each sector has a degenmobj_t in its center for sound origin purposes. +typedef struct +{ + thinker_t thinker; // not used for anything + fixed_t x, y, z; +} degenmobj_t; + +// +// The SECTORS record, at runtime. +// Stores things/mobjs. +// + +typedef struct +{ + fixed_t floorheight; + fixed_t ceilingheight; + int nexttag,firsttag; // killough 1/30/98: improves searches for tags. + int soundtraversed; // 0 = untraversed, 1,2 = sndlines-1 + mobj_t *soundtarget; // thing that made a sound (or null) + int blockbox[4]; // mapblock bounding box for height changes + degenmobj_t soundorg; // origin for any sounds played by the sector + int validcount; // if == validcount, already checked + mobj_t *thinglist; // list of mobjs in sector + + /* killough 8/28/98: friction is a sector property, not an mobj property. + * these fields used to be in mobj_t, but presented performance problems + * when processed as mobj properties. Fix is to make them sector properties. + */ + int friction,movefactor; + + // thinker_t for reversable actions + void *floordata; // jff 2/22/98 make thinkers on + void *ceilingdata; // floors, ceilings, lighting, + void *lightingdata; // independent of one another + + // jff 2/26/98 lockout machinery for stairbuilding + int stairlock; // -2 on first locked -1 after thinker done 0 normally + int prevsec; // -1 or number of sector for previous step + int nextsec; // -1 or number of next step sector + + // killough 3/7/98: support flat heights drawn at another sector's heights + int heightsec; // other sector, or -1 if no other sector + + int bottommap, midmap, topmap; // killough 4/4/98: dynamic colormaps + + // list of mobjs that are at least partially in the sector + // thinglist is a subset of touching_thinglist + struct msecnode_s *touching_thinglist; // phares 3/14/98 + + int linecount; + struct line_s **lines; + + // killough 10/98: support skies coming from sidedefs. Allows scrolling + // skies and other effects. No "level info" kind of lump is needed, + // because you can use an arbitrary number of skies per level with this + // method. This field only applies when skyflatnum is used for floorpic + // or ceilingpic, because the rest of Doom needs to know which is sky + // and which isn't, etc. + + int sky; + + // killough 3/7/98: floor and ceiling texture offsets + fixed_t floor_xoffs, floor_yoffs; + fixed_t ceiling_xoffs, ceiling_yoffs; + + // killough 4/11/98: support for lightlevels coming from another sector + int floorlightsec, ceilinglightsec; + + short floorpic; + short ceilingpic; + short lightlevel; + short special; + short oldspecial; //jff 2/16/98 remembers if sector WAS secret (automap) + short tag; + void* specialdata; // ROCKDOOM obsolete +} sector_t; + +// +// The SideDef. +// + +typedef struct +{ + fixed_t textureoffset; // add this to the calculated texture column + fixed_t rowoffset; // add this to the calculated texture top + short toptexture; // Texture indices. We do not maintain names here. + short bottomtexture; + short midtexture; + sector_t* sector; // Sector the SideDef is facing. + + // killough 4/4/98, 4/11/98: highest referencing special linedef's type, + // or lump number of special effect. Allows texture names to be overloaded + // for other functions. + + int special; + +} side_t; + +// +// Move clipping aid for LineDefs. +// +typedef enum +{ + ST_HORIZONTAL, + ST_VERTICAL, + ST_POSITIVE, + ST_NEGATIVE +} slopetype_t; + +typedef struct line_s +{ + vertex_t *v1, *v2; // Vertices, from v1 to v2. + fixed_t dx, dy; // Precalculated v2 - v1 for side checking. + short flags; // Animation related. + short special; + short tag; + short sidenum[2]; // Visual appearance: SideDefs. + fixed_t bbox[4]; // A bounding box, for the linedef's extent + slopetype_t slopetype; // To aid move clipping. + sector_t *frontsector; // Front and back sector. + sector_t *backsector; + int validcount; // if == validcount, already checked + void *specialdata; // thinker_t for reversable actions + int tranlump; // killough 4/11/98: translucency filter, -1 == none + int firsttag,nexttag; // killough 4/17/98: improves searches for tags. + int r_validcount; // cph: if == gametic, r_flags already done + enum { // cph: + RF_TOP_TILE = 1, // Upper texture needs tiling + RF_MID_TILE = 2, // Mid texture needs tiling + RF_BOT_TILE = 4, // Lower texture needs tiling + RF_IGNORE = 8, // Renderer can skip this line + RF_CLOSED =16, // Line blocks view + } r_flags; +} line_t; + +// phares 3/14/98 +// +// Sector list node showing all sectors an object appears in. +// +// There are two threads that flow through these nodes. The first thread +// starts at touching_thinglist in a sector_t and flows through the m_snext +// links to find all mobjs that are entirely or partially in the sector. +// The second thread starts at touching_sectorlist in an mobj_t and flows +// through the m_tnext links to find all sectors a thing touches. This is +// useful when applying friction or push effects to sectors. These effects +// can be done as thinkers that act upon all objects touching their sectors. +// As an mobj moves through the world, these nodes are created and +// destroyed, with the links changed appropriately. +// +// For the links, NULL means top or end of list. + +typedef struct msecnode_s +{ + sector_t *m_sector; // a sector containing this object + struct mobj_s *m_thing; // this object + struct msecnode_s *m_tprev; // prev msecnode_t for this thing + struct msecnode_s *m_tnext; // next msecnode_t for this thing + struct msecnode_s *m_sprev; // prev msecnode_t for this sector + struct msecnode_s *m_snext; // next msecnode_t for this sector + boolean visited; // killough 4/4/98, 4/7/98: used in search algorithms +} msecnode_t; + +// +// The LineSeg. +// +typedef struct +{ + vertex_t *v1, *v2; + fixed_t offset; + angle_t angle; + side_t* sidedef; + line_t* linedef; + + boolean miniseg; + + // Sector references. + // Could be retrieved from linedef, too + // (but that would be slower -- killough) + // backsector is NULL for one sided lines + + sector_t *frontsector, *backsector; +} seg_t; + +// +// A SubSector. +// References a Sector. +// Basically, this is a list of LineSegs, +// indicating the visible walls that define +// (all or some) sides of a convex BSP leaf. +// + +typedef struct subsector_s +{ + sector_t *sector; + unsigned short numlines, firstline; +} subsector_t; + +// +// BSP node. +// +typedef struct +{ + fixed_t x, y, dx, dy; // Partition line. + fixed_t bbox[2][4]; // Bounding box for each child. + unsigned short children[2]; // If NF_SUBSECTOR its a subsector. +} node_t; + +// posts are runs of non masked source pixels +typedef struct +{ + byte topdelta; // -1 is the last post in a column + byte length; // length data bytes follows +} post_t; + +// column_t is a list of 0 or more post_t, (byte)-1 terminated +typedef post_t column_t; + +// +// OTHER TYPES +// + +// This could be wider for >8 bit display. +// Indeed, true color support is posibble +// precalculating 24bpp lightmap/colormap LUT. +// from darkening PLAYPAL to all black. +// Could even us emore than 32 levels. +typedef byte lighttable_t; + +// +// Masked 2s linedefs +// +typedef struct drawseg_s +{ + seg_t* curline; + int x1, x2; + fixed_t scale1, scale2, scalestep; + int silhouette; // 0=none, 1=bottom, 2=top, 3=both + fixed_t bsilheight; // do not clip sprites above this + fixed_t tsilheight; // do not clip sprites below this + + // Pointers to lists for sprite clipping, + // all three adjusted so [x1] is first value. + short *sprtopclip, *sprbottomclip, *maskedtexturecol; + +} drawseg_t; + +// +// Patches. +// A patch holds one or more columns. +// Patches are used for sprites and all masked pictures, +// and we compose textures from the TEXTURE1/2 lists +// of patches. +// + +typedef struct +{ + short width, height; // bounding box size + short leftoffset; // pixels to the left of origin + short topoffset; // pixels below the origin + int columnofs[8]; // only [width] used +} patch_t; + +// proff: Added for OpenGL +typedef struct +{ + int width,height; + int leftoffset,topoffset; + int lumpnum; +} patchnum_t; + +// +// A vissprite_t is a thing that will be drawn during a refresh. +// i.e. a sprite object that is partly visible. +// + +typedef struct vissprite_s +{ + int x1, x2; + fixed_t gx, gy; // for line side calculation + fixed_t gz, gzt; // global bottom / top for silhouette clipping + fixed_t startfrac; // horizontal position of x1 + fixed_t scale; + fixed_t xiscale; // negative if flipped + fixed_t texturemid; + int patch; + uint_64_t mobjflags; + + // for color translation and shadow draw, maxbright frames as well + lighttable_t *colormap; + + // killough 3/27/98: height sector for underwater/fake ceiling support + int heightsec; +} vissprite_t; + +// +// Sprites are patches with a special naming convention +// so they can be recognized by R_InitSprites. +// The base name is NNNNFx or NNNNFxFx, with +// x indicating the rotation, x = 0, 1-7. +// The sprite and frame specified by a thing_t +// is range checked at run time. +// A sprite is a patch_t that is assumed to represent +// a three dimensional object and may have multiple +// rotations pre drawn. +// Horizontal flipping is used to save space, +// thus NNNNF2F5 defines a mirrored patch. +// Some sprites will only have one picture used +// for all views: NNNNF0 +// +typedef struct +{ + // If false use 0 for any position. + // Note: as eight entries are available, + // we might as well insert the same name eight times. + boolean rotate; + + // Lump to use for view angles 0-7. + short lump[8]; + + // Flip bit (1 = flip) to use for view angles 0-7. + byte flip[8]; + +} spriteframe_t; + +// +// A sprite definition: +// a number of animation frames. +// + +typedef struct +{ + int numframes; + spriteframe_t *spriteframes; +} spritedef_t; + +// +// Now what is a visplane, anyway? +// +typedef struct visplane +{ + struct visplane *next; // Next visplane in hash chain -- killough + int picnum, lightlevel, minx, maxx; + fixed_t height; + fixed_t xoffs, yoffs; // killough 2/28/98: Support scrolling flats + unsigned short pad1; // leave pads for [minx-1]/[maxx+1] + unsigned short top[SCREENWIDTH]; + unsigned short pad2, pad3; // killough 2/8/98, 4/25/98 + unsigned short bottom[SCREENWIDTH]; + unsigned short pad4; +} visplane_t; + +#endif diff --git a/apps/plugins/doom/r_draw.c b/apps/plugins/doom/r_draw.c new file mode 100644 index 0000000000..df682776cd --- /dev/null +++ b/apps/plugins/doom/r_draw.c @@ -0,0 +1,677 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * The actual span/column drawing functions. + * Here find the main potential for optimization, + * e.g. inline assembly, different algorithms. + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "w_wad.h" +#include "r_main.h" +#include "v_video.h" +#include "st_stuff.h" +#include "g_game.h" +#include "am_map.h" +//#include "lprintf.h" +#include "rockmacros.h" + +#define MAXWIDTH 1120 +#define MAXHEIGHT 832 + +// status bar height at bottom of screen +#define SBARHEIGHT 32 + +// +// All drawing to the view buffer is accomplished in this file. +// The other refresh files only know about ccordinates, +// not the architecture of the frame buffer. +// Conveniently, the frame buffer is a linear one, +// and we need only the base address, +// and the total size == width*height*depth/8., +// + +//byte* viewimage; +int viewwidth; +int scaledviewwidth; +int viewheight; +int viewwindowx; +int viewwindowy; + +byte *topleft IBSS_ATTR; + +// Color tables for different players, +// translate a limited part to another +// (color ramps used for suit colors). +// + +// CPhipps - made const*'s +const byte *tranmap IBSS_ATTR; // translucency filter maps 256x256 // phares +const byte *main_tranmap IBSS_ATTR; // killough 4/11/98 + +// +// R_DrawColumn +// Source is the top of the column to scale. +// + +lighttable_t *dc_colormap IBSS_ATTR; +int dc_x IBSS_ATTR; +int dc_yl IBSS_ATTR; +int dc_yh IBSS_ATTR; +fixed_t dc_iscale IBSS_ATTR; +fixed_t dc_texturemid IBSS_ATTR; +int dc_texheight IBSS_ATTR; // killough +const byte *dc_source IBSS_ATTR; // first pixel in a column (possibly virtual) + + +// +// A column is a vertical slice/span from a wall texture that, +// given the DOOM style restrictions on the view orientation, +// will always have constant z depth. +// Thus a special case loop for very fast rendering can +// be used. It has also been used with Wolfenstein 3D. +// +void R_DrawColumn (void) +{ + int count; + register byte *dest; // killough + register fixed_t frac; // killough + + // leban 1/17/99: + // removed the + 1 here, adjusted the if test, and added an increment + // later. this helps a compiler pipeline a bit better. the x86 + // assembler also does this. + count = dc_yh - dc_yl; + + // Zero length, column does not exceed a pixel. + if (count < 0) + return; + +#ifdef RANGECHECK + if ((unsigned)dc_x >= SCREENWIDTH + || dc_yl < 0 + || dc_yh >= SCREENHEIGHT) + I_Error ("R_DrawColumn: %d to %d at %d", dc_yl, dc_yh, dc_x); +#endif + + count++; + + // Framebuffer destination address. + dest = topleft + dc_yl*SCREENWIDTH + dc_x; + + // Determine scaling, + // which is the only mapping to be done. +#define fracstep dc_iscale + frac = dc_texturemid + (dc_yl-centery)*fracstep; + + // Inner loop that does the actual texture mapping, + // e.g. a DDA-lile scaling. + // This is as fast as it gets. (Yeah, right!!! -- killough) + // + // killough 2/1/98: more performance tuning + + if (dc_texheight == 128) { + while(count--) + { + *dest = dc_colormap[dc_source[(frac>>FRACBITS)&127]]; + frac += fracstep; + dest += SCREENWIDTH; + } + } else if (dc_texheight == 0) { + /* cph - another special case */ + while (count--) { + *dest = dc_colormap[dc_source[frac>>FRACBITS]]; + frac += fracstep; + dest += SCREENWIDTH; + } + } else { + register unsigned heightmask = dc_texheight-1; // CPhipps - specify type + if (! (dc_texheight & heightmask) ) // power of 2 -- killough + { + while (count>0) // texture height is a power of 2 -- killough + { + *dest = dc_colormap[dc_source[(frac>>FRACBITS) & heightmask]]; + dest += SCREENWIDTH; + frac += fracstep; + count--; + } + } + else + { + heightmask++; + heightmask <<= FRACBITS; + + if (frac < 0) + while ((frac += heightmask) < 0); + else + while (frac >= (int)heightmask) + frac -= heightmask; + + while(count>0) + { + // Re-map color indices from wall texture column + // using a lighting/special effects LUT. + + // heightmask is the Tutti-Frutti fix -- killough + + *dest = dc_colormap[dc_source[frac>>FRACBITS]]; + dest += SCREENWIDTH; + if ((frac += fracstep) >= (int)heightmask) + frac -= heightmask; + count--; + } + } + } +} +#undef fracstep + +// Here is the version of R_DrawColumn that deals with translucent // phares +// textures and sprites. It's identical to R_DrawColumn except // | +// for the spot where the color index is stuffed into *dest. At // V +// that point, the existing color index and the new color index +// are mapped through the TRANMAP lump filters to get a new color +// index whose RGB values are the average of the existing and new +// colors. +// +// Since we're concerned about performance, the 'translucent or +// opaque' decision is made outside this routine, not down where the +// actual code differences are. + +void R_DrawTLColumn (void) +{ + int count; + register byte *dest; // killough + register fixed_t frac; // killough + + count = dc_yh - dc_yl + 1; + + // Zero length, column does not exceed a pixel. + if (count <= 0) + return; + +#ifdef RANGECHECK + if ((unsigned)dc_x >= (unsigned)SCREENWIDTH + || dc_yl < 0 + || dc_yh >= SCREENHEIGHT) + I_Error("R_DrawTLColumn: %i to %i at %i", dc_yl, dc_yh, dc_x); +#endif + + // Framebuffer destination address. + dest = topleft + dc_yl*SCREENWIDTH + dc_x; + + // Determine scaling, + // which is the only mapping to be done. +#define fracstep dc_iscale + frac = dc_texturemid + (dc_yl-centery)*fracstep; + + // Inner loop that does the actual texture mapping, + // e.g. a DDA-lile scaling. + // This is as fast as it gets. (Yeah, right!!! -- killough) + // + // killough 2/1/98, 2/21/98: more performance tuning + + { + register const byte *source = dc_source; + register const lighttable_t *colormap = dc_colormap; + register unsigned heightmask = dc_texheight-1; // CPhipps - specify type + if (dc_texheight & heightmask) // not a power of 2 -- killough + { + heightmask++; + heightmask <<= FRACBITS; + + if (frac < 0) + while ((frac += heightmask) < 0); + else + while (frac >= (int)heightmask) + frac -= heightmask; + + do + { + // Re-map color indices from wall texture column + // using a lighting/special effects LUT. + + // heightmask is the Tutti-Frutti fix -- killough + + *dest = tranmap[(*dest<<8)+colormap[source[frac>>FRACBITS]]]; // phares + dest += SCREENWIDTH; + if ((frac += fracstep) >= (int)heightmask) + frac -= heightmask; + } + while (--count); + } + else + { + while ((count-=2)>=0) // texture height is a power of 2 -- killough + { + *dest = tranmap[(*dest<<8)+colormap[source[(frac>>FRACBITS) & heightmask]]]; // phares + dest += SCREENWIDTH; + frac += fracstep; + *dest = tranmap[(*dest<<8)+colormap[source[(frac>>FRACBITS) & heightmask]]]; // phares + dest += SCREENWIDTH; + frac += fracstep; + } + if (count & 1) + *dest = tranmap[(*dest<<8)+colormap[source[(frac>>FRACBITS) & heightmask]]]; // phares + } + } +} +#undef fracstep + +// +// Spectre/Invisibility. +// + +#define FUZZTABLE 50 +// proff 08/17/98: Changed for high-res +//#define FUZZOFF (SCREENWIDTH) +#define FUZZOFF 1 + +static const int fuzzoffset_org[FUZZTABLE] ICONST_ATTR = { + FUZZOFF,-FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF, + FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF, + FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF, + FUZZOFF,-FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF, + FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,-FUZZOFF,FUZZOFF, + FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF, + FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF + } ; + +static int fuzzoffset[FUZZTABLE] IBSS_ATTR; + +static int fuzzpos IBSS_ATTR = 0; + +// +// Framebuffer postprocessing. +// Creates a fuzzy image by copying pixels +// from adjacent ones to left and right. +// Used with an all black colormap, this +// could create the SHADOW effect, +// i.e. spectres and invisible players. +// + +void R_DrawFuzzColumn(void) +{ + int count; + byte *dest; + fixed_t frac; + fixed_t fracstep; + + // Adjust borders. Low... + if (!dc_yl) + dc_yl = 1; + + // .. and high. + if (dc_yh == viewheight-1) + dc_yh = viewheight - 2; + + count = dc_yh - dc_yl; + + // Zero length. + if (count < 0) + return; + +#ifdef RANGECHECK + if ((unsigned) dc_x >= (unsigned)SCREENWIDTH + || dc_yl < 0 + || (unsigned)dc_yh >= (unsigned)SCREENHEIGHT) + I_Error("R_DrawFuzzColumn: %i to %i at %i", dc_yl, dc_yh, dc_x); +#endif + + // Keep till detailshift bug in blocky mode fixed, + // or blocky mode removed. + + // Does not work with blocky mode. + dest = topleft + dc_yl*SCREENWIDTH + dc_x; + + // Looks familiar. + fracstep = dc_iscale; + frac = dc_texturemid + (dc_yl-centery)*fracstep; + + // Looks like an attempt at dithering, + // using the colormap #6 (of 0-31, a bit brighter than average). + + do + { + // Lookup framebuffer, and retrieve + // a pixel that is either one column + // left or right of the current one. + // Add index from colormap to index. + // killough 3/20/98: use fullcolormap instead of colormaps + + *dest = fullcolormap[6*256+dest[fuzzoffset[fuzzpos]]]; + + // Some varying invisibility effects can be gotten by playing // phares + // with this logic. For example, try // phares + // // phares + // *dest = fullcolormap[0*256+dest[FUZZOFF]]; // phares + + // Clamp table lookup index. + if (++fuzzpos == FUZZTABLE) + fuzzpos = 0; + + dest += SCREENWIDTH; + + frac += fracstep; + } while (count--); +} + +// +// R_DrawTranslatedColumn +// Used to draw player sprites +// with the green colorramp mapped to others. +// Could be used with different translation +// tables, e.g. the lighter colored version +// of the BaronOfHell, the HellKnight, uses +// identical sprites, kinda brightened up. +// + +byte *dc_translation, *translationtables; + +void R_DrawTranslatedColumn (void) +{ + int count; + byte *dest; + fixed_t frac; + fixed_t fracstep; + + count = dc_yh - dc_yl; + if (count < 0) + return; + +#ifdef RANGECHECK + if ((unsigned)dc_x >= (unsigned)SCREENWIDTH + || dc_yl < 0 + || (unsigned)dc_yh >= (unsigned)SCREENHEIGHT) + I_Error("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x); +#endif + + // FIXME. As above. + dest = topleft + dc_yl*SCREENWIDTH + dc_x; + + // Looks familiar. + fracstep = dc_iscale; + frac = dc_texturemid + (dc_yl-centery)*fracstep; + + // Here we do an additional index re-mapping. + do + { + // Translation tables are used + // to map certain colorramps to other ones, + // used with PLAY sprites. + // Thus the "green" ramp of the player 0 sprite + // is mapped to gray, red, black/indigo. + + *dest = dc_colormap[dc_translation[dc_source[frac>>FRACBITS]]]; + dest += SCREENWIDTH; + + frac += fracstep; + } + while (count--); +} + +// +// R_InitTranslationTables +// Creates the translation tables to map +// the green color ramp to gray, brown, red. +// Assumes a given structure of the PLAYPAL. +// Could be read from a lump instead. +// + +byte playernumtotrans[MAXPLAYERS]; +extern lighttable_t *(*c_zlight)[LIGHTLEVELS][MAXLIGHTZ]; + +void R_InitTranslationTables (void) +{ + int i, j; +#define MAXTRANS 3 + byte transtocolour[MAXTRANS]; + + // killough 5/2/98: + // Remove dependency of colormaps aligned on 256-byte boundary + + if (translationtables == NULL) // CPhipps - allow multiple calls + translationtables = Z_Malloc(256*MAXTRANS, PU_STATIC, 0); + + for (i=0; i= 0x70 && i<= 0x7f) + { + // CPhipps - configurable player colours + translationtables[i] = colormaps[0][((i&0xf)<<9) + transtocolour[0]]; + translationtables[i+256] = colormaps[0][((i&0xf)<<9) + transtocolour[1]]; + translationtables[i+512] = colormaps[0][((i&0xf)<<9) + transtocolour[2]]; + } + else // Keep all other colors as is. + translationtables[i]=translationtables[i+256]=translationtables[i+512]=i; +} + +// +// R_DrawSpan +// With DOOM style restrictions on view orientation, +// the floors and ceilings consist of horizontal slices +// or spans with constant z depth. +// However, rotation around the world z axis is possible, +// thus this mapping, while simpler and faster than +// perspective correct texture mapping, has to traverse +// the texture at an angle in all but a few cases. +// In consequence, flats are not stored by column (like walls), +// and the inner loop has to step in texture space u and v. +// + +int ds_y IBSS_ATTR; +int ds_x1 IBSS_ATTR; +int ds_x2 IBSS_ATTR; + +lighttable_t *ds_colormap IBSS_ATTR; + +fixed_t ds_xfrac IBSS_ATTR; +fixed_t ds_yfrac IBSS_ATTR; +fixed_t ds_xstep IBSS_ATTR; +fixed_t ds_ystep IBSS_ATTR; + +// start of a 64*64 tile image +byte *ds_source IBSS_ATTR; + +void R_DrawSpan (void) +{ + register unsigned count,xfrac = ds_xfrac,yfrac = ds_yfrac; + + byte *source; + byte *colormap; + byte *dest; + + source = ds_source; + colormap = ds_colormap; + dest = topleft + ds_y*SCREENWIDTH + ds_x1; + count = ds_x2 - ds_x1 + 1; + + while (count) + { + register unsigned xtemp = xfrac >> 16; + register unsigned ytemp = yfrac >> 10; + register unsigned spot; + ytemp &= 4032; + xtemp &= 63; + spot = xtemp | ytemp; + xfrac += ds_xstep; + yfrac += ds_ystep; + *dest++ = colormap[source[spot]]; + count--; + } +} + +// +// R_InitBuffer +// Creats lookup tables that avoid +// multiplies and other hazzles +// for getting the framebuffer address +// of a pixel to draw. +// + +void R_InitBuffer(int width, int height) +{ + int i=0; + // Handle resize, + // e.g. smaller view windows + // with border and/or status bar. + + viewwindowx = (SCREENWIDTH-width) >> 1; + + // Same with base row offset. + + viewwindowy = width==SCREENWIDTH ? 0 : (SCREENHEIGHT-(ST_SCALED_HEIGHT-1)-height)>>1; + + topleft = screens[0] + viewwindowy*SCREENWIDTH + viewwindowx; + + // Preclaculate all row offsets. + // CPhipps - merge viewwindowx into here + for (i=0; i= ( SCREENHEIGHT - ST_SCALED_HEIGHT )) + return; // if high-res, donŽt go any further! + + top = ((SCREENHEIGHT-ST_SCALED_HEIGHT)-viewheight)/2; + side = (SCREENWIDTH-scaledviewwidth)/2; + + // copy top and one line of left side + R_VideoErase (0, top*SCREENWIDTH+side); + + // copy one line of right side and bottom + ofs = (viewheight+top)*SCREENWIDTH-side; + R_VideoErase (ofs, top*SCREENWIDTH+side); + + // copy sides using wraparound + ofs = top*SCREENWIDTH + SCREENWIDTH-side; + side <<= 1; + + for (i=1 ; idx) + return x <= node->x ? node->dy > 0 : node->dy < 0; + + if (!node->dy) + return y <= node->y ? node->dx < 0 : node->dx > 0; + + x -= node->x; + y -= node->y; + + // Try to quickly decide by looking at sign bits. + if ((node->dy ^ node->dx ^ x ^ y) < 0) + return (node->dy ^ x) < 0; // (left is negative) + return FixedMul(y, node->dx>>FRACBITS) >= FixedMul(node->dy>>FRACBITS, x); +} + +// killough 5/2/98: reformatted + +int R_PointOnSegSide(fixed_t x, fixed_t y, const seg_t *line) +{ + fixed_t lx = line->v1->x; + fixed_t ly = line->v1->y; + fixed_t ldx = line->v2->x - lx; + fixed_t ldy = line->v2->y - ly; + + if (!ldx) + return x <= lx ? ldy > 0 : ldy < 0; + + if (!ldy) + return y <= ly ? ldx < 0 : ldx > 0; + + x -= lx; + y -= ly; + + // Try to quickly decide by looking at sign bits. + if ((ldy ^ ldx ^ x ^ y) < 0) + return (ldy ^ x) < 0; // (left is negative) + return FixedMul(y, ldx>>FRACBITS) >= FixedMul(ldy>>FRACBITS, x); +} + +// +// R_PointToAngle +// To get a global angle from cartesian coordinates, +// the coordinates are flipped until they are in +// the first octant of the coordinate system, then +// the y (<=x) is scaled and divided by x to get a +// tangent (slope) value which is looked up in the +// tantoangle[] table. The +1 size of tantoangle[] +// is to handle the case when x==y without additional +// checking. +// +// killough 5/2/98: reformatted, cleaned up + +angle_t R_PointToAngle(fixed_t x, fixed_t y) +{ + return (y -= viewy, (x -= viewx) || y) ? + x >= 0 ? + y >= 0 ? + (x > y) ? tantoangle[SlopeDiv(y,x)] : // octant 0 + ANG90-1-tantoangle[SlopeDiv(x,y)] : // octant 1 + x > (y = -y) ? 0-tantoangle[SlopeDiv(y,x)] : // octant 8 + ANG270+tantoangle[SlopeDiv(x,y)] : // octant 7 + y >= 0 ? (x = -x) > y ? ANG180-1-tantoangle[SlopeDiv(y,x)] : // octant 3 + ANG90 + tantoangle[SlopeDiv(x,y)] : // octant 2 + (x = -x) > (y = -y) ? ANG180+tantoangle[ SlopeDiv(y,x)] : // octant 4 + ANG270-1-tantoangle[SlopeDiv(x,y)] : // octant 5 + 0; +} + +angle_t R_PointToAngle2(fixed_t viewx, fixed_t viewy, fixed_t x, fixed_t y) +{ + return (y -= viewy, (x -= viewx) || y) ? + x >= 0 ? + y >= 0 ? + (x > y) ? tantoangle[SlopeDiv(y,x)] : // octant 0 + ANG90-1-tantoangle[SlopeDiv(x,y)] : // octant 1 + x > (y = -y) ? 0-tantoangle[SlopeDiv(y,x)] : // octant 8 + ANG270+tantoangle[SlopeDiv(x,y)] : // octant 7 + y >= 0 ? (x = -x) > y ? ANG180-1-tantoangle[SlopeDiv(y,x)] : // octant 3 + ANG90 + tantoangle[SlopeDiv(x,y)] : // octant 2 + (x = -x) > (y = -y) ? ANG180+tantoangle[ SlopeDiv(y,x)] : // octant 4 + ANG270-1-tantoangle[SlopeDiv(x,y)] : // octant 5 + 0; +} + +// +// R_InitTextureMapping +// +// killough 5/2/98: reformatted + +static void R_InitTextureMapping (void) +{ + register int i,x; + fixed_t focallength; + + // Use tangent table to generate viewangletox: + // viewangletox will give the next greatest x + // after the view angle. + // + // Calc focallength + // so FIELDOFVIEW angles covers SCREENWIDTH. + + focallength = FixedDiv(centerxfrac, finetangent[FINEANGLES/4+FIELDOFVIEW/2]); + + for (i=0 ; i FRACUNIT*2) + t = -1; + else + if (finetangent[i] < -FRACUNIT*2) + t = viewwidth+1; + else + { + t = FixedMul(finetangent[i], focallength); + t = (centerxfrac - t + FRACUNIT-1) >> FRACBITS; + if (t < -1) + t = -1; + else + if (t > viewwidth+1) + t = viewwidth+1; + } + viewangletox[i] = t; + } + + // Scan viewangletox[] to generate xtoviewangle[]: + // xtoviewangle will give the smallest view angle + // that maps to x. + + for (x=0; x<=viewwidth; x++) + { + for (i=0; viewangletox[i] > x; i++) + ; + xtoviewangle[x] = (i<>= LIGHTSCALESHIFT)/DISTMAP; + + if (level < 0) + level = 0; + else + if (level >= NUMCOLORMAPS) + level = NUMCOLORMAPS-1; + + // killough 3/20/98: Initialize multiple colormaps + level *= 256; + for (t=0; t>ANGLETOFINESHIFT]); + distscale[i] = FixedDiv(FRACUNIT,cosadj); + } + + // Calculate the light levels to use + // for each level / scale combination. + for (i=0; i>= LIGHTSCALESHIFT)/DISTMAP; + + if (level < 0) + level = 0; + + if (level >= NUMCOLORMAPS) + level = NUMCOLORMAPS-1; + + // killough 3/20/98: initialize multiple colormaps + level *= 256; + + for (t=0; tmo->x; + viewy = player->mo->y; + viewangle = player->mo->angle + viewangleoffset; + extralight = player->extralight; + + viewz = player->viewz; + + viewsin = finesine[viewangle>>ANGLETOFINESHIFT]; + viewcos = finecosine[viewangle>>ANGLETOFINESHIFT]; + + // killough 3/20/98, 4/4/98: select colormap based on player status + + if (player->mo->subsector->sector->heightsec != -1) + { + const sector_t *s = player->mo->subsector->sector->heightsec + sectors; + cm = viewz < s->floorheight ? s->bottommap : viewz > s->ceilingheight ? + s->topmap : s->midmap; + if (cm < 0 || cm > numcolormaps) + cm = 0; + } + else + cm = 0; + + fullcolormap = colormaps[cm]; + zlight = c_zlight[cm]; + scalelight = c_scalelight[cm]; + + if (player->fixedcolormap) + { + // killough 3/20/98: localize scalelightfixed (readability/optimization) + static lighttable_t *scalelightfixed[MAXLIGHTSCALE]; + + fixedcolormap = fullcolormap // killough 3/20/98: use fullcolormap + + player->fixedcolormap*256*sizeof(lighttable_t); + + walllights = scalelightfixed; + + for (i=0 ; i=viewwidth || (unsigned)y>(unsigned)viewheight) + I_Error ("R_MapPlane: %i, %i at %i",x1,x2,y); +#endif + + if (planeheight != cachedheight[y]) + { + cachedheight[y] = planeheight; + distance = cacheddistance[y] = FixedMul (planeheight, yslope[y]); + ds_xstep = cachedxstep[y] = FixedMul (distance,basexscale); + ds_ystep = cachedystep[y] = FixedMul (distance,baseyscale); + } + else + { + distance = cacheddistance[y]; + ds_xstep = cachedxstep[y]; + ds_ystep = cachedystep[y]; + } + + length = FixedMul (distance,distscale[x1]); + angle = (viewangle + xtoviewangle[x1])>>ANGLETOFINESHIFT; + + // killough 2/28/98: Add offsets + ds_xfrac = viewx + FixedMul(finecosine[angle], length) + xoffs; + ds_yfrac = -viewy - FixedMul(finesine[angle], length) + yoffs; + + if (!(ds_colormap = fixedcolormap)) + { + index = distance >> LIGHTZSHIFT; + if (index >= MAXLIGHTZ ) + index = MAXLIGHTZ-1; + ds_colormap = planezlight[index]; + } + + ds_y = y; + ds_x1 = x1; + ds_x2 = x2; + + R_DrawSpan(); +} + +// +// R_ClearPlanes +// At begining of frame. +// + +void R_ClearPlanes(void) +{ + int i; + angle_t angle; + + // opening / clipping determination + for (i=0 ; inext; + + lastopening = openings; + + // texture calculation + memset (cachedheight, 0, sizeof(cachedheight)); + + // left to right mapping + angle = (viewangle-ANG90)>>ANGLETOFINESHIFT; + + // scale will be unit scale at SCREENWIDTH/2 distance + basexscale = FixedDiv (finecosine[angle],centerxfrac); + baseyscale = -FixedDiv (finesine[angle],centerxfrac); +} + +// New function, by Lee Killough + +static visplane_t *new_visplane(unsigned hash) +{ + visplane_t *check = freetail; + if (!check) + check = calloc(1, sizeof *check); + else + if (!(freetail = freetail->next)) + freehead = &freetail; + check->next = visplanes[hash]; + visplanes[hash] = check; + return check; +} + +/* + * R_DupPlane + * + * cph 2003/04/18 - create duplicate of existing visplane and set initial range + */ +visplane_t *R_DupPlane(const visplane_t *pl, int start, int stop) +{ + unsigned hash = visplane_hash(pl->picnum, pl->lightlevel, pl->height); + visplane_t *new_pl = new_visplane(hash); + + new_pl->height = pl->height; + new_pl->picnum = pl->picnum; + new_pl->lightlevel = pl->lightlevel; + new_pl->xoffs = pl->xoffs; // killough 2/28/98 + new_pl->yoffs = pl->yoffs; + new_pl->minx = start; + new_pl->maxx = stop; + memset(new_pl->top, 0xff, sizeof new_pl->top); + return new_pl; +} + +// +// R_FindPlane +// +// killough 2/28/98: Add offsets + +visplane_t *R_FindPlane(fixed_t height, int picnum, int lightlevel, + fixed_t xoffs, fixed_t yoffs) +{ + visplane_t *check; + unsigned hash; // killough + + if (picnum == skyflatnum || picnum & PL_SKYFLAT) + height = lightlevel = 0; // killough 7/19/98: most skies map together + + // New visplane algorithm uses hash table -- killough + hash = visplane_hash(picnum,lightlevel,height); + + for (check=visplanes[hash]; check; check=check->next) // killough + if (height == check->height && + picnum == check->picnum && + lightlevel == check->lightlevel && + xoffs == check->xoffs && // killough 2/28/98: Add offset checks + yoffs == check->yoffs) + return check; + + check = new_visplane(hash); // killough + + check->height = height; + check->picnum = picnum; + check->lightlevel = lightlevel; + check->minx = viewwidth; // Was SCREENWIDTH -- killough 11/98 + check->maxx = -1; + check->xoffs = xoffs; // killough 2/28/98: Save offsets + check->yoffs = yoffs; + + memset (check->top, 0xff, sizeof check->top); + + return check; +} + +// +// R_CheckPlane +// +visplane_t *R_CheckPlane(visplane_t *pl, int start, int stop) +{ + int intrl, intrh, unionl, unionh, x; + + if (start < pl->minx) + intrl = pl->minx, unionl = start; + else + unionl = pl->minx, intrl = start; + + if (stop > pl->maxx) + intrh = pl->maxx, unionh = stop; + else + unionh = pl->maxx, intrh = stop; + + for (x=intrl ; x <= intrh && pl->top[x] == 0xffff; x++) + ; + + if (x > intrh) { /* Can use existing plane; extend range */ + pl->minx = unionl; pl->maxx = unionh; + return pl; + } else /* Cannot use existing plane; create a new one */ + return R_DupPlane(pl,start,stop); +} + +// +// R_MakeSpans +// + +static void R_MakeSpans(int x, int t1, int b1, int t2, int b2) +{ + for (; t1 < t2 && t1 <= b1; t1++) + R_MapPlane(t1, spanstart[t1], x-1); + for (; b1 > b2 && b1 >= t1; b1--) + R_MapPlane(b1, spanstart[b1] ,x-1); + while (t2 < t1 && t2 <= b2) + spanstart[t2++] = x; + while (b2 > b1 && b2 >= t2) + spanstart[b2--] = x; +} + +// New function, by Lee Killough + +static void R_DoDrawPlane(visplane_t *pl) +{ + register int x; + if (pl->minx <= pl->maxx) { + if (pl->picnum == skyflatnum || pl->picnum & PL_SKYFLAT) { // sky flat + int texture; + angle_t an, flip; + + // killough 10/98: allow skies to come from sidedefs. + // Allows scrolling and/or animated skies, as well as + // arbitrary multiple skies per level without having + // to use info lumps. + + an = viewangle; + + if (pl->picnum & PL_SKYFLAT) + { + // Sky Linedef + const line_t *l = &lines[pl->picnum & ~PL_SKYFLAT]; + + // Sky transferred from first sidedef + const side_t *s = *l->sidenum + sides; + + // Texture comes from upper texture of reference sidedef + texture = texturetranslation[s->toptexture]; + + // Horizontal offset is turned into an angle offset, + // to allow sky rotation as well as careful positioning. + // However, the offset is scaled very small, so that it + // allows a long-period of sky rotation. + + an += s->textureoffset; + + // Vertical offset allows careful sky positioning. + + dc_texturemid = s->rowoffset - 28*FRACUNIT; + + // We sometimes flip the picture horizontally. + // + // Doom always flipped the picture, so we make it optional, + // to make it easier to use the new feature, while to still + // allow old sky textures to be used. + + flip = l->special==272 ? 0u : ~0u; + } + else + { // Normal Doom sky, only one allowed per level + dc_texturemid = skytexturemid; // Default y-offset + texture = skytexture; // Default texture + flip = 0; // Doom flips it + } + + /* Sky is always drawn full bright, i.e. colormaps[0] is used. + * Because of this hack, sky is not affected by INVUL inverse mapping. + * Until Boom fixed this. Compat option added in MBF. */ + + if (comp[comp_skymap] || !(dc_colormap = fixedcolormap)) + dc_colormap = fullcolormap; // killough 3/20/98 + dc_texheight = textureheight[skytexture]>>FRACBITS; // killough + // proff 09/21/98: Changed for high-res + dc_iscale = FRACUNIT*200/viewheight; + + // killough 10/98: Use sky scrolling offset, and possibly flip picture + for (x = pl->minx; (dc_x = x) <= pl->maxx; x++) + if ((dc_yl = pl->top[x]) <= (dc_yh = pl->bottom[x])) + { + dc_source = R_GetColumn(texture, ((an + xtoviewangle[x])^flip) >> + ANGLETOSKYSHIFT); + colfunc(); + } + } else { // regular flat + + int stop, light; + + ds_source = W_CacheLumpNum(firstflat + flattranslation[pl->picnum]); + + xoffs = pl->xoffs; // killough 2/28/98: Add offsets + yoffs = pl->yoffs; + planeheight = D_abs(pl->height-viewz); + light = (pl->lightlevel >> LIGHTSEGSHIFT) + extralight; + + if (light >= LIGHTLEVELS) + light = LIGHTLEVELS-1; + + if (light < 0) + light = 0; + + stop = pl->maxx + 1; + planezlight = zlight[light]; + pl->top[pl->minx-1] = pl->top[stop] = 0xffff; + + for (x = pl->minx ; x <= stop ; x++) + R_MakeSpans(x,pl->top[x-1],pl->bottom[x-1],pl->top[x],pl->bottom[x]); + + W_UnlockLumpNum(firstflat + flattranslation[pl->picnum]); + } + } +} + +// +// RDrawPlanes +// At the end of each frame. +// + +void R_DrawPlanes (void) +{ + visplane_t *pl; + int i; + for (i=0;inext) + R_DoDrawPlane(pl); +} diff --git a/apps/plugins/doom/r_plane.h b/apps/plugins/doom/r_plane.h new file mode 100644 index 0000000000..9696ea28e8 --- /dev/null +++ b/apps/plugins/doom/r_plane.h @@ -0,0 +1,65 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Refresh, visplane stuff (floor, ceilings). + * + *-----------------------------------------------------------------------------*/ + +#ifndef __R_PLANE__ +#define __R_PLANE__ + +#include "r_data.h" + +#ifdef __GNUG__ +#pragma interface +#endif + +/* killough 10/98: special mask indicates sky flat comes from sidedef */ +#define PL_SKYFLAT (0x80000000) + +/* Visplane related. */ +extern short *lastopening; + +extern short floorclip[], ceilingclip[]; +extern fixed_t yslope[], distscale[]; + +void R_InitPlanes(void); +void R_ClearPlanes(void); +void R_DrawPlanes (void); + +visplane_t *R_FindPlane( + fixed_t height, + int picnum, + int lightlevel, + fixed_t xoffs, /* killough 2/28/98: add x-y offsets */ + fixed_t yoffs +); + +visplane_t *R_CheckPlane(visplane_t *pl, int start, int stop); +visplane_t *R_DupPlane(const visplane_t *pl, int start, int stop); + +#endif diff --git a/apps/plugins/doom/r_segs.c b/apps/plugins/doom/r_segs.c new file mode 100644 index 0000000000..4771132c77 --- /dev/null +++ b/apps/plugins/doom/r_segs.c @@ -0,0 +1,843 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * All the clipping: columns, horizontal spans, sky columns. + * + *-----------------------------------------------------------------------------*/ +// +// 4/25/98, 5/2/98 killough: reformatted, beautified + +#include "doomstat.h" +#include "r_main.h" +#include "r_bsp.h" +#include "r_plane.h" +#include "r_things.h" +#include "r_draw.h" +#include "w_wad.h" +//#include "lprintf.h" +#include "rockmacros.h" + +// OPTIMIZE: closed two sided lines as single sided + +// killough 1/6/98: replaced globals with statics where appropriate + +// True if any of the segs textures might be visible. +boolean segtextured; +boolean markfloor; // False if the back side is the same plane. +boolean markceiling; +static boolean maskedtexture; +static int toptexture; +static int bottomtexture; +static int midtexture; + +static fixed_t toptexheight, midtexheight, bottomtexheight; // cph + +angle_t rw_normalangle;// angle to line origin +int rw_angle1; +fixed_t rw_distance; +lighttable_t** walllights; + +// +// regular wall +// +int rw_x; +int rw_stopx; +static angle_t rw_centerangle; +static fixed_t rw_offset; +static fixed_t rw_scale; +static fixed_t rw_scalestep; +static fixed_t rw_midtexturemid; +static fixed_t rw_toptexturemid; +static fixed_t rw_bottomtexturemid; +static int worldtop; +static int worldbottom; +static int worldhigh; +static int worldlow; +static fixed_t pixhigh; +static fixed_t pixlow; +static fixed_t pixhighstep; +static fixed_t pixlowstep; +static fixed_t topfrac; +static fixed_t topstep; +static fixed_t bottomfrac; +static fixed_t bottomstep; +static short *maskedtexturecol; + +// +// R_ScaleFromGlobalAngle +// Returns the texture mapping scale +// for the current line (horizontal span) +// at the given angle. +// rw_distance must be calculated first. +// +// killough 5/2/98: reformatted, cleaned up +static fixed_t R_ScaleFromGlobalAngle (angle_t visangle) +{ + int anglea = ANG90 + (visangle-viewangle); + int angleb = ANG90 + (visangle-rw_normalangle); + int sinea = finesine[anglea>>ANGLETOFINESHIFT]; + int sineb = finesine[angleb>>ANGLETOFINESHIFT]; + fixed_t num = FixedMul(projection,sineb); + int den = FixedMul(rw_distance,sinea); + + return den > num>>16 ? (num=FixedDiv (num, den)) > 64*FRACUNIT ? + 64*FRACUNIT : num < 256 ? 256 : num : 64*FRACUNIT ; +} +// +// R_RenderMaskedSegRange +// + +int fake_contrast IBSS_ATTR; + +void R_RenderMaskedSegRange(drawseg_t *ds, int x1, int x2) +{ + column_t *col; + int lightnum; + int texnum; + sector_t tempsec; // killough 4/13/98 + + // Calculate light table. + // Use different light tables + // for horizontal / vertical / diagonal. Diagonal? + + curline = ds->curline; // OPTIMIZE: get rid of LIGHTSEGSHIFT globally + + // killough 4/11/98: draw translucent 2s normal textures + + colfunc = R_DrawColumn; + if (curline->linedef->tranlump >= 0 && general_translucency) + { + colfunc = R_DrawTLColumn; + tranmap = main_tranmap; + if (curline->linedef->tranlump > 0) + tranmap = W_CacheLumpNum(curline->linedef->tranlump-1); + } + + // killough 4/11/98: end translucent 2s normal code + + frontsector = curline->frontsector; + backsector = curline->backsector; + + texnum = texturetranslation[curline->sidedef->midtexture]; + + // killough 4/13/98: get correct lightlevel for 2s normal textures + lightnum = (R_FakeFlat(frontsector, &tempsec, NULL, NULL, false) + ->lightlevel >> LIGHTSEGSHIFT)+extralight; + + /* cph - ...what is this for? adding contrast to rooms? + * It looks crap in outdoor areas */ + if (fake_contrast) { + if (curline->v1->y == curline->v2->y) + lightnum--; + else + if (curline->v1->x == curline->v2->x) + lightnum++; + } + + walllights = lightnum >= LIGHTLEVELS ? scalelight[LIGHTLEVELS-1] : + lightnum < 0 ? scalelight[0] : scalelight[lightnum]; + + maskedtexturecol = ds->maskedtexturecol; + + rw_scalestep = ds->scalestep; + spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep; + mfloorclip = ds->sprbottomclip; + mceilingclip = ds->sprtopclip; + + // find positioning + if (curline->linedef->flags & ML_DONTPEGBOTTOM) + { + dc_texturemid = frontsector->floorheight > backsector->floorheight + ? frontsector->floorheight : backsector->floorheight; + dc_texturemid = dc_texturemid + textureheight[texnum] - viewz; + } + else + { + dc_texturemid =frontsector->ceilingheightceilingheight + ? frontsector->ceilingheight : backsector->ceilingheight; + dc_texturemid = dc_texturemid - viewz; + } + + dc_texturemid += curline->sidedef->rowoffset; + + if (fixedcolormap) + dc_colormap = fixedcolormap; + + // draw the columns + for (dc_x = x1 ; dc_x <= x2 ; dc_x++, spryscale += rw_scalestep) + if (maskedtexturecol[dc_x] != SHRT_MAX) + { + if (!fixedcolormap) // calculate lighting + { + unsigned index = spryscale>>LIGHTSCALESHIFT; + + if (index >= MAXLIGHTSCALE ) + index = MAXLIGHTSCALE-1; + + dc_colormap = walllights[index]; + } + + // killough 3/2/98: + // + // This calculation used to overflow and cause crashes in Doom: + // + // sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale); + // + // This code fixes it, by using double-precision intermediate + // arithmetic and by skipping the drawing of 2s normals whose + // mapping to screen coordinates is totally out of range: + + { + int_64_t t = ((int_64_t) centeryfrac << FRACBITS) - + (int_64_t) dc_texturemid * spryscale; + if (t + (int_64_t) textureheight[texnum] * spryscale < 0 || + t > (int_64_t) SCREENHEIGHT << FRACBITS*2) + continue; // skip if the texture is out of screen's range + sprtopscreen = (long)(t >> FRACBITS); + } + + dc_iscale = 0xffffffffu / (unsigned) spryscale; + + // killough 1/25/98: here's where Medusa came in, because + // it implicitly assumed that the column was all one patch. + // Originally, Doom did not construct complete columns for + // multipatched textures, so there were no header or trailer + // bytes in the column referred to below, which explains + // the Medusa effect. The fix is to construct true columns + // when forming multipatched textures (see r_data.c). + + // draw the texture + col = (column_t *)((byte *) + R_GetColumn(texnum,maskedtexturecol[dc_x]) - 3); + R_DrawMaskedColumn (col); + maskedtexturecol[dc_x] = SHRT_MAX; + } + + // Except for main_tranmap, mark others purgable at this point + if (curline->linedef->tranlump > 0 && general_translucency) + W_UnlockLumpNum(curline->linedef->tranlump-1); // cph - unlock it +} + +// +// R_RenderSegLoop +// Draws zero, one, or two textures (and possibly a masked texture) for walls. +// Can draw or mark the starting pixel of floor and ceiling textures. +// CALLED: CORE LOOPING ROUTINE. +// + +extern byte solidcol[SCREENWIDTH]; +#define HEIGHTBITS 12 +#define HEIGHTUNIT (1<>HEIGHTBITS; + int yl = (topfrac+HEIGHTUNIT-1)>>HEIGHTBITS; + + // no space above wall? + int bottom,top = ceilingclip[rw_x]+1; + + if (yl < top) + yl = top; + + if (markceiling) + { + bottom = yl-1; + + if (bottom >= floorclip[rw_x]) + bottom = floorclip[rw_x]-1; + + if (top <= bottom) + { + ceilingplane->top[rw_x] = top; + ceilingplane->bottom[rw_x] = bottom; + } + } + + // yh = bottomfrac>>HEIGHTBITS; + + bottom = floorclip[rw_x]-1; + if (yh > bottom) + yh = bottom; + + if (markfloor) + { + + top = yh < ceilingclip[rw_x] ? ceilingclip[rw_x] : yh; + + if (++top <= bottom) + { + floorplane->top[rw_x] = top; + floorplane->bottom[rw_x] = bottom; + } + } + + // texturecolumn and lighting are independent of wall tiers + if (segtextured) + { + unsigned index; + + // calculate texture offset + angle_t angle =(rw_centerangle+xtoviewangle[rw_x])>>ANGLETOFINESHIFT; + + texturecolumn = rw_offset-FixedMul(finetangent[angle],rw_distance); + texturecolumn >>= FRACBITS; + // calculate lighting + index = rw_scale>>LIGHTSCALESHIFT; + + if (index >= MAXLIGHTSCALE ) + index = MAXLIGHTSCALE-1; + + dc_colormap = walllights[index]; + dc_x = rw_x; + dc_iscale = 0xffffffffu / (unsigned)rw_scale; + } + + // draw the wall tiers + if (midtexture) + { + + dc_yl = yl; // single sided line + dc_yh = yh; + dc_texturemid = rw_midtexturemid; + dc_source = R_GetColumn(midtexture, texturecolumn); + dc_texheight = midtexheight; + colfunc (); + ceilingclip[rw_x] = viewheight; + floorclip[rw_x] = -1; + } + else + { + + // two sided line + if (toptexture) + { + // top wall + int mid = pixhigh>>HEIGHTBITS; + pixhigh += pixhighstep; + + if (mid >= floorclip[rw_x]) + mid = floorclip[rw_x]-1; + + if (mid >= yl) + { + dc_yl = yl; + dc_yh = mid; + dc_texturemid = rw_toptexturemid; + dc_source = R_GetColumn(toptexture,texturecolumn); + dc_texheight = toptexheight; + colfunc (); + ceilingclip[rw_x] = mid; + } + else + ceilingclip[rw_x] = yl-1; + } + else // no top wall + { + + if (markceiling) + ceilingclip[rw_x] = yl-1; + } + + if (bottomtexture) // bottom wall + { + int mid = (pixlow+HEIGHTUNIT-1)>>HEIGHTBITS; + pixlow += pixlowstep; + + // no space above wall? + if (mid <= ceilingclip[rw_x]) + mid = ceilingclip[rw_x]+1; + + if (mid <= yh) + { + dc_yl = mid; + dc_yh = yh; + dc_texturemid = rw_bottomtexturemid; + dc_source = R_GetColumn(bottomtexture, + texturecolumn); + dc_texheight = bottomtexheight; + colfunc (); + floorclip[rw_x] = mid; + } + else + floorclip[rw_x] = yh+1; + } + else // no bottom wall + { + if (markfloor) + floorclip[rw_x] = yh+1; + } + + // cph - if we completely blocked further sight through this column, + // add this info to the solid columns array for r_bsp.c + if ((markceiling || markfloor) && + (floorclip[rw_x] <= ceilingclip[rw_x] + 1)) { + solidcol[rw_x] = 1; didsolidcol = 1; + } + + // save texturecol for backdrawing of masked mid texture + if (maskedtexture) + maskedtexturecol[rw_x] = texturecolumn; + } + + rw_scale += rw_scalestep; + topfrac += topstep; + bottomfrac += bottomstep; + } +} + +// killough 5/2/98: move from r_main.c, made static, simplified + +static fixed_t R_PointToDist(fixed_t x, fixed_t y) +{ + fixed_t dx = D_abs(x - viewx); + fixed_t dy = D_abs(y - viewy); + + if (dy > dx) + { + fixed_t t = dx; + dx = dy; + dy = t; + } + + return FixedDiv(dx, finesine[(tantoangle[FixedDiv(dy,dx) >> DBITS] + + ANG90) >> ANGLETOFINESHIFT]); +} + +// +// R_StoreWallRange +// A wall segment will be drawn +// between start and stop pixels (inclusive). +// +void R_StoreWallRange(const int start, const int stop) +{ + fixed_t hyp; + fixed_t sineval; + angle_t distangle, offsetangle; + + if (ds_p == drawsegs+maxdrawsegs) // killough 1/98 -- fix 2s line HOM + { + unsigned pos = ds_p - drawsegs; // jff 8/9/98 fix from ZDOOM1.14a + unsigned newmax = maxdrawsegs ? maxdrawsegs*2 : 128; // killough + drawsegs = realloc(drawsegs,newmax*sizeof(*drawsegs)); + ds_p = drawsegs + pos; // jff 8/9/98 fix from ZDOOM1.14a + maxdrawsegs = newmax; + } + + if(curline->miniseg == false) // figgi -- skip minisegs + curline->linedef->flags |= ML_MAPPED; + + +#ifdef RANGECHECK + if (start >=viewwidth || start > stop) + I_Error ("Bad R_RenderWallRange: %i to %i", start , stop); +#endif + + sidedef = curline->sidedef; + linedef = curline->linedef; + + // mark the segment as visible for auto map + linedef->flags |= ML_MAPPED; + + // calculate rw_distance for scale calculation + rw_normalangle = curline->angle + ANG90; + + offsetangle = D_abs(rw_normalangle-rw_angle1); + + if (offsetangle > ANG90) + offsetangle = ANG90; + + distangle = ANG90 - offsetangle; + hyp = (viewx==curline->v1->x && viewy==curline->v1->y)? + 0 : R_PointToDist (curline->v1->x, curline->v1->y); + sineval = finesine[distangle>>ANGLETOFINESHIFT]; + rw_distance = FixedMul(hyp, sineval); + + ds_p->x1 = rw_x = start; + ds_p->x2 = stop; + ds_p->curline = curline; + rw_stopx = stop+1; + + { // killough 1/6/98, 2/1/98: remove limit on openings + extern short *openings; + extern size_t maxopenings; + size_t pos = lastopening - openings; + size_t need = (rw_stopx - start)*4 + pos; + if (need > maxopenings) + { + drawseg_t *ds; //jff 8/9/98 needed for fix from ZDoom + short *oldopenings = openings; + short *oldlast = lastopening; + + do + maxopenings = maxopenings ? maxopenings*2 : 16384; + while (need > maxopenings); + openings = realloc(openings, maxopenings * sizeof(*openings)); + lastopening = openings + pos; + + // jff 8/9/98 borrowed fix for openings from ZDOOM1.14 + // [RH] We also need to adjust the openings pointers that + // were already stored in drawsegs. + for (ds = drawsegs; ds < ds_p; ds++) + { +#define ADJUST(p) if (ds->p + ds->x1 >= oldopenings && ds->p + ds->x1 <= oldlast)\ + ds->p = ds->p - oldopenings + openings; + ADJUST (maskedtexturecol); + ADJUST (sprtopclip); + ADJUST (sprbottomclip); + } +#undef ADJUST + } + } // killough: end of code to remove limits on openings + + // calculate scale at both ends and step + + ds_p->scale1 = rw_scale = + R_ScaleFromGlobalAngle (viewangle + xtoviewangle[start]); + + if (stop > start) + { + ds_p->scale2 = R_ScaleFromGlobalAngle (viewangle + xtoviewangle[stop]); + ds_p->scalestep = rw_scalestep = (ds_p->scale2-rw_scale) / (stop-start); + } + else + ds_p->scale2 = ds_p->scale1; + + // calculate texture boundaries + // and decide if floor / ceiling marks are needed + + worldtop = frontsector->ceilingheight - viewz; + worldbottom = frontsector->floorheight - viewz; + + midtexture = toptexture = bottomtexture = maskedtexture = 0; + ds_p->maskedtexturecol = NULL; + + if (!backsector) + { + // single sided line + midtexture = texturetranslation[sidedef->midtexture]; + midtexheight = (linedef->r_flags & RF_MID_TILE) ? 0 : textureheight[midtexture] >> FRACBITS; + + // a single sided line is terminal, so it must mark ends + markfloor = markceiling = true; + + if (linedef->flags & ML_DONTPEGBOTTOM) + { // bottom of texture at bottom + fixed_t vtop = frontsector->floorheight + + textureheight[sidedef->midtexture]; + rw_midtexturemid = vtop - viewz; + } + else // top of texture at top + rw_midtexturemid = worldtop; + + rw_midtexturemid += FixedMod(sidedef->rowoffset, textureheight[midtexture]); + + ds_p->silhouette = SIL_BOTH; + ds_p->sprtopclip = screenheightarray; + ds_p->sprbottomclip = negonearray; + ds_p->bsilheight = INT_MAX; + ds_p->tsilheight = INT_MIN; + } + else // two sided line + { + ds_p->sprtopclip = ds_p->sprbottomclip = NULL; + ds_p->silhouette = 0; + + if (linedef->r_flags & RF_CLOSED) { /* cph - closed 2S line e.g. door */ + // cph - killough's (outdated) comment follows - this deals with both + // "automap fixes", his and mine + // killough 1/17/98: this test is required if the fix + // for the automap bug (r_bsp.c) is used, or else some + // sprites will be displayed behind closed doors. That + // fix prevents lines behind closed doors with dropoffs + // from being displayed on the automap. + + ds_p->silhouette = SIL_BOTH; + ds_p->sprbottomclip = negonearray; + ds_p->bsilheight = INT_MAX; + ds_p->sprtopclip = screenheightarray; + ds_p->tsilheight = INT_MIN; + + } else { /* not solid - old code */ + + if (frontsector->floorheight > backsector->floorheight) + { + ds_p->silhouette = SIL_BOTTOM; + ds_p->bsilheight = frontsector->floorheight; + } + else + if (backsector->floorheight > viewz) + { + ds_p->silhouette = SIL_BOTTOM; + ds_p->bsilheight = INT_MAX; + } + + if (frontsector->ceilingheight < backsector->ceilingheight) + { + ds_p->silhouette |= SIL_TOP; + ds_p->tsilheight = frontsector->ceilingheight; + } + else + if (backsector->ceilingheight < viewz) + { + ds_p->silhouette |= SIL_TOP; + ds_p->tsilheight = INT_MIN; + } + } + + worldhigh = backsector->ceilingheight - viewz; + worldlow = backsector->floorheight - viewz; + + // hack to allow height changes in outdoor areas + if (frontsector->ceilingpic == skyflatnum + && backsector->ceilingpic == skyflatnum) + worldtop = worldhigh; + + markfloor = worldlow != worldbottom + || backsector->floorpic != frontsector->floorpic + || backsector->lightlevel != frontsector->lightlevel + + // killough 3/7/98: Add checks for (x,y) offsets + || backsector->floor_xoffs != frontsector->floor_xoffs + || backsector->floor_yoffs != frontsector->floor_yoffs + + // killough 4/15/98: prevent 2s normals + // from bleeding through deep water + || frontsector->heightsec != -1 + + // killough 4/17/98: draw floors if different light levels + || backsector->floorlightsec != frontsector->floorlightsec + ; + + markceiling = worldhigh != worldtop + || backsector->ceilingpic != frontsector->ceilingpic + || backsector->lightlevel != frontsector->lightlevel + + // killough 3/7/98: Add checks for (x,y) offsets + || backsector->ceiling_xoffs != frontsector->ceiling_xoffs + || backsector->ceiling_yoffs != frontsector->ceiling_yoffs + + // killough 4/15/98: prevent 2s normals + // from bleeding through fake ceilings + || (frontsector->heightsec != -1 && + frontsector->ceilingpic!=skyflatnum) + + // killough 4/17/98: draw ceilings if different light levels + || backsector->ceilinglightsec != frontsector->ceilinglightsec + ; + + if (backsector->ceilingheight <= frontsector->floorheight + || backsector->floorheight >= frontsector->ceilingheight) + markceiling = markfloor = true; // closed door + + if (worldhigh < worldtop) // top texture + { + toptexture = texturetranslation[sidedef->toptexture]; + toptexheight = (linedef->r_flags & RF_TOP_TILE) ? 0 : textureheight[toptexture] >> FRACBITS; + rw_toptexturemid = linedef->flags & ML_DONTPEGTOP ? worldtop : + backsector->ceilingheight+textureheight[sidedef->toptexture]-viewz; + rw_toptexturemid += FixedMod(sidedef->rowoffset, textureheight[toptexture]); + } + + if (worldlow > worldbottom) // bottom texture + { + bottomtexture = texturetranslation[sidedef->bottomtexture]; + bottomtexheight = (linedef->r_flags & RF_BOT_TILE) ? 0 : textureheight[bottomtexture] >> FRACBITS; + rw_bottomtexturemid = linedef->flags & ML_DONTPEGBOTTOM ? worldtop : + worldlow; + rw_bottomtexturemid += FixedMod(sidedef->rowoffset, textureheight[bottomtexture]); + } + + // allocate space for masked texture tables + if (sidedef->midtexture) // masked midtexture + { + maskedtexture = true; + ds_p->maskedtexturecol = maskedtexturecol = lastopening - rw_x; + lastopening += rw_stopx - rw_x; + } + } + + // calculate rw_offset (only needed for textured lines) + segtextured = midtexture | toptexture | bottomtexture | maskedtexture; + + if (segtextured) + { + offsetangle = rw_normalangle-rw_angle1; + + if (offsetangle > ANG180) + offsetangle = 0-offsetangle; + + if (offsetangle > ANG90) + offsetangle = ANG90; + + sineval = finesine[offsetangle >>ANGLETOFINESHIFT]; + rw_offset = FixedMul (hyp, sineval); + + if (rw_normalangle-rw_angle1 < ANG180) + rw_offset = -rw_offset; + + rw_offset += sidedef->textureoffset + curline->offset; + + rw_centerangle = ANG90 + viewangle - rw_normalangle; + + // calculate light table + // use different light tables + // for horizontal / vertical / diagonal + // OPTIMIZE: get rid of LIGHTSEGSHIFT globally + if (!fixedcolormap) + { + int lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT)+extralight; + + /* cph - ...what is this for? adding contrast to rooms? + * It looks crap in outdoor areas */ + if (fake_contrast) { + if (curline->v1->y == curline->v2->y) + lightnum--; + else if (curline->v1->x == curline->v2->x) + lightnum++; + } + + if (lightnum < 0) + walllights = scalelight[0]; + else if (lightnum >= LIGHTLEVELS) + walllights = scalelight[LIGHTLEVELS-1]; + else + walllights = scalelight[lightnum]; + } + } + + // if a floor / ceiling plane is on the wrong side of the view + // plane, it is definitely invisible and doesn't need to be marked. + + // killough 3/7/98: add deep water check + if (frontsector->heightsec == -1) + { + if (frontsector->floorheight >= viewz) // above view plane + markfloor = false; + if (frontsector->ceilingheight <= viewz && + frontsector->ceilingpic != skyflatnum) // below view plane + markceiling = false; + } + + // calculate incremental stepping values for texture edges + worldtop >>= 4; + worldbottom >>= 4; + + topstep = -FixedMul (rw_scalestep, worldtop); + topfrac = (centeryfrac>>4) - FixedMul (worldtop, rw_scale); + + bottomstep = -FixedMul (rw_scalestep,worldbottom); + bottomfrac = (centeryfrac>>4) - FixedMul (worldbottom, rw_scale); + + if (backsector) + { + worldhigh >>= 4; + worldlow >>= 4; + + if (worldhigh < worldtop) + { + pixhigh = (centeryfrac>>4) - FixedMul (worldhigh, rw_scale); + pixhighstep = -FixedMul (rw_scalestep,worldhigh); + } + if (worldlow > worldbottom) + { + pixlow = (centeryfrac>>4) - FixedMul (worldlow, rw_scale); + pixlowstep = -FixedMul (rw_scalestep,worldlow); + } + } + + // render it + if (markceiling) { + if (ceilingplane) // killough 4/11/98: add NULL ptr checks + ceilingplane = R_CheckPlane (ceilingplane, rw_x, rw_stopx-1); + else + markceiling = 0; + } + + if (markfloor) { + if (floorplane) // killough 4/11/98: add NULL ptr checks + /* cph 2003/04/18 - ceilingplane and floorplane might be the same + * visplane (e.g. if both skies); R_CheckPlane doesn't know about + * modifications to the plane that might happen in parallel with the check + * being made, so we have to override it and split them anyway if that is + * a possibility, otherwise the floor marking would overwrite the ceiling + * marking, resulting in HOM. */ + if (markceiling && ceilingplane == floorplane) + floorplane = R_DupPlane (floorplane, rw_x, rw_stopx-1); + else + floorplane = R_CheckPlane (floorplane, rw_x, rw_stopx-1); + else + markfloor = 0; + } + + didsolidcol = 0; + R_RenderSegLoop(); + + /* cph - if a column was made solid by this wall, we _must_ save full clipping info */ + if (backsector && didsolidcol) { + if (!(ds_p->silhouette & SIL_BOTTOM)) { + ds_p->silhouette |= SIL_BOTTOM; + ds_p->bsilheight = backsector->floorheight; + } + if (!(ds_p->silhouette & SIL_TOP)) { + ds_p->silhouette |= SIL_TOP; + ds_p->tsilheight = backsector->ceilingheight; + } + } + + // save sprite clipping info + if ((ds_p->silhouette & SIL_TOP || maskedtexture) && !ds_p->sprtopclip) + { + memcpy (lastopening, ceilingclip+start, 2*(rw_stopx-start)); + ds_p->sprtopclip = lastopening - start; + lastopening += rw_stopx - start; + } + if ((ds_p->silhouette & SIL_BOTTOM || maskedtexture) && !ds_p->sprbottomclip) + { + memcpy (lastopening, floorclip+start, 2*(rw_stopx-start)); + ds_p->sprbottomclip = lastopening - start; + lastopening += rw_stopx - start; + } + if (maskedtexture && !(ds_p->silhouette & SIL_TOP)) + { + ds_p->silhouette |= SIL_TOP; + ds_p->tsilheight = INT_MIN; + } + if (maskedtexture && !(ds_p->silhouette & SIL_BOTTOM)) + { + ds_p->silhouette |= SIL_BOTTOM; + ds_p->bsilheight = INT_MAX; + } + ds_p++; +} diff --git a/apps/plugins/doom/r_segs.h b/apps/plugins/doom/r_segs.h new file mode 100644 index 0000000000..bbf56b6d6f --- /dev/null +++ b/apps/plugins/doom/r_segs.h @@ -0,0 +1,42 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Refresh module, drawing LineSegs from BSP. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __R_SEGS__ +#define __R_SEGS__ + +#ifdef __GNUG__ +#pragma interface +#endif + +void R_RenderMaskedSegRange(drawseg_t *ds, int x1, int x2); +void R_StoreWallRange(int start, int stop); + +#endif diff --git a/apps/plugins/doom/r_sky.c b/apps/plugins/doom/r_sky.c new file mode 100644 index 0000000000..2ec2603972 --- /dev/null +++ b/apps/plugins/doom/r_sky.c @@ -0,0 +1,53 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Sky rendering. The DOOM sky is a texture map like any + * wall, wrapping around. A 1024 columns equal 360 degrees. + * The default sky map is 256 columns and repeats 4 times + * on a 320 screen? + * + *-----------------------------------------------------------------------------*/ + +#ifdef __GNUG__ +#pragma implementation "r_sky.h" +#endif +#include "r_sky.h" +// +// sky mapping +// +int skyflatnum; +int skytexture; +int skytexturemid; + +// +// R_InitSkyMap +// Called whenever the view size changes. +// +void R_InitSkyMap (void) +{ + skytexturemid = 100*FRACUNIT; +} diff --git a/apps/plugins/doom/r_sky.h b/apps/plugins/doom/r_sky.h new file mode 100644 index 0000000000..1b817c1a44 --- /dev/null +++ b/apps/plugins/doom/r_sky.h @@ -0,0 +1,53 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Sky rendering. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __R_SKY__ +#define __R_SKY__ + +#include "m_fixed.h" + +#ifdef __GNUG__ +#pragma interface +#endif + +/* SKY, store the number for name. */ +#define SKYFLATNAME "F_SKY1" + +/* The sky map is 256*128*4 maps. */ +#define ANGLETOSKYSHIFT 22 + +extern int skytexture; +extern int skytexturemid; + +/* Called whenever the view size changes. */ +void R_InitSkyMap(void); + +#endif diff --git a/apps/plugins/doom/r_state.h b/apps/plugins/doom/r_state.h new file mode 100644 index 0000000000..2e11bb50c5 --- /dev/null +++ b/apps/plugins/doom/r_state.h @@ -0,0 +1,140 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// $Id$ +// +// Copyright (C) 1993-1996 by id Software, Inc. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// Refresh/render internal state variables (global). +// +//----------------------------------------------------------------------------- + + +#ifndef __R_STATE__ +#define __R_STATE__ + +// Need data structure definitions. +#include "d_player.h" +#include "r_data.h" + + + +#ifdef __GNUG__ +#pragma interface +#endif + + + +// +// Refresh internal data structures, +// for rendering. +// + +// needed for texture pegging +extern fixed_t* textureheight; + +// needed for pre rendering (fracs) +extern fixed_t* spritewidth; + +extern fixed_t* spriteoffset; +extern fixed_t* spritetopoffset; + +extern int viewwidth; +extern int scaledviewwidth; +extern int viewheight; + +extern int firstflat; + +// for global animation +extern int* flattranslation; +extern int* texturetranslation; + + +// Sprite.... +extern int firstspritelump; +extern int lastspritelump; +extern int numspritelumps; + + + +// +// Lookup tables for map data. +// +extern int numsprites; +extern spritedef_t* sprites; + +extern int numvertexes; +extern vertex_t* vertexes; + +extern int numsegs; +extern seg_t* segs; + +extern int numsectors; +extern sector_t* sectors; + +extern int numsubsectors; +extern subsector_t* subsectors; + +extern int numnodes; +extern node_t* nodes; + +extern int numlines; +extern line_t* lines; + +extern int numsides; +extern side_t* sides; + + +// +// POV data. +// +extern fixed_t viewx; +extern fixed_t viewy; +extern fixed_t viewz; + +extern angle_t viewangle; +extern player_t* viewplayer; + + +// ? +extern angle_t clipangle; + +extern int viewangletox[FINEANGLES/2]; +extern angle_t xtoviewangle[SCREENWIDTH+1]; +//extern fixed_t finetangent[FINEANGLES/2]; + +extern fixed_t rw_distance; +extern angle_t rw_normalangle; + + + +// angle to line origin +extern int rw_angle1; + +// Segs count? +extern int sscount; + +extern visplane_t* floorplane; +extern visplane_t* ceilingplane; + + +#endif +//----------------------------------------------------------------------------- +// +// $Log$ +// Revision 1.1 2006/03/28 15:44:01 dave +// Patch #2969 - Doom! Currently only working on the H300. +// +// +//----------------------------------------------------------------------------- diff --git a/apps/plugins/doom/r_things.c b/apps/plugins/doom/r_things.c new file mode 100644 index 0000000000..2e1f72e34c --- /dev/null +++ b/apps/plugins/doom/r_things.c @@ -0,0 +1,976 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Refresh of things, i.e. objects represented by sprites. + * + *-----------------------------------------------------------------------------*/ + +#include "doomdef.h" +#include "m_swap.h" + +#include "doomstat.h" +#include "w_wad.h" +#include "r_main.h" +#include "r_bsp.h" +#include "r_segs.h" +#include "r_draw.h" +#include "r_things.h" +#include "i_system.h" +//#include "lprintf.h" +#include "rockmacros.h" + +#define MINZ (FRACUNIT*4) +#define BASEYCENTER 100 + +typedef struct { + int x1; + int x2; + int column; + int topclip; + int bottomclip; +} maskdraw_t; + +// +// Sprite rotation 0 is facing the viewer, +// rotation 1 is one angle turn CLOCKWISE around the axis. +// This is not the same as the angle, +// which increases counter clockwise (protractor). +// There was a lot of stuff grabbed wrong, so I changed it... +// +fixed_t pspritescale; +fixed_t pspriteiscale; + +static lighttable_t** spritelights; + +// constant arrays +// used for psprite clipping and initializing clipping +short negonearray[SCREENWIDTH]; +short screenheightarray[SCREENWIDTH]; + + +// +// INITIALIZATION FUNCTIONS +// + +// variables used to look up and range check thing_t sprites patches + +spritedef_t* sprites; +int numsprites; + +#define MAX_SPRITE_FRAMES 29 /* Macroized -- killough 1/25/98 */ + +static spriteframe_t sprtemp[MAX_SPRITE_FRAMES]; +static int maxframe; + +// +// R_InstallSpriteLump +// Local function for R_InitSprites. +// + +static void R_InstallSpriteLump(int lump, unsigned frame, + unsigned rotation, boolean flipped) +{ + + if (frame >= MAX_SPRITE_FRAMES || rotation > 8) + I_Error("R_InstallSpriteLump: Bad frame characters in lump %i", lump); + + if ((int)frame > maxframe) + maxframe = frame; + + if (rotation == 0) + { // the lump should be used for all rotations + int r; + for (r=0 ; r<8 ; r++) + if (sprtemp[frame].lump[r]==-1) + { + sprtemp[frame].lump[r] = lump - firstspritelump; + sprtemp[frame].flip[r] = (byte) flipped; + sprtemp[frame].rotate = false; //jff 4/24/98 if any subbed, rotless + } + return; + } + + // the lump is only used for one rotation + + if (sprtemp[frame].lump[--rotation] == -1) + { + sprtemp[frame].lump[rotation] = lump - firstspritelump; + sprtemp[frame].flip[rotation] = (byte) flipped; + sprtemp[frame].rotate = true; //jff 4/24/98 only change if rot used + } +} + +// +// R_InitSpriteDefs +// Pass a null terminated list of sprite names +// (4 chars exactly) to be used. +// +// Builds the sprite rotation matrixes to account +// for horizontally flipped sprites. +// +// Will report an error if the lumps are inconsistent. +// Only called at startup. +// +// Sprite lump names are 4 characters for the actor, +// a letter for the frame, and a number for the rotation. +// +// A sprite that is flippable will have an additional +// letter/number appended. +// +// The rotation character can be 0 to signify no rotations. +// +// 1/25/98, 1/31/98 killough : Rewritten for performance +// +// Empirically verified to have excellent hash +// properties across standard Doom sprites: + +#define R_SpriteNameHash(s) ((unsigned)((s)[0]-((s)[1]*3-(s)[3]*2-(s)[2])*2)) + +void R_InitSpriteDefs(const char * const * namelist) +{ + size_t numentries = lastspritelump-firstspritelump+1; + struct { int index, next; } *hash; + int i; + + if (!numentries || !*namelist) + return; + + // count the number of sprite names + for (i=0; namelist[i]; i++) + ; + + numsprites = i; + + sprites = Z_Malloc(numsprites *sizeof(*sprites), PU_STATIC, NULL); + + // Create hash table based on just the first four letters of each sprite + // killough 1/31/98 + + hash = malloc(sizeof(*hash)*numentries); // allocate hash table + + for (i=0; (size_t)i= 0) + { + memset(sprtemp, -1, sizeof(sprtemp)); + maxframe = -1; + do + { + register lumpinfo_t *lump = lumpinfo + j + firstspritelump; + + // Fast portable comparison -- killough + // (using int pointer cast is nonportable): + + if (!((lump->name[0] ^ spritename[0]) | + (lump->name[1] ^ spritename[1]) | + (lump->name[2] ^ spritename[2]) | + (lump->name[3] ^ spritename[3]))) + { + R_InstallSpriteLump(j+firstspritelump, + lump->name[4] - 'A', + lump->name[5] - '0', + false); + if (lump->name[6]) + R_InstallSpriteLump(j+firstspritelump, + lump->name[6] - 'A', + lump->name[7] - '0', + true); + } + } + while ((j = hash[j].next) >= 0); + + // check the frames that were found for completeness + if ((sprites[i].numframes = ++maxframe)) // killough 1/31/98 + { + int frame; + for (frame = 0; frame < maxframe; frame++) + switch ((int) sprtemp[frame].rotate) + { + case -1: + // no rotations were found for that frame at all + I_Error ("R_InitSprites: No patches found " + "for %.8s frame %c", namelist[i], frame+'A'); + break; + + case 0: + // only the first rotation is needed + break; + + case 1: + // must have all 8 frames + { + int rotation; + for (rotation=0 ; rotation<8 ; rotation++) + if (sprtemp[frame].lump[rotation] == -1) + I_Error ("R_InitSprites: Sprite %.8s frame %c " + "is missing rotations", + namelist[i], frame+'A'); + break; + } + } + // allocate space for the frames present and copy sprtemp to it + sprites[i].spriteframes = + Z_Malloc (maxframe * sizeof(spriteframe_t), PU_STATIC, NULL); + memcpy (sprites[i].spriteframes, sprtemp, + maxframe*sizeof(spriteframe_t)); + } + } + } + free(hash); // free hash table +} + +// +// GAME FUNCTIONS +// + +static vissprite_t *vissprites, **vissprite_ptrs; // killough +static size_t num_vissprite, num_vissprite_alloc, num_vissprite_ptrs; + + +// +// R_InitSprites +// Called at program start. +// +void R_InitSprites(const char * const *namelist) +{ + int i; + + for (i=0 ; i= num_vissprite_alloc) // killough + { + num_vissprite_alloc = num_vissprite_alloc ? num_vissprite_alloc*2 : 128; + vissprites = realloc(vissprites,num_vissprite_alloc*sizeof(*vissprites)); + } + return vissprites + num_vissprite++; +} + +// +// R_DrawMaskedColumn +// Used for sprites and masked mid textures. +// Masked means: partly transparent, i.e. stored +// in posts/runs of opaque pixels. +// + +short* mfloorclip; +short* mceilingclip; +fixed_t spryscale; +fixed_t sprtopscreen; + +void R_DrawMaskedColumn(const column_t *column) +{ + int topscreen; + int bottomscreen; + fixed_t basetexturemid = dc_texturemid; + + dc_texheight = 0; // killough 11/98 + while (column->topdelta != 0xff) + { + // calculate unclipped screen coordinates for post + topscreen = sprtopscreen + spryscale*column->topdelta; + bottomscreen = topscreen + spryscale*column->length; + + dc_yl = (topscreen+FRACUNIT-1)>>FRACBITS; + dc_yh = (bottomscreen-1)>>FRACBITS; + + if (dc_yh >= mfloorclip[dc_x]) + dc_yh = mfloorclip[dc_x]-1; + + if (dc_yl <= mceilingclip[dc_x]) + dc_yl = mceilingclip[dc_x]+1; + + // killough 3/2/98, 3/27/98: Failsafe against overflow/crash: + if (dc_yl <= dc_yh && dc_yh < viewheight) + { + dc_source = (byte *)column + 3; + dc_texturemid = basetexturemid - (column->topdelta<length + 4); + } + dc_texturemid = basetexturemid; +} + +// +// R_DrawVisSprite +// mfloorclip and mceilingclip should also be set. +// +// CPhipps - new wad lump handling, *'s to const*'s +void R_DrawVisSprite(vissprite_t *vis, int x1, int x2) +{ + (void)x1; + (void)x2; + const column_t *column; + int texturecolumn; + fixed_t frac; + const patch_t *patch = W_CacheLumpNum (vis->patch+firstspritelump); + + dc_colormap = vis->colormap; + + // killough 4/11/98: rearrange and handle translucent sprites + // mixed with translucent/non-translucenct 2s normals + + if (!dc_colormap) // NULL colormap = shadow draw + colfunc = R_DrawFuzzColumn; // killough 3/14/98 + else + if (vis->mobjflags & MF_TRANSLATION) + { + colfunc = R_DrawTranslatedColumn; + dc_translation = translationtables - 256 + + ((vis->mobjflags & MF_TRANSLATION) >> (MF_TRANSSHIFT-8) ); + } + else + if (vis->mobjflags & MF_TRANSLUCENT && general_translucency) // phares + { + colfunc = R_DrawTLColumn; + tranmap = main_tranmap; // killough 4/11/98 + } + else + colfunc = R_DrawColumn; // killough 3/14/98, 4/11/98 + + + // proff 11/06/98: Changed for high-res + dc_iscale = D_abs(vis->xiscale); + dc_texturemid = vis->texturemid; + frac = vis->startfrac; + spryscale = vis->scale; + sprtopscreen = centeryfrac - FixedMul(dc_texturemid,spryscale); + + for (dc_x=vis->x1 ; dc_x<=vis->x2 ; dc_x++, frac += vis->xiscale) + { + texturecolumn = frac>>FRACBITS; + +#ifdef RANGECHECK + if (texturecolumn < 0 || texturecolumn >= SHORT(patch->width)) + I_Error ("R_DrawSpriteRange: Bad texturecolumn"); +#endif + + column = (const column_t *)((const byte *) patch + + LONG(patch->columnofs[texturecolumn])); + R_DrawMaskedColumn (column); + } + colfunc = R_DrawColumn; // killough 3/14/98 + W_UnlockLumpNum(vis->patch+firstspritelump); // cph - release lump +} + +// +// R_ProjectSprite +// Generates a vissprite for a thing if it might be visible. +// + +void R_ProjectSprite (mobj_t* thing) +{ + fixed_t gzt; // killough 3/27/98 + fixed_t tx; + fixed_t xscale; + int x1; + int x2; + spritedef_t *sprdef; + spriteframe_t *sprframe; + int lump; + boolean flip; + vissprite_t *vis; +#ifndef GL_DOOM + fixed_t iscale; +#endif + int heightsec; // killough 3/27/98 + + // transform the origin point + fixed_t tr_x = thing->x - viewx; + fixed_t tr_y = thing->y - viewy; + + fixed_t gxt = FixedMul(tr_x,viewcos); + fixed_t gyt = -FixedMul(tr_y,viewsin); + + fixed_t tz = gxt-gyt; + + // thing is behind view plane? + if (tz < MINZ) + return; + + xscale = FixedDiv(projection, tz); + + gxt = -FixedMul(tr_x,viewsin); + gyt = FixedMul(tr_y,viewcos); + tx = -(gyt+gxt); + + // too far off the side? + if (D_abs(tx)>(tz<<2)) + return; + + // decide which patch to use for sprite relative to player +#ifdef RANGECHECK + if ((unsigned) thing->sprite >= (unsigned)numsprites) + I_Error ("R_ProjectSprite: Invalid sprite number %i", thing->sprite); +#endif + + sprdef = &sprites[thing->sprite]; + +#ifdef RANGECHECK + if ((thing->frame&FF_FRAMEMASK) >= sprdef->numframes) + I_Error ("R_ProjectSprite: Invalid sprite frame %i : %i", thing->sprite, + thing->frame); +#endif + + sprframe = &sprdef->spriteframes[thing->frame & FF_FRAMEMASK]; + + if (sprframe->rotate) + { + // choose a different rotation based on player view + angle_t ang = R_PointToAngle(thing->x, thing->y); + unsigned rot = (ang-thing->angle+(unsigned)(ANG45/2)*9)>>29; + lump = sprframe->lump[rot]; + flip = (boolean) sprframe->flip[rot]; + } + else + { + // use single rotation for all views + lump = sprframe->lump[0]; + flip = (boolean) sprframe->flip[0]; + } + + /* calculate edges of the shape + * cph 2003/08/1 - fraggle points out that this offset must be flipped if the + * sprite is flipped; e.g. FreeDoom imp is messed up by this. */ + tx -= flip ? spritewidth[lump] - spriteoffset[lump] : spriteoffset[lump]; + x1 = (centerxfrac + FixedMul(tx,xscale)) >>FRACBITS; + + // off the right side? + if (x1 > viewwidth) + return; + + tx += spritewidth[lump]; + x2 = ((centerxfrac + FixedMul (tx,xscale) ) >>FRACBITS) - 1; + + // off the left side + if (x2 < 0) + return; + + gzt = thing->z + spritetopoffset[lump]; + + // killough 4/9/98: clip things which are out of view due to height + if (thing->z > viewz + FixedDiv(centeryfrac, xscale) || + gzt < viewz - FixedDiv(centeryfrac-viewheight, xscale)) + return; + + // killough 3/27/98: exclude things totally separated + // from the viewer, by either water or fake ceilings + // killough 4/11/98: improve sprite clipping for underwater/fake ceilings + + heightsec = thing->subsector->sector->heightsec; + + if (heightsec != -1) // only clip things which are in special sectors + { + int phs = viewplayer->mo->subsector->sector->heightsec; + if (phs != -1 && viewz < sectors[phs].floorheight ? + thing->z >= sectors[heightsec].floorheight : + gzt < sectors[heightsec].floorheight) + return; + if (phs != -1 && viewz > sectors[phs].ceilingheight ? + gzt < sectors[heightsec].ceilingheight && + viewz >= sectors[heightsec].ceilingheight : + thing->z >= sectors[heightsec].ceilingheight) + return; + } + + // store information in a vissprite + vis = R_NewVisSprite (); + + // killough 3/27/98: save sector for special clipping later + vis->heightsec = heightsec; + + vis->mobjflags = thing->flags; + // proff 11/06/98: Changed for high-res + vis->scale = xscale; + vis->gx = thing->x; + vis->gy = thing->y; + vis->gz = thing->z; + vis->gzt = gzt; // killough 3/27/98 + vis->texturemid = vis->gzt - viewz; + vis->x1 = x1 < 0 ? 0 : x1; + vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2; + iscale = FixedDiv (FRACUNIT, xscale); + + if (flip) + { + vis->startfrac = spritewidth[lump]-1; + vis->xiscale = -iscale; + } + else + { + vis->startfrac = 0; + vis->xiscale = iscale; + } + + if (vis->x1 > x1) + vis->startfrac += vis->xiscale*(vis->x1-x1); + vis->patch = lump; + + // get light level + if (thing->flags & MF_SHADOW) + vis->colormap = NULL; // shadow draw + else if (fixedcolormap) + vis->colormap = fixedcolormap; // fixed map + else if (thing->frame & FF_FULLBRIGHT) + vis->colormap = fullcolormap; // full bright // killough 3/20/98 + else + { // diminished light + int index = xscale>>LIGHTSCALESHIFT; + if (index >= MAXLIGHTSCALE) + index = MAXLIGHTSCALE-1; + vis->colormap = spritelights[index]; + } +} + +// +// R_AddSprites +// During BSP traversal, this adds sprites by sector. +// +// killough 9/18/98: add lightlevel as parameter, fixing underwater lighting +void R_AddSprites(subsector_t* subsec, int lightlevel) +{ + sector_t* sec=subsec->sector; + mobj_t *thing; + int lightnum; + + // BSP is traversed by subsector. + // A sector might have been split into several + // subsectors during BSP building. + // Thus we check whether its already added. + + if (sec->validcount == validcount) + return; + + // Well, now it will be done. + sec->validcount = validcount; + + lightnum = (lightlevel >> LIGHTSEGSHIFT)+extralight; + + if (lightnum < 0) + spritelights = scalelight[0]; + else if (lightnum >= LIGHTLEVELS) + spritelights = scalelight[LIGHTLEVELS-1]; + else + spritelights = scalelight[lightnum]; + + // Handle all things in sector. + + for (thing = sec->thinglist; thing; thing = thing->snext) + R_ProjectSprite(thing); +} + +// +// R_DrawPSprite +// + +void R_DrawPSprite (pspdef_t *psp) +{ + fixed_t tx; + int x1, x2; + spritedef_t *sprdef; + spriteframe_t *sprframe; + int lump; + boolean flip; + vissprite_t *vis; + vissprite_t avis; + + // decide which patch to use + +#ifdef RANGECHECK + if ( (unsigned)psp->state->sprite >= (unsigned)numsprites) + I_Error ("R_ProjectSprite: Invalid sprite number %i", psp->state->sprite); +#endif + + sprdef = &sprites[psp->state->sprite]; + +#ifdef RANGECHECK + if ( (psp->state->frame & FF_FRAMEMASK) >= sprdef->numframes) + I_Error ("R_ProjectSprite: Invalid sprite frame %i : %li", + psp->state->sprite, psp->state->frame); +#endif + + sprframe = &sprdef->spriteframes[psp->state->frame & FF_FRAMEMASK]; + + lump = sprframe->lump[0]; + flip = (boolean) sprframe->flip[0]; + + // calculate edges of the shape + tx = psp->sx-160*FRACUNIT; + + tx -= spriteoffset[lump]; + x1 = (centerxfrac + FixedMul (tx,pspritescale))>>FRACBITS; + + // off the right side + if (x1 > viewwidth) + return; + + tx += spritewidth[lump]; + x2 = ((centerxfrac + FixedMul (tx, pspritescale) ) >>FRACBITS) - 1; + + // off the left side + if (x2 < 0) + return; + + // store information in a vissprite + vis = &avis; + vis->mobjflags = 0; + // killough 12/98: fix psprite positioning problem + vis->texturemid = (BASEYCENTER<sy-spritetopoffset[lump]); + vis->x1 = x1 < 0 ? 0 : x1; + vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2; + // proff 11/06/98: Added for high-res + vis->scale = pspritescale; + + if (flip) + { + vis->xiscale = -pspriteiscale; + vis->startfrac = spritewidth[lump]-1; + } + else + { + vis->xiscale = pspriteiscale; + vis->startfrac = 0; + } + + if (vis->x1 > x1) + vis->startfrac += vis->xiscale*(vis->x1-x1); + + vis->patch = lump; + + if (viewplayer->powers[pw_invisibility] > 4*32 + || viewplayer->powers[pw_invisibility] & 8) + vis->colormap = NULL; // shadow draw + else if (fixedcolormap) + vis->colormap = fixedcolormap; // fixed color + else if (psp->state->frame & FF_FULLBRIGHT) + vis->colormap = fullcolormap; // full bright // killough 3/20/98 + else + vis->colormap = spritelights[MAXLIGHTSCALE-1]; // local light + + R_DrawVisSprite(vis, vis->x1, vis->x2); +} + +// +// R_DrawPlayerSprites +// + +void R_DrawPlayerSprites(void) +{ + int i, lightnum; + pspdef_t *psp; + + // get light level + lightnum = (viewplayer->mo->subsector->sector->lightlevel >> LIGHTSEGSHIFT) + + extralight; + + if (lightnum < 0) + spritelights = scalelight[0]; + else if (lightnum >= LIGHTLEVELS) + spritelights = scalelight[LIGHTLEVELS-1]; + else + spritelights = scalelight[lightnum]; + + // clip to screen bounds + mfloorclip = screenheightarray; + mceilingclip = negonearray; + + // add all active psprites + for (i=0, psp=viewplayer->psprites; istate) + R_DrawPSprite (psp); +} + +// +// R_SortVisSprites +// +// Rewritten by Lee Killough to avoid using unnecessary +// linked lists, and to use faster sorting algorithm. +// + +#define bcopyp(d, s, n) memcpy(d, s, (n) * sizeof(void *)) + +// killough 9/2/98: merge sort + +static void msort(vissprite_t **s, vissprite_t **t, int n) +{ + if (n >= 16) + { + int n1 = n/2, n2 = n - n1; + vissprite_t **s1 = s, **s2 = s + n1, **d = t; + + msort(s1, t, n1); + msort(s2, t, n2); + + while ((*s1)->scale > (*s2)->scale ? + (*d++ = *s1++, --n1) : (*d++ = *s2++, --n2)); + + if (n2) + bcopyp(d, s2, n2); + else + bcopyp(d, s1, n1); + + bcopyp(s, t, n); + } + else + { + int i; + for (i = 1; i < n; i++) + { + vissprite_t *temp = s[i]; + if (s[i-1]->scale < temp->scale) + { + int j = i; + while ((s[j] = s[j-1])->scale < temp->scale && --j); + s[j] = temp; + } + } + } +} + +void R_SortVisSprites (void) +{ + if (num_vissprite) + { + int i = num_vissprite; + + // If we need to allocate more pointers for the vissprites, + // allocate as many as were allocated for sprites -- killough + // killough 9/22/98: allocate twice as many + + if (num_vissprite_ptrs < num_vissprite*2) + { + free(vissprite_ptrs); // better than realloc -- no preserving needed + vissprite_ptrs = malloc((num_vissprite_ptrs = num_vissprite_alloc*2) + * sizeof *vissprite_ptrs); + } + + while (--i>=0) + vissprite_ptrs[i] = vissprites+i; + + // killough 9/22/98: replace qsort with merge sort, since the keys + // are roughly in order to begin with, due to BSP rendering. + + msort(vissprite_ptrs, vissprite_ptrs + num_vissprite, num_vissprite); + } +} + +// +// R_DrawSprite +// + +void R_DrawSprite (vissprite_t* spr) +{ + drawseg_t *ds; + short clipbot[SCREENWIDTH]; // killough 2/8/98: + short cliptop[SCREENWIDTH]; // change to MAX_* + int x; + int r1; + int r2; + fixed_t scale; + fixed_t lowscale; + + for (x = spr->x1 ; x<=spr->x2 ; x++) + clipbot[x] = cliptop[x] = -2; + + // Scan drawsegs from end to start for obscuring segs. + // The first drawseg that has a greater scale is the clip seg. + + // Modified by Lee Killough: + // (pointer check was originally nonportable + // and buggy, by going past LEFT end of array): + + // for (ds=ds_p-1 ; ds >= drawsegs ; ds--) old buggy code + + for (ds=ds_p ; ds-- > drawsegs ; ) // new -- killough + { // determine if the drawseg obscures the sprite + if (ds->x1 > spr->x2 || ds->x2 < spr->x1 || + (!ds->silhouette && !ds->maskedtexturecol)) + continue; // does not cover sprite + + r1 = ds->x1 < spr->x1 ? spr->x1 : ds->x1; + r2 = ds->x2 > spr->x2 ? spr->x2 : ds->x2; + + if (ds->scale1 > ds->scale2) + { + lowscale = ds->scale2; + scale = ds->scale1; + } + else + { + lowscale = ds->scale1; + scale = ds->scale2; + } + + if (scale < spr->scale || (lowscale < spr->scale && + !R_PointOnSegSide (spr->gx, spr->gy, ds->curline))) + { + if (ds->maskedtexturecol) // masked mid texture? + R_RenderMaskedSegRange(ds, r1, r2); + continue; // seg is behind sprite + } + + // clip this piece of the sprite + // killough 3/27/98: optimized and made much shorter + + if (ds->silhouette&SIL_BOTTOM && spr->gz < ds->bsilheight) //bottom sil + for (x=r1 ; x<=r2 ; x++) + if (clipbot[x] == -2) + clipbot[x] = ds->sprbottomclip[x]; + + if (ds->silhouette&SIL_TOP && spr->gzt > ds->tsilheight) // top sil + for (x=r1 ; x<=r2 ; x++) + if (cliptop[x] == -2) + cliptop[x] = ds->sprtopclip[x]; + } + + // killough 3/27/98: + // Clip the sprite against deep water and/or fake ceilings. + // killough 4/9/98: optimize by adding mh + // killough 4/11/98: improve sprite clipping for underwater/fake ceilings + // killough 11/98: fix disappearing sprites + + if (spr->heightsec != -1) // only things in specially marked sectors + { + fixed_t h,mh; + int phs = viewplayer->mo->subsector->sector->heightsec; + if ((mh = sectors[spr->heightsec].floorheight) > spr->gz && + (h = centeryfrac - FixedMul(mh-=viewz, spr->scale)) >= 0 && + (h >>= FRACBITS) < viewheight) { + if (mh <= 0 || (phs != -1 && viewz > sectors[phs].floorheight)) + { // clip bottom + for (x=spr->x1 ; x<=spr->x2 ; x++) + if (clipbot[x] == -2 || h < clipbot[x]) + clipbot[x] = h; + } + else // clip top + if (phs != -1 && viewz <= sectors[phs].floorheight) // killough 11/98 + for (x=spr->x1 ; x<=spr->x2 ; x++) + if (cliptop[x] == -2 || h > cliptop[x]) + cliptop[x] = h; + } + + if ((mh = sectors[spr->heightsec].ceilingheight) < spr->gzt && + (h = centeryfrac - FixedMul(mh-viewz, spr->scale)) >= 0 && + (h >>= FRACBITS) < viewheight) { + if (phs != -1 && viewz >= sectors[phs].ceilingheight) + { // clip bottom + for (x=spr->x1 ; x<=spr->x2 ; x++) + if (clipbot[x] == -2 || h < clipbot[x]) + clipbot[x] = h; + } + else // clip top + for (x=spr->x1 ; x<=spr->x2 ; x++) + if (cliptop[x] == -2 || h > cliptop[x]) + cliptop[x] = h; + } + } + // killough 3/27/98: end special clipping for deep water / fake ceilings + + // all clipping has been performed, so draw the sprite + // check for unclipped columns + + for (x = spr->x1 ; x<=spr->x2 ; x++) { + if (clipbot[x] == -2) + clipbot[x] = viewheight; + + if (cliptop[x] == -2) + cliptop[x] = -1; + } + + mfloorclip = clipbot; + mceilingclip = cliptop; + R_DrawVisSprite (spr, spr->x1, spr->x2); +} + +// +// R_DrawMasked +// + +void R_DrawMasked(void) +{ + int i; + drawseg_t *ds; + + R_SortVisSprites(); + + // draw all vissprites back to front + +// rendered_vissprites = num_vissprite; + for (i = num_vissprite ;--i>=0; ) + R_DrawSprite(vissprite_ptrs[i]); // killough + + // render any remaining masked mid textures + + // Modified by Lee Killough: + // (pointer check was originally nonportable + // and buggy, by going past LEFT end of array): + + // for (ds=ds_p-1 ; ds >= drawsegs ; ds--) old buggy code + + for (ds=ds_p ; ds-- > drawsegs ; ) // new -- killough + if (ds->maskedtexturecol) + R_RenderMaskedSegRange(ds, ds->x1, ds->x2); + + // draw the psprites on top of everything + // but does not draw on side views + if (!viewangleoffset) + R_DrawPlayerSprites (); +} diff --git a/apps/plugins/doom/r_things.h b/apps/plugins/doom/r_things.h new file mode 100644 index 0000000000..dc93e30d54 --- /dev/null +++ b/apps/plugins/doom/r_things.h @@ -0,0 +1,80 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// $Id$ +// +// Copyright (C) 1993-1996 by id Software, Inc. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// Rendering of moving objects, sprites. +// +//----------------------------------------------------------------------------- + + +#ifndef __R_THINGS__ +#define __R_THINGS__ + + +#ifdef __GNUG__ +#pragma interface +#endif + +#define MAXVISSPRITES 128 +/* +extern vissprite_t vissprites[MAXVISSPRITES]; +extern vissprite_t* vissprite_p; +extern vissprite_t vsprsortedhead;*/ + +// Constant arrays used for psprite clipping +// and initializing clipping. +extern short negonearray[SCREENWIDTH]; +extern short screenheightarray[SCREENWIDTH]; + +// vars for R_DrawMaskedColumn +extern short* mfloorclip; +extern short* mceilingclip; +extern fixed_t spryscale; +extern fixed_t sprtopscreen; + +extern fixed_t pspritescale; +extern fixed_t pspriteiscale; + + +void R_DrawMaskedColumn (const column_t* column); + + +void R_SortVisSprites (void); + +void R_AddSprites(subsector_t* subsec, int lightlevel); +void R_AddPSprites (void); +void R_DrawSprites (void); +void R_InitSprites(const char * const * namelist); +void R_ClearSprites (void); +void R_DrawMasked (void); + +void +R_ClipVisSprite +( vissprite_t* vis, + int xl, + int xh ); + + +#endif +//----------------------------------------------------------------------------- +// +// $Log$ +// Revision 1.1 2006/03/28 15:44:01 dave +// Patch #2969 - Doom! Currently only working on the H300. +// +// +//----------------------------------------------------------------------------- diff --git a/apps/plugins/doom/rockdoom.c b/apps/plugins/doom/rockdoom.c new file mode 100644 index 0000000000..ae994c1acd --- /dev/null +++ b/apps/plugins/doom/rockdoom.c @@ -0,0 +1,706 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * + * Copyright (C) 2005 Karl Kurbjun + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * H300 Port by Karl Kurbjun + * IPod port by Dave Chapman and Paul Louden + * Additional code contributed by Thom Johansen + * Based off work by: Digita Doom, IDoom, Prboom, lSDLDoom, LxDoom, + * MBF, Boom, DosDoom, + * and of course Original Doom by ID Software + * See: http://prboom.sourceforge.net/about.html for the history + * + * + ****************************************************************************/ + +#include "d_main.h" +#include "doomdef.h" +#include "settings.h" +#include "m_fixed.h" +#include "m_argv.h" +#include "m_misc.h" +#include "g_game.h" +#include "rockmacros.h" +#include "doomstat.h" +#include "i_system.h" + +PLUGIN_HEADER + +#ifdef USE_IRAM +extern char iramcopy[]; +extern char iramstart[]; +extern char iramend[]; +extern char iedata[]; +extern char iend[]; +#endif + +extern boolean timingdemo, singledemo, demoplayback, fastdemo; // killough + +int filearray[9]; +int fpoint=1; // save 0 for closing + +int fileexists(const char * fname) +{ + int fd; + fd = open(fname,O_RDONLY); + + if (fd>=0) + { + close(fd); + return 0; + } + return -1; +} + +#ifndef SIMULATOR +int my_open(const char *file, int flags) +{ + if(fpoint==8) + return -1; +#undef open + filearray[fpoint]=rb->open(file, flags); + + if(filearray[fpoint]<0) + return filearray[fpoint]; + + fpoint++; + return filearray[fpoint-1]; +} + +int my_close(int id) +{ + int i=0; + if(id<0) + return id; + while(filearray[i]!=id && i<8) + i++; + + if(i==8) + { + printf("A requested FID did not exist!!!!"); + return -9; + } +#undef close + rb->close(id); + + for(; ilcd_putsxy(1,p_xtpt, (unsigned char *)p_buf); + rb->lcd_update(); + + p_xtpt+=8; + if(p_xtpt>LCD_HEIGHT-8) + { + p_xtpt=0; + rb->lcd_clear_display(); + } + return 1; +} + +char *my_strtok( char * s, const char * delim ) +{ + register char *spanp; + register int c, sc; + char *tok; + static char *lasts; + + + if (s == NULL && (s = lasts) == NULL) + return (NULL); + + /* + * Skip (span) leading delimiters (s += strspn(s, delim), sort of). + */ +cont: + c = *s++; + for (spanp = (char *)delim; (sc = *spanp++) != 0;) { + if (c == sc) + goto cont; + } + + if (c == 0) { /* no non-delimiter characters */ + lasts = NULL; + return (NULL); + } + tok = s - 1; + + /* + * Scan token (scan for delimiters: s += strcspn(s, delim), sort of). + * Note that delim must have one NUL; we stop if we see that, too. + */ + for (;;) { + c = *s++; + spanp = (char *)delim; + do { + if ((sc = *spanp++) == c) { + if (c == 0) + s = NULL; + else + s[-1] = 0; + lasts = s; + return (tok); + } + } while (sc != 0); + } + /* NOTREACHED */ +} +#if 0 + static char *tp=NULL; + + if(string!=NULL) + tp=string; + + while(*tp!=NULL) + { + if(*tp==*delimiters) + break; + tp++; + } + *tp=0; + return tp; +} +#endif + +inline void* memcpy(void* dst, const void* src, size_t size) +{ + return rb->memcpy(dst, src, size); +} + +// From suduku +int doom_menu_cb(int key, int m) +{ + (void)m; + switch(key) + { +#ifdef MENU_ENTER2 + case MENU_ENTER2: +#endif + case MENU_ENTER: + key = BUTTON_NONE; /* eat the downpress, next menu reacts on release */ + break; + +#ifdef MENU_ENTER2 + case MENU_ENTER2 | BUTTON_REL: +#endif + case MENU_ENTER | BUTTON_REL: + key = MENU_ENTER; /* fake downpress, next menu doesn't like release */ + break; + } + + return key; +} + +struct argvlist +{ + int timedemo; // 1 says there's a timedemo + int demonum; + int addonnum; +} argvlist; + +const unsigned char versions_builtin[7][20] = +{ + "Doom Shareware", + "Doom Registered", + "Ultimate Doom", + "Doom 2", + "Doom 2 French", + "Plutonia", + "TNT" +}; + +const unsigned char wads_builtin[7][30] = +{ + GAMEBASE"doom1.wad", + GAMEBASE"doom.wad", + GAMEBASE"doomu.wad", + GAMEBASE"doom2.wad", + GAMEBASE"doom2f.wad", + GAMEBASE"plutonia.wad", + GAMEBASE"tnt.wad" +}; + +int namemap[7]; +char *addonfiles[10]; +static struct opt_items demolmp[11]; +char addon[200]; +// This sets up the base game and builds up myargv/c +bool Dhandle_ver (int dver) +{ + switch (dver) { + case 0: /* Doom Shareware */ + gamemode = shareware; + gamemission = doom; + D_AddFile(wads_builtin[0],source_iwad); + break; + case 1: /* Doom registered */ + gamemode = registered; + gamemission = doom; + D_AddFile(wads_builtin[1],source_iwad); + break; + case 2: /* Ultimate Doom */ + gamemode = retail; + gamemission = doom; + D_AddFile(wads_builtin[2],source_iwad); + break; + case 3: /* Doom2 */ + gamemode = commercial; + gamemission = doom2; + D_AddFile(wads_builtin[3],source_iwad); + break; + case 4: /* Doom2f */ + gamemode = commercial; + gamemission = doom2; + D_AddFile(wads_builtin[4],source_iwad); + break; + case 5: /* Plutonia */ + gamemode = commercial; + gamemission = pack_plut; + D_AddFile(wads_builtin[5],source_iwad); + break; + case 6: /* TNT */ + gamemode = commercial; + gamemission = pack_tnt; + D_AddFile(wads_builtin[6],source_iwad); + break; + default: + gamemission = none; + return 0; + } + // Start adding to myargv + if(argvlist.timedemo && (gamemode == shareware)) + { + singletics = true; + timingdemo = true; // show stats after quit + G_DeferedPlayDemo("demo3"); + singledemo = true; // quit after one demo + } + + if(argvlist.addonnum) + { + snprintf(addon,sizeof(addon),"%s%s", GAMEBASE"addons/", addonfiles[argvlist.addonnum]); + D_AddFile(addon,source_pwad); + modifiedgame = true; + } + + if(argvlist.demonum) + { + snprintf(addon, sizeof(addon),"%s%s", GAMEBASE"demos/", demolmp[argvlist.demonum].string); + D_AddFile(addon, source_lmp); + G_DeferedPlayDemo(addon); + singledemo = true; // quit after one demo + } + return 1; +} + +// This function builds up the basegame list for use in the options selection +// it also sets the defaults for the argvlist +int Dbuild_base (struct opt_items *names) +{ + if ( fileexists(GAMEBASE"prboom.wad") ) + return 0; + + D_AddFile (GAMEBASE"prboom.wad", source_pwad); + + int i=0; + /* Doom Shareware */ + if ( !fileexists (wads_builtin[0]) ) + { + names[i].string=versions_builtin[0]; + names[i].voice_id=0; + namemap[i]=0; + i++; + } + + /* Doom registered */ + if ( !fileexists (wads_builtin[1]) ) + { + names[i].string=versions_builtin[1]; + names[i].voice_id=0; + namemap[i]=1; + i++; + } + + /* Ultimate Doom */ + if ( !fileexists (wads_builtin[2]) ) + { + names[i].string=versions_builtin[2]; + names[i].voice_id=0; + namemap[i]=2; + i++; + } + + /* Doom2 */ + if ( !fileexists (wads_builtin[3]) ) + { + names[i].string=versions_builtin[3]; + names[i].voice_id=0; + namemap[i]=3; + i++; + } + + /* Doom2f */ + if ( !fileexists (wads_builtin[4]) ) + { + names[i].string=versions_builtin[4]; + names[i].voice_id=0; + namemap[i]=4; + i++; + } + + /* Plutonia */ + if ( !fileexists (wads_builtin[5]) ) + { + names[i].string=versions_builtin[5]; + names[i].voice_id=0; + namemap[i]=5; + i++; + } + + /* TNT */ + if ( !fileexists (wads_builtin[6]) ) + { + names[i].string=versions_builtin[6]; + names[i].voice_id=0; + namemap[i]=6; + i++; + } + // Set argvlist defaults + argvlist.timedemo=0; + + return i; +} + +int Dbuild_addons(struct opt_items *names) +{ + int i=1; + + DIR *addons; + struct dirent *dptr; + char *startpt; + + startpt=malloc(strlen("No Addon")*sizeof(char)); // Add this on to allow for no addon to be played + strcpy(startpt,"No Addon"); + names[0].string=startpt; + names[0].voice_id=0; + + addons=opendir(GAMEBASE"Addons/"); + if(addons==NULL) + return 1; + + while((dptr=rb->readdir(addons)) && i<10) + { + if(rb->strcasestr(dptr->d_name, ".WAD")) + { + addonfiles[i]=malloc(strlen(dptr->d_name)*sizeof(char)); + strcpy(addonfiles[i],dptr->d_name); + names[i].string=addonfiles[i]; + names[i].voice_id=0; + i++; + } + } + closedir(addons); + return i; +} + + +int Dbuild_demos(struct opt_items *names) +{ + int i=1; + + DIR *demos; + struct dirent *dptr; + char *startpt; + + startpt=malloc(strlen("No Demo")*sizeof(char)); // Add this on to allow for no demo to be played + strcpy(startpt,"No Demo"); + names[0].string=startpt; + names[0].voice_id=0; + + demos=opendir(GAMEBASE"Demos/"); + if(demos==NULL) + return 1; + + while((dptr=rb->readdir(demos)) && i<11) + { + if(rb->strcasestr(dptr->d_name, ".LMP")) + { + startpt=malloc(strlen(dptr->d_name)*sizeof(char)); + strcpy(startpt,dptr->d_name); + names[i].string=startpt; + names[i].voice_id=0; + i++; + } + } + closedir(demos); + return i; +} + +void Oset_keys() +{ +} + +static const struct opt_items onoff[2] = { + { "Off", NULL }, + { "On", NULL }, +}; + +static struct opt_items addons[10]; + +extern int fake_contrast; + +static bool Doptions() +{ + int m, result; + int menuquit=0; + + static const struct menu_item items[] = { + { "Sound", NULL }, + { "Set Keys(not working)", NULL }, + { "Timedemo", NULL }, + { "Player Bobbing", NULL }, + { "Weapon Recoil", NULL }, + { "Translucency", NULL }, + { "Fake Contrast", NULL }, + }; + + m = rb->menu_init(items, sizeof(items) / sizeof(*items), + doom_menu_cb, NULL, NULL, NULL); + + while(!menuquit) + { + result=rb->menu_show(m); + switch (result) + { + case 0: /* Sound */ + nosfxparm=!nosfxparm; // Have to invert it before setting + rb->set_option("Sound", &nosfxparm, INT, onoff, 2, NULL ); + break; + + case 1: /* Keys */ + Oset_keys(); + break; + + case 2: /* Timedemo */ + rb->set_option("Timedemo", &argvlist.timedemo, INT, onoff, 2, NULL ); + break; + + case 3: /* Player Bobbing */ + rb->set_option("Player Bobbing", &default_player_bobbing, INT, onoff, 2, NULL ); + break; + + case 4: /* Weapon Recoil */ + rb->set_option("Weapon Recoil", &default_weapon_recoil, INT, onoff, 2, NULL ); + break; + + case 5: /* Translucency */ + rb->set_option("Translucency", &default_translucency, INT, onoff, 2, NULL ); + break; + + case 6: /* Fake Contrast */ + rb->set_option("Fake Contrast", &fake_contrast, INT, onoff, 2, NULL ); + break; + + default: + menuquit=1; + break; + } + } + + rb->menu_exit(m); + + return (1); +} + +// +// Doom Menu +// +int doom_menu() +{ + int m; + int result; + int status; + int gamever; + bool menuquit=0; + + static struct opt_items names[7]; + + static const struct menu_item items[] = { + { "Game", NULL }, + { "Addons", NULL }, + { "Demos", NULL }, + { "Options", NULL }, + { "Play Game", NULL }, + { "Quit", NULL }, + }; + + if( (status=Dbuild_base(names)) == 0 ) // Build up the base wad files (select last added file) + { + rb->splash(HZ, true, "Sorry, you have no base wads"); + return -1; + } + + int numadd=Dbuild_addons(addons); + + int numdemos=Dbuild_demos(demolmp); + argvlist.demonum=0; + + argvlist.addonnum=0; + + gamever=status-1; + + m = rb->menu_init(items, sizeof(items) / sizeof(*items), + doom_menu_cb, NULL, NULL, NULL); + + while(!menuquit) + { + result=rb->menu_show(m); + switch (result) { + case 0: /* Game picker */ + rb->set_option("Base Game", &gamever, INT, names, status, NULL ); + break; + + case 1: /* Addon picker */ + rb->set_option("Select Addon", &argvlist.addonnum, INT, addons, numadd, NULL ); + //Daddons(numadd); + break; + + case 2: /* Demo's */ + rb->set_option("Demo's", &argvlist.demonum, INT, demolmp, numdemos, NULL ); + break; + + case 3: /* Options */ + Doptions(); + break; + + case 4: /* Play Game */ + menuquit=1; + break; + + case 5: /* Quit */ + menuquit=1; + gamever=-1; + break; + + default: + break; + } + } + + rb->menu_exit(m); + + return (gamever); +} + +extern int systemvol; +/* this is the plugin entry point */ +enum plugin_status plugin_start(struct plugin_api* api, void* parameter) +{ + rb = api; + (void)parameter; + +#if !defined(SIMULATOR) && defined(HAVE_ADJUSTABLE_CPU_FREQ) + rb->cpu_boost(true); +#endif + +#ifdef USE_IRAM + memcpy(iramstart, iramcopy, iramend-iramstart); + memset(iedata, 0, iend - iedata); +#endif + + rb->lcd_setfont(0); + +#ifdef FANCY_MENU + if(rb->load_main_backdrop(GAMEBASE"backdrop.bmp")) + rb->lcd_set_foreground(LCD_RGBPACK(85,208,56)); + + rb->lcd_clear_display(); +#endif + + // We're using doom's memory management since it implements a proper free (and re-uses the memory) + // and now with prboom's code: realloc and calloc + printf ("Z_Init: Init zone memory allocation daemon. \n"); + Z_Init (); + + printf ("M_LoadDefaults: Load system defaults.\n"); + M_LoadDefaults (); // load before initing other systems + +#ifdef FANCY_MENU + rb->lcd_setfont(FONT_UI); + rb->lcd_putsxy(5,LCD_HEIGHT-20, "RockDoom v0.90"); + rb->lcd_update(); + rb->sleep(HZ*2); + rb->lcd_setfont(0); +#else + rb->splash(HZ*2, true, "RockDoom v0.90"); +#endif + + myargv = malloc(sizeof(char *)*MAXARGVS); + memset(myargv,0,sizeof(char *)*MAXARGVS); + myargv[0]="doom.rock"; + myargc=1; + + int result=doom_menu(); + + if( result == -1) return PLUGIN_OK; // No base wads found or quit was selected + + Dhandle_ver( namemap[ result ] ); + + rb->lcd_setfont(0); + + rb->lcd_clear_display(); + +// systemvol= rb->global_settings->volume-rb->global_settings->volume%((rb->sound_max(SOUND_VOLUME)-rb->sound_min(SOUND_VOLUME))/15); + general_translucency = default_translucency; // phares + D_DoomMain (); + + M_SaveDefaults (); + + I_Quit(); // Make SURE everything was closed out right + + printf("There were still: %d files open", fpoint); + while(fpoint>0) + { + rb->close(filearray[fpoint]); + fpoint--; + } + + rb->splash(HZ, true, "Bye"); + +#if !defined(SIMULATOR) && defined(HAVE_ADJUSTABLE_CPU_FREQ) + rb->cpu_boost(false); +#endif + + return PLUGIN_OK; +} diff --git a/apps/plugins/doom/rockmacros.h b/apps/plugins/doom/rockmacros.h new file mode 100644 index 0000000000..6caeb2aa8a --- /dev/null +++ b/apps/plugins/doom/rockmacros.h @@ -0,0 +1,93 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2005 Michiel van der Kolk, Jens Arnold + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef __ROCKMACROS_H__ +#define __ROCKMACROS_H__ + +#include "plugin.h" +#include "ctype.h" +#include "autoconf.h" +#include "z_zone.h" + +extern struct plugin_api* rb; + +/* libc functions */ +int printf(const char *fmt, ...); +int fileexists(const char * fname); +int my_open(const char *file, int flags); +int my_close(int id); +char *my_strtok( char * s, const char * delim ); +#define alloca __builtin_alloca +#define fprintf(...) rb->fdprintf(__VA_ARGS__) +#define vsnprintf(...) rb->vsnprintf(__VA_ARGS__) + +#ifdef SIMULATOR +#undef opendir +#undef closedir +#undef mkdir +#undef open +#undef lseek +#undef filesize +#define opendir(a) rb->sim_opendir((a)) +#define closedir(a) rb->sim_closedir((a)) +#define mkdir(a,b) rb->sim_mkdir((a),(b)) +#define open(a,b) rb->sim_open((a),(b)) +#define lseek(a,b,c) rb->sim_lseek((a),(b),(c)) +#define filesize(a) rb->sim_filesize((a)) +#else /* !SIMULATOR */ +#define opendir(a) rb->opendir((a)) +#define closedir(a) rb->closedir((a)) +#define filesize(a) rb->filesize((a)) +#define mkdir(a) rb->mkdir((a),0777) +#define open(a,b) my_open((a),(b)) +#define close(a) my_close((a)) +#define lseek(a,b,c) rb->lseek((a),(b),(c)) +#endif /* !SIMULATOR */ + +#define strcat(a,b) rb->strcat((a),(b)) +#define read(a,b,c) rb->read((a),(b),(c)) +#define write(a,b,c) rb->write((a),(b),(c)) +#define memset(a,b,c) rb->memset((a),(b),(c)) +#define memmove(a,b,c) rb->memmove((a),(b),(c)) +#define memcmp(a,b,c) rb->memcmp((a),(b),(c)) +#define memchr(a,b,c) rb->memchr((a),(b),(c)) +#define strcpy(a,b) rb->strcpy((a),(b)) +#define strncpy(a,b,c) rb->strncpy((a),(b),(c)) +#define strlen(a) rb->strlen((a)) +#define strcmp(a,b) rb->strcmp((a),(b)) +#define strncmp(a,b,c) rb->strncmp((a),(b),(c)) +#define strchr(a,b) rb->strchr((a),(b)) +#define strrchr(a,b) rb->strrchr((a),(b)) +#define strcasecmp(a,b) rb->strcasecmp((a),(b)) +#define strncasecmp(a,b,c) rb->strncasecmp((a),(b),(c)) +#define srand(a) rb->srand((a)) +#define rand() rb->rand() +#define atoi(a) rb->atoi((a)) +#define strcat(a,b) rb->strcat((a),(b)) +#define snprintf rb->snprintf + +/* Using #define isn't enough with GCC 4.0.1 */ +inline void* memcpy(void* dst, const void* src, size_t size); + +#define PACKEDATTR __attribute__((packed)) // Needed for a few things +#define GAMEBASE "/games/doom/" +//#define SIMPLECHECKS +#define NO_PREDEFINED_LUMPS +#define TABLES_AS_LUMPS // This frees up alot of space in the plugin buffer +#define FANCY_MENU // This is a call to allow load_main_backdrop to run in doom +#endif diff --git a/apps/plugins/doom/s_sound.c b/apps/plugins/doom/s_sound.c new file mode 100644 index 0000000000..c8ed7b2839 --- /dev/null +++ b/apps/plugins/doom/s_sound.c @@ -0,0 +1,608 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: Platform-independent sound code + * + *-----------------------------------------------------------------------------*/ + +#include "i_system.h" +#include "i_sound.h" +#include "sounds.h" +#include "s_sound.h" + +#include "z_zone.h" +#include "m_random.h" +#include "w_wad.h" +#include "d_main.h" +#include "doomdef.h" +#include "r_main.h" + +#include "doomstat.h" + +#include "rockmacros.h" + +// when to clip out sounds +// Does not fit the large outdoor areas. +#define S_CLIPPING_DIST (1200<>FRACBITS) + +// Adjustable by menu. +#define NORM_PITCH 128 +#define NORM_PRIORITY 64 +#define NORM_SEP 128 +#define S_STEREO_SWING (96<= prboom_2_compatibility && sfx_id == sfx_noway); // killough 4/25/98 + sfx_id &= ~PICKUP_SOUND; + + // check for bogus sound # + if (sfx_id < 1 || sfx_id > NUMSFX) + I_Error("S_StartSoundAtVolume: Bad sfx #: %d", sfx_id); + + sfx = &S_sfx[sfx_id]; + + // Initialize sound parameters + if (sfx->link) + { + pitch = sfx->pitch; + priority = sfx->priority; + volume += sfx->volume; + + if (volume < 1) + return; + + if (volume > snd_SfxVolume) + volume = snd_SfxVolume; + } + else + { + pitch = NORM_PITCH; + priority = NORM_PRIORITY; + } + + + // Check to see if it is audible, + // and if not, modify the params + + if (!origin || origin == players[displayplayer].mo) { + sep = NORM_SEP; + volume *= 8; + } else + if (!S_AdjustSoundParams(players[displayplayer].mo, origin, &volume, + &sep, &pitch)) + return; + else + if ( origin->x == players[displayplayer].mo->x && + origin->y == players[displayplayer].mo->y) + sep = NORM_SEP; + + // hacks to vary the sfx pitches + if (sfx_id >= sfx_sawup && sfx_id <= sfx_sawhit) + pitch += 8 - (M_Random()&15); + else + if (sfx_id != sfx_itemup && sfx_id != sfx_tink) + pitch += 16 - (M_Random()&31); + + if (pitch<0) + pitch = 0; + + if (pitch>255) + pitch = 255; + + // kill old sound + for (cnum=0 ; cnumlumpnum < 0 && (sfx->lumpnum = I_GetSfxLumpNum(sfx)) < 0) + return; + + // increase the usefulness + if (sfx->usefulness++ < 0) + sfx->usefulness = 1; + + // Assigns the handle to one of the channels in the mix/output buffer. + channels[cnum].handle = I_StartSound(sfx_id, cnum, volume, sep, pitch, priority); +} + +void S_StartSound(void *origin, int sfx_id) +{ + S_StartSoundAtVolume(origin, sfx_id, snd_SfxVolume); +} + +void S_StopSound(void *origin) +{ + int cnum; + + if (nosfxparm) + return; + + for (cnum=0 ; cnumhandle); + mus_paused = true; + } +} + +void S_ResumeSound(void) +{ + if (nosfxparm) + return; + + if (mus_playing && mus_paused) + { + I_ResumeSong(mus_playing->handle); + mus_paused = false; + } +} + +// +// Updates music & sounds +// +void S_UpdateSounds(void* listener_p) +{ + int cnum; + + mobj_t* listener = (mobj_t*)listener_p; + + if (nosfxparm) + return; + + for (cnum=0 ; cnumsfxinfo)) + { + if (I_SoundIsPlaying(c->handle)) + { + // initialize parameters + int volume = snd_SfxVolume; + int sep = NORM_PITCH; + int pitch = NORM_SEP; + + if (sfx->link) + { + pitch = sfx->pitch; + volume += sfx->volume; + if (volume < 1) + { + S_StopChannel(cnum); + continue; + } + else + if (volume > snd_SfxVolume) + volume = snd_SfxVolume; + } + + // check non-local sounds for distance clipping + // or modify their params + if (c->origin && listener_p != c->origin) // killough 3/20/98 + { + if (!S_AdjustSoundParams(listener, c->origin, + &volume, &sep, &pitch)) + S_StopChannel(cnum); + else + I_UpdateSoundParams(c->handle, volume, sep, pitch); + } + } + else + S_StopChannel(cnum); + } + } +} + +void S_SetMusicVolume(int volume) +{ + if (nosfxparm) + return; + + if (volume < 0 || volume > 15) + I_Error("S_SetMusicVolume: Attempt to set music volume at %d", volume); + I_SetMusicVolume(volume); + snd_MusicVolume = volume; +} + +void S_SetSfxVolume(int volume) +{ + if (nosfxparm) + return; + + if (volume < 0 || volume > 127) + I_Error("S_SetSfxVolume: Attempt to set sfx volume at %d", volume); + snd_SfxVolume = volume; +} + +// +// Starts some music with the music id found in sounds.h. +// +void S_StartMusic(int m_id) +{ + if (nosfxparm) + return; + S_ChangeMusic(m_id, false); +} + +void S_ChangeMusic(int musicnum, int looping) +{ + musicinfo_t *music; + + if (nosfxparm) + return; + + if (musicnum <= mus_None || musicnum >= NUMMUSIC) + I_Error("S_ChangeMusic: Bad music number %d", musicnum); + + music = &S_music[musicnum]; + + if (mus_playing == music) + return; + + // shutdown old music + S_StopMusic(); + + // get lumpnum if neccessary + if (!music->lumpnum) + { + char namebuf[9]; + snprintf(namebuf,sizeof(namebuf),"d_%s", music->name); + music->lumpnum = W_GetNumForName(namebuf); + } + + // load & register it + music->data = W_CacheLumpNum(music->lumpnum); +// music->handle = I_RegisterSong(music->data, W_LumpLength(music->lumpnum)); + + // load & register it +// music->data = (void *) W_CacheLumpNum(music->lumpnum); + music->handle = I_RegisterSong(music->data); + + // play it + I_PlaySong(music->handle, looping); + + mus_playing = music; +} + + +void S_StopMusic(void) +{ + if (nosfxparm) + return; + + if (mus_playing) + { + if (mus_paused) + I_ResumeSong(mus_playing->handle); + + I_StopSong(mus_playing->handle); + I_UnRegisterSong(mus_playing->handle); + if (mus_playing->lumpnum >= 0) + W_UnlockLumpNum(mus_playing->lumpnum); // cph - release the music data + + mus_playing->data = 0; + mus_playing = 0; + } +} + +void S_StopChannel(int cnum) +{ + int i; + channel_t* c = &channels[cnum]; + + if (nosfxparm) + return; + + if (c->sfxinfo) + { + // stop the sound playing + if (I_SoundIsPlaying(c->handle)) + I_StopSound(c->handle); + + // check to see + // if other channels are playing the sound + for (i=0 ; isfxinfo == channels[i].sfxinfo) + break; + + // degrade usefulness of sound data + c->sfxinfo->usefulness--; + c->sfxinfo = 0; + } +} + +// +// Changes volume, stereo-separation, and pitch variables +// from the norm of a sound effect to be played. +// If the sound is not audible, returns a 0. +// Otherwise, modifies parameters and returns 1. +// +int S_AdjustSoundParams(mobj_t *listener, mobj_t *source, + int *vol, int *sep, int *pitch) +{ + (void)pitch; + fixed_t adx, ady, approx_dist; + angle_t angle; + + if (nosfxparm) + return 0; + + // calculate the distance to sound origin + // and clip it if necessary + adx = D_abs(listener->x - source->x); + ady = D_abs(listener->y - source->y); + + // From _GG1_ p.428. Appox. eucledian distance fast. + approx_dist = adx + ady - ((adx < ady ? adx : ady)>>1); + + if (!approx_dist) // killough 11/98: handle zero-distance as special case + { + *sep = NORM_SEP; + *vol = snd_SfxVolume; + return *vol > 0; + } + + if (approx_dist > S_CLIPPING_DIST) + return 0; + + // angle of source to listener + angle = R_PointToAngle2(listener->x, listener->y, source->x, source->y); + + if (angle <= listener->angle) + angle += 0xffffffff; + angle -= listener->angle; + angle >>= ANGLETOFINESHIFT; + + // stereo separation + *sep = 128 - (FixedMul(S_STEREO_SWING,finesine[angle])>>FRACBITS); + + // volume calculation + if (approx_dist < S_CLOSE_DIST) + *vol = snd_SfxVolume*8; + else + // distance effect + *vol = (snd_SfxVolume * ((S_CLIPPING_DIST-approx_dist)>>FRACBITS) * 8) + / S_ATTENUATOR; + + return (*vol > 0); +} + +// +// S_getChannel : +// If none available, return -1. Otherwise channel #. +// +// killough 4/25/98: made static, added is_pickup argument + +static int S_getChannel(void *origin, sfxinfo_t *sfxinfo, int is_pickup) +{ + // channel number to use + int cnum; + channel_t* c; + + if (nosfxparm) + return -1; + + // Find an open channel + for (cnum=0; cnumpriority >= sfxinfo->priority) + break; + if (cnum == numChannels) + return -1; // No lower priority. Sorry, Charlie. + else + S_StopChannel(cnum); // Otherwise, kick out lower priority. + } + + c = &channels[cnum]; // channel is decided to be cnum. + c->sfxinfo = sfxinfo; + c->origin = origin; + c->is_pickup = is_pickup; // killough 4/25/98 + return cnum; +} diff --git a/apps/plugins/doom/s_sound.h b/apps/plugins/doom/s_sound.h new file mode 100644 index 0000000000..0a4857e82f --- /dev/null +++ b/apps/plugins/doom/s_sound.h @@ -0,0 +1,96 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * The not so system specific sound interface. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __S_SOUND__ +#define __S_SOUND__ + + +#ifdef __GNUG__ +#pragma interface +#endif + +// +// Initializes sound stuff, including volume +// Sets channels, SFX and music volume, +// allocates channel buffer, sets S_sfx lookup. +// +void S_Init(int sfxVolume, int musicVolume); + +// +// Per level startup code. +// Kills playing sounds at start of level, +// determines music if any, changes music. +// +void S_Start(void); + +// +// Start sound for thing at +// using from sounds.h +// +void S_StartSound(void *origin, int sound_id); + +// Will start a sound at a given volume. +void S_StartSoundAtVolume(void *origin, int sound_id, int volume); + +// killough 4/25/98: mask used to indicate sound origin is player item pickup +#define PICKUP_SOUND (0x8000) + +// Stop sound for thing at +void S_StopSound(void* origin); + +// Start music using from sounds.h +void S_StartMusic(int music_id); + +// Start music using from sounds.h, and set whether looping +void S_ChangeMusic(int music_id, int looping); + +// Stops the music fer sure. +void S_StopMusic(void); + +// Stop and resume music, during game PAUSE. +void S_PauseSound(void); +void S_ResumeSound(void); + +// +// Updates music & sounds +// +void S_UpdateSounds(void* listener); +void S_SetMusicVolume(int volume); +void S_SetSfxVolume(int volume); + +// machine-independent sound params +extern int default_numChannels; +extern int numChannels; + +//jff 3/17/98 holds last IDMUS number, or -1 +extern int idmusnum; + +#endif diff --git a/apps/plugins/doom/sounds.c b/apps/plugins/doom/sounds.c new file mode 100644 index 0000000000..200a402403 --- /dev/null +++ b/apps/plugins/doom/sounds.c @@ -0,0 +1,240 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Created by a sound utility. + * Kept as a sample, DOOM2 sounds. + * + *-----------------------------------------------------------------------------*/ + +#include "doomtype.h" +#include "sounds.h" + +// +// Information about all the music +// + +musicinfo_t S_music[] = + { + { 0, 0, 0, 0 }, + { "e1m1", 0, 0, 0 }, + { "e1m2", 0, 0, 0 }, + { "e1m3", 0, 0, 0 }, + { "e1m4", 0, 0, 0 }, + { "e1m5", 0, 0, 0 }, + { "e1m6", 0, 0, 0 }, + { "e1m7", 0, 0, 0 }, + { "e1m8", 0, 0, 0 }, + { "e1m9", 0, 0, 0 }, + { "e2m1", 0, 0, 0 }, + { "e2m2", 0, 0, 0 }, + { "e2m3", 0, 0, 0 }, + { "e2m4", 0, 0, 0 }, + { "e2m5", 0, 0, 0 }, + { "e2m6", 0, 0, 0 }, + { "e2m7", 0, 0, 0 }, + { "e2m8", 0, 0, 0 }, + { "e2m9", 0, 0, 0 }, + { "e3m1", 0, 0, 0 }, + { "e3m2", 0, 0, 0 }, + { "e3m3", 0, 0, 0 }, + { "e3m4", 0, 0, 0 }, + { "e3m5", 0, 0, 0 }, + { "e3m6", 0, 0, 0 }, + { "e3m7", 0, 0, 0 }, + { "e3m8", 0, 0, 0 }, + { "e3m9", 0, 0, 0 }, + { "inter", 0, 0, 0 }, + { "intro", 0, 0, 0 }, + { "bunny", 0, 0, 0 }, + { "victor", 0, 0, 0 }, + { "introa", 0, 0, 0 }, + { "runnin", 0, 0, 0 }, + { "stalks", 0, 0, 0 }, + { "countd", 0, 0, 0 }, + { "betwee", 0, 0, 0 }, + { "doom", 0, 0, 0 }, + { "the_da", 0, 0, 0 }, + { "shawn", 0, 0, 0 }, + { "ddtblu", 0, 0, 0 }, + { "in_cit", 0, 0, 0 }, + { "dead", 0, 0, 0 }, + { "stlks2", 0, 0, 0 }, + { "theda2", 0, 0, 0 }, + { "doom2", 0, 0, 0 }, + { "ddtbl2", 0, 0, 0 }, + { "runni2", 0, 0, 0 }, + { "dead2", 0, 0, 0 }, + { "stlks3", 0, 0, 0 }, + { "romero", 0, 0, 0 }, + { "shawn2", 0, 0, 0 }, + { "messag", 0, 0, 0 }, + { "count2", 0, 0, 0 }, + { "ddtbl3", 0, 0, 0 }, + { "ampie", 0, 0, 0 }, + { "theda3", 0, 0, 0 }, + { "adrian", 0, 0, 0 }, + { "messg2", 0, 0, 0 }, + { "romer2", 0, 0, 0 }, + { "tense", 0, 0, 0 }, + { "shawn3", 0, 0, 0 }, + { "openin", 0, 0, 0 }, + { "evil", 0, 0, 0 }, + { "ultima", 0, 0, 0 }, + { "read_m", 0, 0, 0 }, + { "dm2ttl", 0, 0, 0 }, + { "dm2int", 0, 0, 0 } + }; + + +// +// Information about all the sfx +// + +sfxinfo_t S_sfx[] = + { + // S_sfx[0] needs to be a dummy for odd reasons. + { "none", false, 0, 0, -1, -1, 0, 0, 0 }, + + { "pistol", false, 64, 0, -1, -1, 0, 0, 0 }, + { "shotgn", false, 64, 0, -1, -1, 0, 0, 0 }, + { "sgcock", false, 64, 0, -1, -1, 0, 0, 0 }, + { "dshtgn", false, 64, 0, -1, -1, 0, 0, 0 }, + { "dbopn", false, 64, 0, -1, -1, 0, 0, 0 }, + { "dbcls", false, 64, 0, -1, -1, 0, 0, 0 }, + { "dbload", false, 64, 0, -1, -1, 0, 0, 0 }, + { "plasma", false, 64, 0, -1, -1, 0, 0, 0 }, + { "bfg", false, 64, 0, -1, -1, 0, 0, 0 }, + { "sawup", false, 64, 0, -1, -1, 0, 0, 0 }, + { "sawidl", false, 118, 0, -1, -1, 0, 0, 0 }, + { "sawful", false, 64, 0, -1, -1, 0, 0, 0 }, + { "sawhit", false, 64, 0, -1, -1, 0, 0, 0 }, + { "rlaunc", false, 64, 0, -1, -1, 0, 0, 0 }, + { "rxplod", false, 70, 0, -1, -1, 0, 0, 0 }, + { "firsht", false, 70, 0, -1, -1, 0, 0, 0 }, + { "firxpl", false, 70, 0, -1, -1, 0, 0, 0 }, + { "pstart", false, 100, 0, -1, -1, 0, 0, 0 }, + { "pstop", false, 100, 0, -1, -1, 0, 0, 0 }, + { "doropn", false, 100, 0, -1, -1, 0, 0, 0 }, + { "dorcls", false, 100, 0, -1, -1, 0, 0, 0 }, + { "stnmov", false, 119, 0, -1, -1, 0, 0, 0 }, + { "swtchn", false, 78, 0, -1, -1, 0, 0, 0 }, + { "swtchx", false, 78, 0, -1, -1, 0, 0, 0 }, + { "plpain", false, 96, 0, -1, -1, 0, 0, 0 }, + { "dmpain", false, 96, 0, -1, -1, 0, 0, 0 }, + { "popain", false, 96, 0, -1, -1, 0, 0, 0 }, + { "vipain", false, 96, 0, -1, -1, 0, 0, 0 }, + { "mnpain", false, 96, 0, -1, -1, 0, 0, 0 }, + { "pepain", false, 96, 0, -1, -1, 0, 0, 0 }, + { "slop", false, 78, 0, -1, -1, 0, 0, 0 }, + { "itemup", true, 78, 0, -1, -1, 0, 0, 0 }, + { "wpnup", true, 78, 0, -1, -1, 0, 0, 0 }, + { "oof", false, 96, 0, -1, -1, 0, 0, 0 }, + { "telept", false, 32, 0, -1, -1, 0, 0, 0 }, + { "posit1", true, 98, 0, -1, -1, 0, 0, 0 }, + { "posit2", true, 98, 0, -1, -1, 0, 0, 0 }, + { "posit3", true, 98, 0, -1, -1, 0, 0, 0 }, + { "bgsit1", true, 98, 0, -1, -1, 0, 0, 0 }, + { "bgsit2", true, 98, 0, -1, -1, 0, 0, 0 }, + { "sgtsit", true, 98, 0, -1, -1, 0, 0, 0 }, + { "cacsit", true, 98, 0, -1, -1, 0, 0, 0 }, + { "brssit", true, 94, 0, -1, -1, 0, 0, 0 }, + { "cybsit", true, 92, 0, -1, -1, 0, 0, 0 }, + { "spisit", true, 90, 0, -1, -1, 0, 0, 0 }, + { "bspsit", true, 90, 0, -1, -1, 0, 0, 0 }, + { "kntsit", true, 90, 0, -1, -1, 0, 0, 0 }, + { "vilsit", true, 90, 0, -1, -1, 0, 0, 0 }, + { "mansit", true, 90, 0, -1, -1, 0, 0, 0 }, + { "pesit", true, 90, 0, -1, -1, 0, 0, 0 }, + { "sklatk", false, 70, 0, -1, -1, 0, 0, 0 }, + { "sgtatk", false, 70, 0, -1, -1, 0, 0, 0 }, + { "skepch", false, 70, 0, -1, -1, 0, 0, 0 }, + { "vilatk", false, 70, 0, -1, -1, 0, 0, 0 }, + { "claw", false, 70, 0, -1, -1, 0, 0, 0 }, + { "skeswg", false, 70, 0, -1, -1, 0, 0, 0 }, + { "pldeth", false, 32, 0, -1, -1, 0, 0, 0 }, + { "pdiehi", false, 32, 0, -1, -1, 0, 0, 0 }, + { "podth1", false, 70, 0, -1, -1, 0, 0, 0 }, + { "podth2", false, 70, 0, -1, -1, 0, 0, 0 }, + { "podth3", false, 70, 0, -1, -1, 0, 0, 0 }, + { "bgdth1", false, 70, 0, -1, -1, 0, 0, 0 }, + { "bgdth2", false, 70, 0, -1, -1, 0, 0, 0 }, + { "sgtdth", false, 70, 0, -1, -1, 0, 0, 0 }, + { "cacdth", false, 70, 0, -1, -1, 0, 0, 0 }, + { "skldth", false, 70, 0, -1, -1, 0, 0, 0 }, + { "brsdth", false, 32, 0, -1, -1, 0, 0, 0 }, + { "cybdth", false, 32, 0, -1, -1, 0, 0, 0 }, + { "spidth", false, 32, 0, -1, -1, 0, 0, 0 }, + { "bspdth", false, 32, 0, -1, -1, 0, 0, 0 }, + { "vildth", false, 32, 0, -1, -1, 0, 0, 0 }, + { "kntdth", false, 32, 0, -1, -1, 0, 0, 0 }, + { "pedth", false, 32, 0, -1, -1, 0, 0, 0 }, + { "skedth", false, 32, 0, -1, -1, 0, 0, 0 }, + { "posact", true, 120, 0, -1, -1, 0, 0, 0 }, + { "bgact", true, 120, 0, -1, -1, 0, 0, 0 }, + { "dmact", true, 120, 0, -1, -1, 0, 0, 0 }, + { "bspact", true, 100, 0, -1, -1, 0, 0, 0 }, + { "bspwlk", true, 100, 0, -1, -1, 0, 0, 0 }, + { "vilact", true, 100, 0, -1, -1, 0, 0, 0 }, + { "noway", false, 78, 0, -1, -1, 0, 0, 0 }, + { "barexp", false, 60, 0, -1, -1, 0, 0, 0 }, + { "punch", false, 64, 0, -1, -1, 0, 0, 0 }, + { "hoof", false, 70, 0, -1, -1, 0, 0, 0 }, + { "metal", false, 70, 0, -1, -1, 0, 0, 0 }, + { "chgun", false, 64, &S_sfx[sfx_pistol], 150, 0, 0, 0, 0 }, + { "tink", false, 60, 0, -1, -1, 0, 0, 0 }, + { "bdopn", false, 100, 0, -1, -1, 0, 0, 0 }, + { "bdcls", false, 100, 0, -1, -1, 0, 0, 0 }, + { "itmbk", false, 100, 0, -1, -1, 0, 0, 0 }, + { "flame", false, 32, 0, -1, -1, 0, 0, 0 }, + { "flamst", false, 32, 0, -1, -1, 0, 0, 0 }, + { "getpow", false, 60, 0, -1, -1, 0, 0, 0 }, + { "bospit", false, 70, 0, -1, -1, 0, 0, 0 }, + { "boscub", false, 70, 0, -1, -1, 0, 0, 0 }, + { "bossit", false, 70, 0, -1, -1, 0, 0, 0 }, + { "bospn", false, 70, 0, -1, -1, 0, 0, 0 }, + { "bosdth", false, 70, 0, -1, -1, 0, 0, 0 }, + { "manatk", false, 70, 0, -1, -1, 0, 0, 0 }, + { "mandth", false, 70, 0, -1, -1, 0, 0, 0 }, + { "sssit", false, 70, 0, -1, -1, 0, 0, 0 }, + { "ssdth", false, 70, 0, -1, -1, 0, 0, 0 }, + { "keenpn", false, 70, 0, -1, -1, 0, 0, 0 }, + { "keendt", false, 70, 0, -1, -1, 0, 0, 0 }, + { "skeact", false, 70, 0, -1, -1, 0, 0, 0 }, + { "skesit", false, 70, 0, -1, -1, 0, 0, 0 }, + { "skeatk", false, 70, 0, -1, -1, 0, 0, 0 }, + { "radio", false, 60, 0, -1, -1, 0, 0, 0 }, + +#ifdef DOGS + // killough 11/98: dog sounds + { "dgsit", false, 98, 0, -1, -1, 0, 0, 0 }, + { "dgatk", false, 70, 0, -1, -1, 0, 0, 0 }, + { "dgact", false, 120, 0, -1, -1, 0, 0, 0 }, + { "dgdth", false, 70, 0, -1, -1, 0, 0, 0 }, + { "dgpain", false, 96, 0, -1, -1, 0, 0, 0 }, +#endif + }; + diff --git a/apps/plugins/doom/sounds.h b/apps/plugins/doom/sounds.h new file mode 100644 index 0000000000..887a8e785f --- /dev/null +++ b/apps/plugins/doom/sounds.h @@ -0,0 +1,303 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Created by the sound utility written by Dave Taylor. + * Kept as a sample, DOOM2 sounds. Frozen. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __SOUNDS__ +#define __SOUNDS__ + +// +// SoundFX struct. +// + +struct sfxinfo_struct; + +typedef struct sfxinfo_struct sfxinfo_t; + +struct sfxinfo_struct { + + // up to 6-character name + const char *name; // CPhipps - const + + // Sfx singularity (only one at a time) + int singularity; + + // Sfx priority + int priority; + + // referenced sound if a link + sfxinfo_t *link; + + // pitch if a link + int pitch; + + // volume if a link + int volume; + + // sound data + void *data; + + // this is checked every second to see if sound + // can be thrown out (if 0, then decrement, if -1, + // then throw out, if > 0, then it is in use) + int usefulness; + + // lump number of sfx + int lumpnum; +}; + +// +// MusicInfo struct. +// + +typedef struct { + // up to 6-character name + const char *name; // CPhipps - const + + // lump number of music + int lumpnum; + + /* music data - cphipps 4/11 made const void* */ + const void *data; + + // music handle once registered + int handle; +} musicinfo_t; + +// the complete set of sound effects +extern sfxinfo_t S_sfx[]; + +// the complete set of music +extern musicinfo_t S_music[]; + +// +// Identifiers for all music in game. +// + +typedef enum { + mus_None, + mus_e1m1, + mus_e1m2, + mus_e1m3, + mus_e1m4, + mus_e1m5, + mus_e1m6, + mus_e1m7, + mus_e1m8, + mus_e1m9, + mus_e2m1, + mus_e2m2, + mus_e2m3, + mus_e2m4, + mus_e2m5, + mus_e2m6, + mus_e2m7, + mus_e2m8, + mus_e2m9, + mus_e3m1, + mus_e3m2, + mus_e3m3, + mus_e3m4, + mus_e3m5, + mus_e3m6, + mus_e3m7, + mus_e3m8, + mus_e3m9, + mus_inter, + mus_intro, + mus_bunny, + mus_victor, + mus_introa, + mus_runnin, + mus_stalks, + mus_countd, + mus_betwee, + mus_doom, + mus_the_da, + mus_shawn, + mus_ddtblu, + mus_in_cit, + mus_dead, + mus_stlks2, + mus_theda2, + mus_doom2, + mus_ddtbl2, + mus_runni2, + mus_dead2, + mus_stlks3, + mus_romero, + mus_shawn2, + mus_messag, + mus_count2, + mus_ddtbl3, + mus_ampie, + mus_theda3, + mus_adrian, + mus_messg2, + mus_romer2, + mus_tense, + mus_shawn3, + mus_openin, + mus_evil, + mus_ultima, + mus_read_m, + mus_dm2ttl, + mus_dm2int, + NUMMUSIC +} musicenum_t; + +// +// Identifiers for all sfx in game. +// + +typedef enum { + sfx_None, + sfx_pistol, + sfx_shotgn, + sfx_sgcock, + sfx_dshtgn, + sfx_dbopn, + sfx_dbcls, + sfx_dbload, + sfx_plasma, + sfx_bfg, + sfx_sawup, + sfx_sawidl, + sfx_sawful, + sfx_sawhit, + sfx_rlaunc, + sfx_rxplod, + sfx_firsht, + sfx_firxpl, + sfx_pstart, + sfx_pstop, + sfx_doropn, + sfx_dorcls, + sfx_stnmov, + sfx_swtchn, + sfx_swtchx, + sfx_plpain, + sfx_dmpain, + sfx_popain, + sfx_vipain, + sfx_mnpain, + sfx_pepain, + sfx_slop, + sfx_itemup, + sfx_wpnup, + sfx_oof, + sfx_telept, + sfx_posit1, + sfx_posit2, + sfx_posit3, + sfx_bgsit1, + sfx_bgsit2, + sfx_sgtsit, + sfx_cacsit, + sfx_brssit, + sfx_cybsit, + sfx_spisit, + sfx_bspsit, + sfx_kntsit, + sfx_vilsit, + sfx_mansit, + sfx_pesit, + sfx_sklatk, + sfx_sgtatk, + sfx_skepch, + sfx_vilatk, + sfx_claw, + sfx_skeswg, + sfx_pldeth, + sfx_pdiehi, + sfx_podth1, + sfx_podth2, + sfx_podth3, + sfx_bgdth1, + sfx_bgdth2, + sfx_sgtdth, + sfx_cacdth, + sfx_skldth, + sfx_brsdth, + sfx_cybdth, + sfx_spidth, + sfx_bspdth, + sfx_vildth, + sfx_kntdth, + sfx_pedth, + sfx_skedth, + sfx_posact, + sfx_bgact, + sfx_dmact, + sfx_bspact, + sfx_bspwlk, + sfx_vilact, + sfx_noway, + sfx_barexp, + sfx_punch, + sfx_hoof, + sfx_metal, + sfx_chgun, + sfx_tink, + sfx_bdopn, + sfx_bdcls, + sfx_itmbk, + sfx_flame, + sfx_flamst, + sfx_getpow, + sfx_bospit, + sfx_boscub, + sfx_bossit, + sfx_bospn, + sfx_bosdth, + sfx_manatk, + sfx_mandth, + sfx_sssit, + sfx_ssdth, + sfx_keenpn, + sfx_keendt, + sfx_skeact, + sfx_skesit, + sfx_skeatk, + sfx_radio, + +#ifdef DOGS + /* killough 11/98: dog sounds */ + sfx_dgsit, + sfx_dgatk, + sfx_dgact, + sfx_dgdth, + sfx_dgpain, +#endif + + NUMSFX +} sfxenum_t; + +#endif diff --git a/apps/plugins/doom/st_lib.c b/apps/plugins/doom/st_lib.c new file mode 100644 index 0000000000..adcd0e6688 --- /dev/null +++ b/apps/plugins/doom/st_lib.c @@ -0,0 +1,372 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * The status bar widget code. + * + *-----------------------------------------------------------------------------*/ + +#include "doomdef.h" +#include "doomstat.h" +#include "v_video.h" +#include "w_wad.h" +#include "m_swap.h" +#include "st_stuff.h" +#include "st_lib.h" +#include "r_main.h" + +int sts_always_red; //jff 2/18/98 control to disable status color changes +int sts_pct_always_gray; // killough 2/21/98: always gray %'s? bug or feature? + +// +// STlib_init() +// +void STlib_init(void) +{ + // cph - no longer hold STMINUS pointer +} + +// +// STlib_initNum() +// +// Initializes an st_number_t widget +// +// Passed the widget, its position, the patches for the digits, a pointer +// to the value displayed, a pointer to the on/off control, and the width +// Returns nothing +// +void STlib_initNum +( st_number_t* n, + int x, + int y, + const patchnum_t* pl, + int* num, + boolean* on, + int width ) +{ + n->x = x; + n->y = y; + n->oldnum = 0; + n->width = width; + n->num = num; + n->on = on; + n->p = pl; +} + +/* + * STlib_drawNum() + * + * A fairly efficient way to draw a number based on differences from the + * old number. + * + * Passed a st_number_t widget, a color range for output, and a flag + * indicating whether refresh is needed. + * Returns nothing + * + * jff 2/16/98 add color translation to digit output + * cphipps 10/99 - const pointer to colour trans table, made function static + */ +static void STlib_drawNum +( st_number_t* n, + int cm, + boolean refresh ) +{ + + int numdigits = n->width; + int num = *n->num; + + int w = SHORT(n->p[0].width); + int h = SHORT(n->p[0].height); + int x = n->x; + + int neg; + + // leban 1/20/99: + // strange that somebody went through all the work to draw only the + // differences, and then went and constantly redrew all the numbers. + // return without drawing if the number didn't change and the bar + // isn't refreshing. + if(n->oldnum == num && !refresh) + return; + + // CPhipps - compact some code, use num instead of *n->num + if ((neg = (n->oldnum = num) < 0)) + { + if (numdigits == 2 && num < -9) + num = -9; + else if (numdigits == 3 && num < -99) + num = -99; + + num = -num; + } + + // clear the area + x = n->x - numdigits*w; + +#ifdef RANGECHECK + if (n->y - ST_Y < 0) + I_Error("STlib_drawNum: n->y - ST_Y < 0"); +#endif + + V_CopyRect(x, n->y - ST_Y, BG, w*numdigits, h, x, n->y, FG, VPT_STRETCH); + + // if non-number, do not draw it + if (num == 1994) + return; + + x = n->x; + + //jff 2/16/98 add color translation to digit output + // in the special case of 0, you draw 0 + if (!num) + // CPhipps - patch drawing updated, reformatted + V_DrawNumPatch(x - w, n->y, FG, n->p[0].lumpnum, cm, + (((cm!=CR_DEFAULT) && !sts_always_red) ? VPT_TRANS : VPT_NONE) | VPT_STRETCH); + + // draw the new number + //jff 2/16/98 add color translation to digit output + while (num && numdigits--) { + // CPhipps - patch drawing updated, reformatted + x -= w; + V_DrawNumPatch(x, n->y, FG, n->p[num % 10].lumpnum, cm, + (((cm!=CR_DEFAULT) && !sts_always_red) ? VPT_TRANS : VPT_NONE) | VPT_STRETCH); + num /= 10; + } + + // draw a minus sign if necessary + //jff 2/16/98 add color translation to digit output + // cph - patch drawing updated, load by name instead of acquiring pointer earlier + if (neg) + V_DrawNamePatch(x - w, n->y, FG, "STTMINUS", cm, + (((cm!=CR_DEFAULT) && !sts_always_red) ? VPT_TRANS : VPT_NONE) | VPT_STRETCH); +} + +/* + * STlib_updateNum() + * + * Draws a number conditionally based on the widget's enable + * + * Passed a number widget, the output color range, and a refresh flag + * Returns nothing + * + * jff 2/16/98 add color translation to digit output + * cphipps 10/99 - make that pointer const + */ +void STlib_updateNum +( st_number_t* n, + int cm, + boolean refresh ) +{ + if (*n->on) STlib_drawNum(n, cm, refresh); +} + +// +// STlib_initPercent() +// +// Initialize a st_percent_t number with percent sign widget +// +// Passed a st_percent_t widget, the position, the digit patches, a pointer +// to the number to display, a pointer to the enable flag, and patch +// for the percent sign. +// Returns nothing. +// +void STlib_initPercent +( st_percent_t* p, + int x, + int y, + const patchnum_t* pl, + int* num, + boolean* on, + const patchnum_t* percent ) +{ + STlib_initNum(&p->n, x, y, pl, num, on, 3); + p->p = percent; +} + +/* + * STlib_updatePercent() + * + * Draws a number/percent conditionally based on the widget's enable + * + * Passed a precent widget, the output color range, and a refresh flag + * Returns nothing + * + * jff 2/16/98 add color translation to digit output + * cphipps - const for pointer to the colour translation table + */ + +void STlib_updatePercent +( st_percent_t* per, + int cm, + int refresh ) +{ + if (*per->n.on && (refresh || (per->n.oldnum != *per->n.num))) { + // killough 2/21/98: fix percents not updated; + /* CPhipps - make %'s only be updated if number changed */ + // CPhipps - patch drawing updated + V_DrawNumPatch(per->n.x, per->n.y, FG, per->p->lumpnum, + sts_pct_always_gray ? CR_GRAY : cm, + (sts_always_red ? VPT_NONE : VPT_TRANS) | VPT_STRETCH); + } + + STlib_updateNum(&per->n, cm, refresh); +} + +// +// STlib_initMultIcon() +// +// Initialize a st_multicon_t widget, used for a multigraphic display +// like the status bar's keys. +// +// Passed a st_multicon_t widget, the position, the graphic patches, a pointer +// to the numbers representing what to display, and pointer to the enable flag +// Returns nothing. +// +void STlib_initMultIcon +( st_multicon_t* i, + int x, + int y, + const patchnum_t* il, + int* inum, + boolean* on ) +{ + i->x = x; + i->y = y; + i->oldinum = -1; + i->inum = inum; + i->on = on; + i->p = il; +} + +// +// STlib_updateMultIcon() +// +// Draw a st_multicon_t widget, used for a multigraphic display +// like the status bar's keys. Displays each when the control +// numbers change or refresh is true +// +// Passed a st_multicon_t widget, and a refresh flag +// Returns nothing. +// +void STlib_updateMultIcon +( st_multicon_t* mi, + boolean refresh ) +{ + int w; + int h; + int x; + int y; + + if (*mi->on && (mi->oldinum != *mi->inum || refresh)) + { + if (mi->oldinum != -1) + { + x = mi->x - SHORT(mi->p[mi->oldinum].leftoffset); + y = mi->y - SHORT(mi->p[mi->oldinum].topoffset); + w = SHORT(mi->p[mi->oldinum].width); + h = SHORT(mi->p[mi->oldinum].height); + +#ifdef RANGECHECK + if (y - ST_Y < 0) + I_Error("STlib_updateMultIcon: y - ST_Y < 0"); +#endif + + V_CopyRect(x, y-ST_Y, BG, w, h, x, y, FG, VPT_STRETCH); + } + if (*mi->inum != -1) // killough 2/16/98: redraw only if != -1 + V_DrawNumPatch(mi->x, mi->y, FG, mi->p[*mi->inum].lumpnum, CR_DEFAULT, VPT_STRETCH); + mi->oldinum = *mi->inum; + } +} + +// +// STlib_initBinIcon() +// +// Initialize a st_binicon_t widget, used for a multinumber display +// like the status bar's weapons, that are present or not. +// +// Passed a st_binicon_t widget, the position, the digit patches, a pointer +// to the flags representing what is displayed, and pointer to the enable flag +// Returns nothing. +// +void STlib_initBinIcon +( st_binicon_t* b, + int x, + int y, + const patchnum_t* i, + boolean* val, + boolean* on ) +{ + b->x = x; + b->y = y; + b->oldval = 0; + b->val = val; + b->on = on; + b->p = i; +} + +// +// STlib_updateBinIcon() +// +// DInitialize a st_binicon_t widget, used for a multinumber display +// like the status bar's weapons, that are present or not. +// +// Draw a st_binicon_t widget, used for a multinumber display +// like the status bar's weapons that are present or not. Displays each +// when the control flag changes or refresh is true +// +// Passed a st_binicon_t widget, and a refresh flag +// Returns nothing. +// +void STlib_updateBinIcon +( st_binicon_t* bi, + boolean refresh ) +{ + int x; + int y; + int w; + int h; + + if (*bi->on && (bi->oldval != (signed)*bi->val || refresh)) + { + x = bi->x - SHORT(bi->p->leftoffset); + y = bi->y - SHORT(bi->p->topoffset); + w = SHORT(bi->p->width); + h = SHORT(bi->p->height); + +#ifdef RANGECHECK + if (y - ST_Y < 0) + I_Error("STlib_updateBinIcon: y - ST_Y < 0"); +#endif + + if (*bi->val) + V_DrawNumPatch(bi->x, bi->y, FG, bi->p->lumpnum, CR_DEFAULT, VPT_STRETCH); + else + V_CopyRect(x, y-ST_Y, BG, w, h, x, y, FG, VPT_STRETCH); + + bi->oldval = *bi->val; + } +} diff --git a/apps/plugins/doom/st_lib.h b/apps/plugins/doom/st_lib.h new file mode 100644 index 0000000000..09e5faaf87 --- /dev/null +++ b/apps/plugins/doom/st_lib.h @@ -0,0 +1,207 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * The status bar widget definitions and prototypes + * + *-----------------------------------------------------------------------------*/ + +#ifndef __STLIB__ +#define __STLIB__ + +// We are referring to patches. +#include "r_defs.h" +#include "v_video.h" // color ranges + +// +// Background and foreground screen numbers +// +#define BG 4 +#define FG 0 + +// +// Typedefs of widgets +// + +// Number widget + +typedef struct +{ + // upper right-hand corner + // of the number (right-justified) + int x; + int y; + + // max # of digits in number + int width; + + // last number value + int oldnum; + + // pointer to current value + int* num; + + // pointer to boolean stating + // whether to update number + boolean* on; + + // list of patches for 0-9 + const patchnum_t* p; + + // user data + int data; +} st_number_t; + +// Percent widget ("child" of number widget, +// or, more precisely, contains a number widget.) +typedef struct +{ + // number information + st_number_t n; + + // percent sign graphic + const patchnum_t* p; +} st_percent_t; + +// Multiple Icon widget +typedef struct +{ + // center-justified location of icons + int x; + int y; + + // last icon number + int oldinum; + + // pointer to current icon + int* inum; + + // pointer to boolean stating + // whether to update icon + boolean* on; + + // list of icons + const patchnum_t* p; + + // user data + int data; + +} st_multicon_t; + +// Binary Icon widget + +typedef struct +{ + // center-justified location of icon + int x; + int y; + + // last icon value + int oldval; + + // pointer to current icon status + boolean* val; + + // pointer to boolean + // stating whether to update icon + boolean* on; + + const patchnum_t* p; // icon + int data; // user data +} st_binicon_t; + +// +// Widget creation, access, and update routines +// + +// Initializes widget library. +// More precisely, initialize STMINUS, +// everything else is done somewhere else. +// +void STlib_init(void); + +// Number widget routines +void STlib_initNum +( st_number_t* n, + int x, + int y, + const patchnum_t* pl, + int* num, + boolean* on, + int width ); + +void STlib_updateNum +( st_number_t* n, + int cm, + boolean refresh ); + + +// Percent widget routines +void STlib_initPercent +( st_percent_t* p, + int x, + int y, + const patchnum_t* pl, + int* num, + boolean* on, + const patchnum_t* percent ); + + +void STlib_updatePercent +( st_percent_t* per, + int cm, + int refresh ); + + +// Multiple Icon widget routines +void STlib_initMultIcon +( st_multicon_t* mi, + int x, + int y, + const patchnum_t* il, + int* inum, + boolean* on ); + + +void STlib_updateMultIcon +( st_multicon_t* mi, + boolean refresh ); + +// Binary Icon widget routines + +void STlib_initBinIcon +( st_binicon_t* b, + int x, + int y, + const patchnum_t* i, + boolean* val, + boolean* on ); + +void STlib_updateBinIcon +( st_binicon_t* bi, + boolean refresh ); + +#endif diff --git a/apps/plugins/doom/st_stuff.c b/apps/plugins/doom/st_stuff.c new file mode 100644 index 0000000000..5d9244d951 --- /dev/null +++ b/apps/plugins/doom/st_stuff.c @@ -0,0 +1,1153 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Status bar code. + * Does the face/direction indicator animatin. + * Does palette indicators as well (red pain/berserk, bright pickup) + * + *-----------------------------------------------------------------------------*/ + +#include "doomdef.h" +#include "doomstat.h" +#include "m_random.h" +#include "i_video.h" +#include "w_wad.h" +#include "st_stuff.h" +#include "st_lib.h" +#include "r_main.h" +#include "am_map.h" +#include "m_cheat.h" +#include "s_sound.h" +#include "sounds.h" +#include "dstrings.h" +#include "r_draw.h" + +// +// STATUS BAR DATA +// + +// Palette indices. +// For damage/bonus red-/gold-shifts +#define STARTREDPALS 1 +#define STARTBONUSPALS 9 +#define NUMREDPALS 8 +#define NUMBONUSPALS 4 +// Radiation suit, green shift. +#define RADIATIONPAL 13 + +// Location of status bar +#define ST_X 0 +#define ST_X2 104 + +// proff 08/18/98: Changed for high-res +#define ST_FX (ST_X+143) +#define ST_FY (ST_Y+1) +//#define ST_FX 143 +//#define ST_FY 169 + +// Should be set to patch width +// for tall numbers later on +#define ST_TALLNUMWIDTH (tallnum[0]->width) + +// Number of status faces. +#define ST_NUMPAINFACES 5 +#define ST_NUMSTRAIGHTFACES 3 +#define ST_NUMTURNFACES 2 +#define ST_NUMSPECIALFACES 3 + +#define ST_FACESTRIDE \ + (ST_NUMSTRAIGHTFACES+ST_NUMTURNFACES+ST_NUMSPECIALFACES) + +#define ST_NUMEXTRAFACES 2 + +#define ST_NUMFACES \ + (ST_FACESTRIDE*ST_NUMPAINFACES+ST_NUMEXTRAFACES) + +#define ST_TURNOFFSET (ST_NUMSTRAIGHTFACES) +#define ST_OUCHOFFSET (ST_TURNOFFSET + ST_NUMTURNFACES) +#define ST_EVILGRINOFFSET (ST_OUCHOFFSET + 1) +#define ST_RAMPAGEOFFSET (ST_EVILGRINOFFSET + 1) +#define ST_GODFACE (ST_NUMPAINFACES*ST_FACESTRIDE) +#define ST_DEADFACE (ST_GODFACE+1) + +// proff 08/18/98: Changed for high-res +#define ST_FACESX (ST_X+143) +#define ST_FACESY (ST_Y) +//#define ST_FACESX 143 +//#define ST_FACESY 168 + +#define ST_EVILGRINCOUNT (2*TICRATE) +#define ST_STRAIGHTFACECOUNT (TICRATE/2) +#define ST_TURNCOUNT (1*TICRATE) +#define ST_OUCHCOUNT (1*TICRATE) +#define ST_RAMPAGEDELAY (2*TICRATE) + +#define ST_MUCHPAIN 20 + +// Location and size of statistics, +// justified according to widget type. +// Problem is, within which space? STbar? Screen? +// Note: this could be read in by a lump. +// Problem is, is the stuff rendered +// into a buffer, +// or into the frame buffer? +// I dunno, why don't you go and find out!!! killough + +// AMMO number pos. +#define ST_AMMOWIDTH 3 +// proff 08/18/98: Changed for high-res +#define ST_AMMOX (ST_X+44) +#define ST_AMMOY (ST_Y+3) +//#define ST_AMMOX 44 +//#define ST_AMMOY 171 + +// HEALTH number pos. +#define ST_HEALTHWIDTH 3 +// proff 08/18/98: Changed for high-res +#define ST_HEALTHX (ST_X+90) +#define ST_HEALTHY (ST_Y+3) +//#define ST_HEALTHX 90 +//#define ST_HEALTHY 171 + +// Weapon pos. +// proff 08/18/98: Changed for high-res +#define ST_ARMSX (ST_X+111) +#define ST_ARMSY (ST_Y+4) +#define ST_ARMSBGX (ST_X+104) +#define ST_ARMSBGY (ST_Y) +//#define ST_ARMSX 111 +//#define ST_ARMSY 172 +//#define ST_ARMSBGX 104 +//#define ST_ARMSBGY 168 +#define ST_ARMSXSPACE 12 +#define ST_ARMSYSPACE 10 + +// Frags pos. +// proff 08/18/98: Changed for high-res +#define ST_FRAGSX (ST_X+138) +#define ST_FRAGSY (ST_Y+3) +//#define ST_FRAGSX 138 +//#define ST_FRAGSY 171 +#define ST_FRAGSWIDTH 2 + +// ARMOR number pos. +#define ST_ARMORWIDTH 3 +// proff 08/18/98: Changed for high-res +#define ST_ARMORX (ST_X+221) +#define ST_ARMORY (ST_Y+3) +//#define ST_ARMORX 221 +//#define ST_ARMORY 171 + +// Key icon positions. +#define ST_KEY0WIDTH 8 +#define ST_KEY0HEIGHT 5 +// proff 08/18/98: Changed for high-res +#define ST_KEY0X (ST_X+239) +#define ST_KEY0Y (ST_Y+3) +//#define ST_KEY0X 239 +//#define ST_KEY0Y 171 +#define ST_KEY1WIDTH ST_KEY0WIDTH +// proff 08/18/98: Changed for high-res +#define ST_KEY1X (ST_X+239) +#define ST_KEY1Y (ST_Y+13) +//#define ST_KEY1X 239 +//#define ST_KEY1Y 181 +#define ST_KEY2WIDTH ST_KEY0WIDTH +// proff 08/18/98: Changed for high-res +#define ST_KEY2X (ST_X+239) +#define ST_KEY2Y (ST_Y+23) +//#define ST_KEY2X 239 +//#define ST_KEY2Y 191 + +// Ammunition counter. +#define ST_AMMO0WIDTH 3 +#define ST_AMMO0HEIGHT 6 +// proff 08/18/98: Changed for high-res +#define ST_AMMO0X (ST_X+288) +#define ST_AMMO0Y (ST_Y+5) +//#define ST_AMMO0X 288 +//#define ST_AMMO0Y 173 +#define ST_AMMO1WIDTH ST_AMMO0WIDTH +// proff 08/18/98: Changed for high-res +#define ST_AMMO1X (ST_X+288) +#define ST_AMMO1Y (ST_Y+11) +//#define ST_AMMO1X 288 +//#define ST_AMMO1Y 179 +#define ST_AMMO2WIDTH ST_AMMO0WIDTH +// proff 08/18/98: Changed for high-res +#define ST_AMMO2X (ST_X+288) +#define ST_AMMO2Y (ST_Y+23) +//#define ST_AMMO2X 288 +//#define ST_AMMO2Y 191 +#define ST_AMMO3WIDTH ST_AMMO0WIDTH +// proff 08/18/98: Changed for high-res +#define ST_AMMO3X (ST_X+288) +#define ST_AMMO3Y (ST_Y+17) +//#define ST_AMMO3X 288 +//#define ST_AMMO3Y 185 + +// Indicate maximum ammunition. +// Only needed because backpack exists. +#define ST_MAXAMMO0WIDTH 3 +#define ST_MAXAMMO0HEIGHT 5 +// proff 08/18/98: Changed for high-res +#define ST_MAXAMMO0X (ST_X+314) +#define ST_MAXAMMO0Y (ST_Y+5) +//#define ST_MAXAMMO0X 314 +//#define ST_MAXAMMO0Y 173 +#define ST_MAXAMMO1WIDTH ST_MAXAMMO0WIDTH +// proff 08/18/98: Changed for high-res +#define ST_MAXAMMO1X (ST_X+314) +#define ST_MAXAMMO1Y (ST_Y+11) +//#define ST_MAXAMMO1X 314 +//#define ST_MAXAMMO1Y 179 +#define ST_MAXAMMO2WIDTH ST_MAXAMMO0WIDTH +// proff 08/18/98: Changed for high-res +#define ST_MAXAMMO2X (ST_X+314) +#define ST_MAXAMMO2Y (ST_Y+23) +//#define ST_MAXAMMO2X 314 +//#define ST_MAXAMMO2Y 191 +#define ST_MAXAMMO3WIDTH ST_MAXAMMO0WIDTH +// proff 08/18/98: Changed for high-res +#define ST_MAXAMMO3X (ST_X+314) +#define ST_MAXAMMO3Y (ST_Y+17) +//#define ST_MAXAMMO3X 314 +//#define ST_MAXAMMO3Y 185 + +// killough 2/8/98: weapon info position macros UNUSED, removed here + +// main player in game +static player_t *plyr; + +// ST_Start() has just been called +static boolean st_firsttime; + +// used to execute ST_Init() only once +static int veryfirsttime = 1; + +// CPhipps - no longer do direct PLAYPAL handling here + +// used for timing +static unsigned int st_clock; + +// used for making messages go away +static int st_msgcounter=0; + +// used when in chat +static st_chatstateenum_t st_chatstate; + +// whether in automap or first-person +static st_stateenum_t st_gamestate; + +// whether left-side main status bar is active +static boolean st_statusbaron; + +// whether status bar chat is active +static boolean st_chat; + +// value of st_chat before message popped up +static boolean st_oldchat; + +// whether chat window has the cursor on +static boolean st_cursoron; + +// !deathmatch +static boolean st_notdeathmatch; + +// !deathmatch && st_statusbaron +static boolean st_armson; + +// !deathmatch +static boolean st_fragson; + +// main bar left +// CPhipps - convert to a bitmap +static byte *sbar; +static unsigned short sbar_width, sbar_height; + +// 0-9, tall numbers +static patchnum_t tallnum[10]; + +// tall % sign +static patchnum_t tallpercent; + +// 0-9, short, yellow (,different!) numbers +static patchnum_t shortnum[10]; + +// 3 key-cards, 3 skulls, 3 card/skull combos +// jff 2/24/98 extend number of patches by three skull/card combos +static patchnum_t keys[NUMCARDS+3]; + +// face status patches +static patchnum_t faces[ST_NUMFACES]; + +// face background +static patchnum_t faceback; // CPhipps - single background, translated for different players + +// main bar right +static patchnum_t armsbg; + +// weapon ownership patches +static patchnum_t arms[6][2]; + +// ready-weapon widget +static st_number_t w_ready; + +//jff 2/16/98 status color change levels +int ammo_red; // ammo percent less than which status is red +int ammo_yellow; // ammo percent less is yellow more green +int health_red; // health amount less than which status is red +int health_yellow; // health amount less than which status is yellow +int health_green; // health amount above is blue, below is green +int armor_red; // armor amount less than which status is red +int armor_yellow; // armor amount less than which status is yellow +int armor_green; // armor amount above is blue, below is green + +// in deathmatch only, summary of frags stats +static st_number_t w_frags; + +// health widget +static st_percent_t w_health; + +// arms background +static st_binicon_t w_armsbg; + +// weapon ownership widgets +static st_multicon_t w_arms[6]; + +// face status widget +static st_multicon_t w_faces; + +// keycard widgets +static st_multicon_t w_keyboxes[3]; + +// armor widget +static st_percent_t w_armor; + +// ammo widgets +static st_number_t w_ammo[4]; + +// max ammo widgets +static st_number_t w_maxammo[4]; + +// number of frags so far in deathmatch +static int st_fragscount; + +// used to use appopriately pained face +static int st_oldhealth = -1; + +// used for evil grin +static boolean oldweaponsowned[NUMWEAPONS]; + +// count until face changes +static int st_facecount = 0; + +// current face index, used by w_faces +static int st_faceindex = 0; + +// holds key-type for each key box on bar +static int keyboxes[3]; + +// a random number per tick +static int st_randomnumber; + +extern char *mapnames[]; + + +// +// STATUS BAR CODE +// +void ST_Stop(void); + +void ST_refreshBackground(void) +{ + int y=0; + int screen=BG; + + if (st_statusbaron) + { + V_DrawNamePatch(ST_X, y, screen, "STBAR", CR_DEFAULT, VPT_STRETCH); + + // killough 3/7/98: make face background change with displayplayer + if (netgame) + { + V_DrawNumPatch(ST_FX, y, BG, faceback.lumpnum, + displayplayer ? CR_LIMIT+displayplayer : CR_DEFAULT, + displayplayer ? (VPT_TRANS | VPT_STRETCH) : VPT_STRETCH); + } + + V_CopyRect(ST_X, y, screen, ST_SCALED_WIDTH, ST_SCALED_HEIGHT, ST_X, ST_SCALED_Y, FG, VPT_NONE); + } +} + + +// Respond to keyboard input events, +// intercept cheats. +boolean ST_Responder(event_t *ev) +{ + // Filter automap on/off. + if (ev->type == ev_keyup && (ev->data1 & 0xffff0000) == AM_MSGHEADER) + { + switch(ev->data1) + { + case AM_MSGENTERED: + st_gamestate = AutomapState; + st_firsttime = true; + break; + + case AM_MSGEXITED: + st_gamestate = FirstPersonState; + break; + } + } +// else // if a user keypress... +// if (ev->type == ev_keydown) // Try cheat responder in m_cheat.c +// return M_FindCheats(ev->data1); // killough 4/17/98, 5/2/98 + return false; +} + +int ST_calcPainOffset(void) +{ + static int lastcalc; + static int oldhealth = -1; + int health = plyr->health > 100 ? 100 : plyr->health; + + if (health != oldhealth) + { + lastcalc = ST_FACESTRIDE * (((100 - health) * ST_NUMPAINFACES) / 101); + oldhealth = health; + } + return lastcalc; +} + + +// +// This is a not-very-pretty routine which handles +// the face states and their timing. +// the precedence of expressions is: +// dead > evil grin > turned head > straight ahead +// + +void ST_updateFaceWidget(void) +{ + int i; + angle_t badguyangle; + angle_t diffang; + static int lastattackdown = -1; + static int priority = 0; + boolean doevilgrin; + + if (priority < 10) + { + // dead + if (!plyr->health) + { + priority = 9; + st_faceindex = ST_DEADFACE; + st_facecount = 1; + } + } + + if (priority < 9) + { + if (plyr->bonuscount) + { + // picking up bonus + doevilgrin = false; + + for (i=0;iweaponowned[i]) + { + doevilgrin = true; + oldweaponsowned[i] = plyr->weaponowned[i]; + } + } + if (doevilgrin) + { + // evil grin if just picked up weapon + priority = 8; + st_facecount = ST_EVILGRINCOUNT; + st_faceindex = ST_calcPainOffset() + ST_EVILGRINOFFSET; + } + } + + } + + if (priority < 8) + { + if (plyr->damagecount && plyr->attacker && plyr->attacker != plyr->mo) + { + // being attacked + priority = 7; + + if (plyr->health - st_oldhealth > ST_MUCHPAIN) + { + st_facecount = ST_TURNCOUNT; + st_faceindex = ST_calcPainOffset() + ST_OUCHOFFSET; + } + else + { + badguyangle = R_PointToAngle2(plyr->mo->x, + plyr->mo->y, + plyr->attacker->x, + plyr->attacker->y); + + if (badguyangle > plyr->mo->angle) + { + // whether right or left + diffang = badguyangle - plyr->mo->angle; + i = diffang > ANG180; + } + else + { + // whether left or right + diffang = plyr->mo->angle - badguyangle; + i = diffang <= ANG180; + } // confusing, aint it? + + + st_facecount = ST_TURNCOUNT; + st_faceindex = ST_calcPainOffset(); + + if (diffang < ANG45) + { + // head-on + st_faceindex += ST_RAMPAGEOFFSET; + } + else if (i) + { + // turn face right + st_faceindex += ST_TURNOFFSET; + } + else + { + // turn face left + st_faceindex += ST_TURNOFFSET+1; + } + } + } + } + + if (priority < 7) + { + // getting hurt because of your own damn stupidity + if (plyr->damagecount) + { + if (plyr->health - st_oldhealth > ST_MUCHPAIN) + { + priority = 7; + st_facecount = ST_TURNCOUNT; + st_faceindex = ST_calcPainOffset() + ST_OUCHOFFSET; + } + else + { + priority = 6; + st_facecount = ST_TURNCOUNT; + st_faceindex = ST_calcPainOffset() + ST_RAMPAGEOFFSET; + } + + } + + } + + if (priority < 6) + { + // rapid firing + if (plyr->attackdown) + { + if (lastattackdown==-1) + lastattackdown = ST_RAMPAGEDELAY; + else if (!--lastattackdown) + { + priority = 5; + st_faceindex = ST_calcPainOffset() + ST_RAMPAGEOFFSET; + st_facecount = 1; + lastattackdown = 1; + } + } + else + lastattackdown = -1; + + } + + if (priority < 5) + { + // invulnerability + if ((plyr->cheats & CF_GODMODE) + || plyr->powers[pw_invulnerability]) + { + priority = 4; + + st_faceindex = ST_GODFACE; + st_facecount = 1; + + } + + } + + // look left or look right if the facecount has timed out + if (!st_facecount) + { + st_faceindex = ST_calcPainOffset() + (st_randomnumber % 3); + st_facecount = ST_STRAIGHTFACECOUNT; + priority = 0; + } + + st_facecount--; + +} + +int sts_traditional_keys; // killough 2/28/98: traditional status bar keys + +void ST_updateWidgets(void) +{ + static int largeammo = 1994; // means "n/a" + int i; + + // must redirect the pointer if the ready weapon has changed. + // if (w_ready.data != plyr->readyweapon) + // { + if (weaponinfo[plyr->readyweapon].ammo == am_noammo) + w_ready.num = &largeammo; + else + w_ready.num = &plyr->ammo[weaponinfo[plyr->readyweapon].ammo]; + //{ + // static int tic=0; + // static int dir=-1; + // if (!(tic&15)) + // plyr->ammo[weaponinfo[plyr->readyweapon].ammo]+=dir; + // if (plyr->ammo[weaponinfo[plyr->readyweapon].ammo] == -100) + // dir = 1; + // tic++; + // } + w_ready.data = plyr->readyweapon; + + // if (*w_ready.on) + // STlib_updateNum(&w_ready, true); + // refresh weapon change + // } + + // update keycard multiple widgets + for (i=0;i<3;i++) + { + keyboxes[i] = plyr->cards[i] ? i : -1; + + //jff 2/24/98 select double key + //killough 2/28/98: preserve traditional keys by config option + + if (plyr->cards[i+3]) + keyboxes[i] = keyboxes[i]==-1 || sts_traditional_keys ? i+3 : i+6; + } + + // refresh everything if this is him coming back to life + ST_updateFaceWidget(); + + // used by the w_armsbg widget + st_notdeathmatch = !deathmatch; + + // used by w_arms[] widgets + st_armson = st_statusbaron && !deathmatch; + + // used by w_frags widget + st_fragson = deathmatch && st_statusbaron; + st_fragscount = 0; + + for (i=0 ; ifrags[i]; + else + st_fragscount -= plyr->frags[i]; + } + + // get rid of chat window if up because of message + if (!--st_msgcounter) + st_chat = st_oldchat; + +} + +void ST_Ticker (void) +{ + st_clock++; + st_randomnumber = M_Random(); + ST_updateWidgets(); + st_oldhealth = plyr->health; +} + +static int st_palette = 0; + +void ST_doPaletteStuff(void) +{ + int palette; + int cnt = plyr->damagecount; + + if (plyr->powers[pw_strength]) + { + // slowly fade the berzerk out + int bzc = 12 - (plyr->powers[pw_strength]>>6); + if (bzc > cnt) + cnt = bzc; + } + + if (cnt) + { + palette = (cnt+7)>>3; + if (palette >= NUMREDPALS) + palette = NUMREDPALS-1; + palette += STARTREDPALS; + } + else + if (plyr->bonuscount) + { + palette = (plyr->bonuscount+7)>>3; + if (palette >= NUMBONUSPALS) + palette = NUMBONUSPALS-1; + palette += STARTBONUSPALS; + } + else + if (plyr->powers[pw_ironfeet] > 4*32 || plyr->powers[pw_ironfeet] & 8) + palette = RADIATIONPAL; + else + palette = 0; + + if (palette != st_palette) + V_SetPalette(st_palette = palette); // CPhipps - use new palette function +} + +void ST_drawWidgets(boolean refresh) +{ + int i; + + // used by w_arms[] widgets + st_armson = st_statusbaron && !deathmatch; + + // used by w_frags widget + st_fragson = deathmatch && st_statusbaron; + + //jff 2/16/98 make color of ammo depend on amount + if (*w_ready.num*100 < ammo_red*plyr->maxammo[weaponinfo[w_ready.data].ammo]) + STlib_updateNum(&w_ready, CR_RED, refresh); + else + if (*w_ready.num*100 < + ammo_yellow*plyr->maxammo[weaponinfo[w_ready.data].ammo]) + STlib_updateNum(&w_ready, CR_GOLD, refresh); + else + STlib_updateNum(&w_ready, CR_GREEN, refresh); + + for (i=0;i<4;i++) + { + STlib_updateNum(&w_ammo[i], CR_DEFAULT, refresh); + STlib_updateNum(&w_maxammo[i], CR_DEFAULT, refresh); + } + + //jff 2/16/98 make color of health depend on amount + if (*w_health.n.numweaponowned[i]; + + for (i=0;i<3;i++) + keyboxes[i] = -1; + + STlib_init(); +} + +void ST_createWidgets(void) +{ + int i; + + // ready weapon ammo + STlib_initNum(&w_ready, + ST_AMMOX, + ST_AMMOY, + tallnum, + &plyr->ammo[weaponinfo[plyr->readyweapon].ammo], + &st_statusbaron, + ST_AMMOWIDTH ); + + // the last weapon type + w_ready.data = plyr->readyweapon; + + // health percentage + STlib_initPercent(&w_health, + ST_HEALTHX, + ST_HEALTHY, + tallnum, + &plyr->health, + &st_statusbaron, + &tallpercent); + + // arms background + STlib_initBinIcon(&w_armsbg, + ST_ARMSBGX, + ST_ARMSBGY, + &armsbg, + &st_notdeathmatch, + &st_statusbaron); + + // weapons owned + for(i=0;i<6;i++) + { + STlib_initMultIcon(&w_arms[i], + ST_ARMSX+(i%3)*ST_ARMSXSPACE, + ST_ARMSY+(i/3)*ST_ARMSYSPACE, + arms[i], (int *) &plyr->weaponowned[i+1], + &st_armson); + } + + // frags sum + STlib_initNum(&w_frags, + ST_FRAGSX, + ST_FRAGSY, + tallnum, + &st_fragscount, + &st_fragson, + ST_FRAGSWIDTH); + + // faces + STlib_initMultIcon(&w_faces, + ST_FACESX, + ST_FACESY, + faces, + &st_faceindex, + &st_statusbaron); + + // armor percentage - should be colored later + STlib_initPercent(&w_armor, + ST_ARMORX, + ST_ARMORY, + tallnum, + &plyr->armorpoints, + &st_statusbaron, &tallpercent); + + // keyboxes 0-2 + STlib_initMultIcon(&w_keyboxes[0], + ST_KEY0X, + ST_KEY0Y, + keys, + &keyboxes[0], + &st_statusbaron); + + STlib_initMultIcon(&w_keyboxes[1], + ST_KEY1X, + ST_KEY1Y, + keys, + &keyboxes[1], + &st_statusbaron); + + STlib_initMultIcon(&w_keyboxes[2], + ST_KEY2X, + ST_KEY2Y, + keys, + &keyboxes[2], + &st_statusbaron); + + // ammo count (all four kinds) + STlib_initNum(&w_ammo[0], + ST_AMMO0X, + ST_AMMO0Y, + shortnum, + &plyr->ammo[0], + &st_statusbaron, + ST_AMMO0WIDTH); + + STlib_initNum(&w_ammo[1], + ST_AMMO1X, + ST_AMMO1Y, + shortnum, + &plyr->ammo[1], + &st_statusbaron, + ST_AMMO1WIDTH); + + STlib_initNum(&w_ammo[2], + ST_AMMO2X, + ST_AMMO2Y, + shortnum, + &plyr->ammo[2], + &st_statusbaron, + ST_AMMO2WIDTH); + + STlib_initNum(&w_ammo[3], + ST_AMMO3X, + ST_AMMO3Y, + shortnum, + &plyr->ammo[3], + &st_statusbaron, + ST_AMMO3WIDTH); + + // max ammo count (all four kinds) + STlib_initNum(&w_maxammo[0], + ST_MAXAMMO0X, + ST_MAXAMMO0Y, + shortnum, + &plyr->maxammo[0], + &st_statusbaron, + ST_MAXAMMO0WIDTH); + + STlib_initNum(&w_maxammo[1], + ST_MAXAMMO1X, + ST_MAXAMMO1Y, + shortnum, + &plyr->maxammo[1], + &st_statusbaron, + ST_MAXAMMO1WIDTH); + + STlib_initNum(&w_maxammo[2], + ST_MAXAMMO2X, + ST_MAXAMMO2Y, + shortnum, + &plyr->maxammo[2], + &st_statusbaron, + ST_MAXAMMO2WIDTH); + + STlib_initNum(&w_maxammo[3], + ST_MAXAMMO3X, + ST_MAXAMMO3Y, + shortnum, + &plyr->maxammo[3], + &st_statusbaron, + ST_MAXAMMO3WIDTH); +} + +static boolean st_stopped = true; + +void ST_Start(void) +{ + if (!st_stopped) + ST_Stop(); + ST_initData(); + ST_createWidgets(); + st_stopped = false; +} + +void ST_Stop(void) +{ + if (st_stopped) + return; + V_SetPalette(0); + st_stopped = true; +} + +void ST_Init(void) +{ + veryfirsttime = 0; + ST_loadData(); + // proff 08/18/98: Changed for high-res + screens[4] = Z_Malloc(SCREENWIDTH*(ST_SCALED_HEIGHT+1), PU_STATIC, 0); + // screens[4] = Z_Malloc(ST_WIDTH*ST_HEIGHT, PU_STATIC, 0); +} diff --git a/apps/plugins/doom/st_stuff.h b/apps/plugins/doom/st_stuff.h new file mode 100644 index 0000000000..d65b01e571 --- /dev/null +++ b/apps/plugins/doom/st_stuff.h @@ -0,0 +1,101 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Status bar code. + * Does the face/direction indicator animatin. + * Does palette indicators as well (red pain/berserk, bright pickup) + * + *-----------------------------------------------------------------------------*/ + +#ifndef __STSTUFF_H__ +#define __STSTUFF_H__ + +#include "doomtype.h" +#include "d_event.h" + +// Size of statusbar. +// Now sensitive for scaling. + +// proff 08/18/98: Changed for high-res +#define ST_HEIGHT 32 +#define ST_WIDTH 320 +#define ST_Y (200 - ST_HEIGHT) +#define ST_SCALED_HEIGHT (ST_HEIGHT*SCREENHEIGHT/200) +#define ST_SCALED_WIDTH SCREENWIDTH +#define ST_SCALED_Y (SCREENHEIGHT - ST_SCALED_HEIGHT) + +// +// STATUS BAR +// + +// Called by main loop. +boolean ST_Responder(event_t* ev); + +// Called by main loop. +void ST_Ticker(void); + +// Called by main loop. +void ST_Drawer(boolean st_statusbaron, boolean refresh); + +// Called when the console player is spawned on each level. +void ST_Start(void); + +// Called by startup code. +void ST_Init(void); + +// States for status bar code. +typedef enum +{ + AutomapState, + FirstPersonState +} st_stateenum_t; + +// States for the chat code. +typedef enum +{ + StartChatState, + WaitDestState, + GetChatState +} st_chatstateenum_t; + +boolean ST_Responder(event_t* ev); + +// killough 5/2/98: moved from m_misc.c: + +extern int health_red; // health amount less than which status is red +extern int health_yellow; // health amount less than which status is yellow +extern int health_green; // health amount above is blue, below is green +extern int armor_red; // armor amount less than which status is red +extern int armor_yellow; // armor amount less than which status is yellow +extern int armor_green; // armor amount above is blue, below is green +extern int ammo_red; // ammo percent less than which status is red +extern int ammo_yellow; // ammo percent less is yellow more green +extern int sts_always_red;// status numbers do not change colors +extern int sts_pct_always_gray;// status percents do not change colors +extern int sts_traditional_keys; // display keys the traditional way + +#endif diff --git a/apps/plugins/doom/tables.c b/apps/plugins/doom/tables.c new file mode 100644 index 0000000000..dfb237649a --- /dev/null +++ b/apps/plugins/doom/tables.c @@ -0,0 +1,2196 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Lookup tables. + * Do not try to look them up :-). + * In the order of appearance: + * + * int finetangent[4096] - Tangens LUT. + * Should work with BAM fairly well (12 of 16bit, + * effectively, by shifting). + * + * int finesine[10240] - Sine lookup. + * Guess what, serves as cosine, too. + * Remarkable thing is, how to use BAMs with this? + * + * int tantoangle[2049] - ArcTan LUT, + * maps tan(angle) to angle fast. Gotta search. + * + *----------------------------------------------------------------------------- + */ + +#include "w_wad.h" +#include "tables.h" +#include "i_system.h" + +// killough 5/3/98: reformatted + +int SlopeDiv(unsigned num, unsigned den) +{ + unsigned ans; + + if (den < 512) + return SLOPERANGE; + ans = (num<<3)/(den>>8); + return ans <= SLOPERANGE ? ans : SLOPERANGE; +} + +#ifdef TABLES_AS_LUMPS +fixed_t *finetangent; +#else +const fixed_t finetangent[4096] = { -170910304, + -56965752,-34178904,-24413316,-18988036,-15535599,-13145455,-11392683, + -10052327,-8994149,-8137527,-7429880,-6835455,-6329090,-5892567,-5512368, + -5178251,-4882318,-4618375,-4381502,-4167737,-3973855,-3797206,-3635590, + -3487165,-3350381,-3223918,-3106651,-2997613,-2895966,-2800983,-2712030, + -2628549,-2550052,-2476104,-2406322,-2340362,-2277919,-2218719,-2162516, + -2109087,-2058233,-2009771,-1963536,-1919378,-1877161,-1836758,-1798063, + -1760956,-1725348,-1691149,-1658278,-1626658,-1596220,-1566898,-1538632, + -1511367,-1485049,-1459630,-1435065,-1411312,-1388330,-1366084,-1344537, + -1323658,-1303416,-1283783,-1264730,-1246234,-1228269,-1210813,-1193846, + -1177345,-1161294,-1145673,-1130465,-1115654,-1101225,-1087164,-1073455, + -1060087,-1047046,-1034322,-1021901,-1009774,-997931,-986361,-975054, + -964003,-953199,-942633,-932298,-922186,-912289,-902602,-893117, + -883829,-874730,-865817,-857081,-848520,-840127,-831898,-823827, + -815910,-808143,-800521,-793041,-785699,-778490,-771411,-764460, + -757631,-750922,-744331,-737853,-731486,-725227,-719074,-713023, + -707072,-701219,-695462,-689797,-684223,-678737,-673338,-668024, + -662792,-657640,-652568,-647572,-642651,-637803,-633028,-628323, + -623686,-619117,-614613,-610174,-605798,-601483,-597229,-593033, + -588896,-584815,-580789,-576818,-572901,-569035,-565221,-561456, + -557741,-554074,-550455,-546881,-543354,-539870,-536431,-533034, + -529680,-526366,-523094,-519861,-516667,-513512,-510394,-507313, + -504269,-501261,-498287,-495348,-492443,-489571,-486732,-483925, + -481150,-478406,-475692,-473009,-470355,-467730,-465133,-462565, + -460024,-457511,-455024,-452564,-450129,-447720,-445337,-442978, + -440643,-438332,-436045,-433781,-431540,-429321,-427125,-424951, + -422798,-420666,-418555,-416465,-414395,-412344,-410314,-408303, + -406311,-404338,-402384,-400448,-398530,-396630,-394747,-392882, + -391034,-389202,-387387,-385589,-383807,-382040,-380290,-378555, + -376835,-375130,-373440,-371765,-370105,-368459,-366826,-365208, + -363604,-362013,-360436,-358872,-357321,-355783,-354257,-352744, + -351244,-349756,-348280,-346816,-345364,-343924,-342495,-341078, + -339671,-338276,-336892,-335519,-334157,-332805,-331464,-330133, + -328812,-327502,-326201,-324910,-323629,-322358,-321097,-319844, + -318601,-317368,-316143,-314928,-313721,-312524,-311335,-310154, + -308983,-307819,-306664,-305517,-304379,-303248,-302126,-301011, + -299904,-298805,-297714,-296630,-295554,-294485,-293423,-292369, + -291322,-290282,-289249,-288223,-287204,-286192,-285186,-284188, + -283195,-282210,-281231,-280258,-279292,-278332,-277378,-276430, + -275489,-274553,-273624,-272700,-271782,-270871,-269965,-269064, + -268169,-267280,-266397,-265519,-264646,-263779,-262917,-262060, + -261209,-260363,-259522,-258686,-257855,-257029,-256208,-255392, + -254581,-253774,-252973,-252176,-251384,-250596,-249813,-249035, + -248261,-247492,-246727,-245966,-245210,-244458,-243711,-242967, + -242228,-241493,-240763,-240036,-239314,-238595,-237881,-237170, + -236463,-235761,-235062,-234367,-233676,-232988,-232304,-231624, + -230948,-230275,-229606,-228941,-228279,-227621,-226966,-226314, + -225666,-225022,-224381,-223743,-223108,-222477,-221849,-221225, + -220603,-219985,-219370,-218758,-218149,-217544,-216941,-216341, + -215745,-215151,-214561,-213973,-213389,-212807,-212228,-211652, + -211079,-210509,-209941,-209376,-208815,-208255,-207699,-207145, + -206594,-206045,-205500,-204956,-204416,-203878,-203342,-202809, + -202279,-201751,-201226,-200703,-200182,-199664,-199149,-198636, + -198125,-197616,-197110,-196606,-196105,-195606,-195109,-194614, + -194122,-193631,-193143,-192658,-192174,-191693,-191213,-190736, + -190261,-189789,-189318,-188849,-188382,-187918,-187455,-186995, + -186536,-186080,-185625,-185173,-184722,-184274,-183827,-183382, + -182939,-182498,-182059,-181622,-181186,-180753,-180321,-179891, + -179463,-179037,-178612,-178190,-177769,-177349,-176932,-176516, + -176102,-175690,-175279,-174870,-174463,-174057,-173653,-173251, + -172850,-172451,-172053,-171657,-171263,-170870,-170479,-170089, + -169701,-169315,-168930,-168546,-168164,-167784,-167405,-167027, + -166651,-166277,-165904,-165532,-165162,-164793,-164426,-164060, + -163695,-163332,-162970,-162610,-162251,-161893,-161537,-161182, + -160828,-160476,-160125,-159775,-159427,-159079,-158734,-158389, + -158046,-157704,-157363,-157024,-156686,-156349,-156013,-155678, + -155345,-155013,-154682,-154352,-154024,-153697,-153370,-153045, + -152722,-152399,-152077,-151757,-151438,-151120,-150803,-150487, + -150172,-149859,-149546,-149235,-148924,-148615,-148307,-148000, + -147693,-147388,-147084,-146782,-146480,-146179,-145879,-145580, + -145282,-144986,-144690,-144395,-144101,-143808,-143517,-143226, + -142936,-142647,-142359,-142072,-141786,-141501,-141217,-140934, + -140651,-140370,-140090,-139810,-139532,-139254,-138977,-138701, + -138426,-138152,-137879,-137607,-137335,-137065,-136795,-136526, + -136258,-135991,-135725,-135459,-135195,-134931,-134668,-134406, + -134145,-133884,-133625,-133366,-133108,-132851,-132594,-132339, + -132084,-131830,-131576,-131324,-131072,-130821,-130571,-130322, + -130073,-129825,-129578,-129332,-129086,-128841,-128597,-128353, + -128111,-127869,-127627,-127387,-127147,-126908,-126669,-126432, + -126195,-125959,-125723,-125488,-125254,-125020,-124787,-124555, + -124324,-124093,-123863,-123633,-123404,-123176,-122949,-122722, + -122496,-122270,-122045,-121821,-121597,-121374,-121152,-120930, + -120709,-120489,-120269,-120050,-119831,-119613,-119396,-119179, + -118963,-118747,-118532,-118318,-118104,-117891,-117678,-117466, + -117254,-117044,-116833,-116623,-116414,-116206,-115998,-115790, + -115583,-115377,-115171,-114966,-114761,-114557,-114354,-114151, + -113948,-113746,-113545,-113344,-113143,-112944,-112744,-112546, + -112347,-112150,-111952,-111756,-111560,-111364,-111169,-110974, + -110780,-110586,-110393,-110200,-110008,-109817,-109626,-109435, + -109245,-109055,-108866,-108677,-108489,-108301,-108114,-107927, + -107741,-107555,-107369,-107184,-107000,-106816,-106632,-106449, + -106266,-106084,-105902,-105721,-105540,-105360,-105180,-105000, + -104821,-104643,-104465,-104287,-104109,-103933,-103756,-103580, + -103404,-103229,-103054,-102880,-102706,-102533,-102360,-102187, + -102015,-101843,-101671,-101500,-101330,-101159,-100990,-100820, + -100651,-100482,-100314,-100146,-99979,-99812,-99645,-99479, + -99313,-99148,-98982,-98818,-98653,-98489,-98326,-98163, + -98000,-97837,-97675,-97513,-97352,-97191,-97030,-96870, + -96710,-96551,-96391,-96233,-96074,-95916,-95758,-95601, + -95444,-95287,-95131,-94975,-94819,-94664,-94509,-94354, + -94200,-94046,-93892,-93739,-93586,-93434,-93281,-93129, + -92978,-92826,-92675,-92525,-92375,-92225,-92075,-91926, + -91777,-91628,-91480,-91332,-91184,-91036,-90889,-90742, + -90596,-90450,-90304,-90158,-90013,-89868,-89724,-89579, + -89435,-89292,-89148,-89005,-88862,-88720,-88577,-88435, + -88294,-88152,-88011,-87871,-87730,-87590,-87450,-87310, + -87171,-87032,-86893,-86755,-86616,-86479,-86341,-86204, + -86066,-85930,-85793,-85657,-85521,-85385,-85250,-85114, + -84980,-84845,-84710,-84576,-84443,-84309,-84176,-84043, + -83910,-83777,-83645,-83513,-83381,-83250,-83118,-82987, + -82857,-82726,-82596,-82466,-82336,-82207,-82078,-81949, + -81820,-81691,-81563,-81435,-81307,-81180,-81053,-80925, + -80799,-80672,-80546,-80420,-80294,-80168,-80043,-79918, + -79793,-79668,-79544,-79420,-79296,-79172,-79048,-78925, + -78802,-78679,-78557,-78434,-78312,-78190,-78068,-77947, + -77826,-77705,-77584,-77463,-77343,-77223,-77103,-76983, + -76864,-76744,-76625,-76506,-76388,-76269,-76151,-76033, + -75915,-75797,-75680,-75563,-75446,-75329,-75213,-75096, + -74980,-74864,-74748,-74633,-74517,-74402,-74287,-74172, + -74058,-73944,-73829,-73715,-73602,-73488,-73375,-73262, + -73149,-73036,-72923,-72811,-72699,-72587,-72475,-72363, + -72252,-72140,-72029,-71918,-71808,-71697,-71587,-71477, + -71367,-71257,-71147,-71038,-70929,-70820,-70711,-70602, + -70494,-70385,-70277,-70169,-70061,-69954,-69846,-69739, + -69632,-69525,-69418,-69312,-69205,-69099,-68993,-68887, + -68781,-68676,-68570,-68465,-68360,-68255,-68151,-68046, + -67942,-67837,-67733,-67629,-67526,-67422,-67319,-67216, + -67113,-67010,-66907,-66804,-66702,-66600,-66498,-66396, + -66294,-66192,-66091,-65989,-65888,-65787,-65686,-65586, + -65485,-65385,-65285,-65185,-65085,-64985,-64885,-64786, + -64687,-64587,-64488,-64389,-64291,-64192,-64094,-63996, + -63897,-63799,-63702,-63604,-63506,-63409,-63312,-63215, + -63118,-63021,-62924,-62828,-62731,-62635,-62539,-62443, + -62347,-62251,-62156,-62060,-61965,-61870,-61775,-61680, + -61585,-61491,-61396,-61302,-61208,-61114,-61020,-60926, + -60833,-60739,-60646,-60552,-60459,-60366,-60273,-60181, + -60088,-59996,-59903,-59811,-59719,-59627,-59535,-59444, + -59352,-59261,-59169,-59078,-58987,-58896,-58805,-58715, + -58624,-58534,-58443,-58353,-58263,-58173,-58083,-57994, + -57904,-57815,-57725,-57636,-57547,-57458,-57369,-57281, + -57192,-57104,-57015,-56927,-56839,-56751,-56663,-56575, + -56487,-56400,-56312,-56225,-56138,-56051,-55964,-55877, + -55790,-55704,-55617,-55531,-55444,-55358,-55272,-55186, + -55100,-55015,-54929,-54843,-54758,-54673,-54587,-54502, + -54417,-54333,-54248,-54163,-54079,-53994,-53910,-53826, + -53741,-53657,-53574,-53490,-53406,-53322,-53239,-53156, + -53072,-52989,-52906,-52823,-52740,-52657,-52575,-52492, + -52410,-52327,-52245,-52163,-52081,-51999,-51917,-51835, + -51754,-51672,-51591,-51509,-51428,-51347,-51266,-51185, + -51104,-51023,-50942,-50862,-50781,-50701,-50621,-50540, + -50460,-50380,-50300,-50221,-50141,-50061,-49982,-49902, + -49823,-49744,-49664,-49585,-49506,-49427,-49349,-49270, + -49191,-49113,-49034,-48956,-48878,-48799,-48721,-48643, + -48565,-48488,-48410,-48332,-48255,-48177,-48100,-48022, + -47945,-47868,-47791,-47714,-47637,-47560,-47484,-47407, + -47331,-47254,-47178,-47102,-47025,-46949,-46873,-46797, + -46721,-46646,-46570,-46494,-46419,-46343,-46268,-46193, + -46118,-46042,-45967,-45892,-45818,-45743,-45668,-45593, + -45519,-45444,-45370,-45296,-45221,-45147,-45073,-44999, + -44925,-44851,-44778,-44704,-44630,-44557,-44483,-44410, + -44337,-44263,-44190,-44117,-44044,-43971,-43898,-43826, + -43753,-43680,-43608,-43535,-43463,-43390,-43318,-43246, + -43174,-43102,-43030,-42958,-42886,-42814,-42743,-42671, + -42600,-42528,-42457,-42385,-42314,-42243,-42172,-42101, + -42030,-41959,-41888,-41817,-41747,-41676,-41605,-41535, + -41465,-41394,-41324,-41254,-41184,-41113,-41043,-40973, + -40904,-40834,-40764,-40694,-40625,-40555,-40486,-40416, + -40347,-40278,-40208,-40139,-40070,-40001,-39932,-39863, + -39794,-39726,-39657,-39588,-39520,-39451,-39383,-39314, + -39246,-39178,-39110,-39042,-38973,-38905,-38837,-38770, + -38702,-38634,-38566,-38499,-38431,-38364,-38296,-38229, + -38161,-38094,-38027,-37960,-37893,-37826,-37759,-37692, + -37625,-37558,-37491,-37425,-37358,-37291,-37225,-37158, + -37092,-37026,-36959,-36893,-36827,-36761,-36695,-36629, + -36563,-36497,-36431,-36365,-36300,-36234,-36168,-36103, + -36037,-35972,-35907,-35841,-35776,-35711,-35646,-35580, + -35515,-35450,-35385,-35321,-35256,-35191,-35126,-35062, + -34997,-34932,-34868,-34803,-34739,-34675,-34610,-34546, + -34482,-34418,-34354,-34289,-34225,-34162,-34098,-34034, + -33970,-33906,-33843,-33779,-33715,-33652,-33588,-33525, + -33461,-33398,-33335,-33272,-33208,-33145,-33082,-33019, + -32956,-32893,-32830,-32767,-32705,-32642,-32579,-32516, + -32454,-32391,-32329,-32266,-32204,-32141,-32079,-32017, + -31955,-31892,-31830,-31768,-31706,-31644,-31582,-31520, + -31458,-31396,-31335,-31273,-31211,-31150,-31088,-31026, + -30965,-30904,-30842,-30781,-30719,-30658,-30597,-30536, + -30474,-30413,-30352,-30291,-30230,-30169,-30108,-30048, + -29987,-29926,-29865,-29805,-29744,-29683,-29623,-29562, + -29502,-29441,-29381,-29321,-29260,-29200,-29140,-29080, + -29020,-28959,-28899,-28839,-28779,-28719,-28660,-28600, + -28540,-28480,-28420,-28361,-28301,-28241,-28182,-28122, + -28063,-28003,-27944,-27884,-27825,-27766,-27707,-27647, + -27588,-27529,-27470,-27411,-27352,-27293,-27234,-27175, + -27116,-27057,-26998,-26940,-26881,-26822,-26763,-26705, + -26646,-26588,-26529,-26471,-26412,-26354,-26295,-26237, + -26179,-26120,-26062,-26004,-25946,-25888,-25830,-25772, + -25714,-25656,-25598,-25540,-25482,-25424,-25366,-25308, + -25251,-25193,-25135,-25078,-25020,-24962,-24905,-24847, + -24790,-24732,-24675,-24618,-24560,-24503,-24446,-24389, + -24331,-24274,-24217,-24160,-24103,-24046,-23989,-23932, + -23875,-23818,-23761,-23704,-23647,-23591,-23534,-23477, + -23420,-23364,-23307,-23250,-23194,-23137,-23081,-23024, + -22968,-22911,-22855,-22799,-22742,-22686,-22630,-22573, + -22517,-22461,-22405,-22349,-22293,-22237,-22181,-22125, + -22069,-22013,-21957,-21901,-21845,-21789,-21733,-21678, + -21622,-21566,-21510,-21455,-21399,-21343,-21288,-21232, + -21177,-21121,-21066,-21010,-20955,-20900,-20844,-20789, + -20734,-20678,-20623,-20568,-20513,-20457,-20402,-20347, + -20292,-20237,-20182,-20127,-20072,-20017,-19962,-19907, + -19852,-19797,-19742,-19688,-19633,-19578,-19523,-19469, + -19414,-19359,-19305,-19250,-19195,-19141,-19086,-19032, + -18977,-18923,-18868,-18814,-18760,-18705,-18651,-18597, + -18542,-18488,-18434,-18380,-18325,-18271,-18217,-18163, + -18109,-18055,-18001,-17946,-17892,-17838,-17784,-17731, + -17677,-17623,-17569,-17515,-17461,-17407,-17353,-17300, + -17246,-17192,-17138,-17085,-17031,-16977,-16924,-16870, + -16817,-16763,-16710,-16656,-16603,-16549,-16496,-16442, + -16389,-16335,-16282,-16229,-16175,-16122,-16069,-16015, + -15962,-15909,-15856,-15802,-15749,-15696,-15643,-15590, + -15537,-15484,-15431,-15378,-15325,-15272,-15219,-15166, + -15113,-15060,-15007,-14954,-14901,-14848,-14795,-14743, + -14690,-14637,-14584,-14531,-14479,-14426,-14373,-14321, + -14268,-14215,-14163,-14110,-14057,-14005,-13952,-13900, + -13847,-13795,-13742,-13690,-13637,-13585,-13533,-13480, + -13428,-13375,-13323,-13271,-13218,-13166,-13114,-13062, + -13009,-12957,-12905,-12853,-12800,-12748,-12696,-12644, + -12592,-12540,-12488,-12436,-12383,-12331,-12279,-12227, + -12175,-12123,-12071,-12019,-11967,-11916,-11864,-11812, + -11760,-11708,-11656,-11604,-11552,-11501,-11449,-11397, + -11345,-11293,-11242,-11190,-11138,-11086,-11035,-10983, + -10931,-10880,-10828,-10777,-10725,-10673,-10622,-10570, + -10519,-10467,-10415,-10364,-10312,-10261,-10209,-10158, + -10106,-10055,-10004,-9952,-9901,-9849,-9798,-9747, + -9695,-9644,-9592,-9541,-9490,-9438,-9387,-9336, + -9285,-9233,-9182,-9131,-9080,-9028,-8977,-8926, + -8875,-8824,-8772,-8721,-8670,-8619,-8568,-8517, + -8466,-8414,-8363,-8312,-8261,-8210,-8159,-8108, + -8057,-8006,-7955,-7904,-7853,-7802,-7751,-7700, + -7649,-7598,-7547,-7496,-7445,-7395,-7344,-7293, + -7242,-7191,-7140,-7089,-7038,-6988,-6937,-6886, + -6835,-6784,-6733,-6683,-6632,-6581,-6530,-6480, + -6429,-6378,-6327,-6277,-6226,-6175,-6124,-6074, + -6023,-5972,-5922,-5871,-5820,-5770,-5719,-5668, + -5618,-5567,-5517,-5466,-5415,-5365,-5314,-5264, + -5213,-5162,-5112,-5061,-5011,-4960,-4910,-4859, + -4808,-4758,-4707,-4657,-4606,-4556,-4505,-4455, + -4404,-4354,-4303,-4253,-4202,-4152,-4101,-4051, + -4001,-3950,-3900,-3849,-3799,-3748,-3698,-3648, + -3597,-3547,-3496,-3446,-3395,-3345,-3295,-3244, + -3194,-3144,-3093,-3043,-2992,-2942,-2892,-2841, + -2791,-2741,-2690,-2640,-2590,-2539,-2489,-2439, + -2388,-2338,-2288,-2237,-2187,-2137,-2086,-2036, + -1986,-1935,-1885,-1835,-1784,-1734,-1684,-1633, + -1583,-1533,-1483,-1432,-1382,-1332,-1281,-1231, + -1181,-1131,-1080,-1030,-980,-929,-879,-829, + -779,-728,-678,-628,-578,-527,-477,-427, + -376,-326,-276,-226,-175,-125,-75,-25, + 25,75,125,175,226,276,326,376, + 427,477,527,578,628,678,728,779, + 829,879,929,980,1030,1080,1131,1181, + 1231,1281,1332,1382,1432,1483,1533,1583, + 1633,1684,1734,1784,1835,1885,1935,1986, + 2036,2086,2137,2187,2237,2288,2338,2388, + 2439,2489,2539,2590,2640,2690,2741,2791, + 2841,2892,2942,2992,3043,3093,3144,3194, + 3244,3295,3345,3395,3446,3496,3547,3597, + 3648,3698,3748,3799,3849,3900,3950,4001, + 4051,4101,4152,4202,4253,4303,4354,4404, + 4455,4505,4556,4606,4657,4707,4758,4808, + 4859,4910,4960,5011,5061,5112,5162,5213, + 5264,5314,5365,5415,5466,5517,5567,5618, + 5668,5719,5770,5820,5871,5922,5972,6023, + 6074,6124,6175,6226,6277,6327,6378,6429, + 6480,6530,6581,6632,6683,6733,6784,6835, + 6886,6937,6988,7038,7089,7140,7191,7242, + 7293,7344,7395,7445,7496,7547,7598,7649, + 7700,7751,7802,7853,7904,7955,8006,8057, + 8108,8159,8210,8261,8312,8363,8414,8466, + 8517,8568,8619,8670,8721,8772,8824,8875, + 8926,8977,9028,9080,9131,9182,9233,9285, + 9336,9387,9438,9490,9541,9592,9644,9695, + 9747,9798,9849,9901,9952,10004,10055,10106, + 10158,10209,10261,10312,10364,10415,10467,10519, + 10570,10622,10673,10725,10777,10828,10880,10931, + 10983,11035,11086,11138,11190,11242,11293,11345, + 11397,11449,11501,11552,11604,11656,11708,11760, + 11812,11864,11916,11967,12019,12071,12123,12175, + 12227,12279,12331,12383,12436,12488,12540,12592, + 12644,12696,12748,12800,12853,12905,12957,13009, + 13062,13114,13166,13218,13271,13323,13375,13428, + 13480,13533,13585,13637,13690,13742,13795,13847, + 13900,13952,14005,14057,14110,14163,14215,14268, + 14321,14373,14426,14479,14531,14584,14637,14690, + 14743,14795,14848,14901,14954,15007,15060,15113, + 15166,15219,15272,15325,15378,15431,15484,15537, + 15590,15643,15696,15749,15802,15856,15909,15962, + 16015,16069,16122,16175,16229,16282,16335,16389, + 16442,16496,16549,16603,16656,16710,16763,16817, + 16870,16924,16977,17031,17085,17138,17192,17246, + 17300,17353,17407,17461,17515,17569,17623,17677, + 17731,17784,17838,17892,17946,18001,18055,18109, + 18163,18217,18271,18325,18380,18434,18488,18542, + 18597,18651,18705,18760,18814,18868,18923,18977, + 19032,19086,19141,19195,19250,19305,19359,19414, + 19469,19523,19578,19633,19688,19742,19797,19852, + 19907,19962,20017,20072,20127,20182,20237,20292, + 20347,20402,20457,20513,20568,20623,20678,20734, + 20789,20844,20900,20955,21010,21066,21121,21177, + 21232,21288,21343,21399,21455,21510,21566,21622, + 21678,21733,21789,21845,21901,21957,22013,22069, + 22125,22181,22237,22293,22349,22405,22461,22517, + 22573,22630,22686,22742,22799,22855,22911,22968, + 23024,23081,23137,23194,23250,23307,23364,23420, + 23477,23534,23591,23647,23704,23761,23818,23875, + 23932,23989,24046,24103,24160,24217,24274,24331, + 24389,24446,24503,24560,24618,24675,24732,24790, + 24847,24905,24962,25020,25078,25135,25193,25251, + 25308,25366,25424,25482,25540,25598,25656,25714, + 25772,25830,25888,25946,26004,26062,26120,26179, + 26237,26295,26354,26412,26471,26529,26588,26646, + 26705,26763,26822,26881,26940,26998,27057,27116, + 27175,27234,27293,27352,27411,27470,27529,27588, + 27647,27707,27766,27825,27884,27944,28003,28063, + 28122,28182,28241,28301,28361,28420,28480,28540, + 28600,28660,28719,28779,28839,28899,28959,29020, + 29080,29140,29200,29260,29321,29381,29441,29502, + 29562,29623,29683,29744,29805,29865,29926,29987, + 30048,30108,30169,30230,30291,30352,30413,30474, + 30536,30597,30658,30719,30781,30842,30904,30965, + 31026,31088,31150,31211,31273,31335,31396,31458, + 31520,31582,31644,31706,31768,31830,31892,31955, + 32017,32079,32141,32204,32266,32329,32391,32454, + 32516,32579,32642,32705,32767,32830,32893,32956, + 33019,33082,33145,33208,33272,33335,33398,33461, + 33525,33588,33652,33715,33779,33843,33906,33970, + 34034,34098,34162,34225,34289,34354,34418,34482, + 34546,34610,34675,34739,34803,34868,34932,34997, + 35062,35126,35191,35256,35321,35385,35450,35515, + 35580,35646,35711,35776,35841,35907,35972,36037, + 36103,36168,36234,36300,36365,36431,36497,36563, + 36629,36695,36761,36827,36893,36959,37026,37092, + 37158,37225,37291,37358,37425,37491,37558,37625, + 37692,37759,37826,37893,37960,38027,38094,38161, + 38229,38296,38364,38431,38499,38566,38634,38702, + 38770,38837,38905,38973,39042,39110,39178,39246, + 39314,39383,39451,39520,39588,39657,39726,39794, + 39863,39932,40001,40070,40139,40208,40278,40347, + 40416,40486,40555,40625,40694,40764,40834,40904, + 40973,41043,41113,41184,41254,41324,41394,41465, + 41535,41605,41676,41747,41817,41888,41959,42030, + 42101,42172,42243,42314,42385,42457,42528,42600, + 42671,42743,42814,42886,42958,43030,43102,43174, + 43246,43318,43390,43463,43535,43608,43680,43753, + 43826,43898,43971,44044,44117,44190,44263,44337, + 44410,44483,44557,44630,44704,44778,44851,44925, + 44999,45073,45147,45221,45296,45370,45444,45519, + 45593,45668,45743,45818,45892,45967,46042,46118, + 46193,46268,46343,46419,46494,46570,46646,46721, + 46797,46873,46949,47025,47102,47178,47254,47331, + 47407,47484,47560,47637,47714,47791,47868,47945, + 48022,48100,48177,48255,48332,48410,48488,48565, + 48643,48721,48799,48878,48956,49034,49113,49191, + 49270,49349,49427,49506,49585,49664,49744,49823, + 49902,49982,50061,50141,50221,50300,50380,50460, + 50540,50621,50701,50781,50862,50942,51023,51104, + 51185,51266,51347,51428,51509,51591,51672,51754, + 51835,51917,51999,52081,52163,52245,52327,52410, + 52492,52575,52657,52740,52823,52906,52989,53072, + 53156,53239,53322,53406,53490,53574,53657,53741, + 53826,53910,53994,54079,54163,54248,54333,54417, + 54502,54587,54673,54758,54843,54929,55015,55100, + 55186,55272,55358,55444,55531,55617,55704,55790, + 55877,55964,56051,56138,56225,56312,56400,56487, + 56575,56663,56751,56839,56927,57015,57104,57192, + 57281,57369,57458,57547,57636,57725,57815,57904, + 57994,58083,58173,58263,58353,58443,58534,58624, + 58715,58805,58896,58987,59078,59169,59261,59352, + 59444,59535,59627,59719,59811,59903,59996,60088, + 60181,60273,60366,60459,60552,60646,60739,60833, + 60926,61020,61114,61208,61302,61396,61491,61585, + 61680,61775,61870,61965,62060,62156,62251,62347, + 62443,62539,62635,62731,62828,62924,63021,63118, + 63215,63312,63409,63506,63604,63702,63799,63897, + 63996,64094,64192,64291,64389,64488,64587,64687, + 64786,64885,64985,65085,65185,65285,65385,65485, + 65586,65686,65787,65888,65989,66091,66192,66294, + 66396,66498,66600,66702,66804,66907,67010,67113, + 67216,67319,67422,67526,67629,67733,67837,67942, + 68046,68151,68255,68360,68465,68570,68676,68781, + 68887,68993,69099,69205,69312,69418,69525,69632, + 69739,69846,69954,70061,70169,70277,70385,70494, + 70602,70711,70820,70929,71038,71147,71257,71367, + 71477,71587,71697,71808,71918,72029,72140,72252, + 72363,72475,72587,72699,72811,72923,73036,73149, + 73262,73375,73488,73602,73715,73829,73944,74058, + 74172,74287,74402,74517,74633,74748,74864,74980, + 75096,75213,75329,75446,75563,75680,75797,75915, + 76033,76151,76269,76388,76506,76625,76744,76864, + 76983,77103,77223,77343,77463,77584,77705,77826, + 77947,78068,78190,78312,78434,78557,78679,78802, + 78925,79048,79172,79296,79420,79544,79668,79793, + 79918,80043,80168,80294,80420,80546,80672,80799, + 80925,81053,81180,81307,81435,81563,81691,81820, + 81949,82078,82207,82336,82466,82596,82726,82857, + 82987,83118,83250,83381,83513,83645,83777,83910, + 84043,84176,84309,84443,84576,84710,84845,84980, + 85114,85250,85385,85521,85657,85793,85930,86066, + 86204,86341,86479,86616,86755,86893,87032,87171, + 87310,87450,87590,87730,87871,88011,88152,88294, + 88435,88577,88720,88862,89005,89148,89292,89435, + 89579,89724,89868,90013,90158,90304,90450,90596, + 90742,90889,91036,91184,91332,91480,91628,91777, + 91926,92075,92225,92375,92525,92675,92826,92978, + 93129,93281,93434,93586,93739,93892,94046,94200, + 94354,94509,94664,94819,94975,95131,95287,95444, + 95601,95758,95916,96074,96233,96391,96551,96710, + 96870,97030,97191,97352,97513,97675,97837,98000, + 98163,98326,98489,98653,98818,98982,99148,99313, + 99479,99645,99812,99979,100146,100314,100482,100651, + 100820,100990,101159,101330,101500,101671,101843,102015, + 102187,102360,102533,102706,102880,103054,103229,103404, + 103580,103756,103933,104109,104287,104465,104643,104821, + 105000,105180,105360,105540,105721,105902,106084,106266, + 106449,106632,106816,107000,107184,107369,107555,107741, + 107927,108114,108301,108489,108677,108866,109055,109245, + 109435,109626,109817,110008,110200,110393,110586,110780, + 110974,111169,111364,111560,111756,111952,112150,112347, + 112546,112744,112944,113143,113344,113545,113746,113948, + 114151,114354,114557,114761,114966,115171,115377,115583, + 115790,115998,116206,116414,116623,116833,117044,117254, + 117466,117678,117891,118104,118318,118532,118747,118963, + 119179,119396,119613,119831,120050,120269,120489,120709, + 120930,121152,121374,121597,121821,122045,122270,122496, + 122722,122949,123176,123404,123633,123863,124093,124324, + 124555,124787,125020,125254,125488,125723,125959,126195, + 126432,126669,126908,127147,127387,127627,127869,128111, + 128353,128597,128841,129086,129332,129578,129825,130073, + 130322,130571,130821,131072,131324,131576,131830,132084, + 132339,132594,132851,133108,133366,133625,133884,134145, + 134406,134668,134931,135195,135459,135725,135991,136258, + 136526,136795,137065,137335,137607,137879,138152,138426, + 138701,138977,139254,139532,139810,140090,140370,140651, + 140934,141217,141501,141786,142072,142359,142647,142936, + 143226,143517,143808,144101,144395,144690,144986,145282, + 145580,145879,146179,146480,146782,147084,147388,147693, + 148000,148307,148615,148924,149235,149546,149859,150172, + 150487,150803,151120,151438,151757,152077,152399,152722, + 153045,153370,153697,154024,154352,154682,155013,155345, + 155678,156013,156349,156686,157024,157363,157704,158046, + 158389,158734,159079,159427,159775,160125,160476,160828, + 161182,161537,161893,162251,162610,162970,163332,163695, + 164060,164426,164793,165162,165532,165904,166277,166651, + 167027,167405,167784,168164,168546,168930,169315,169701, + 170089,170479,170870,171263,171657,172053,172451,172850, + 173251,173653,174057,174463,174870,175279,175690,176102, + 176516,176932,177349,177769,178190,178612,179037,179463, + 179891,180321,180753,181186,181622,182059,182498,182939, + 183382,183827,184274,184722,185173,185625,186080,186536, + 186995,187455,187918,188382,188849,189318,189789,190261, + 190736,191213,191693,192174,192658,193143,193631,194122, + 194614,195109,195606,196105,196606,197110,197616,198125, + 198636,199149,199664,200182,200703,201226,201751,202279, + 202809,203342,203878,204416,204956,205500,206045,206594, + 207145,207699,208255,208815,209376,209941,210509,211079, + 211652,212228,212807,213389,213973,214561,215151,215745, + 216341,216941,217544,218149,218758,219370,219985,220603, + 221225,221849,222477,223108,223743,224381,225022,225666, + 226314,226966,227621,228279,228941,229606,230275,230948, + 231624,232304,232988,233676,234367,235062,235761,236463, + 237170,237881,238595,239314,240036,240763,241493,242228, + 242967,243711,244458,245210,245966,246727,247492,248261, + 249035,249813,250596,251384,252176,252973,253774,254581, + 255392,256208,257029,257855,258686,259522,260363,261209, + 262060,262917,263779,264646,265519,266397,267280,268169, + 269064,269965,270871,271782,272700,273624,274553,275489, + 276430,277378,278332,279292,280258,281231,282210,283195, + 284188,285186,286192,287204,288223,289249,290282,291322, + 292369,293423,294485,295554,296630,297714,298805,299904, + 301011,302126,303248,304379,305517,306664,307819,308983, + 310154,311335,312524,313721,314928,316143,317368,318601, + 319844,321097,322358,323629,324910,326201,327502,328812, + 330133,331464,332805,334157,335519,336892,338276,339671, + 341078,342495,343924,345364,346816,348280,349756,351244, + 352744,354257,355783,357321,358872,360436,362013,363604, + 365208,366826,368459,370105,371765,373440,375130,376835, + 378555,380290,382040,383807,385589,387387,389202,391034, + 392882,394747,396630,398530,400448,402384,404338,406311, + 408303,410314,412344,414395,416465,418555,420666,422798, + 424951,427125,429321,431540,433781,436045,438332,440643, + 442978,445337,447720,450129,452564,455024,457511,460024, + 462565,465133,467730,470355,473009,475692,478406,481150, + 483925,486732,489571,492443,495348,498287,501261,504269, + 507313,510394,513512,516667,519861,523094,526366,529680, + 533034,536431,539870,543354,546881,550455,554074,557741, + 561456,565221,569035,572901,576818,580789,584815,588896, + 593033,597229,601483,605798,610174,614613,619117,623686, + 628323,633028,637803,642651,647572,652568,657640,662792, + 668024,673338,678737,684223,689797,695462,701219,707072, + 713023,719074,725227,731486,737853,744331,750922,757631, + 764460,771411,778490,785699,793041,800521,808143,815910, + 823827,831898,840127,848520,857081,865817,874730,883829, + 893117,902602,912289,922186,932298,942633,953199,964003, + 975054,986361,997931,1009774,1021901,1034322,1047046,1060087, + 1073455,1087164,1101225,1115654,1130465,1145673,1161294,1177345, + 1193846,1210813,1228269,1246234,1264730,1283783,1303416,1323658, + 1344537,1366084,1388330,1411312,1435065,1459630,1485049,1511367, + 1538632,1566898,1596220,1626658,1658278,1691149,1725348,1760956, + 1798063,1836758,1877161,1919378,1963536,2009771,2058233,2109087, + 2162516,2218719,2277919,2340362,2406322,2476104,2550052,2628549, + 2712030,2800983,2895966,2997613,3106651,3223918,3350381,3487165, + 3635590,3797206,3973855,4167737,4381502,4618375,4882318,5178251, + 5512368,5892567,6329090,6835455,7429880,8137527,8994149,10052327, + 11392683,13145455,15535599,18988036,24413316,34178904,56965752,170910304 + }; +#endif + +fixed_t *finecosine; + +#ifdef TABLES_AS_LUMPS +fixed_t *finesine; +#else +const fixed_t finesine[10240] = { + 25,75,125,175,226,276,326,376, + 427,477,527,578,628,678,728,779, + 829,879,929,980,1030,1080,1130,1181, + 1231,1281,1331,1382,1432,1482,1532,1583, + 1633,1683,1733,1784,1834,1884,1934,1985, + 2035,2085,2135,2186,2236,2286,2336,2387, + 2437,2487,2537,2587,2638,2688,2738,2788, + 2839,2889,2939,2989,3039,3090,3140,3190, + 3240,3291,3341,3391,3441,3491,3541,3592, + 3642,3692,3742,3792,3843,3893,3943,3993, + 4043,4093,4144,4194,4244,4294,4344,4394, + 4445,4495,4545,4595,4645,4695,4745,4796, + 4846,4896,4946,4996,5046,5096,5146,5197, + 5247,5297,5347,5397,5447,5497,5547,5597, + 5647,5697,5748,5798,5848,5898,5948,5998, + 6048,6098,6148,6198,6248,6298,6348,6398, + 6448,6498,6548,6598,6648,6698,6748,6798, + 6848,6898,6948,6998,7048,7098,7148,7198, + 7248,7298,7348,7398,7448,7498,7548,7598, + 7648,7697,7747,7797,7847,7897,7947,7997, + 8047,8097,8147,8196,8246,8296,8346,8396, + 8446,8496,8545,8595,8645,8695,8745,8794, + 8844,8894,8944,8994,9043,9093,9143,9193, + 9243,9292,9342,9392,9442,9491,9541,9591, + 9640,9690,9740,9790,9839,9889,9939,9988, + 10038,10088,10137,10187,10237,10286,10336,10386, + 10435,10485,10534,10584,10634,10683,10733,10782, + 10832,10882,10931,10981,11030,11080,11129,11179, + 11228,11278,11327,11377,11426,11476,11525,11575, + 11624,11674,11723,11773,11822,11872,11921,11970, + 12020,12069,12119,12168,12218,12267,12316,12366, + 12415,12464,12514,12563,12612,12662,12711,12760, + 12810,12859,12908,12957,13007,13056,13105,13154, + 13204,13253,13302,13351,13401,13450,13499,13548, + 13597,13647,13696,13745,13794,13843,13892,13941, + 13990,14040,14089,14138,14187,14236,14285,14334, + 14383,14432,14481,14530,14579,14628,14677,14726, + 14775,14824,14873,14922,14971,15020,15069,15118, + 15167,15215,15264,15313,15362,15411,15460,15509, + 15557,15606,15655,15704,15753,15802,15850,15899, + 15948,15997,16045,16094,16143,16191,16240,16289, + 16338,16386,16435,16484,16532,16581,16629,16678, + 16727,16775,16824,16872,16921,16970,17018,17067, + 17115,17164,17212,17261,17309,17358,17406,17455, + 17503,17551,17600,17648,17697,17745,17793,17842, + 17890,17939,17987,18035,18084,18132,18180,18228, + 18277,18325,18373,18421,18470,18518,18566,18614, + 18663,18711,18759,18807,18855,18903,18951,19000, + 19048,19096,19144,19192,19240,19288,19336,19384, + 19432,19480,19528,19576,19624,19672,19720,19768, + 19816,19864,19912,19959,20007,20055,20103,20151, + 20199,20246,20294,20342,20390,20438,20485,20533, + 20581,20629,20676,20724,20772,20819,20867,20915, + 20962,21010,21057,21105,21153,21200,21248,21295, + 21343,21390,21438,21485,21533,21580,21628,21675, + 21723,21770,21817,21865,21912,21960,22007,22054, + 22102,22149,22196,22243,22291,22338,22385,22433, + 22480,22527,22574,22621,22668,22716,22763,22810, + 22857,22904,22951,22998,23045,23092,23139,23186, + 23233,23280,23327,23374,23421,23468,23515,23562, + 23609,23656,23703,23750,23796,23843,23890,23937, + 23984,24030,24077,24124,24171,24217,24264,24311, + 24357,24404,24451,24497,24544,24591,24637,24684, + 24730,24777,24823,24870,24916,24963,25009,25056, + 25102,25149,25195,25241,25288,25334,25381,25427, + 25473,25520,25566,25612,25658,25705,25751,25797, + 25843,25889,25936,25982,26028,26074,26120,26166, + 26212,26258,26304,26350,26396,26442,26488,26534, + 26580,26626,26672,26718,26764,26810,26856,26902, + 26947,26993,27039,27085,27131,27176,27222,27268, + 27313,27359,27405,27450,27496,27542,27587,27633, + 27678,27724,27770,27815,27861,27906,27952,27997, + 28042,28088,28133,28179,28224,28269,28315,28360, + 28405,28451,28496,28541,28586,28632,28677,28722, + 28767,28812,28858,28903,28948,28993,29038,29083, + 29128,29173,29218,29263,29308,29353,29398,29443, + 29488,29533,29577,29622,29667,29712,29757,29801, + 29846,29891,29936,29980,30025,30070,30114,30159, + 30204,30248,30293,30337,30382,30426,30471,30515, + 30560,30604,30649,30693,30738,30782,30826,30871, + 30915,30959,31004,31048,31092,31136,31181,31225, + 31269,31313,31357,31402,31446,31490,31534,31578, + 31622,31666,31710,31754,31798,31842,31886,31930, + 31974,32017,32061,32105,32149,32193,32236,32280, + 32324,32368,32411,32455,32499,32542,32586,32630, + 32673,32717,32760,32804,32847,32891,32934,32978, + 33021,33065,33108,33151,33195,33238,33281,33325, + 33368,33411,33454,33498,33541,33584,33627,33670, + 33713,33756,33799,33843,33886,33929,33972,34015, + 34057,34100,34143,34186,34229,34272,34315,34358, + 34400,34443,34486,34529,34571,34614,34657,34699, + 34742,34785,34827,34870,34912,34955,34997,35040, + 35082,35125,35167,35210,35252,35294,35337,35379, + 35421,35464,35506,35548,35590,35633,35675,35717, + 35759,35801,35843,35885,35927,35969,36011,36053, + 36095,36137,36179,36221,36263,36305,36347,36388, + 36430,36472,36514,36555,36597,36639,36681,36722, + 36764,36805,36847,36889,36930,36972,37013,37055, + 37096,37137,37179,37220,37262,37303,37344,37386, + 37427,37468,37509,37551,37592,37633,37674,37715, + 37756,37797,37838,37879,37920,37961,38002,38043, + 38084,38125,38166,38207,38248,38288,38329,38370, + 38411,38451,38492,38533,38573,38614,38655,38695, + 38736,38776,38817,38857,38898,38938,38979,39019, + 39059,39100,39140,39180,39221,39261,39301,39341, + 39382,39422,39462,39502,39542,39582,39622,39662, + 39702,39742,39782,39822,39862,39902,39942,39982, + 40021,40061,40101,40141,40180,40220,40260,40300, + 40339,40379,40418,40458,40497,40537,40576,40616, + 40655,40695,40734,40773,40813,40852,40891,40931, + 40970,41009,41048,41087,41127,41166,41205,41244, + 41283,41322,41361,41400,41439,41478,41517,41556, + 41595,41633,41672,41711,41750,41788,41827,41866, + 41904,41943,41982,42020,42059,42097,42136,42174, + 42213,42251,42290,42328,42366,42405,42443,42481, + 42520,42558,42596,42634,42672,42711,42749,42787, + 42825,42863,42901,42939,42977,43015,43053,43091, + 43128,43166,43204,43242,43280,43317,43355,43393, + 43430,43468,43506,43543,43581,43618,43656,43693, + 43731,43768,43806,43843,43880,43918,43955,43992, + 44029,44067,44104,44141,44178,44215,44252,44289, + 44326,44363,44400,44437,44474,44511,44548,44585, + 44622,44659,44695,44732,44769,44806,44842,44879, + 44915,44952,44989,45025,45062,45098,45135,45171, + 45207,45244,45280,45316,45353,45389,45425,45462, + 45498,45534,45570,45606,45642,45678,45714,45750, + 45786,45822,45858,45894,45930,45966,46002,46037, + 46073,46109,46145,46180,46216,46252,46287,46323, + 46358,46394,46429,46465,46500,46536,46571,46606, + 46642,46677,46712,46747,46783,46818,46853,46888, + 46923,46958,46993,47028,47063,47098,47133,47168, + 47203,47238,47273,47308,47342,47377,47412,47446, + 47481,47516,47550,47585,47619,47654,47688,47723, + 47757,47792,47826,47860,47895,47929,47963,47998, + 48032,48066,48100,48134,48168,48202,48237,48271, + 48305,48338,48372,48406,48440,48474,48508,48542, + 48575,48609,48643,48676,48710,48744,48777,48811, + 48844,48878,48911,48945,48978,49012,49045,49078, + 49112,49145,49178,49211,49244,49278,49311,49344, + 49377,49410,49443,49476,49509,49542,49575,49608, + 49640,49673,49706,49739,49771,49804,49837,49869, + 49902,49935,49967,50000,50032,50065,50097,50129, + 50162,50194,50226,50259,50291,50323,50355,50387, + 50420,50452,50484,50516,50548,50580,50612,50644, + 50675,50707,50739,50771,50803,50834,50866,50898, + 50929,50961,50993,51024,51056,51087,51119,51150, + 51182,51213,51244,51276,51307,51338,51369,51401, + 51432,51463,51494,51525,51556,51587,51618,51649, + 51680,51711,51742,51773,51803,51834,51865,51896, + 51926,51957,51988,52018,52049,52079,52110,52140, + 52171,52201,52231,52262,52292,52322,52353,52383, + 52413,52443,52473,52503,52534,52564,52594,52624, + 52653,52683,52713,52743,52773,52803,52832,52862, + 52892,52922,52951,52981,53010,53040,53069,53099, + 53128,53158,53187,53216,53246,53275,53304,53334, + 53363,53392,53421,53450,53479,53508,53537,53566, + 53595,53624,53653,53682,53711,53739,53768,53797, + 53826,53854,53883,53911,53940,53969,53997,54026, + 54054,54082,54111,54139,54167,54196,54224,54252, + 54280,54308,54337,54365,54393,54421,54449,54477, + 54505,54533,54560,54588,54616,54644,54672,54699, + 54727,54755,54782,54810,54837,54865,54892,54920, + 54947,54974,55002,55029,55056,55084,55111,55138, + 55165,55192,55219,55246,55274,55300,55327,55354, + 55381,55408,55435,55462,55489,55515,55542,55569, + 55595,55622,55648,55675,55701,55728,55754,55781, + 55807,55833,55860,55886,55912,55938,55965,55991, + 56017,56043,56069,56095,56121,56147,56173,56199, + 56225,56250,56276,56302,56328,56353,56379,56404, + 56430,56456,56481,56507,56532,56557,56583,56608, + 56633,56659,56684,56709,56734,56760,56785,56810, + 56835,56860,56885,56910,56935,56959,56984,57009, + 57034,57059,57083,57108,57133,57157,57182,57206, + 57231,57255,57280,57304,57329,57353,57377,57402, + 57426,57450,57474,57498,57522,57546,57570,57594, + 57618,57642,57666,57690,57714,57738,57762,57785, + 57809,57833,57856,57880,57903,57927,57950,57974, + 57997,58021,58044,58067,58091,58114,58137,58160, + 58183,58207,58230,58253,58276,58299,58322,58345, + 58367,58390,58413,58436,58459,58481,58504,58527, + 58549,58572,58594,58617,58639,58662,58684,58706, + 58729,58751,58773,58795,58818,58840,58862,58884, + 58906,58928,58950,58972,58994,59016,59038,59059, + 59081,59103,59125,59146,59168,59190,59211,59233, + 59254,59276,59297,59318,59340,59361,59382,59404, + 59425,59446,59467,59488,59509,59530,59551,59572, + 59593,59614,59635,59656,59677,59697,59718,59739, + 59759,59780,59801,59821,59842,59862,59883,59903, + 59923,59944,59964,59984,60004,60025,60045,60065, + 60085,60105,60125,60145,60165,60185,60205,60225, + 60244,60264,60284,60304,60323,60343,60363,60382, + 60402,60421,60441,60460,60479,60499,60518,60537, + 60556,60576,60595,60614,60633,60652,60671,60690, + 60709,60728,60747,60766,60785,60803,60822,60841, + 60859,60878,60897,60915,60934,60952,60971,60989, + 61007,61026,61044,61062,61081,61099,61117,61135, + 61153,61171,61189,61207,61225,61243,61261,61279, + 61297,61314,61332,61350,61367,61385,61403,61420, + 61438,61455,61473,61490,61507,61525,61542,61559, + 61577,61594,61611,61628,61645,61662,61679,61696, + 61713,61730,61747,61764,61780,61797,61814,61831, + 61847,61864,61880,61897,61913,61930,61946,61963, + 61979,61995,62012,62028,62044,62060,62076,62092, + 62108,62125,62141,62156,62172,62188,62204,62220, + 62236,62251,62267,62283,62298,62314,62329,62345, + 62360,62376,62391,62407,62422,62437,62453,62468, + 62483,62498,62513,62528,62543,62558,62573,62588, + 62603,62618,62633,62648,62662,62677,62692,62706, + 62721,62735,62750,62764,62779,62793,62808,62822, + 62836,62850,62865,62879,62893,62907,62921,62935, + 62949,62963,62977,62991,63005,63019,63032,63046, + 63060,63074,63087,63101,63114,63128,63141,63155, + 63168,63182,63195,63208,63221,63235,63248,63261, + 63274,63287,63300,63313,63326,63339,63352,63365, + 63378,63390,63403,63416,63429,63441,63454,63466, + 63479,63491,63504,63516,63528,63541,63553,63565, + 63578,63590,63602,63614,63626,63638,63650,63662, + 63674,63686,63698,63709,63721,63733,63745,63756, + 63768,63779,63791,63803,63814,63825,63837,63848, + 63859,63871,63882,63893,63904,63915,63927,63938, + 63949,63960,63971,63981,63992,64003,64014,64025, + 64035,64046,64057,64067,64078,64088,64099,64109, + 64120,64130,64140,64151,64161,64171,64181,64192, + 64202,64212,64222,64232,64242,64252,64261,64271, + 64281,64291,64301,64310,64320,64330,64339,64349, + 64358,64368,64377,64387,64396,64405,64414,64424, + 64433,64442,64451,64460,64469,64478,64487,64496, + 64505,64514,64523,64532,64540,64549,64558,64566, + 64575,64584,64592,64601,64609,64617,64626,64634, + 64642,64651,64659,64667,64675,64683,64691,64699, + 64707,64715,64723,64731,64739,64747,64754,64762, + 64770,64777,64785,64793,64800,64808,64815,64822, + 64830,64837,64844,64852,64859,64866,64873,64880, + 64887,64895,64902,64908,64915,64922,64929,64936, + 64943,64949,64956,64963,64969,64976,64982,64989, + 64995,65002,65008,65015,65021,65027,65033,65040, + 65046,65052,65058,65064,65070,65076,65082,65088, + 65094,65099,65105,65111,65117,65122,65128,65133, + 65139,65144,65150,65155,65161,65166,65171,65177, + 65182,65187,65192,65197,65202,65207,65212,65217, + 65222,65227,65232,65237,65242,65246,65251,65256, + 65260,65265,65270,65274,65279,65283,65287,65292, + 65296,65300,65305,65309,65313,65317,65321,65325, + 65329,65333,65337,65341,65345,65349,65352,65356, + 65360,65363,65367,65371,65374,65378,65381,65385, + 65388,65391,65395,65398,65401,65404,65408,65411, + 65414,65417,65420,65423,65426,65429,65431,65434, + 65437,65440,65442,65445,65448,65450,65453,65455, + 65458,65460,65463,65465,65467,65470,65472,65474, + 65476,65478,65480,65482,65484,65486,65488,65490, + 65492,65494,65496,65497,65499,65501,65502,65504, + 65505,65507,65508,65510,65511,65513,65514,65515, + 65516,65518,65519,65520,65521,65522,65523,65524, + 65525,65526,65527,65527,65528,65529,65530,65530, + 65531,65531,65532,65532,65533,65533,65534,65534, + 65534,65535,65535,65535,65535,65535,65535,65535, + 65535,65535,65535,65535,65535,65535,65535,65534, + 65534,65534,65533,65533,65532,65532,65531,65531, + 65530,65530,65529,65528,65527,65527,65526,65525, + 65524,65523,65522,65521,65520,65519,65518,65516, + 65515,65514,65513,65511,65510,65508,65507,65505, + 65504,65502,65501,65499,65497,65496,65494,65492, + 65490,65488,65486,65484,65482,65480,65478,65476, + 65474,65472,65470,65467,65465,65463,65460,65458, + 65455,65453,65450,65448,65445,65442,65440,65437, + 65434,65431,65429,65426,65423,65420,65417,65414, + 65411,65408,65404,65401,65398,65395,65391,65388, + 65385,65381,65378,65374,65371,65367,65363,65360, + 65356,65352,65349,65345,65341,65337,65333,65329, + 65325,65321,65317,65313,65309,65305,65300,65296, + 65292,65287,65283,65279,65274,65270,65265,65260, + 65256,65251,65246,65242,65237,65232,65227,65222, + 65217,65212,65207,65202,65197,65192,65187,65182, + 65177,65171,65166,65161,65155,65150,65144,65139, + 65133,65128,65122,65117,65111,65105,65099,65094, + 65088,65082,65076,65070,65064,65058,65052,65046, + 65040,65033,65027,65021,65015,65008,65002,64995, + 64989,64982,64976,64969,64963,64956,64949,64943, + 64936,64929,64922,64915,64908,64902,64895,64887, + 64880,64873,64866,64859,64852,64844,64837,64830, + 64822,64815,64808,64800,64793,64785,64777,64770, + 64762,64754,64747,64739,64731,64723,64715,64707, + 64699,64691,64683,64675,64667,64659,64651,64642, + 64634,64626,64617,64609,64600,64592,64584,64575, + 64566,64558,64549,64540,64532,64523,64514,64505, + 64496,64487,64478,64469,64460,64451,64442,64433, + 64424,64414,64405,64396,64387,64377,64368,64358, + 64349,64339,64330,64320,64310,64301,64291,64281, + 64271,64261,64252,64242,64232,64222,64212,64202, + 64192,64181,64171,64161,64151,64140,64130,64120, + 64109,64099,64088,64078,64067,64057,64046,64035, + 64025,64014,64003,63992,63981,63971,63960,63949, + 63938,63927,63915,63904,63893,63882,63871,63859, + 63848,63837,63825,63814,63803,63791,63779,63768, + 63756,63745,63733,63721,63709,63698,63686,63674, + 63662,63650,63638,63626,63614,63602,63590,63578, + 63565,63553,63541,63528,63516,63504,63491,63479, + 63466,63454,63441,63429,63416,63403,63390,63378, + 63365,63352,63339,63326,63313,63300,63287,63274, + 63261,63248,63235,63221,63208,63195,63182,63168, + 63155,63141,63128,63114,63101,63087,63074,63060, + 63046,63032,63019,63005,62991,62977,62963,62949, + 62935,62921,62907,62893,62879,62865,62850,62836, + 62822,62808,62793,62779,62764,62750,62735,62721, + 62706,62692,62677,62662,62648,62633,62618,62603, + 62588,62573,62558,62543,62528,62513,62498,62483, + 62468,62453,62437,62422,62407,62391,62376,62360, + 62345,62329,62314,62298,62283,62267,62251,62236, + 62220,62204,62188,62172,62156,62141,62125,62108, + 62092,62076,62060,62044,62028,62012,61995,61979, + 61963,61946,61930,61913,61897,61880,61864,61847, + 61831,61814,61797,61780,61764,61747,61730,61713, + 61696,61679,61662,61645,61628,61611,61594,61577, + 61559,61542,61525,61507,61490,61473,61455,61438, + 61420,61403,61385,61367,61350,61332,61314,61297, + 61279,61261,61243,61225,61207,61189,61171,61153, + 61135,61117,61099,61081,61062,61044,61026,61007, + 60989,60971,60952,60934,60915,60897,60878,60859, + 60841,60822,60803,60785,60766,60747,60728,60709, + 60690,60671,60652,60633,60614,60595,60576,60556, + 60537,60518,60499,60479,60460,60441,60421,60402, + 60382,60363,60343,60323,60304,60284,60264,60244, + 60225,60205,60185,60165,60145,60125,60105,60085, + 60065,60045,60025,60004,59984,59964,59944,59923, + 59903,59883,59862,59842,59821,59801,59780,59759, + 59739,59718,59697,59677,59656,59635,59614,59593, + 59572,59551,59530,59509,59488,59467,59446,59425, + 59404,59382,59361,59340,59318,59297,59276,59254, + 59233,59211,59190,59168,59146,59125,59103,59081, + 59059,59038,59016,58994,58972,58950,58928,58906, + 58884,58862,58840,58818,58795,58773,58751,58729, + 58706,58684,58662,58639,58617,58594,58572,58549, + 58527,58504,58481,58459,58436,58413,58390,58367, + 58345,58322,58299,58276,58253,58230,58207,58183, + 58160,58137,58114,58091,58067,58044,58021,57997, + 57974,57950,57927,57903,57880,57856,57833,57809, + 57785,57762,57738,57714,57690,57666,57642,57618, + 57594,57570,57546,57522,57498,57474,57450,57426, + 57402,57377,57353,57329,57304,57280,57255,57231, + 57206,57182,57157,57133,57108,57083,57059,57034, + 57009,56984,56959,56935,56910,56885,56860,56835, + 56810,56785,56760,56734,56709,56684,56659,56633, + 56608,56583,56557,56532,56507,56481,56456,56430, + 56404,56379,56353,56328,56302,56276,56250,56225, + 56199,56173,56147,56121,56095,56069,56043,56017, + 55991,55965,55938,55912,55886,55860,55833,55807, + 55781,55754,55728,55701,55675,55648,55622,55595, + 55569,55542,55515,55489,55462,55435,55408,55381, + 55354,55327,55300,55274,55246,55219,55192,55165, + 55138,55111,55084,55056,55029,55002,54974,54947, + 54920,54892,54865,54837,54810,54782,54755,54727, + 54699,54672,54644,54616,54588,54560,54533,54505, + 54477,54449,54421,54393,54365,54337,54308,54280, + 54252,54224,54196,54167,54139,54111,54082,54054, + 54026,53997,53969,53940,53911,53883,53854,53826, + 53797,53768,53739,53711,53682,53653,53624,53595, + 53566,53537,53508,53479,53450,53421,53392,53363, + 53334,53304,53275,53246,53216,53187,53158,53128, + 53099,53069,53040,53010,52981,52951,52922,52892, + 52862,52832,52803,52773,52743,52713,52683,52653, + 52624,52594,52564,52534,52503,52473,52443,52413, + 52383,52353,52322,52292,52262,52231,52201,52171, + 52140,52110,52079,52049,52018,51988,51957,51926, + 51896,51865,51834,51803,51773,51742,51711,51680, + 51649,51618,51587,51556,51525,51494,51463,51432, + 51401,51369,51338,51307,51276,51244,51213,51182, + 51150,51119,51087,51056,51024,50993,50961,50929, + 50898,50866,50834,50803,50771,50739,50707,50675, + 50644,50612,50580,50548,50516,50484,50452,50420, + 50387,50355,50323,50291,50259,50226,50194,50162, + 50129,50097,50065,50032,50000,49967,49935,49902, + 49869,49837,49804,49771,49739,49706,49673,49640, + 49608,49575,49542,49509,49476,49443,49410,49377, + 49344,49311,49278,49244,49211,49178,49145,49112, + 49078,49045,49012,48978,48945,48911,48878,48844, + 48811,48777,48744,48710,48676,48643,48609,48575, + 48542,48508,48474,48440,48406,48372,48338,48304, + 48271,48237,48202,48168,48134,48100,48066,48032, + 47998,47963,47929,47895,47860,47826,47792,47757, + 47723,47688,47654,47619,47585,47550,47516,47481, + 47446,47412,47377,47342,47308,47273,47238,47203, + 47168,47133,47098,47063,47028,46993,46958,46923, + 46888,46853,46818,46783,46747,46712,46677,46642, + 46606,46571,46536,46500,46465,46429,46394,46358, + 46323,46287,46252,46216,46180,46145,46109,46073, + 46037,46002,45966,45930,45894,45858,45822,45786, + 45750,45714,45678,45642,45606,45570,45534,45498, + 45462,45425,45389,45353,45316,45280,45244,45207, + 45171,45135,45098,45062,45025,44989,44952,44915, + 44879,44842,44806,44769,44732,44695,44659,44622, + 44585,44548,44511,44474,44437,44400,44363,44326, + 44289,44252,44215,44178,44141,44104,44067,44029, + 43992,43955,43918,43880,43843,43806,43768,43731, + 43693,43656,43618,43581,43543,43506,43468,43430, + 43393,43355,43317,43280,43242,43204,43166,43128, + 43091,43053,43015,42977,42939,42901,42863,42825, + 42787,42749,42711,42672,42634,42596,42558,42520, + 42481,42443,42405,42366,42328,42290,42251,42213, + 42174,42136,42097,42059,42020,41982,41943,41904, + 41866,41827,41788,41750,41711,41672,41633,41595, + 41556,41517,41478,41439,41400,41361,41322,41283, + 41244,41205,41166,41127,41088,41048,41009,40970, + 40931,40891,40852,40813,40773,40734,40695,40655, + 40616,40576,40537,40497,40458,40418,40379,40339, + 40300,40260,40220,40180,40141,40101,40061,40021, + 39982,39942,39902,39862,39822,39782,39742,39702, + 39662,39622,39582,39542,39502,39462,39422,39382, + 39341,39301,39261,39221,39180,39140,39100,39059, + 39019,38979,38938,38898,38857,38817,38776,38736, + 38695,38655,38614,38573,38533,38492,38451,38411, + 38370,38329,38288,38248,38207,38166,38125,38084, + 38043,38002,37961,37920,37879,37838,37797,37756, + 37715,37674,37633,37592,37551,37509,37468,37427, + 37386,37344,37303,37262,37220,37179,37137,37096, + 37055,37013,36972,36930,36889,36847,36805,36764, + 36722,36681,36639,36597,36556,36514,36472,36430, + 36388,36347,36305,36263,36221,36179,36137,36095, + 36053,36011,35969,35927,35885,35843,35801,35759, + 35717,35675,35633,35590,35548,35506,35464,35421, + 35379,35337,35294,35252,35210,35167,35125,35082, + 35040,34997,34955,34912,34870,34827,34785,34742, + 34699,34657,34614,34571,34529,34486,34443,34400, + 34358,34315,34272,34229,34186,34143,34100,34057, + 34015,33972,33929,33886,33843,33799,33756,33713, + 33670,33627,33584,33541,33498,33454,33411,33368, + 33325,33281,33238,33195,33151,33108,33065,33021, + 32978,32934,32891,32847,32804,32760,32717,32673, + 32630,32586,32542,32499,32455,32411,32368,32324, + 32280,32236,32193,32149,32105,32061,32017,31974, + 31930,31886,31842,31798,31754,31710,31666,31622, + 31578,31534,31490,31446,31402,31357,31313,31269, + 31225,31181,31136,31092,31048,31004,30959,30915, + 30871,30826,30782,30738,30693,30649,30604,30560, + 30515,30471,30426,30382,30337,30293,30248,30204, + 30159,30114,30070,30025,29980,29936,29891,29846, + 29801,29757,29712,29667,29622,29577,29533,29488, + 29443,29398,29353,29308,29263,29218,29173,29128, + 29083,29038,28993,28948,28903,28858,28812,28767, + 28722,28677,28632,28586,28541,28496,28451,28405, + 28360,28315,28269,28224,28179,28133,28088,28042, + 27997,27952,27906,27861,27815,27770,27724,27678, + 27633,27587,27542,27496,27450,27405,27359,27313, + 27268,27222,27176,27131,27085,27039,26993,26947, + 26902,26856,26810,26764,26718,26672,26626,26580, + 26534,26488,26442,26396,26350,26304,26258,26212, + 26166,26120,26074,26028,25982,25936,25889,25843, + 25797,25751,25705,25658,25612,25566,25520,25473, + 25427,25381,25334,25288,25241,25195,25149,25102, + 25056,25009,24963,24916,24870,24823,24777,24730, + 24684,24637,24591,24544,24497,24451,24404,24357, + 24311,24264,24217,24171,24124,24077,24030,23984, + 23937,23890,23843,23796,23750,23703,23656,23609, + 23562,23515,23468,23421,23374,23327,23280,23233, + 23186,23139,23092,23045,22998,22951,22904,22857, + 22810,22763,22716,22668,22621,22574,22527,22480, + 22433,22385,22338,22291,22243,22196,22149,22102, + 22054,22007,21960,21912,21865,21817,21770,21723, + 21675,21628,21580,21533,21485,21438,21390,21343, + 21295,21248,21200,21153,21105,21057,21010,20962, + 20915,20867,20819,20772,20724,20676,20629,20581, + 20533,20485,20438,20390,20342,20294,20246,20199, + 20151,20103,20055,20007,19959,19912,19864,19816, + 19768,19720,19672,19624,19576,19528,19480,19432, + 19384,19336,19288,19240,19192,19144,19096,19048, + 19000,18951,18903,18855,18807,18759,18711,18663, + 18614,18566,18518,18470,18421,18373,18325,18277, + 18228,18180,18132,18084,18035,17987,17939,17890, + 17842,17793,17745,17697,17648,17600,17551,17503, + 17455,17406,17358,17309,17261,17212,17164,17115, + 17067,17018,16970,16921,16872,16824,16775,16727, + 16678,16629,16581,16532,16484,16435,16386,16338, + 16289,16240,16191,16143,16094,16045,15997,15948, + 15899,15850,15802,15753,15704,15655,15606,15557, + 15509,15460,15411,15362,15313,15264,15215,15167, + 15118,15069,15020,14971,14922,14873,14824,14775, + 14726,14677,14628,14579,14530,14481,14432,14383, + 14334,14285,14236,14187,14138,14089,14040,13990, + 13941,13892,13843,13794,13745,13696,13646,13597, + 13548,13499,13450,13401,13351,13302,13253,13204, + 13154,13105,13056,13007,12957,12908,12859,12810, + 12760,12711,12662,12612,12563,12514,12464,12415, + 12366,12316,12267,12218,12168,12119,12069,12020, + 11970,11921,11872,11822,11773,11723,11674,11624, + 11575,11525,11476,11426,11377,11327,11278,11228, + 11179,11129,11080,11030,10981,10931,10882,10832, + 10782,10733,10683,10634,10584,10534,10485,10435, + 10386,10336,10286,10237,10187,10137,10088,10038, + 9988,9939,9889,9839,9790,9740,9690,9640, + 9591,9541,9491,9442,9392,9342,9292,9243, + 9193,9143,9093,9043,8994,8944,8894,8844, + 8794,8745,8695,8645,8595,8545,8496,8446, + 8396,8346,8296,8246,8196,8147,8097,8047, + 7997,7947,7897,7847,7797,7747,7697,7648, + 7598,7548,7498,7448,7398,7348,7298,7248, + 7198,7148,7098,7048,6998,6948,6898,6848, + 6798,6748,6698,6648,6598,6548,6498,6448, + 6398,6348,6298,6248,6198,6148,6098,6048, + 5998,5948,5898,5848,5798,5748,5697,5647, + 5597,5547,5497,5447,5397,5347,5297,5247, + 5197,5146,5096,5046,4996,4946,4896,4846, + 4796,4745,4695,4645,4595,4545,4495,4445, + 4394,4344,4294,4244,4194,4144,4093,4043, + 3993,3943,3893,3843,3792,3742,3692,3642, + 3592,3541,3491,3441,3391,3341,3291,3240, + 3190,3140,3090,3039,2989,2939,2889,2839, + 2788,2738,2688,2638,2587,2537,2487,2437, + 2387,2336,2286,2236,2186,2135,2085,2035, + 1985,1934,1884,1834,1784,1733,1683,1633, + 1583,1532,1482,1432,1382,1331,1281,1231, + 1181,1130,1080,1030,980,929,879,829, + 779,728,678,628,578,527,477,427, + 376,326,276,226,175,125,75,25, + -25,-75,-125,-175,-226,-276,-326,-376, + -427,-477,-527,-578,-628,-678,-728,-779, + -829,-879,-929,-980,-1030,-1080,-1130,-1181, + -1231,-1281,-1331,-1382,-1432,-1482,-1532,-1583, + -1633,-1683,-1733,-1784,-1834,-1884,-1934,-1985, + -2035,-2085,-2135,-2186,-2236,-2286,-2336,-2387, + -2437,-2487,-2537,-2588,-2638,-2688,-2738,-2788, + -2839,-2889,-2939,-2989,-3039,-3090,-3140,-3190, + -3240,-3291,-3341,-3391,-3441,-3491,-3541,-3592, + -3642,-3692,-3742,-3792,-3843,-3893,-3943,-3993, + -4043,-4093,-4144,-4194,-4244,-4294,-4344,-4394, + -4445,-4495,-4545,-4595,-4645,-4695,-4745,-4796, + -4846,-4896,-4946,-4996,-5046,-5096,-5146,-5197, + -5247,-5297,-5347,-5397,-5447,-5497,-5547,-5597, + -5647,-5697,-5748,-5798,-5848,-5898,-5948,-5998, + -6048,-6098,-6148,-6198,-6248,-6298,-6348,-6398, + -6448,-6498,-6548,-6598,-6648,-6698,-6748,-6798, + -6848,-6898,-6948,-6998,-7048,-7098,-7148,-7198, + -7248,-7298,-7348,-7398,-7448,-7498,-7548,-7598, + -7648,-7697,-7747,-7797,-7847,-7897,-7947,-7997, + -8047,-8097,-8147,-8196,-8246,-8296,-8346,-8396, + -8446,-8496,-8545,-8595,-8645,-8695,-8745,-8794, + -8844,-8894,-8944,-8994,-9043,-9093,-9143,-9193, + -9243,-9292,-9342,-9392,-9442,-9491,-9541,-9591, + -9640,-9690,-9740,-9790,-9839,-9889,-9939,-9988, + -10038,-10088,-10137,-10187,-10237,-10286,-10336,-10386, + -10435,-10485,-10534,-10584,-10634,-10683,-10733,-10782, + -10832,-10882,-10931,-10981,-11030,-11080,-11129,-11179, + -11228,-11278,-11327,-11377,-11426,-11476,-11525,-11575, + -11624,-11674,-11723,-11773,-11822,-11872,-11921,-11970, + -12020,-12069,-12119,-12168,-12218,-12267,-12316,-12366, + -12415,-12464,-12514,-12563,-12612,-12662,-12711,-12760, + -12810,-12859,-12908,-12957,-13007,-13056,-13105,-13154, + -13204,-13253,-13302,-13351,-13401,-13450,-13499,-13548, + -13597,-13647,-13696,-13745,-13794,-13843,-13892,-13941, + -13990,-14040,-14089,-14138,-14187,-14236,-14285,-14334, + -14383,-14432,-14481,-14530,-14579,-14628,-14677,-14726, + -14775,-14824,-14873,-14922,-14971,-15020,-15069,-15118, + -15167,-15215,-15264,-15313,-15362,-15411,-15460,-15509, + -15557,-15606,-15655,-15704,-15753,-15802,-15850,-15899, + -15948,-15997,-16045,-16094,-16143,-16191,-16240,-16289, + -16338,-16386,-16435,-16484,-16532,-16581,-16629,-16678, + -16727,-16775,-16824,-16872,-16921,-16970,-17018,-17067, + -17115,-17164,-17212,-17261,-17309,-17358,-17406,-17455, + -17503,-17551,-17600,-17648,-17697,-17745,-17793,-17842, + -17890,-17939,-17987,-18035,-18084,-18132,-18180,-18228, + -18277,-18325,-18373,-18421,-18470,-18518,-18566,-18614, + -18663,-18711,-18759,-18807,-18855,-18903,-18951,-19000, + -19048,-19096,-19144,-19192,-19240,-19288,-19336,-19384, + -19432,-19480,-19528,-19576,-19624,-19672,-19720,-19768, + -19816,-19864,-19912,-19959,-20007,-20055,-20103,-20151, + -20199,-20246,-20294,-20342,-20390,-20438,-20485,-20533, + -20581,-20629,-20676,-20724,-20772,-20819,-20867,-20915, + -20962,-21010,-21057,-21105,-21153,-21200,-21248,-21295, + -21343,-21390,-21438,-21485,-21533,-21580,-21628,-21675, + -21723,-21770,-21817,-21865,-21912,-21960,-22007,-22054, + -22102,-22149,-22196,-22243,-22291,-22338,-22385,-22433, + -22480,-22527,-22574,-22621,-22668,-22716,-22763,-22810, + -22857,-22904,-22951,-22998,-23045,-23092,-23139,-23186, + -23233,-23280,-23327,-23374,-23421,-23468,-23515,-23562, + -23609,-23656,-23703,-23750,-23796,-23843,-23890,-23937, + -23984,-24030,-24077,-24124,-24171,-24217,-24264,-24311, + -24357,-24404,-24451,-24497,-24544,-24591,-24637,-24684, + -24730,-24777,-24823,-24870,-24916,-24963,-25009,-25056, + -25102,-25149,-25195,-25241,-25288,-25334,-25381,-25427, + -25473,-25520,-25566,-25612,-25658,-25705,-25751,-25797, + -25843,-25889,-25936,-25982,-26028,-26074,-26120,-26166, + -26212,-26258,-26304,-26350,-26396,-26442,-26488,-26534, + -26580,-26626,-26672,-26718,-26764,-26810,-26856,-26902, + -26947,-26993,-27039,-27085,-27131,-27176,-27222,-27268, + -27313,-27359,-27405,-27450,-27496,-27542,-27587,-27633, + -27678,-27724,-27770,-27815,-27861,-27906,-27952,-27997, + -28042,-28088,-28133,-28179,-28224,-28269,-28315,-28360, + -28405,-28451,-28496,-28541,-28586,-28632,-28677,-28722, + -28767,-28812,-28858,-28903,-28948,-28993,-29038,-29083, + -29128,-29173,-29218,-29263,-29308,-29353,-29398,-29443, + -29488,-29533,-29577,-29622,-29667,-29712,-29757,-29801, + -29846,-29891,-29936,-29980,-30025,-30070,-30114,-30159, + -30204,-30248,-30293,-30337,-30382,-30426,-30471,-30515, + -30560,-30604,-30649,-30693,-30738,-30782,-30826,-30871, + -30915,-30959,-31004,-31048,-31092,-31136,-31181,-31225, + -31269,-31313,-31357,-31402,-31446,-31490,-31534,-31578, + -31622,-31666,-31710,-31754,-31798,-31842,-31886,-31930, + -31974,-32017,-32061,-32105,-32149,-32193,-32236,-32280, + -32324,-32368,-32411,-32455,-32499,-32542,-32586,-32630, + -32673,-32717,-32760,-32804,-32847,-32891,-32934,-32978, + -33021,-33065,-33108,-33151,-33195,-33238,-33281,-33325, + -33368,-33411,-33454,-33498,-33541,-33584,-33627,-33670, + -33713,-33756,-33799,-33843,-33886,-33929,-33972,-34015, + -34057,-34100,-34143,-34186,-34229,-34272,-34315,-34358, + -34400,-34443,-34486,-34529,-34571,-34614,-34657,-34699, + -34742,-34785,-34827,-34870,-34912,-34955,-34997,-35040, + -35082,-35125,-35167,-35210,-35252,-35294,-35337,-35379, + -35421,-35464,-35506,-35548,-35590,-35633,-35675,-35717, + -35759,-35801,-35843,-35885,-35927,-35969,-36011,-36053, + -36095,-36137,-36179,-36221,-36263,-36305,-36347,-36388, + -36430,-36472,-36514,-36555,-36597,-36639,-36681,-36722, + -36764,-36805,-36847,-36889,-36930,-36972,-37013,-37055, + -37096,-37137,-37179,-37220,-37262,-37303,-37344,-37386, + -37427,-37468,-37509,-37551,-37592,-37633,-37674,-37715, + -37756,-37797,-37838,-37879,-37920,-37961,-38002,-38043, + -38084,-38125,-38166,-38207,-38248,-38288,-38329,-38370, + -38411,-38451,-38492,-38533,-38573,-38614,-38655,-38695, + -38736,-38776,-38817,-38857,-38898,-38938,-38979,-39019, + -39059,-39100,-39140,-39180,-39221,-39261,-39301,-39341, + -39382,-39422,-39462,-39502,-39542,-39582,-39622,-39662, + -39702,-39742,-39782,-39822,-39862,-39902,-39942,-39982, + -40021,-40061,-40101,-40141,-40180,-40220,-40260,-40299, + -40339,-40379,-40418,-40458,-40497,-40537,-40576,-40616, + -40655,-40695,-40734,-40773,-40813,-40852,-40891,-40931, + -40970,-41009,-41048,-41087,-41127,-41166,-41205,-41244, + -41283,-41322,-41361,-41400,-41439,-41478,-41517,-41556, + -41595,-41633,-41672,-41711,-41750,-41788,-41827,-41866, + -41904,-41943,-41982,-42020,-42059,-42097,-42136,-42174, + -42213,-42251,-42290,-42328,-42366,-42405,-42443,-42481, + -42520,-42558,-42596,-42634,-42672,-42711,-42749,-42787, + -42825,-42863,-42901,-42939,-42977,-43015,-43053,-43091, + -43128,-43166,-43204,-43242,-43280,-43317,-43355,-43393, + -43430,-43468,-43506,-43543,-43581,-43618,-43656,-43693, + -43731,-43768,-43806,-43843,-43880,-43918,-43955,-43992, + -44029,-44067,-44104,-44141,-44178,-44215,-44252,-44289, + -44326,-44363,-44400,-44437,-44474,-44511,-44548,-44585, + -44622,-44659,-44695,-44732,-44769,-44806,-44842,-44879, + -44915,-44952,-44989,-45025,-45062,-45098,-45135,-45171, + -45207,-45244,-45280,-45316,-45353,-45389,-45425,-45462, + -45498,-45534,-45570,-45606,-45642,-45678,-45714,-45750, + -45786,-45822,-45858,-45894,-45930,-45966,-46002,-46037, + -46073,-46109,-46145,-46180,-46216,-46252,-46287,-46323, + -46358,-46394,-46429,-46465,-46500,-46536,-46571,-46606, + -46642,-46677,-46712,-46747,-46783,-46818,-46853,-46888, + -46923,-46958,-46993,-47028,-47063,-47098,-47133,-47168, + -47203,-47238,-47273,-47308,-47342,-47377,-47412,-47446, + -47481,-47516,-47550,-47585,-47619,-47654,-47688,-47723, + -47757,-47792,-47826,-47860,-47895,-47929,-47963,-47998, + -48032,-48066,-48100,-48134,-48168,-48202,-48236,-48271, + -48304,-48338,-48372,-48406,-48440,-48474,-48508,-48542, + -48575,-48609,-48643,-48676,-48710,-48744,-48777,-48811, + -48844,-48878,-48911,-48945,-48978,-49012,-49045,-49078, + -49112,-49145,-49178,-49211,-49244,-49278,-49311,-49344, + -49377,-49410,-49443,-49476,-49509,-49542,-49575,-49608, + -49640,-49673,-49706,-49739,-49771,-49804,-49837,-49869, + -49902,-49935,-49967,-50000,-50032,-50065,-50097,-50129, + -50162,-50194,-50226,-50259,-50291,-50323,-50355,-50387, + -50420,-50452,-50484,-50516,-50548,-50580,-50612,-50644, + -50675,-50707,-50739,-50771,-50803,-50834,-50866,-50898, + -50929,-50961,-50993,-51024,-51056,-51087,-51119,-51150, + -51182,-51213,-51244,-51276,-51307,-51338,-51369,-51401, + -51432,-51463,-51494,-51525,-51556,-51587,-51618,-51649, + -51680,-51711,-51742,-51773,-51803,-51834,-51865,-51896, + -51926,-51957,-51988,-52018,-52049,-52079,-52110,-52140, + -52171,-52201,-52231,-52262,-52292,-52322,-52353,-52383, + -52413,-52443,-52473,-52503,-52534,-52564,-52594,-52624, + -52653,-52683,-52713,-52743,-52773,-52803,-52832,-52862, + -52892,-52922,-52951,-52981,-53010,-53040,-53069,-53099, + -53128,-53158,-53187,-53216,-53246,-53275,-53304,-53334, + -53363,-53392,-53421,-53450,-53479,-53508,-53537,-53566, + -53595,-53624,-53653,-53682,-53711,-53739,-53768,-53797, + -53826,-53854,-53883,-53911,-53940,-53969,-53997,-54026, + -54054,-54082,-54111,-54139,-54167,-54196,-54224,-54252, + -54280,-54308,-54337,-54365,-54393,-54421,-54449,-54477, + -54505,-54533,-54560,-54588,-54616,-54644,-54672,-54699, + -54727,-54755,-54782,-54810,-54837,-54865,-54892,-54920, + -54947,-54974,-55002,-55029,-55056,-55084,-55111,-55138, + -55165,-55192,-55219,-55246,-55274,-55300,-55327,-55354, + -55381,-55408,-55435,-55462,-55489,-55515,-55542,-55569, + -55595,-55622,-55648,-55675,-55701,-55728,-55754,-55781, + -55807,-55833,-55860,-55886,-55912,-55938,-55965,-55991, + -56017,-56043,-56069,-56095,-56121,-56147,-56173,-56199, + -56225,-56250,-56276,-56302,-56328,-56353,-56379,-56404, + -56430,-56456,-56481,-56507,-56532,-56557,-56583,-56608, + -56633,-56659,-56684,-56709,-56734,-56760,-56785,-56810, + -56835,-56860,-56885,-56910,-56935,-56959,-56984,-57009, + -57034,-57059,-57083,-57108,-57133,-57157,-57182,-57206, + -57231,-57255,-57280,-57304,-57329,-57353,-57377,-57402, + -57426,-57450,-57474,-57498,-57522,-57546,-57570,-57594, + -57618,-57642,-57666,-57690,-57714,-57738,-57762,-57785, + -57809,-57833,-57856,-57880,-57903,-57927,-57950,-57974, + -57997,-58021,-58044,-58067,-58091,-58114,-58137,-58160, + -58183,-58207,-58230,-58253,-58276,-58299,-58322,-58345, + -58367,-58390,-58413,-58436,-58459,-58481,-58504,-58527, + -58549,-58572,-58594,-58617,-58639,-58662,-58684,-58706, + -58729,-58751,-58773,-58795,-58818,-58840,-58862,-58884, + -58906,-58928,-58950,-58972,-58994,-59016,-59038,-59059, + -59081,-59103,-59125,-59146,-59168,-59190,-59211,-59233, + -59254,-59276,-59297,-59318,-59340,-59361,-59382,-59404, + -59425,-59446,-59467,-59488,-59509,-59530,-59551,-59572, + -59593,-59614,-59635,-59656,-59677,-59697,-59718,-59739, + -59759,-59780,-59801,-59821,-59842,-59862,-59883,-59903, + -59923,-59944,-59964,-59984,-60004,-60025,-60045,-60065, + -60085,-60105,-60125,-60145,-60165,-60185,-60205,-60225, + -60244,-60264,-60284,-60304,-60323,-60343,-60363,-60382, + -60402,-60421,-60441,-60460,-60479,-60499,-60518,-60537, + -60556,-60576,-60595,-60614,-60633,-60652,-60671,-60690, + -60709,-60728,-60747,-60766,-60785,-60803,-60822,-60841, + -60859,-60878,-60897,-60915,-60934,-60952,-60971,-60989, + -61007,-61026,-61044,-61062,-61081,-61099,-61117,-61135, + -61153,-61171,-61189,-61207,-61225,-61243,-61261,-61279, + -61297,-61314,-61332,-61350,-61367,-61385,-61403,-61420, + -61438,-61455,-61473,-61490,-61507,-61525,-61542,-61559, + -61577,-61594,-61611,-61628,-61645,-61662,-61679,-61696, + -61713,-61730,-61747,-61764,-61780,-61797,-61814,-61831, + -61847,-61864,-61880,-61897,-61913,-61930,-61946,-61963, + -61979,-61995,-62012,-62028,-62044,-62060,-62076,-62092, + -62108,-62125,-62141,-62156,-62172,-62188,-62204,-62220, + -62236,-62251,-62267,-62283,-62298,-62314,-62329,-62345, + -62360,-62376,-62391,-62407,-62422,-62437,-62453,-62468, + -62483,-62498,-62513,-62528,-62543,-62558,-62573,-62588, + -62603,-62618,-62633,-62648,-62662,-62677,-62692,-62706, + -62721,-62735,-62750,-62764,-62779,-62793,-62808,-62822, + -62836,-62850,-62865,-62879,-62893,-62907,-62921,-62935, + -62949,-62963,-62977,-62991,-63005,-63019,-63032,-63046, + -63060,-63074,-63087,-63101,-63114,-63128,-63141,-63155, + -63168,-63182,-63195,-63208,-63221,-63235,-63248,-63261, + -63274,-63287,-63300,-63313,-63326,-63339,-63352,-63365, + -63378,-63390,-63403,-63416,-63429,-63441,-63454,-63466, + -63479,-63491,-63504,-63516,-63528,-63541,-63553,-63565, + -63578,-63590,-63602,-63614,-63626,-63638,-63650,-63662, + -63674,-63686,-63698,-63709,-63721,-63733,-63745,-63756, + -63768,-63779,-63791,-63803,-63814,-63825,-63837,-63848, + -63859,-63871,-63882,-63893,-63904,-63915,-63927,-63938, + -63949,-63960,-63971,-63981,-63992,-64003,-64014,-64025, + -64035,-64046,-64057,-64067,-64078,-64088,-64099,-64109, + -64120,-64130,-64140,-64151,-64161,-64171,-64181,-64192, + -64202,-64212,-64222,-64232,-64242,-64252,-64261,-64271, + -64281,-64291,-64301,-64310,-64320,-64330,-64339,-64349, + -64358,-64368,-64377,-64387,-64396,-64405,-64414,-64424, + -64433,-64442,-64451,-64460,-64469,-64478,-64487,-64496, + -64505,-64514,-64523,-64532,-64540,-64549,-64558,-64566, + -64575,-64584,-64592,-64601,-64609,-64617,-64626,-64634, + -64642,-64651,-64659,-64667,-64675,-64683,-64691,-64699, + -64707,-64715,-64723,-64731,-64739,-64747,-64754,-64762, + -64770,-64777,-64785,-64793,-64800,-64808,-64815,-64822, + -64830,-64837,-64844,-64852,-64859,-64866,-64873,-64880, + -64887,-64895,-64902,-64908,-64915,-64922,-64929,-64936, + -64943,-64949,-64956,-64963,-64969,-64976,-64982,-64989, + -64995,-65002,-65008,-65015,-65021,-65027,-65033,-65040, + -65046,-65052,-65058,-65064,-65070,-65076,-65082,-65088, + -65094,-65099,-65105,-65111,-65117,-65122,-65128,-65133, + -65139,-65144,-65150,-65155,-65161,-65166,-65171,-65177, + -65182,-65187,-65192,-65197,-65202,-65207,-65212,-65217, + -65222,-65227,-65232,-65237,-65242,-65246,-65251,-65256, + -65260,-65265,-65270,-65274,-65279,-65283,-65287,-65292, + -65296,-65300,-65305,-65309,-65313,-65317,-65321,-65325, + -65329,-65333,-65337,-65341,-65345,-65349,-65352,-65356, + -65360,-65363,-65367,-65371,-65374,-65378,-65381,-65385, + -65388,-65391,-65395,-65398,-65401,-65404,-65408,-65411, + -65414,-65417,-65420,-65423,-65426,-65429,-65431,-65434, + -65437,-65440,-65442,-65445,-65448,-65450,-65453,-65455, + -65458,-65460,-65463,-65465,-65467,-65470,-65472,-65474, + -65476,-65478,-65480,-65482,-65484,-65486,-65488,-65490, + -65492,-65494,-65496,-65497,-65499,-65501,-65502,-65504, + -65505,-65507,-65508,-65510,-65511,-65513,-65514,-65515, + -65516,-65518,-65519,-65520,-65521,-65522,-65523,-65524, + -65525,-65526,-65527,-65527,-65528,-65529,-65530,-65530, + -65531,-65531,-65532,-65532,-65533,-65533,-65534,-65534, + -65534,-65535,-65535,-65535,-65535,-65535,-65535,-65535, + -65535,-65535,-65535,-65535,-65535,-65535,-65535,-65534, + -65534,-65534,-65533,-65533,-65532,-65532,-65531,-65531, + -65530,-65530,-65529,-65528,-65527,-65527,-65526,-65525, + -65524,-65523,-65522,-65521,-65520,-65519,-65518,-65516, + -65515,-65514,-65513,-65511,-65510,-65508,-65507,-65505, + -65504,-65502,-65501,-65499,-65497,-65496,-65494,-65492, + -65490,-65488,-65486,-65484,-65482,-65480,-65478,-65476, + -65474,-65472,-65470,-65467,-65465,-65463,-65460,-65458, + -65455,-65453,-65450,-65448,-65445,-65442,-65440,-65437, + -65434,-65431,-65429,-65426,-65423,-65420,-65417,-65414, + -65411,-65408,-65404,-65401,-65398,-65395,-65391,-65388, + -65385,-65381,-65378,-65374,-65371,-65367,-65363,-65360, + -65356,-65352,-65349,-65345,-65341,-65337,-65333,-65329, + -65325,-65321,-65317,-65313,-65309,-65305,-65300,-65296, + -65292,-65287,-65283,-65279,-65274,-65270,-65265,-65260, + -65256,-65251,-65246,-65242,-65237,-65232,-65227,-65222, + -65217,-65212,-65207,-65202,-65197,-65192,-65187,-65182, + -65177,-65171,-65166,-65161,-65155,-65150,-65144,-65139, + -65133,-65128,-65122,-65117,-65111,-65105,-65099,-65094, + -65088,-65082,-65076,-65070,-65064,-65058,-65052,-65046, + -65040,-65033,-65027,-65021,-65015,-65008,-65002,-64995, + -64989,-64982,-64976,-64969,-64963,-64956,-64949,-64943, + -64936,-64929,-64922,-64915,-64908,-64902,-64895,-64887, + -64880,-64873,-64866,-64859,-64852,-64844,-64837,-64830, + -64822,-64815,-64808,-64800,-64793,-64785,-64777,-64770, + -64762,-64754,-64747,-64739,-64731,-64723,-64715,-64707, + -64699,-64691,-64683,-64675,-64667,-64659,-64651,-64642, + -64634,-64626,-64617,-64609,-64601,-64592,-64584,-64575, + -64566,-64558,-64549,-64540,-64532,-64523,-64514,-64505, + -64496,-64487,-64478,-64469,-64460,-64451,-64442,-64433, + -64424,-64414,-64405,-64396,-64387,-64377,-64368,-64358, + -64349,-64339,-64330,-64320,-64310,-64301,-64291,-64281, + -64271,-64261,-64252,-64242,-64232,-64222,-64212,-64202, + -64192,-64181,-64171,-64161,-64151,-64140,-64130,-64120, + -64109,-64099,-64088,-64078,-64067,-64057,-64046,-64035, + -64025,-64014,-64003,-63992,-63981,-63971,-63960,-63949, + -63938,-63927,-63915,-63904,-63893,-63882,-63871,-63859, + -63848,-63837,-63825,-63814,-63803,-63791,-63779,-63768, + -63756,-63745,-63733,-63721,-63709,-63698,-63686,-63674, + -63662,-63650,-63638,-63626,-63614,-63602,-63590,-63578, + -63565,-63553,-63541,-63528,-63516,-63504,-63491,-63479, + -63466,-63454,-63441,-63429,-63416,-63403,-63390,-63378, + -63365,-63352,-63339,-63326,-63313,-63300,-63287,-63274, + -63261,-63248,-63235,-63221,-63208,-63195,-63182,-63168, + -63155,-63141,-63128,-63114,-63101,-63087,-63074,-63060, + -63046,-63032,-63019,-63005,-62991,-62977,-62963,-62949, + -62935,-62921,-62907,-62893,-62879,-62865,-62850,-62836, + -62822,-62808,-62793,-62779,-62764,-62750,-62735,-62721, + -62706,-62692,-62677,-62662,-62648,-62633,-62618,-62603, + -62588,-62573,-62558,-62543,-62528,-62513,-62498,-62483, + -62468,-62453,-62437,-62422,-62407,-62391,-62376,-62360, + -62345,-62329,-62314,-62298,-62283,-62267,-62251,-62236, + -62220,-62204,-62188,-62172,-62156,-62141,-62125,-62108, + -62092,-62076,-62060,-62044,-62028,-62012,-61995,-61979, + -61963,-61946,-61930,-61913,-61897,-61880,-61864,-61847, + -61831,-61814,-61797,-61780,-61764,-61747,-61730,-61713, + -61696,-61679,-61662,-61645,-61628,-61611,-61594,-61577, + -61559,-61542,-61525,-61507,-61490,-61473,-61455,-61438, + -61420,-61403,-61385,-61367,-61350,-61332,-61314,-61297, + -61279,-61261,-61243,-61225,-61207,-61189,-61171,-61153, + -61135,-61117,-61099,-61081,-61062,-61044,-61026,-61007, + -60989,-60971,-60952,-60934,-60915,-60897,-60878,-60859, + -60841,-60822,-60803,-60785,-60766,-60747,-60728,-60709, + -60690,-60671,-60652,-60633,-60614,-60595,-60576,-60556, + -60537,-60518,-60499,-60479,-60460,-60441,-60421,-60402, + -60382,-60363,-60343,-60323,-60304,-60284,-60264,-60244, + -60225,-60205,-60185,-60165,-60145,-60125,-60105,-60085, + -60065,-60045,-60025,-60004,-59984,-59964,-59944,-59923, + -59903,-59883,-59862,-59842,-59821,-59801,-59780,-59759, + -59739,-59718,-59697,-59677,-59656,-59635,-59614,-59593, + -59572,-59551,-59530,-59509,-59488,-59467,-59446,-59425, + -59404,-59382,-59361,-59340,-59318,-59297,-59276,-59254, + -59233,-59211,-59189,-59168,-59146,-59125,-59103,-59081, + -59059,-59038,-59016,-58994,-58972,-58950,-58928,-58906, + -58884,-58862,-58840,-58818,-58795,-58773,-58751,-58729, + -58706,-58684,-58662,-58639,-58617,-58594,-58572,-58549, + -58527,-58504,-58481,-58459,-58436,-58413,-58390,-58367, + -58345,-58322,-58299,-58276,-58253,-58230,-58207,-58183, + -58160,-58137,-58114,-58091,-58067,-58044,-58021,-57997, + -57974,-57950,-57927,-57903,-57880,-57856,-57833,-57809, + -57785,-57762,-57738,-57714,-57690,-57666,-57642,-57618, + -57594,-57570,-57546,-57522,-57498,-57474,-57450,-57426, + -57402,-57377,-57353,-57329,-57304,-57280,-57255,-57231, + -57206,-57182,-57157,-57133,-57108,-57083,-57059,-57034, + -57009,-56984,-56959,-56935,-56910,-56885,-56860,-56835, + -56810,-56785,-56760,-56734,-56709,-56684,-56659,-56633, + -56608,-56583,-56557,-56532,-56507,-56481,-56456,-56430, + -56404,-56379,-56353,-56328,-56302,-56276,-56250,-56225, + -56199,-56173,-56147,-56121,-56095,-56069,-56043,-56017, + -55991,-55965,-55938,-55912,-55886,-55860,-55833,-55807, + -55781,-55754,-55728,-55701,-55675,-55648,-55622,-55595, + -55569,-55542,-55515,-55489,-55462,-55435,-55408,-55381, + -55354,-55327,-55300,-55274,-55246,-55219,-55192,-55165, + -55138,-55111,-55084,-55056,-55029,-55002,-54974,-54947, + -54920,-54892,-54865,-54837,-54810,-54782,-54755,-54727, + -54699,-54672,-54644,-54616,-54588,-54560,-54533,-54505, + -54477,-54449,-54421,-54393,-54365,-54337,-54308,-54280, + -54252,-54224,-54196,-54167,-54139,-54111,-54082,-54054, + -54026,-53997,-53969,-53940,-53911,-53883,-53854,-53826, + -53797,-53768,-53739,-53711,-53682,-53653,-53624,-53595, + -53566,-53537,-53508,-53479,-53450,-53421,-53392,-53363, + -53334,-53304,-53275,-53246,-53216,-53187,-53158,-53128, + -53099,-53069,-53040,-53010,-52981,-52951,-52922,-52892, + -52862,-52832,-52803,-52773,-52743,-52713,-52683,-52653, + -52624,-52594,-52564,-52534,-52503,-52473,-52443,-52413, + -52383,-52353,-52322,-52292,-52262,-52231,-52201,-52171, + -52140,-52110,-52079,-52049,-52018,-51988,-51957,-51926, + -51896,-51865,-51834,-51803,-51773,-51742,-51711,-51680, + -51649,-51618,-51587,-51556,-51525,-51494,-51463,-51432, + -51401,-51369,-51338,-51307,-51276,-51244,-51213,-51182, + -51150,-51119,-51087,-51056,-51024,-50993,-50961,-50929, + -50898,-50866,-50834,-50803,-50771,-50739,-50707,-50675, + -50644,-50612,-50580,-50548,-50516,-50484,-50452,-50420, + -50387,-50355,-50323,-50291,-50259,-50226,-50194,-50162, + -50129,-50097,-50065,-50032,-50000,-49967,-49935,-49902, + -49869,-49837,-49804,-49771,-49739,-49706,-49673,-49640, + -49608,-49575,-49542,-49509,-49476,-49443,-49410,-49377, + -49344,-49311,-49278,-49244,-49211,-49178,-49145,-49112, + -49078,-49045,-49012,-48978,-48945,-48911,-48878,-48844, + -48811,-48777,-48744,-48710,-48676,-48643,-48609,-48575, + -48542,-48508,-48474,-48440,-48406,-48372,-48338,-48305, + -48271,-48237,-48202,-48168,-48134,-48100,-48066,-48032, + -47998,-47963,-47929,-47895,-47860,-47826,-47792,-47757, + -47723,-47688,-47654,-47619,-47585,-47550,-47516,-47481, + -47446,-47412,-47377,-47342,-47307,-47273,-47238,-47203, + -47168,-47133,-47098,-47063,-47028,-46993,-46958,-46923, + -46888,-46853,-46818,-46783,-46747,-46712,-46677,-46642, + -46606,-46571,-46536,-46500,-46465,-46429,-46394,-46358, + -46323,-46287,-46251,-46216,-46180,-46145,-46109,-46073, + -46037,-46002,-45966,-45930,-45894,-45858,-45822,-45786, + -45750,-45714,-45678,-45642,-45606,-45570,-45534,-45498, + -45462,-45425,-45389,-45353,-45316,-45280,-45244,-45207, + -45171,-45135,-45098,-45062,-45025,-44989,-44952,-44915, + -44879,-44842,-44806,-44769,-44732,-44695,-44659,-44622, + -44585,-44548,-44511,-44474,-44437,-44400,-44363,-44326, + -44289,-44252,-44215,-44178,-44141,-44104,-44067,-44029, + -43992,-43955,-43918,-43880,-43843,-43806,-43768,-43731, + -43693,-43656,-43618,-43581,-43543,-43506,-43468,-43430, + -43393,-43355,-43317,-43280,-43242,-43204,-43166,-43128, + -43091,-43053,-43015,-42977,-42939,-42901,-42863,-42825, + -42787,-42749,-42711,-42672,-42634,-42596,-42558,-42520, + -42481,-42443,-42405,-42366,-42328,-42290,-42251,-42213, + -42174,-42136,-42097,-42059,-42020,-41982,-41943,-41904, + -41866,-41827,-41788,-41750,-41711,-41672,-41633,-41595, + -41556,-41517,-41478,-41439,-41400,-41361,-41322,-41283, + -41244,-41205,-41166,-41127,-41087,-41048,-41009,-40970, + -40931,-40891,-40852,-40813,-40773,-40734,-40695,-40655, + -40616,-40576,-40537,-40497,-40458,-40418,-40379,-40339, + -40299,-40260,-40220,-40180,-40141,-40101,-40061,-40021, + -39982,-39942,-39902,-39862,-39822,-39782,-39742,-39702, + -39662,-39622,-39582,-39542,-39502,-39462,-39422,-39382, + -39341,-39301,-39261,-39221,-39180,-39140,-39100,-39059, + -39019,-38979,-38938,-38898,-38857,-38817,-38776,-38736, + -38695,-38655,-38614,-38573,-38533,-38492,-38451,-38411, + -38370,-38329,-38288,-38248,-38207,-38166,-38125,-38084, + -38043,-38002,-37961,-37920,-37879,-37838,-37797,-37756, + -37715,-37674,-37633,-37592,-37550,-37509,-37468,-37427, + -37386,-37344,-37303,-37262,-37220,-37179,-37137,-37096, + -37055,-37013,-36972,-36930,-36889,-36847,-36805,-36764, + -36722,-36681,-36639,-36597,-36556,-36514,-36472,-36430, + -36388,-36347,-36305,-36263,-36221,-36179,-36137,-36095, + -36053,-36011,-35969,-35927,-35885,-35843,-35801,-35759, + -35717,-35675,-35633,-35590,-35548,-35506,-35464,-35421, + -35379,-35337,-35294,-35252,-35210,-35167,-35125,-35082, + -35040,-34997,-34955,-34912,-34870,-34827,-34785,-34742, + -34699,-34657,-34614,-34571,-34529,-34486,-34443,-34400, + -34358,-34315,-34272,-34229,-34186,-34143,-34100,-34057, + -34015,-33972,-33929,-33886,-33843,-33799,-33756,-33713, + -33670,-33627,-33584,-33541,-33498,-33454,-33411,-33368, + -33325,-33281,-33238,-33195,-33151,-33108,-33065,-33021, + -32978,-32934,-32891,-32847,-32804,-32760,-32717,-32673, + -32630,-32586,-32542,-32499,-32455,-32411,-32368,-32324, + -32280,-32236,-32193,-32149,-32105,-32061,-32017,-31974, + -31930,-31886,-31842,-31798,-31754,-31710,-31666,-31622, + -31578,-31534,-31490,-31446,-31402,-31357,-31313,-31269, + -31225,-31181,-31136,-31092,-31048,-31004,-30959,-30915, + -30871,-30826,-30782,-30738,-30693,-30649,-30604,-30560, + -30515,-30471,-30426,-30382,-30337,-30293,-30248,-30204, + -30159,-30114,-30070,-30025,-29980,-29936,-29891,-29846, + -29801,-29757,-29712,-29667,-29622,-29577,-29533,-29488, + -29443,-29398,-29353,-29308,-29263,-29218,-29173,-29128, + -29083,-29038,-28993,-28948,-28903,-28858,-28812,-28767, + -28722,-28677,-28632,-28586,-28541,-28496,-28451,-28405, + -28360,-28315,-28269,-28224,-28179,-28133,-28088,-28042, + -27997,-27952,-27906,-27861,-27815,-27770,-27724,-27678, + -27633,-27587,-27542,-27496,-27450,-27405,-27359,-27313, + -27268,-27222,-27176,-27131,-27085,-27039,-26993,-26947, + -26902,-26856,-26810,-26764,-26718,-26672,-26626,-26580, + -26534,-26488,-26442,-26396,-26350,-26304,-26258,-26212, + -26166,-26120,-26074,-26028,-25982,-25936,-25889,-25843, + -25797,-25751,-25705,-25658,-25612,-25566,-25520,-25473, + -25427,-25381,-25334,-25288,-25241,-25195,-25149,-25102, + -25056,-25009,-24963,-24916,-24870,-24823,-24777,-24730, + -24684,-24637,-24591,-24544,-24497,-24451,-24404,-24357, + -24311,-24264,-24217,-24171,-24124,-24077,-24030,-23984, + -23937,-23890,-23843,-23796,-23750,-23703,-23656,-23609, + -23562,-23515,-23468,-23421,-23374,-23327,-23280,-23233, + -23186,-23139,-23092,-23045,-22998,-22951,-22904,-22857, + -22810,-22763,-22716,-22668,-22621,-22574,-22527,-22480, + -22432,-22385,-22338,-22291,-22243,-22196,-22149,-22102, + -22054,-22007,-21960,-21912,-21865,-21817,-21770,-21723, + -21675,-21628,-21580,-21533,-21485,-21438,-21390,-21343, + -21295,-21248,-21200,-21153,-21105,-21057,-21010,-20962, + -20915,-20867,-20819,-20772,-20724,-20676,-20629,-20581, + -20533,-20485,-20438,-20390,-20342,-20294,-20246,-20199, + -20151,-20103,-20055,-20007,-19959,-19912,-19864,-19816, + -19768,-19720,-19672,-19624,-19576,-19528,-19480,-19432, + -19384,-19336,-19288,-19240,-19192,-19144,-19096,-19048, + -19000,-18951,-18903,-18855,-18807,-18759,-18711,-18663, + -18614,-18566,-18518,-18470,-18421,-18373,-18325,-18277, + -18228,-18180,-18132,-18084,-18035,-17987,-17939,-17890, + -17842,-17793,-17745,-17697,-17648,-17600,-17551,-17503, + -17455,-17406,-17358,-17309,-17261,-17212,-17164,-17115, + -17067,-17018,-16970,-16921,-16872,-16824,-16775,-16727, + -16678,-16629,-16581,-16532,-16484,-16435,-16386,-16338, + -16289,-16240,-16191,-16143,-16094,-16045,-15997,-15948, + -15899,-15850,-15802,-15753,-15704,-15655,-15606,-15557, + -15509,-15460,-15411,-15362,-15313,-15264,-15215,-15167, + -15118,-15069,-15020,-14971,-14922,-14873,-14824,-14775, + -14726,-14677,-14628,-14579,-14530,-14481,-14432,-14383, + -14334,-14285,-14236,-14187,-14138,-14089,-14040,-13990, + -13941,-13892,-13843,-13794,-13745,-13696,-13647,-13597, + -13548,-13499,-13450,-13401,-13351,-13302,-13253,-13204, + -13154,-13105,-13056,-13007,-12957,-12908,-12859,-12810, + -12760,-12711,-12662,-12612,-12563,-12514,-12464,-12415, + -12366,-12316,-12267,-12217,-12168,-12119,-12069,-12020, + -11970,-11921,-11872,-11822,-11773,-11723,-11674,-11624, + -11575,-11525,-11476,-11426,-11377,-11327,-11278,-11228, + -11179,-11129,-11080,-11030,-10981,-10931,-10882,-10832, + -10782,-10733,-10683,-10634,-10584,-10534,-10485,-10435, + -10386,-10336,-10286,-10237,-10187,-10137,-10088,-10038, + -9988,-9939,-9889,-9839,-9790,-9740,-9690,-9640, + -9591,-9541,-9491,-9442,-9392,-9342,-9292,-9243, + -9193,-9143,-9093,-9043,-8994,-8944,-8894,-8844, + -8794,-8745,-8695,-8645,-8595,-8545,-8496,-8446, + -8396,-8346,-8296,-8246,-8196,-8147,-8097,-8047, + -7997,-7947,-7897,-7847,-7797,-7747,-7697,-7648, + -7598,-7548,-7498,-7448,-7398,-7348,-7298,-7248, + -7198,-7148,-7098,-7048,-6998,-6948,-6898,-6848, + -6798,-6748,-6698,-6648,-6598,-6548,-6498,-6448, + -6398,-6348,-6298,-6248,-6198,-6148,-6098,-6048, + -5998,-5948,-5898,-5848,-5798,-5747,-5697,-5647, + -5597,-5547,-5497,-5447,-5397,-5347,-5297,-5247, + -5197,-5146,-5096,-5046,-4996,-4946,-4896,-4846, + -4796,-4745,-4695,-4645,-4595,-4545,-4495,-4445, + -4394,-4344,-4294,-4244,-4194,-4144,-4093,-4043, + -3993,-3943,-3893,-3843,-3792,-3742,-3692,-3642, + -3592,-3541,-3491,-3441,-3391,-3341,-3291,-3240, + -3190,-3140,-3090,-3039,-2989,-2939,-2889,-2839, + -2788,-2738,-2688,-2638,-2588,-2537,-2487,-2437, + -2387,-2336,-2286,-2236,-2186,-2135,-2085,-2035, + -1985,-1934,-1884,-1834,-1784,-1733,-1683,-1633, + -1583,-1532,-1482,-1432,-1382,-1331,-1281,-1231, + -1181,-1130,-1080,-1030,-980,-929,-879,-829, + -779,-728,-678,-628,-578,-527,-477,-427, + -376,-326,-276,-226,-175,-125,-75,-25, + 25,75,125,175,226,276,326,376, + 427,477,527,578,628,678,728,779, + 829,879,929,980,1030,1080,1130,1181, + 1231,1281,1331,1382,1432,1482,1532,1583, + 1633,1683,1733,1784,1834,1884,1934,1985, + 2035,2085,2135,2186,2236,2286,2336,2387, + 2437,2487,2537,2587,2638,2688,2738,2788, + 2839,2889,2939,2989,3039,3090,3140,3190, + 3240,3291,3341,3391,3441,3491,3542,3592, + 3642,3692,3742,3792,3843,3893,3943,3993, + 4043,4093,4144,4194,4244,4294,4344,4394, + 4445,4495,4545,4595,4645,4695,4745,4796, + 4846,4896,4946,4996,5046,5096,5146,5197, + 5247,5297,5347,5397,5447,5497,5547,5597, + 5647,5697,5747,5798,5848,5898,5948,5998, + 6048,6098,6148,6198,6248,6298,6348,6398, + 6448,6498,6548,6598,6648,6698,6748,6798, + 6848,6898,6948,6998,7048,7098,7148,7198, + 7248,7298,7348,7398,7448,7498,7548,7598, + 7648,7697,7747,7797,7847,7897,7947,7997, + 8047,8097,8147,8196,8246,8296,8346,8396, + 8446,8496,8545,8595,8645,8695,8745,8794, + 8844,8894,8944,8994,9043,9093,9143,9193, + 9243,9292,9342,9392,9442,9491,9541,9591, + 9640,9690,9740,9790,9839,9889,9939,9988, + 10038,10088,10137,10187,10237,10286,10336,10386, + 10435,10485,10534,10584,10634,10683,10733,10782, + 10832,10882,10931,10981,11030,11080,11129,11179, + 11228,11278,11327,11377,11426,11476,11525,11575, + 11624,11674,11723,11773,11822,11872,11921,11970, + 12020,12069,12119,12168,12218,12267,12316,12366, + 12415,12464,12514,12563,12612,12662,12711,12760, + 12810,12859,12908,12957,13007,13056,13105,13154, + 13204,13253,13302,13351,13401,13450,13499,13548, + 13597,13647,13696,13745,13794,13843,13892,13941, + 13990,14040,14089,14138,14187,14236,14285,14334, + 14383,14432,14481,14530,14579,14628,14677,14726, + 14775,14824,14873,14922,14971,15020,15069,15118, + 15167,15215,15264,15313,15362,15411,15460,15509, + 15557,15606,15655,15704,15753,15802,15850,15899, + 15948,15997,16045,16094,16143,16191,16240,16289, + 16338,16386,16435,16484,16532,16581,16629,16678, + 16727,16775,16824,16872,16921,16970,17018,17067, + 17115,17164,17212,17261,17309,17358,17406,17455, + 17503,17551,17600,17648,17697,17745,17793,17842, + 17890,17939,17987,18035,18084,18132,18180,18228, + 18277,18325,18373,18421,18470,18518,18566,18614, + 18663,18711,18759,18807,18855,18903,18951,19000, + 19048,19096,19144,19192,19240,19288,19336,19384, + 19432,19480,19528,19576,19624,19672,19720,19768, + 19816,19864,19912,19959,20007,20055,20103,20151, + 20199,20246,20294,20342,20390,20438,20485,20533, + 20581,20629,20676,20724,20772,20819,20867,20915, + 20962,21010,21057,21105,21153,21200,21248,21295, + 21343,21390,21438,21485,21533,21580,21628,21675, + 21723,21770,21817,21865,21912,21960,22007,22054, + 22102,22149,22196,22243,22291,22338,22385,22432, + 22480,22527,22574,22621,22668,22716,22763,22810, + 22857,22904,22951,22998,23045,23092,23139,23186, + 23233,23280,23327,23374,23421,23468,23515,23562, + 23609,23656,23703,23750,23796,23843,23890,23937, + 23984,24030,24077,24124,24171,24217,24264,24311, + 24357,24404,24451,24497,24544,24591,24637,24684, + 24730,24777,24823,24870,24916,24963,25009,25056, + 25102,25149,25195,25241,25288,25334,25381,25427, + 25473,25520,25566,25612,25658,25705,25751,25797, + 25843,25889,25936,25982,26028,26074,26120,26166, + 26212,26258,26304,26350,26396,26442,26488,26534, + 26580,26626,26672,26718,26764,26810,26856,26902, + 26947,26993,27039,27085,27131,27176,27222,27268, + 27313,27359,27405,27450,27496,27542,27587,27633, + 27678,27724,27770,27815,27861,27906,27952,27997, + 28042,28088,28133,28179,28224,28269,28315,28360, + 28405,28451,28496,28541,28586,28632,28677,28722, + 28767,28812,28858,28903,28948,28993,29038,29083, + 29128,29173,29218,29263,29308,29353,29398,29443, + 29488,29533,29577,29622,29667,29712,29757,29801, + 29846,29891,29936,29980,30025,30070,30114,30159, + 30204,30248,30293,30337,30382,30427,30471,30516, + 30560,30604,30649,30693,30738,30782,30826,30871, + 30915,30959,31004,31048,31092,31136,31181,31225, + 31269,31313,31357,31402,31446,31490,31534,31578, + 31622,31666,31710,31754,31798,31842,31886,31930, + 31974,32017,32061,32105,32149,32193,32236,32280, + 32324,32368,32411,32455,32499,32542,32586,32630, + 32673,32717,32760,32804,32847,32891,32934,32978, + 33021,33065,33108,33151,33195,33238,33281,33325, + 33368,33411,33454,33498,33541,33584,33627,33670, + 33713,33756,33799,33843,33886,33929,33972,34015, + 34057,34100,34143,34186,34229,34272,34315,34358, + 34400,34443,34486,34529,34571,34614,34657,34699, + 34742,34785,34827,34870,34912,34955,34997,35040, + 35082,35125,35167,35210,35252,35294,35337,35379, + 35421,35464,35506,35548,35590,35633,35675,35717, + 35759,35801,35843,35885,35927,35969,36011,36053, + 36095,36137,36179,36221,36263,36305,36347,36388, + 36430,36472,36514,36556,36597,36639,36681,36722, + 36764,36805,36847,36889,36930,36972,37013,37055, + 37096,37137,37179,37220,37262,37303,37344,37386, + 37427,37468,37509,37551,37592,37633,37674,37715, + 37756,37797,37838,37879,37920,37961,38002,38043, + 38084,38125,38166,38207,38248,38288,38329,38370, + 38411,38451,38492,38533,38573,38614,38655,38695, + 38736,38776,38817,38857,38898,38938,38979,39019, + 39059,39100,39140,39180,39221,39261,39301,39341, + 39382,39422,39462,39502,39542,39582,39622,39662, + 39702,39742,39782,39822,39862,39902,39942,39982, + 40021,40061,40101,40141,40180,40220,40260,40299, + 40339,40379,40418,40458,40497,40537,40576,40616, + 40655,40695,40734,40773,40813,40852,40891,40931, + 40970,41009,41048,41087,41127,41166,41205,41244, + 41283,41322,41361,41400,41439,41478,41517,41556, + 41595,41633,41672,41711,41750,41788,41827,41866, + 41904,41943,41982,42020,42059,42097,42136,42174, + 42213,42251,42290,42328,42366,42405,42443,42481, + 42520,42558,42596,42634,42672,42711,42749,42787, + 42825,42863,42901,42939,42977,43015,43053,43091, + 43128,43166,43204,43242,43280,43317,43355,43393, + 43430,43468,43506,43543,43581,43618,43656,43693, + 43731,43768,43806,43843,43880,43918,43955,43992, + 44029,44067,44104,44141,44178,44215,44252,44289, + 44326,44363,44400,44437,44474,44511,44548,44585, + 44622,44659,44695,44732,44769,44806,44842,44879, + 44915,44952,44989,45025,45062,45098,45135,45171, + 45207,45244,45280,45316,45353,45389,45425,45462, + 45498,45534,45570,45606,45642,45678,45714,45750, + 45786,45822,45858,45894,45930,45966,46002,46037, + 46073,46109,46145,46180,46216,46252,46287,46323, + 46358,46394,46429,46465,46500,46536,46571,46606, + 46642,46677,46712,46747,46783,46818,46853,46888, + 46923,46958,46993,47028,47063,47098,47133,47168, + 47203,47238,47273,47308,47342,47377,47412,47446, + 47481,47516,47550,47585,47619,47654,47688,47723, + 47757,47792,47826,47861,47895,47929,47963,47998, + 48032,48066,48100,48134,48168,48202,48237,48271, + 48305,48338,48372,48406,48440,48474,48508,48542, + 48575,48609,48643,48676,48710,48744,48777,48811, + 48844,48878,48911,48945,48978,49012,49045,49078, + 49112,49145,49178,49211,49244,49278,49311,49344, + 49377,49410,49443,49476,49509,49542,49575,49608, + 49640,49673,49706,49739,49771,49804,49837,49869, + 49902,49935,49967,50000,50032,50064,50097,50129, + 50162,50194,50226,50259,50291,50323,50355,50387, + 50420,50452,50484,50516,50548,50580,50612,50644, + 50675,50707,50739,50771,50803,50834,50866,50898, + 50929,50961,50993,51024,51056,51087,51119,51150, + 51182,51213,51244,51276,51307,51338,51369,51401, + 51432,51463,51494,51525,51556,51587,51618,51649, + 51680,51711,51742,51773,51803,51834,51865,51896, + 51926,51957,51988,52018,52049,52079,52110,52140, + 52171,52201,52231,52262,52292,52322,52353,52383, + 52413,52443,52473,52503,52534,52564,52594,52624, + 52653,52683,52713,52743,52773,52803,52832,52862, + 52892,52922,52951,52981,53010,53040,53069,53099, + 53128,53158,53187,53216,53246,53275,53304,53334, + 53363,53392,53421,53450,53479,53508,53537,53566, + 53595,53624,53653,53682,53711,53739,53768,53797, + 53826,53854,53883,53912,53940,53969,53997,54026, + 54054,54082,54111,54139,54167,54196,54224,54252, + 54280,54309,54337,54365,54393,54421,54449,54477, + 54505,54533,54560,54588,54616,54644,54672,54699, + 54727,54755,54782,54810,54837,54865,54892,54920, + 54947,54974,55002,55029,55056,55084,55111,55138, + 55165,55192,55219,55246,55274,55300,55327,55354, + 55381,55408,55435,55462,55489,55515,55542,55569, + 55595,55622,55648,55675,55701,55728,55754,55781, + 55807,55833,55860,55886,55912,55938,55965,55991, + 56017,56043,56069,56095,56121,56147,56173,56199, + 56225,56250,56276,56302,56328,56353,56379,56404, + 56430,56456,56481,56507,56532,56557,56583,56608, + 56633,56659,56684,56709,56734,56760,56785,56810, + 56835,56860,56885,56910,56935,56959,56984,57009, + 57034,57059,57083,57108,57133,57157,57182,57206, + 57231,57255,57280,57304,57329,57353,57377,57402, + 57426,57450,57474,57498,57522,57546,57570,57594, + 57618,57642,57666,57690,57714,57738,57762,57785, + 57809,57833,57856,57880,57903,57927,57950,57974, + 57997,58021,58044,58067,58091,58114,58137,58160, + 58183,58207,58230,58253,58276,58299,58322,58345, + 58367,58390,58413,58436,58459,58481,58504,58527, + 58549,58572,58594,58617,58639,58662,58684,58706, + 58729,58751,58773,58795,58818,58840,58862,58884, + 58906,58928,58950,58972,58994,59016,59038,59059, + 59081,59103,59125,59146,59168,59190,59211,59233, + 59254,59276,59297,59318,59340,59361,59382,59404, + 59425,59446,59467,59488,59509,59530,59551,59572, + 59593,59614,59635,59656,59677,59697,59718,59739, + 59759,59780,59801,59821,59842,59862,59883,59903, + 59923,59944,59964,59984,60004,60025,60045,60065, + 60085,60105,60125,60145,60165,60185,60205,60225, + 60244,60264,60284,60304,60323,60343,60363,60382, + 60402,60421,60441,60460,60479,60499,60518,60537, + 60556,60576,60595,60614,60633,60652,60671,60690, + 60709,60728,60747,60766,60785,60803,60822,60841, + 60859,60878,60897,60915,60934,60952,60971,60989, + 61007,61026,61044,61062,61081,61099,61117,61135, + 61153,61171,61189,61207,61225,61243,61261,61279, + 61297,61314,61332,61350,61367,61385,61403,61420, + 61438,61455,61473,61490,61507,61525,61542,61559, + 61577,61594,61611,61628,61645,61662,61679,61696, + 61713,61730,61747,61764,61780,61797,61814,61831, + 61847,61864,61880,61897,61913,61930,61946,61963, + 61979,61995,62012,62028,62044,62060,62076,62092, + 62108,62125,62141,62156,62172,62188,62204,62220, + 62236,62251,62267,62283,62298,62314,62329,62345, + 62360,62376,62391,62407,62422,62437,62453,62468, + 62483,62498,62513,62528,62543,62558,62573,62588, + 62603,62618,62633,62648,62662,62677,62692,62706, + 62721,62735,62750,62764,62779,62793,62808,62822, + 62836,62850,62865,62879,62893,62907,62921,62935, + 62949,62963,62977,62991,63005,63019,63032,63046, + 63060,63074,63087,63101,63114,63128,63141,63155, + 63168,63182,63195,63208,63221,63235,63248,63261, + 63274,63287,63300,63313,63326,63339,63352,63365, + 63378,63390,63403,63416,63429,63441,63454,63466, + 63479,63491,63504,63516,63528,63541,63553,63565, + 63578,63590,63602,63614,63626,63638,63650,63662, + 63674,63686,63698,63709,63721,63733,63745,63756, + 63768,63779,63791,63803,63814,63825,63837,63848, + 63859,63871,63882,63893,63904,63915,63927,63938, + 63949,63960,63971,63981,63992,64003,64014,64025, + 64035,64046,64057,64067,64078,64088,64099,64109, + 64120,64130,64140,64151,64161,64171,64181,64192, + 64202,64212,64222,64232,64242,64252,64261,64271, + 64281,64291,64301,64310,64320,64330,64339,64349, + 64358,64368,64377,64387,64396,64405,64414,64424, + 64433,64442,64451,64460,64469,64478,64487,64496, + 64505,64514,64523,64532,64540,64549,64558,64566, + 64575,64584,64592,64600,64609,64617,64626,64634, + 64642,64651,64659,64667,64675,64683,64691,64699, + 64707,64715,64723,64731,64739,64747,64754,64762, + 64770,64777,64785,64793,64800,64808,64815,64822, + 64830,64837,64844,64852,64859,64866,64873,64880, + 64887,64895,64902,64908,64915,64922,64929,64936, + 64943,64949,64956,64963,64969,64976,64982,64989, + 64995,65002,65008,65015,65021,65027,65033,65040, + 65046,65052,65058,65064,65070,65076,65082,65088, + 65094,65099,65105,65111,65117,65122,65128,65133, + 65139,65144,65150,65155,65161,65166,65171,65177, + 65182,65187,65192,65197,65202,65207,65212,65217, + 65222,65227,65232,65237,65242,65246,65251,65256, + 65260,65265,65270,65274,65279,65283,65287,65292, + 65296,65300,65305,65309,65313,65317,65321,65325, + 65329,65333,65337,65341,65345,65349,65352,65356, + 65360,65363,65367,65371,65374,65378,65381,65385, + 65388,65391,65395,65398,65401,65404,65408,65411, + 65414,65417,65420,65423,65426,65429,65431,65434, + 65437,65440,65442,65445,65448,65450,65453,65455, + 65458,65460,65463,65465,65467,65470,65472,65474, + 65476,65478,65480,65482,65484,65486,65488,65490, + 65492,65494,65496,65497,65499,65501,65502,65504, + 65505,65507,65508,65510,65511,65513,65514,65515, + 65516,65518,65519,65520,65521,65522,65523,65524, + 65525,65526,65527,65527,65528,65529,65530,65530, + 65531,65531,65532,65532,65533,65533,65534,65534, + 65534,65535,65535,65535,65535,65535,65535,65535 + }; +#endif + +#ifdef TABLES_AS_LUMPS +angle_t *tantoangle; +#else +const angle_t tantoangle[2049] = { + 0,333772,667544,1001315,1335086,1668857,2002626,2336395, + 2670163,3003929,3337694,3671457,4005219,4338979,4672736,5006492, + 5340245,5673995,6007743,6341488,6675230,7008968,7342704,7676435, + 8010164,8343888,8677609,9011325,9345037,9678744,10012447,10346145, + 10679838,11013526,11347209,11680887,12014558,12348225,12681885,13015539, + 13349187,13682829,14016464,14350092,14683714,15017328,15350936,15684536, + 16018129,16351714,16685291,17018860,17352422,17685974,18019518,18353054, + 18686582,19020100,19353610,19687110,20020600,20354080,20687552,21021014, + 21354466,21687906,22021338,22354758,22688168,23021568,23354956,23688332, + 24021698,24355052,24688396,25021726,25355046,25688352,26021648,26354930, + 26688200,27021456,27354702,27687932,28021150,28354356,28687548,29020724, + 29353888,29687038,30020174,30353296,30686404,31019496,31352574,31685636, + 32018684,32351718,32684734,33017736,33350722,33683692,34016648,34349584, + 34682508,35015412,35348300,35681172,36014028,36346868,36679688,37012492, + 37345276,37678044,38010792,38343524,38676240,39008936,39341612,39674272, + 40006912,40339532,40672132,41004716,41337276,41669820,42002344,42334848, + 42667332,42999796,43332236,43664660,43997060,44329444,44661800,44994140, + 45326456,45658752,45991028,46323280,46655512,46987720,47319908,47652072, + 47984212,48316332,48648428,48980500,49312548,49644576,49976580,50308556, + 50640512,50972444,51304352,51636236,51968096,52299928,52631740,52963524, + 53295284,53627020,53958728,54290412,54622068,54953704,55285308,55616888, + 55948444,56279972,56611472,56942948,57274396,57605816,57937212,58268576, + 58599916,58931228,59262512,59593768,59924992,60256192,60587364,60918508, + 61249620,61580704,61911760,62242788,62573788,62904756,63235692,63566604, + 63897480,64228332,64559148,64889940,65220696,65551424,65882120,66212788, + 66543420,66874024,67204600,67535136,67865648,68196120,68526568,68856984, + 69187360,69517712,69848024,70178304,70508560,70838776,71168960,71499112, + 71829224,72159312,72489360,72819376,73149360,73479304,73809216,74139096, + 74468936,74798744,75128520,75458264,75787968,76117632,76447264,76776864, + 77106424,77435952,77765440,78094888,78424304,78753688,79083032,79412336, + 79741608,80070840,80400032,80729192,81058312,81387392,81716432,82045440, + 82374408,82703336,83032224,83361080,83689896,84018664,84347400,84676096, + 85004760,85333376,85661952,85990488,86318984,86647448,86975864,87304240, + 87632576,87960872,88289128,88617344,88945520,89273648,89601736,89929792, + 90257792,90585760,90913688,91241568,91569408,91897200,92224960,92552672, + 92880336,93207968,93535552,93863088,94190584,94518040,94845448,95172816, + 95500136,95827416,96154648,96481832,96808976,97136080,97463136,97790144, + 98117112,98444032,98770904,99097736,99424520,99751256,100077944,100404592, + 100731192,101057744,101384248,101710712,102037128,102363488,102689808,103016080, + 103342312,103668488,103994616,104320696,104646736,104972720,105298656,105624552, + 105950392,106276184,106601928,106927624,107253272,107578872,107904416,108229920, + 108555368,108880768,109206120,109531416,109856664,110181872,110507016,110832120, + 111157168,111482168,111807112,112132008,112456856,112781648,113106392,113431080, + 113755720,114080312,114404848,114729328,115053760,115378136,115702464,116026744, + 116350960,116675128,116999248,117323312,117647320,117971272,118295176,118619024, + 118942816,119266560,119590248,119913880,120237456,120560984,120884456,121207864, + 121531224,121854528,122177784,122500976,122824112,123147200,123470224,123793200, + 124116120,124438976,124761784,125084528,125407224,125729856,126052432,126374960, + 126697424,127019832,127342184,127664472,127986712,128308888,128631008,128953072, + 129275080,129597024,129918912,130240744,130562520,130884232,131205888,131527480, + 131849016,132170496,132491912,132813272,133134576,133455816,133776992,134098120, + 134419184,134740176,135061120,135382000,135702816,136023584,136344272,136664912, + 136985488,137306016,137626464,137946864,138267184,138587456,138907664,139227808, + 139547904,139867920,140187888,140507776,140827616,141147392,141467104,141786752, + 142106336,142425856,142745312,143064720,143384048,143703312,144022512,144341664, + 144660736,144979744,145298704,145617584,145936400,146255168,146573856,146892480, + 147211040,147529536,147847968,148166336,148484640,148802880,149121056,149439152, + 149757200,150075168,150393072,150710912,151028688,151346400,151664048,151981616, + 152299136,152616576,152933952,153251264,153568496,153885680,154202784,154519824, + 154836784,155153696,155470528,155787296,156104000,156420624,156737200,157053696, + 157370112,157686480,158002768,158318976,158635136,158951216,159267232,159583168, + 159899040,160214848,160530592,160846256,161161840,161477376,161792832,162108208, + 162423520,162738768,163053952,163369040,163684080,163999040,164313936,164628752, + 164943504,165258176,165572784,165887312,166201776,166516160,166830480,167144736, + 167458912,167773008,168087040,168400992,168714880,169028688,169342432,169656096, + 169969696,170283216,170596672,170910032,171223344,171536576,171849728,172162800, + 172475808,172788736,173101600,173414384,173727104,174039728,174352288,174664784, + 174977200,175289536,175601792,175913984,176226096,176538144,176850096,177161984, + 177473792,177785536,178097200,178408784,178720288,179031728,179343088,179654368, + 179965568,180276704,180587744,180898720,181209616,181520448,181831184,182141856, + 182452448,182762960,183073408,183383760,183694048,184004240,184314368,184624416, + 184934400,185244288,185554096,185863840,186173504,186483072,186792576,187102000, + 187411344,187720608,188029808,188338912,188647936,188956896,189265760,189574560, + 189883264,190191904,190500448,190808928,191117312,191425632,191733872,192042016, + 192350096,192658096,192966000,193273840,193581584,193889264,194196848,194504352, + 194811792,195119136,195426400,195733584,196040688,196347712,196654656,196961520, + 197268304,197574992,197881616,198188144,198494592,198800960,199107248,199413456, + 199719584,200025616,200331584,200637456,200943248,201248960,201554576,201860128, + 202165584,202470960,202776256,203081456,203386592,203691632,203996592,204301472, + 204606256,204910976,205215600,205520144,205824592,206128960,206433248,206737456, + 207041584,207345616,207649568,207953424,208257216,208560912,208864512,209168048, + 209471488,209774832,210078112,210381296,210684384,210987408,211290336,211593184, + 211895936,212198608,212501184,212803680,213106096,213408432,213710672,214012816, + 214314880,214616864,214918768,215220576,215522288,215823920,216125472,216426928, + 216728304,217029584,217330784,217631904,217932928,218233856,218534704,218835472, + 219136144,219436720,219737216,220037632,220337952,220638192,220938336,221238384, + 221538352,221838240,222138032,222437728,222737344,223036880,223336304,223635664, + 223934912,224234096,224533168,224832160,225131072,225429872,225728608,226027232, + 226325776,226624240,226922608,227220880,227519056,227817152,228115168,228413088, + 228710912,229008640,229306288,229603840,229901312,230198688,230495968,230793152, + 231090256,231387280,231684192,231981024,232277760,232574416,232870960,233167440, + 233463808,233760096,234056288,234352384,234648384,234944304,235240128,235535872, + 235831504,236127056,236422512,236717888,237013152,237308336,237603424,237898416, + 238193328,238488144,238782864,239077488,239372016,239666464,239960816,240255072, + 240549232,240843312,241137280,241431168,241724960,242018656,242312256,242605776, + 242899200,243192512,243485744,243778896,244071936,244364880,244657744,244950496, + 245243168,245535744,245828224,246120608,246412912,246705104,246997216,247289216, + 247581136,247872960,248164688,248456320,248747856,249039296,249330640,249621904, + 249913056,250204128,250495088,250785968,251076736,251367424,251658016,251948512, + 252238912,252529200,252819408,253109520,253399536,253689456,253979280,254269008, + 254558640,254848176,255137632,255426976,255716224,256005376,256294432,256583392, + 256872256,257161024,257449696,257738272,258026752,258315136,258603424,258891600, + 259179696,259467696,259755600,260043392,260331104,260618704,260906224,261193632, + 261480960,261768176,262055296,262342320,262629248,262916080,263202816,263489456, + 263776000,264062432,264348784,264635024,264921168,265207216,265493168,265779024, + 266064784,266350448,266636000,266921472,267206832,267492096,267777264,268062336, + 268347312,268632192,268916960,269201632,269486208,269770688,270055072,270339360, + 270623552,270907616,271191616,271475488,271759296,272042976,272326560,272610048, + 272893440,273176736,273459936,273743040,274026048,274308928,274591744,274874432, + 275157024,275439520,275721920,276004224,276286432,276568512,276850528,277132416, + 277414240,277695936,277977536,278259040,278540448,278821728,279102944,279384032, + 279665056,279945952,280226752,280507456,280788064,281068544,281348960,281629248, + 281909472,282189568,282469568,282749440,283029248,283308960,283588544,283868032, + 284147424,284426720,284705920,284985024,285264000,285542912,285821696,286100384, + 286378976,286657440,286935840,287214112,287492320,287770400,288048384,288326240, + 288604032,288881696,289159264,289436768,289714112,289991392,290268576,290545632, + 290822592,291099456,291376224,291652896,291929440,292205888,292482272,292758528, + 293034656,293310720,293586656,293862496,294138240,294413888,294689440,294964864, + 295240192,295515424,295790560,296065600,296340512,296615360,296890080,297164704, + 297439200,297713632,297987936,298262144,298536256,298810240,299084160,299357952, + 299631648,299905248,300178720,300452128,300725408,300998592,301271680,301544640, + 301817536,302090304,302362976,302635520,302908000,303180352,303452608,303724768, + 303996800,304268768,304540608,304812320,305083968,305355520,305626944,305898272, + 306169472,306440608,306711616,306982528,307253344,307524064,307794656,308065152, + 308335552,308605856,308876032,309146112,309416096,309685984,309955744,310225408, + 310494976,310764448,311033824,311303072,311572224,311841280,312110208,312379040, + 312647776,312916416,313184960,313453376,313721696,313989920,314258016,314526016, + 314793920,315061728,315329408,315597024,315864512,316131872,316399168,316666336, + 316933408,317200384,317467232,317733984,318000640,318267200,318533632,318799968, + 319066208,319332352,319598368,319864288,320130112,320395808,320661408,320926912, + 321192320,321457632,321722816,321987904,322252864,322517760,322782528,323047200, + 323311744,323576192,323840544,324104800,324368928,324632992,324896928,325160736, + 325424448,325688096,325951584,326215008,326478304,326741504,327004608,327267584, + 327530464,327793248,328055904,328318496,328580960,328843296,329105568,329367712, + 329629760,329891680,330153536,330415264,330676864,330938400,331199808,331461120, + 331722304,331983392,332244384,332505280,332766048,333026752,333287296,333547776, + 333808128,334068384,334328544,334588576,334848512,335108352,335368064,335627712, + 335887200,336146624,336405920,336665120,336924224,337183200,337442112,337700864, + 337959552,338218112,338476576,338734944,338993184,339251328,339509376,339767296, + 340025120,340282848,340540480,340797984,341055392,341312704,341569888,341826976, + 342083968,342340832,342597600,342854272,343110848,343367296,343623648,343879904, + 344136032,344392064,344648000,344903808,345159520,345415136,345670656,345926048, + 346181344,346436512,346691616,346946592,347201440,347456224,347710880,347965440, + 348219872,348474208,348728448,348982592,349236608,349490528,349744320,349998048, + 350251648,350505152,350758528,351011808,351264992,351518048,351771040,352023872, + 352276640,352529280,352781824,353034272,353286592,353538816,353790944,354042944, + 354294880,354546656,354798368,355049952,355301440,355552800,355804096,356055264, + 356306304,356557280,356808128,357058848,357309504,357560032,357810464,358060768, + 358311008,358561088,358811104,359060992,359310784,359560480,359810048,360059520, + 360308896,360558144,360807296,361056352,361305312,361554144,361802880,362051488, + 362300032,362548448,362796736,363044960,363293056,363541024,363788928,364036704, + 364284384,364531936,364779392,365026752,365274016,365521152,365768192,366015136, + 366261952,366508672,366755296,367001792,367248192,367494496,367740704,367986784, + 368232768,368478656,368724416,368970080,369215648,369461088,369706432,369951680, + 370196800,370441824,370686752,370931584,371176288,371420896,371665408,371909792, + 372154080,372398272,372642336,372886304,373130176,373373952,373617600,373861152, + 374104608,374347936,374591168,374834304,375077312,375320224,375563040,375805760, + 376048352,376290848,376533248,376775520,377017696,377259776,377501728,377743584, + 377985344,378227008,378468544,378709984,378951328,379192544,379433664,379674688, + 379915584,380156416,380397088,380637696,380878176,381118560,381358848,381599040, + 381839104,382079072,382318912,382558656,382798304,383037856,383277280,383516640, + 383755840,383994976,384233984,384472896,384711712,384950400,385188992,385427488, + 385665888,385904160,386142336,386380384,386618368,386856224,387093984,387331616, + 387569152,387806592,388043936,388281152,388518272,388755296,388992224,389229024, + 389465728,389702336,389938816,390175200,390411488,390647680,390883744,391119712, + 391355584,391591328,391826976,392062528,392297984,392533312,392768544,393003680, + 393238720,393473632,393708448,393943168,394177760,394412256,394646656,394880960, + 395115136,395349216,395583200,395817088,396050848,396284512,396518080,396751520, + 396984864,397218112,397451264,397684288,397917248,398150080,398382784,398615424, + 398847936,399080320,399312640,399544832,399776928,400008928,400240832,400472608, + 400704288,400935872,401167328,401398720,401629984,401861120,402092192,402323136, + 402553984,402784736,403015360,403245888,403476320,403706656,403936896,404167008, + 404397024,404626944,404856736,405086432,405316032,405545536,405774912,406004224, + 406233408,406462464,406691456,406920320,407149088,407377760,407606336,407834784, + 408063136,408291392,408519520,408747584,408975520,409203360,409431072,409658720, + 409886240,410113664,410340992,410568192,410795296,411022304,411249216,411476032, + 411702720,411929312,412155808,412382176,412608480,412834656,413060736,413286720, + 413512576,413738336,413964000,414189568,414415040,414640384,414865632,415090784, + 415315840,415540800,415765632,415990368,416215008,416439552,416663968,416888288, + 417112512,417336640,417560672,417784576,418008384,418232096,418455712,418679200, + 418902624,419125920,419349120,419572192,419795200,420018080,420240864,420463552, + 420686144,420908608,421130976,421353280,421575424,421797504,422019488,422241344, + 422463104,422684768,422906336,423127776,423349120,423570400,423791520,424012576, + 424233536,424454368,424675104,424895744,425116288,425336736,425557056,425777280, + 425997408,426217440,426437376,426657184,426876928,427096544,427316064,427535488, + 427754784,427974016,428193120,428412128,428631040,428849856,429068544,429287168, + 429505664,429724064,429942368,430160576,430378656,430596672,430814560,431032352, + 431250048,431467616,431685120,431902496,432119808,432336992,432554080,432771040, + 432987936,433204736,433421408,433637984,433854464,434070848,434287104,434503296, + 434719360,434935360,435151232,435367008,435582656,435798240,436013696,436229088, + 436444352,436659520,436874592,437089568,437304416,437519200,437733856,437948416, + 438162880,438377248,438591520,438805696,439019744,439233728,439447584,439661344, + 439875008,440088576,440302048,440515392,440728672,440941824,441154880,441367872, + 441580736,441793472,442006144,442218720,442431168,442643552,442855808,443067968, + 443280032,443492000,443703872,443915648,444127296,444338880,444550336,444761696, + 444972992,445184160,445395232,445606176,445817056,446027840,446238496,446449088, + 446659552,446869920,447080192,447290400,447500448,447710432,447920320,448130112, + 448339776,448549376,448758848,448968224,449177536,449386720,449595808,449804800, + 450013664,450222464,450431168,450639776,450848256,451056640,451264960,451473152, + 451681248,451889248,452097152,452304960,452512672,452720288,452927808,453135232, + 453342528,453549760,453756864,453963904,454170816,454377632,454584384,454791008, + 454997536,455203968,455410304,455616544,455822688,456028704,456234656,456440512, + 456646240,456851904,457057472,457262912,457468256,457673536,457878688,458083744, + 458288736,458493600,458698368,458903040,459107616,459312096,459516480,459720768, + 459924960,460129056,460333056,460536960,460740736,460944448,461148064,461351584, + 461554976,461758304,461961536,462164640,462367680,462570592,462773440,462976160, + 463178816,463381344,463583776,463786144,463988384,464190560,464392608,464594560, + 464796448,464998208,465199872,465401472,465602944,465804320,466005600,466206816, + 466407904,466608896,466809824,467010624,467211328,467411936,467612480,467812896, + 468013216,468213440,468413600,468613632,468813568,469013440,469213184,469412832, + 469612416,469811872,470011232,470210528,470409696,470608800,470807776,471006688, + 471205472,471404192,471602784,471801312,471999712,472198048,472396288,472594400, + 472792448,472990400,473188256,473385984,473583648,473781216,473978688,474176064, + 474373344,474570528,474767616,474964608,475161504,475358336,475555040,475751648, + 475948192,476144608,476340928,476537184,476733312,476929376,477125344,477321184, + 477516960,477712640,477908224,478103712,478299104,478494400,478689600,478884704, + 479079744,479274656,479469504,479664224,479858880,480053408,480247872,480442240, + 480636512,480830656,481024736,481218752,481412640,481606432,481800128,481993760, + 482187264,482380704,482574016,482767264,482960416,483153472,483346432,483539296, + 483732064,483924768,484117344,484309856,484502240,484694560,484886784,485078912, + 485270944,485462880,485654720,485846464,486038144,486229696,486421184,486612576, + 486803840,486995040,487186176,487377184,487568096,487758912,487949664,488140320, + 488330880,488521312,488711712,488901984,489092160,489282240,489472256,489662176, + 489851968,490041696,490231328,490420896,490610336,490799712,490988960,491178144, + 491367232,491556224,491745120,491933920,492122656,492311264,492499808,492688256, + 492876608,493064864,493253056,493441120,493629120,493817024,494004832,494192544, + 494380160,494567712,494755136,494942496,495129760,495316928,495504000,495691008, + 495877888,496064704,496251424,496438048,496624608,496811040,496997408,497183680, + 497369856,497555936,497741920,497927840,498113632,498299360,498484992,498670560, + 498856000,499041376,499226656,499411840,499596928,499781920,499966848,500151680, + 500336416,500521056,500705600,500890080,501074464,501258752,501442944,501627040, + 501811072,501995008,502178848,502362592,502546240,502729824,502913312,503096704, + 503280000,503463232,503646368,503829408,504012352,504195200,504377984,504560672, + 504743264,504925760,505108192,505290496,505472736,505654912,505836960,506018944, + 506200832,506382624,506564320,506745952,506927488,507108928,507290272,507471552, + 507652736,507833824,508014816,508195744,508376576,508557312,508737952,508918528, + 509099008,509279392,509459680,509639904,509820032,510000064,510180000,510359872, + 510539648,510719328,510898944,511078432,511257856,511437216,511616448,511795616, + 511974688,512153664,512332576,512511392,512690112,512868768,513047296,513225792, + 513404160,513582432,513760640,513938784,514116800,514294752,514472608,514650368, + 514828064,515005664,515183168,515360608,515537952,515715200,515892352,516069440, + 516246432,516423328,516600160,516776896,516953536,517130112,517306592,517482976, + 517659264,517835488,518011616,518187680,518363648,518539520,518715296,518891008, + 519066624,519242144,519417600,519592960,519768256,519943424,520118528,520293568, + 520468480,520643328,520818112,520992800,521167392,521341888,521516320,521690656, + 521864896,522039072,522213152,522387168,522561056,522734912,522908640,523082304, + 523255872,523429376,523602784,523776096,523949312,524122464,524295552,524468512, + 524641440,524814240,524986976,525159616,525332192,525504640,525677056,525849344, + 526021568,526193728,526365792,526537760,526709632,526881440,527053152,527224800, + 527396352,527567840,527739200,527910528,528081728,528252864,528423936,528594880, + 528765760,528936576,529107296,529277920,529448480,529618944,529789344,529959648, + 530129856,530300000,530470048,530640000,530809888,530979712,531149440,531319072, + 531488608,531658080,531827488,531996800,532166016,532335168,532504224,532673184, + 532842080,533010912,533179616,533348288,533516832,533685312,533853728,534022048, + 534190272,534358432,534526496,534694496,534862400,535030240,535197984,535365632, + 535533216,535700704,535868128,536035456,536202720,536369888,536536992,536704000, + 536870912 + }; +#endif + +#ifdef TABLES_AS_LUMPS + +#include "m_swap.h" + + + +// R_LoadTrigTables +// Load trig tables from a wad file lump +// CPhipps 24/12/98 - fix endianness (!) +// KKurbjun 3/09/2006 - Modified to reduce initial footprint +// +void R_LoadTrigTables(void) +{ + finesine=malloc(10240*sizeof(fixed_t)); + finetangent=malloc(4096*sizeof(fixed_t)); + tantoangle=malloc(2049*sizeof(angle_t)); + + finecosine=finesine + FINEANGLES/4; + + int lump; + { + lump = W_GetNumForName("SINETABL"); + if (W_LumpLength(lump) != 10240*sizeof(fixed_t)) + I_Error("R_LoadTrigTables: Invalid SINETABL"); + W_ReadLump(lump,(unsigned char*)finesine); + } + + { + lump = W_GetNumForName("TANGTABL"); + if (W_LumpLength(lump) != 4096*sizeof(fixed_t)) + I_Error("R_LoadTrigTables: Invalid TANGTABL"); + W_ReadLump(lump,(unsigned char*)finetangent); + } + + { + lump = W_GetNumForName("TANTOANG"); + if (W_LumpLength(lump) != 2049*sizeof(fixed_t)) + I_Error("R_LoadTrigTables: Invalid TANTOANG"); + W_ReadLump(lump,(unsigned char*)tantoangle); + } + // Endianness correction - might still be non-portable, but is fast where possible + { + size_t n; + printf("Endianness..."); + + // This test doesn't assume the endianness of the tables, but deduces them from + // en entry. I hope this is portable. + if ((10 < finesine[1]) && (finesine[1] < 100)) { + printf("ok."); + return; // Endianness is correct + } + + // Must correct endianness of every long loaded (!) +#define CORRECT_TABLE_ENDIAN(tbl, size) \ + for (n = 0; nname; p++) + *p->map = W_CacheLumpName(p->name); +} + +// +// V_MarkRect +// +// Marks a rectangular portion of the screen specified by +// upper left origin and height and width dirty to minimize +// the amount of screen update necessary. No return. +// +#ifndef GL_DOOM +void V_MarkRect(int x, int y, int width, int height) +{ + M_AddToBox(dirtybox, x, y); + M_AddToBox(dirtybox, x+width-1, y+height-1); +} +#endif /* GL_DOOM */ + +// +// V_CopyRect +// +// Copies a source rectangle in a screen buffer to a destination +// rectangle in another screen buffer. Source origin in srcx,srcy, +// destination origin in destx,desty, common size in width and height. +// Source buffer specfified by srcscrn, destination buffer by destscrn. +// +// Marks the destination rectangle on the screen dirty. +// +// No return. +// +#ifndef GL_DOOM +void V_CopyRect(int srcx, int srcy, int srcscrn, int width, + int height, int destx, int desty, int destscrn, + enum patch_translation_e flags) +{ + byte *src; + byte *dest; + + if (flags & VPT_STRETCH) + { + srcx=srcx*SCREENWIDTH/320; + srcy=srcy*SCREENHEIGHT/200; + width=width*SCREENWIDTH/320; + height=height*SCREENHEIGHT/200; + destx=destx*SCREENWIDTH/320; + desty=desty*SCREENHEIGHT/200; + } + +#ifdef RANGECHECK + if (srcx<0 + ||srcx+width >SCREENWIDTH + || srcy<0 + || srcy+height>SCREENHEIGHT + ||destx<0||destx+width >SCREENWIDTH + || desty<0 + || desty+height>SCREENHEIGHT) + I_Error ("V_CopyRect: Bad arguments"); +#endif + + V_MarkRect (destx, desty, width, height); + + src = screens[srcscrn]+SCREENWIDTH*srcy+srcx; + dest = screens[destscrn]+SCREENWIDTH*desty+destx; + + for ( ; height>0 ; height--) + { + memcpy (dest, src, width); + src += SCREENWIDTH; + dest += SCREENWIDTH; + } +} +#endif /* GL_DOOM */ + +// +// V_DrawBlock +// +// Draw a linear block of pixels into the view buffer. +// +// The bytes at src are copied in linear order to the screen rectangle +// at x,y in screenbuffer scrn, with size width by height. +// +// The destination rectangle is marked dirty. +// +// No return. +// +// CPhipps - modified to take the patch translation flags. For now, only stretching is +// implemented, to support highres in the menus +// +#ifndef GL_DOOM +void V_DrawBlock(int x, int y, int scrn, int width, int height, + const byte *src, enum patch_translation_e flags) +{ + byte *dest; + +#ifdef RANGECHECK + if (x<0 + ||x+width >((flags & VPT_STRETCH) ? 320 : SCREENWIDTH) + || y<0 + || y+height>((flags & VPT_STRETCH) ? 200 : SCREENHEIGHT)) + I_Error ("V_DrawBlock: Bad V_DrawBlock"); + + if (flags & (VPT_TRANS | VPT_FLIP)) + I_Error("V_DrawBlock: Unsupported flags (%u)", flags); +#endif + + if (flags & VPT_STRETCH) { + byte *dest; + int s_width; + fixed_t dx = (320 << FRACBITS) / SCREENWIDTH; + + x = (x * SCREENWIDTH) / 320; y = (y * SCREENHEIGHT) / 200; + s_width = (width * SCREENWIDTH) / 320; height = (height * SCREENHEIGHT) / 200; + + if (!scrn) + V_MarkRect (x, y, width, height); + + dest = screens[scrn] + y*SCREENWIDTH+x; + // x & y no longer needed + + while (height--) { + const byte *const src_row = src + width * ((height * 200) / SCREENHEIGHT); + byte *const dst_row = dest + SCREENWIDTH * height; + fixed_t tx; + + for (x=0, tx=0; x> FRACBITS]; + } + } else { + V_MarkRect (x, y, width, height); + + dest = screens[scrn] + y*SCREENWIDTH+x; + + while (height--) { + memcpy (dest, src, width); + src += width; + dest += SCREENWIDTH; + } + } +} +#endif /* GL_DOOM */ + +/* + * V_DrawBackground tiles a 64x64 patch over the entire screen, providing the + * background for the Help and Setup screens, and plot text betwen levels. + * cphipps - used to have M_DrawBackground, but that was used the framebuffer + * directly, so this is my code from the equivalent function in f_finale.c + */ +#ifndef GL_DOOM +void V_DrawBackground(const char* flatname, int scrn) +{ + /* erase the entire screen to a tiled background */ + const byte *src; + int x,y; + int lump; + + // killough 4/17/98: + src = W_CacheLumpNum(lump = firstflat + R_FlatNumForName(flatname)); + + V_DrawBlock(0, 0, scrn, 64, 64, src, 0); + + for (y=0 ; ySCREENWIDTH + || y<0 + || y+height>SCREENHEIGHT) + I_Error ("V_GetBlock: Bad arguments"); +#endif + + src = screens[scrn] + y*SCREENWIDTH+x; + + while (height--) + { + memcpy (dest, src, width); + src += SCREENWIDTH; + dest += width; + } +} +#endif /* GL_DOOM */ + +// +// V_Init +// +// Allocates the 4 full screen buffers in low DOS memory +// No return +// + +void V_Init (void) +{ + int i; + // CPhipps - allocate only 2 screens all the time, the rest can be allocated as and when needed +#define PREALLOCED_SCREENS 2 + + // CPhipps - no point in "stick these in low dos memory on PCs" anymore + // Allocate the screens individually, so I_InitGraphics can release screens[0] + // if e.g. it wants a MitSHM buffer instead + + for (i=0 ; itopoffset); + x -= SHORT(patch->leftoffset); + + // CPhipps - auto-no-stretch if not high-res + if (flags & VPT_STRETCH) + if ((SCREENWIDTH==320) && (SCREENHEIGHT==200)) + flags &= ~VPT_STRETCH; + + // CPhipps - null translation pointer => no translation + if (!trans) + flags &= ~VPT_TRANS; + + if (x<0 + ||x+SHORT(patch->width) > ((flags & VPT_STRETCH) ? 320 : SCREENWIDTH) + || y<0 + || y+SHORT(patch->height) > ((flags & VPT_STRETCH) ? 200 : SCREENHEIGHT)) + // killough 1/19/98: improved error message: + I_Error("V_DrawMemPatch: Patch (%d,%d)-(%d,%d) exceeds LFB" + "Bad V_DrawMemPatch (flags=%u)", x, y, x+SHORT(patch->width), y+SHORT(patch->height), flags); + + if (!(flags & VPT_STRETCH)) { + unsigned int col; + const column_t *column; + byte *desttop = screens[scrn]+y*SCREENWIDTH+x; + unsigned int w = SHORT(patch->width); + + if (!scrn) + V_MarkRect (x, y, w, SHORT(patch->height)); + + w--; // CPhipps - note: w = width-1 now, speeds up flipping + + for (col=0 ; (unsigned int)col<=w ; desttop++, col++) { + column = (column_t *)((byte *)patch + + LONG(patch->columnofs[(flags & VPT_FLIP) ? w-col : col])); + + // step through the posts in a column + while (column->topdelta != 0xff ) { + // killough 2/21/98: Unrolled and performance-tuned + + register const byte *source = (byte *)column + 3; + register byte *dest = desttop + column->topdelta*SCREENWIDTH; + register int count = column->length; + + if (!(flags & VPT_TRANS)) { + if ((count-=4)>=0) + do { + register byte s0,s1; + s0 = source[0]; + s1 = source[1]; + dest[0] = s0; + dest[SCREENWIDTH] = s1; + dest += SCREENWIDTH*2; + s0 = source[2]; + s1 = source[3]; + source += 4; + dest[0] = s0; + dest[SCREENWIDTH] = s1; + dest += SCREENWIDTH*2; + } while ((count-=4)>=0); + if (count+=4) + do { + *dest = *source++; + dest += SCREENWIDTH; + } while (--count); + column = (column_t *)(source+1); //killough 2/21/98 even faster + } else { + // CPhipps - merged translation code here + if ((count-=4)>=0) + do { + register byte s0,s1; + s0 = source[0]; + s1 = source[1]; + s0 = trans[s0]; + s1 = trans[s1]; + dest[0] = s0; + dest[SCREENWIDTH] = s1; + dest += SCREENWIDTH*2; + s0 = source[2]; + s1 = source[3]; + s0 = trans[s0]; + s1 = trans[s1]; + source += 4; + dest[0] = s0; + dest[SCREENWIDTH] = s1; + dest += SCREENWIDTH*2; + } while ((count-=4)>=0); + if (count+=4) + do { + *dest = trans[*source++]; + dest += SCREENWIDTH; + } while (--count); + column = (column_t *)(source+1); + } + } + } + } + else { + // CPhipps - move stretched patch drawing code here + // - reformat initialisers, move variables into inner blocks + + byte *desttop; + int col; + int w = (SHORT( patch->width ) << 16) - 1; // CPhipps - -1 for faster flipping + int stretchx, stretchy; + int DX = (SCREENWIDTH<<16) / 320; + int DXI = (320<<16) / SCREENWIDTH; + int DY = (SCREENHEIGHT<<16) / 200; + register int DYI = (200<<16) / SCREENHEIGHT; + int DY2, DYI2; + + stretchx = ( x * DX ) >> 16; + stretchy = ( y * DY ) >> 16; + DY2 = DY / 2; + DYI2 = DYI* 2; + + if (!scrn) + V_MarkRect ( stretchx, stretchy, (SHORT( patch->width ) * DX ) >> 16, + (SHORT( patch->height) * DY ) >> 16 ); + + desttop = screens[scrn] + stretchy * SCREENWIDTH + stretchx; + + for ( col = 0; col <= w; x++, col+=DXI, desttop++ ) { + const column_t *column; + { + unsigned int d = patch->columnofs[(flags & VPT_FLIP) ? ((w - col)>>16): (col>>16)]; + column = (column_t*)((byte*)patch + LONG(d)); + } + + while ( column->topdelta != 0xff ) { + register const byte *source = ( byte* ) column + 3; + register byte *dest = desttop + (( column->topdelta * DY ) >> 16 ) * SCREENWIDTH; + register int count = ( column->length * DY ) >> 16; + register int srccol = 0x8000; + + if (flags & VPT_TRANS) + while (count--) { + *dest = trans[source[srccol>>16]]; + dest += SCREENWIDTH; + srccol+= DYI; + } + else + while (count--) { + *dest = source[srccol>>16]; + dest += SCREENWIDTH; + srccol+= DYI; + } + column = ( column_t* ) (( byte* ) column + ( column->length ) + 4 ); + } + } + } +} +#endif // GL_DOOM + +// CPhipps - some simple, useful wrappers for that function, for drawing patches from wads + +// CPhipps - GNU C only suppresses generating a copy of a function if it is +// static inline; other compilers have different behaviour. +// This inline is _only_ for the function below + +#ifndef GL_DOOM +#ifdef __GNUC__ +inline +#endif +void V_DrawNumPatch(int x, int y, int scrn, int lump, + int cm, enum patch_translation_e flags) +{ + V_DrawMemPatch(x, y, scrn, (const patch_t*)W_CacheLumpNum(lump), + cm, flags); + W_UnlockLumpNum(lump); +} +#endif // GL_DOOM + +/* cph - + * V_NamePatchWidth - returns width of a patch. + * V_NamePatchHeight- returns height of a patch. + * + * Doesn't really belong here, but is often used in conjunction with + * this code. + * This is needed to reduce the number of patches being held locked + * in memory, since a lot of code was locking and holding pointers + * to graphics in order to get this info easily. Also, we do endian + * correction here, which reduces the chance of other code forgetting + * this. + */ +int V_NamePatchWidth(const char* name) +{ + int lump = W_GetNumForName(name); + int w; + + w = SHORT(((const patch_t*)W_CacheLumpNum(lump))->width); + W_UnlockLumpNum(lump); + return w; +} + +int V_NamePatchHeight(const char* name) +{ + int lump = W_GetNumForName(name); + int w; + + w = SHORT(((const patch_t*)W_CacheLumpNum(lump))->height); + W_UnlockLumpNum(lump); + return w; +} + +// CPhipps - +// V_PatchToBlock +// +// Returns a simple bitmap which contains the patch. See-through parts of the +// patch will be undefined (in fact black for now) + +#ifndef GL_DOOM +byte *V_PatchToBlock(const char* name, int cm, + enum patch_translation_e flags, + unsigned short* width, unsigned short* height) +{ + byte *oldscr = screens[1]; + byte *block; + const patch_t *patch; + + screens[1] = calloc(SCREENWIDTH*SCREENHEIGHT, 1); + + patch = W_CacheLumpName(name); + V_DrawMemPatch(SHORT(patch->leftoffset), SHORT(patch->topoffset), + 1, patch, cm, flags); + +#ifdef RANGECHECK + if (flags & VPT_STRETCH) + I_Error("V_PatchToBlock: Stretching not supported"); +#endif + + *width = SHORT(patch->width); *height = SHORT(patch->height); + + W_UnlockLumpName(name); + + V_GetBlock(0, 0, 1, *width, *height, + block = malloc((long)(*width) * (*height))); + + free(screens[1]); + screens[1] = oldscr; + return block; +} +#endif /* GL_DOOM */ + +// +// V_SetPalette +// +// CPhipps - New function to set the palette to palette number pal. +// Handles loading of PLAYPAL and calls I_SetPalette + +void V_SetPalette(int pal) +{ +#ifndef GL_DOOM + I_SetPalette(pal); +#else + // proff 11/99: update the palette + gld_SetPalette(pal); +#endif +} + +// +// V_FillRect +// +// CPhipps - New function to fill a rectangle with a given colour +#ifndef GL_DOOM +void V_FillRect(int scrn, int x, int y, int width, int height, byte colour) +{ + byte* dest = screens[scrn] + x + y*SCREENWIDTH; + while (height--) { + memset(dest, colour, width); + dest += SCREENWIDTH; + } +} +#endif diff --git a/apps/plugins/doom/v_video.h b/apps/plugins/doom/v_video.h new file mode 100644 index 0000000000..c9926e8997 --- /dev/null +++ b/apps/plugins/doom/v_video.h @@ -0,0 +1,185 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Gamma correction LUT. + * Color range translation support + * Functions to draw patches (by post) directly to screen. + * Functions to blit a block to the screen. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __V_VIDEO__ +#define __V_VIDEO__ + +#include "doomtype.h" +#include "doomdef.h" +// Needed because we are refering to patches. +#include "r_data.h" + +// +// VIDEO +// + +#define CENTERY (SCREENHEIGHT/2) + +// Screen 0 is the screen updated by I_Update screen. +// Screen 1 is an extra buffer. + +// array of pointers to color translation tables +extern const byte *colrngs[]; + +// symbolic indices into color translation table pointer array +typedef enum +{ + CR_BRICK, //0 + CR_TAN, //1 + CR_GRAY, //2 + CR_GREEN, //3 + CR_BROWN, //4 + CR_GOLD, //5 + CR_RED, //6 + CR_BLUE, //7 + CR_ORANGE, //8 + CR_YELLOW, //9 + CR_BLUE2, //10 // proff + CR_LIMIT //11 //jff 2/27/98 added for range check +} crange_idx_e; +//jff 1/16/98 end palette color range additions + +#define CR_DEFAULT CR_RED /* default value for out of range colors */ + +extern byte *screens[6]; +extern int dirtybox[4]; +extern const byte gammatable[5][256]; +extern int usegamma; + +//jff 4/24/98 loads color translation lumps +void V_InitColorTranslation(void); + +// Allocates buffer screens, call before R_Init. +void V_Init (void); + +enum patch_translation_e { + VPT_NONE = 0, // Normal + VPT_FLIP = 1, // Flip image horizontally + VPT_TRANS = 2, // Translate image via a translation table + VPT_STRETCH = 4, // Stretch to compensate for high-res +}; + +#ifndef GL_DOOM +void V_CopyRect(int srcx, int srcy, int srcscrn, int width, int height, + int destx, int desty, int destscrn, + enum patch_translation_e flags); +#else +#define V_CopyRect(sx,sy,ss,w,h,dx,dy,ds,f) +#endif /* GL_DOOM */ + +#ifdef GL_DOOM +#define V_FillRect(s,x,y,w,h,c) gld_FillBlock(x,y,w,h,c) +#else +void V_FillRect(int scrn, int x, int y, int width, int height, byte colour); +#endif + +// CPhipps - patch drawing +// Consolidated into the 3 really useful functions: +// V_DrawMemPatch - Draws the given patch_t +#ifdef GL_DOOM +#define V_DrawMemPatch(x,y,s,p,t,f) gld_DrawPatchFromMem(x,y,p,t,f) +#else +void V_DrawMemPatch(int x, int y, int scrn, const patch_t *patch, + int cm, enum patch_translation_e flags); +#endif +// V_DrawNumPatch - Draws the patch from lump num +#ifdef GL_DOOM +#define V_DrawNumPatch(x,y,s,l,t,f) gld_DrawNumPatch(x,y,l,t,f) +#else +void V_DrawNumPatch(int x, int y, int scrn, int lump, + int cm, enum patch_translation_e flags); +#endif +// V_DrawNamePatch - Draws the patch from lump "name" +#ifdef GL_DOOM +#define V_DrawNamePatch(x,y,s,n,t,f) gld_DrawNumPatch(x,y,W_GetNumForName(n),t,f) +#else +#define V_DrawNamePatch(x,y,s,n,t,f) V_DrawNumPatch(x,y,s,W_GetNumForName(n),t,f) +#endif + +/* cph - + * Functions to return width & height of a patch. + * Doesn't really belong here, but is often used in conjunction with + * this code. + */ +int V_NamePatchWidth(const char* name); +int V_NamePatchHeight(const char* name); + +// Draw a linear block of pixels into the view buffer. + +// CPhipps - added const's, patch translation flags for stretching +#ifndef GL_DOOM +void V_DrawBlock(int x, int y, int scrn, int width, int height, + const byte *src, enum patch_translation_e flags); +#endif + +/* cphipps 10/99: function to tile a flat over the screen */ +#ifdef GL_DOOM +#define V_DrawBackground(n,s) gld_DrawBackground(n) +#else +void V_DrawBackground(const char* flatname, int scrn); +#endif + +// Reads a linear block of pixels into the view buffer. + +#ifndef GL_DOOM +void V_GetBlock(int x, int y, int scrn, int width, int height, byte *dest); + +void V_MarkRect(int x, int y, int width,int height); + +// CPhipps - function to convert a patch_t into a simple block bitmap +// Returns pointer to the malloc()'ed bitmap, and its width and height +byte *V_PatchToBlock(const char* name, int cm, + enum patch_translation_e flags, + unsigned short* width, unsigned short* height); +#else +#define V_MarkRect(x,y,w,h) +#define V_PatchToBlock(n,cm,f,w,h) NULL +#endif + +// CPhipps - function to set the palette to palette number pal. +void V_SetPalette(int pal); + +// CPhipps - function to plot a pixel + +#ifndef GL_DOOM +#define V_PlotPixel(s,x,y,c) screens[s][x+SCREENWIDTH*y]=c +#endif + +#define V_AllocScreen(scrn) screens[scrn] = malloc(SCREENWIDTH*SCREENHEIGHT) +#define V_FreeScreen(scrn) free(screens[scrn]); screens[scrn] = NULL + +#ifdef GL_DOOM +#include "gl_struct.h" +#endif +#endif diff --git a/apps/plugins/doom/w_wad.c b/apps/plugins/doom/w_wad.c new file mode 100644 index 0000000000..4bd3807191 --- /dev/null +++ b/apps/plugins/doom/w_wad.c @@ -0,0 +1,683 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Handles WAD file header, directory, lump I/O. + * + *----------------------------------------------------------------------------- + */ + +#include "doomstat.h" +#include "doomtype.h" + +#ifdef __GNUG__ +#pragma implementation "w_wad.h" +#endif +#include "w_wad.h" +#include "m_swap.h" +#include "i_system.h" + +#include "rockmacros.h" +// +// GLOBALS +// + +// Location of each lump on disk. +lumpinfo_t *lumpinfo IBSS_ATTR; +int numlumps IBSS_ATTR; // killough +void **lumpcache IBSS_ATTR; // killough +#ifdef TIMEDIAG +static int *locktic; // cph + +static void W_ReportLocks(void) +{ + int i; + lprintf(LO_DEBUG, "W_ReportLocks:\nLump Size Locks Tics\n"); + for (i=0; ipath && *p!='/' && *p!='\\') + if (*p=='.') + return path; + if (*ext!='.') + strcat(path,"."); + return strcat(path,ext); +} + +// +// LUMP BASED ROUTINES. +// + +// +// W_AddFile +// All files are optional, but at least one file must be +// found (PWAD, if all required lumps are present). +// Files with a .wad extension are wadlink files +// with multiple lumps. +// Other files are single lumps with the base filename +// for the lump name. +// +// Reload hack removed by Lee Killough +// CPhipps - source is an enum +// + +static void W_AddFile(const char *filename, wad_source_t source) +// killough 1/31/98: static, const +{ + wadinfo_t header; + lumpinfo_t* lump_p; + unsigned i; + int handle; + int length; + int startlump; + filelump_t *fileinfo, *fileinfo2free=NULL; //killough + filelump_t singleinfo; + + // open the file and add to directory + + handle = open(filename,O_RDONLY); + +#ifdef HAVE_NET + if (handle == -1 && D_NetGetWad(filename)) // CPhipps + handle = open(filename,O_RDONLY); +#endif + + if (handle == -1) + { + if ( strlen(filename)<=4 || // add error check -- killough + (strcasecmp(filename+strlen(filename)-4 , ".lmp" ) && + strcasecmp(filename+strlen(filename)-4 , ".gwa" ) ) + ) + I_Error("W_AddFile: couldn't open %s",filename); + return; + } + + //jff 8/3/98 use logical output routine + printf (" adding %s\n",filename); + startlump = numlumps; + + if ( strlen(filename)<=4 || + ( + strcasecmp(filename+strlen(filename)-4,".wad") && + strcasecmp(filename+strlen(filename)-4,".gwa") + ) + ) + { + // single lump file + fileinfo = &singleinfo; + singleinfo.filepos = 0; + singleinfo.size = LONG(W_Filelength(handle)); + ExtractFileBase(filename, singleinfo.name); + numlumps++; + } + else + { + // WAD file + read(handle, &header, sizeof(header)); + if (strncmp(header.identification,"IWAD",4) && + strncmp(header.identification,"PWAD",4)) + I_Error("W_AddFile: Wad file %s doesn't have IWAD or PWAD id", filename); + header.numlumps = LONG(header.numlumps); + header.infotableofs = LONG(header.infotableofs); + length = header.numlumps*sizeof(filelump_t); + fileinfo2free = fileinfo = malloc(length); // killough + lseek(handle, header.infotableofs, SEEK_SET); + read(handle, fileinfo, length); + numlumps += header.numlumps; + } + + // Fill in lumpinfo + lumpinfo = realloc(lumpinfo, numlumps*sizeof(lumpinfo_t)); + + lump_p = &lumpinfo[startlump]; + for (i=startlump ; (int)ihandle = handle; // killough 4/25/98 + lump_p->position = LONG(fileinfo->filepos); + lump_p->size = LONG(fileinfo->size); +#ifndef NO_PREDEFINED_LUMPS + lump_p->data = NULL; // killough 1/31/98 +#endif + lump_p->namespace = ns_global; // killough 4/17/98 + strncpy (lump_p->name, fileinfo->name, 8); + lump_p->source = source; // Ty 08/29/98 + lump_p->locks = 0; // CPhipps - initialise locks + } + + free(fileinfo2free); // killough +} + +// jff 1/23/98 Create routines to reorder the master directory +// putting all flats into one marked block, and all sprites into another. +// This will allow loading of sprites and flats from a PWAD with no +// other changes to code, particularly fast hashes of the lumps. +// +// killough 1/24/98 modified routines to be a little faster and smaller + +static int IsMarker(const char *marker, const char *name) +{ + return !strncasecmp(name, marker, 8) || + (*name == *marker && !strncasecmp(name+1, marker, 7)); +} + +// killough 4/17/98: add namespace tags + +static void W_CoalesceMarkedResource(const char *start_marker, + const char *end_marker, int namespace) +{ + lumpinfo_t *marked = malloc(sizeof(*marked) * numlumps); + size_t i, num_marked = 0, num_unmarked = 0; + int is_marked = 0, mark_end = 0; + lumpinfo_t *lump = lumpinfo; + + for (i=numlumps; i--; lump++) + if (IsMarker(start_marker, lump->name)) // start marker found + { // If this is the first start marker, add start marker to marked lumps + if (!num_marked) + { + strncpy(marked->name, start_marker, 8); + marked->size = 0; // killough 3/20/98: force size to be 0 + marked->namespace = ns_global; // killough 4/17/98 + num_marked = 1; + } + is_marked = 1; // start marking lumps + } + else + if (IsMarker(end_marker, lump->name)) // end marker found + { + mark_end = 1; // add end marker below + is_marked = 0; // stop marking lumps + } + else + if (is_marked) // if we are marking lumps, + { // move lump to marked list + marked[num_marked] = *lump; + marked[num_marked++].namespace = namespace; // killough 4/17/98 + } + else + lumpinfo[num_unmarked++] = *lump; // else move down THIS list + + // Append marked list to end of unmarked list + memcpy(lumpinfo + num_unmarked, marked, num_marked * sizeof(*marked)); + + free(marked); // free marked list + + numlumps = num_unmarked + num_marked; // new total number of lumps + + if (mark_end) // add end marker + { + lumpinfo[numlumps].size = 0; // killough 3/20/98: force size to be 0 + lumpinfo[numlumps].namespace = ns_global; // killough 4/17/98 + strncpy(lumpinfo[numlumps++].name, end_marker, 8); + } +} + +// Hash function used for lump names. +// Must be mod'ed with table size. +// Can be used for any 8-character names. +// by Lee Killough + +unsigned W_LumpNameHash(const char *s) +{ + unsigned hash; + (void) ((hash = toupper(s[0]), s[1]) && + (hash = hash*3+toupper(s[1]), s[2]) && + (hash = hash*2+toupper(s[2]), s[3]) && + (hash = hash*2+toupper(s[3]), s[4]) && + (hash = hash*2+toupper(s[4]), s[5]) && + (hash = hash*2+toupper(s[5]), s[6]) && + (hash = hash*2+toupper(s[6]), + hash = hash*2+toupper(s[7])) + ); + return hash; +} + +// +// W_CheckNumForName +// Returns -1 if name not found. +// +// Rewritten by Lee Killough to use hash table for performance. Significantly +// cuts down on time -- increases Doom performance over 300%. This is the +// single most important optimization of the original Doom sources, because +// lump name lookup is used so often, and the original Doom used a sequential +// search. For large wads with > 1000 lumps this meant an average of over +// 500 were probed during every search. Now the average is under 2 probes per +// search. There is no significant benefit to packing the names into longwords +// with this new hashing algorithm, because the work to do the packing is +// just as much work as simply doing the string comparisons with the new +// algorithm, which minimizes the expected number of comparisons to under 2. +// +// killough 4/17/98: add namespace parameter to prevent collisions +// between different resources such as flats, sprites, colormaps +// + +int (W_CheckNumForName)(register const char *name, register int namespace) +{ + // Hash function maps the name to one of possibly numlump chains. + // It has been tuned so that the average chain length never exceeds 2. + + int i; + + if (!lumpinfo) + return -1; + + i = lumpinfo[W_LumpNameHash(name) % (unsigned) numlumps].index; + + // We search along the chain until end, looking for case-insensitive + // matches which also match a namespace tag. Separate hash tables are + // not used for each namespace, because the performance benefit is not + // worth the overhead, considering namespace collisions are rare in + // Doom wads. + + while (i >= 0 && (strncasecmp(lumpinfo[i].name, name, 8) || + lumpinfo[i].namespace != (unsigned)namespace)) + i = lumpinfo[i].next; + + // Return the matching lump, or -1 if none found. + + return i; +} + +// +// killough 1/31/98: Initialize lump hash table +// + +static void W_InitLumpHash(void) +{ + int i; + + for (i=0; i= numlumps) + I_Error ("W_LumpLength: %i >= numlumps",lump); + return lumpinfo[lump].size; +} + +// +// W_ReadLump +// Loads the lump into the given buffer, +// which must be >= W_LumpLength(). +// + +void W_ReadLump(int lump, void *dest) +{ + lumpinfo_t *l = lumpinfo + lump; + +#ifdef RANGECHECK + if (lump >= numlumps) + I_Error ("W_ReadLump: %i >= numlumps",lump); +#endif + +#ifndef NO_PREDEFINED_LUMPS + if (l->data) // killough 1/31/98: predefined lump data + memcpy(dest, l->data, l->size); + else +#endif + { + int c; + + // killough 1/31/98: Reload hack (-wart) removed + + lseek(l->handle, l->position, SEEK_SET); + c = read(l->handle, dest, l->size); + if (c < l->size) + I_Error("W_ReadLump: only read %i of %i on lump %i", c, l->size, lump); + } +} + +// +// W_CacheLumpNum +/* + * killough 4/25/98: simplified + * CPhipps - modified for new lump locking scheme + * returns a const* + */ + +void * (W_CacheLumpNum)(int lump, unsigned short locks) +{ +#ifdef RANGECHECK + if ((unsigned)lump >= (unsigned)numlumps) + I_Error ("W_CacheLumpNum: %i >= numlumps",lump); +#endif + + if (!lumpcache[lump]) // read the lump in + W_ReadLump(lump, Z_Malloc(W_LumpLength(lump), PU_CACHE, &lumpcache[lump])); + + /* cph - if wasn't locked but now is, tell z_zone to hold it */ + if (!lumpinfo[lump].locks && locks) { + Z_ChangeTag(lumpcache[lump],PU_STATIC); +#ifdef TIMEDIAG + locktic[lump] = gametic; +#endif + } + lumpinfo[lump].locks += locks; + +#ifdef SIMPLECHECKS + if (!((lumpinfo[lump].locks+1) & 0xf)) + printf("W_CacheLumpNum: High lock on %s (%d)\n", + lumpinfo[lump].name, lumpinfo[lump].locks); +#endif + + // CPhipps - if not locked, can't give you a pointer + return (locks ? lumpcache[lump] : NULL); +} + +/* cph - + * W_CacheLumpNumPadded + * + * Caches a lump and pads the memory following it. + * The thing returned is *only* guaranteed to be padded if + * the lump isn't already cached (otherwise, you get whatever is + * currently cached, which if it was cached by a previous call + * to this will also be padded) + */ + +void * W_CacheLumpNumPadded(int lump, size_t len, unsigned char pad) +{ + const int locks = 1; +#ifdef RANGECHECK + if ((unsigned)lump >= (unsigned)numlumps) + I_Error ("W_CacheLumpNum: %i >= numlumps",lump); +#endif + + if (!lumpcache[lump]) { /* read the lump in */ + size_t lumplen = W_LumpLength(lump); + unsigned char* p; + W_ReadLump(lump, p = Z_Malloc(len, PU_CACHE, &lumpcache[lump])); + memset(p+lumplen, pad, len-lumplen); + } + + /* cph - if wasn't locked but now is, tell z_zone to hold it */ + if (!lumpinfo[lump].locks && locks) { + Z_ChangeTag(lumpcache[lump],PU_STATIC); +#ifdef TIMEDIAG + locktic[lump] = gametic; +#endif + } + lumpinfo[lump].locks += locks; + +#ifdef SIMPLECHECKS + if (!((lumpinfo[lump].locks+1) & 0xf)) + printf("W_CacheLumpNum: High lock on %s (%d)\n", + lumpinfo[lump].name, lumpinfo[lump].locks); +#endif + + return lumpcache[lump]; +} + +// +// W_UnlockLumpNum +// +// CPhipps - this changes (should reduce) the number of locks on a lump + +void (W_UnlockLumpNum)(int lump, signed short unlocks) +{ +#ifdef SIMPLECHECKS + if ((signed short)lumpinfo[lump].locks < unlocks) + printf("W_UnlockLumpNum: Excess unlocks on %s (%d-%d)\n", + lumpinfo[lump].name, lumpinfo[lump].locks, unlocks); +#endif + lumpinfo[lump].locks -= unlocks; + // cph - Note: must only tell z_zone to make purgeable if currently locked, + // else it might already have been purged + if (unlocks && !lumpinfo[lump].locks) + Z_ChangeTag(lumpcache[lump], PU_CACHE); +} + +// W_CacheLumpName macroized in w_wad.h -- killough + +#ifndef NO_PREDEFINED_LUMPS +// WritePredefinedLumpWad +// Args: Filename - string with filename to write to +// Returns: void +// +// If the user puts a -dumplumps switch on the command line, we will +// write all those predefined lumps above out into a pwad. User +// supplies the pwad name. +// +// killough 4/22/98: make endian-independent, remove tab chars +void WritePredefinedLumpWad(const char *filename) +{ + int handle; // for file open + char filenam[256]; // we may have to add ".wad" to the name they pass + + if (!filename || !*filename) // check for null pointer or empty name + return; // early return + + AddDefaultExtension(strcpy(filenam, filename), ".wad"); + + // The following code writes a PWAD from the predefined lumps array + // How to write a PWAD will not be explained here. +#ifdef _MSC_VER // proff: In Visual C open is defined a bit different + if ( (handle = open (filenam, O_RDWR | O_CREAT | O_BINARY, _S_IWRITE|_S_IREAD)) != -1) +#else + if ( (handle = open (filenam, O_RDWR | O_CREAT | O_BINARY, S_IWUSR|S_IRUSR)) != -1) +#endif + { + wadinfo_t header = {"PWAD"}; + size_t filepos = sizeof(wadinfo_t) + num_predefined_lumps * sizeof(filelump_t); + int i; + + header.numlumps = LONG(num_predefined_lumps); + header.infotableofs = LONG(sizeof(header)); + + // write header + write(handle, &header, sizeof(header)); + + // write directory + for (i=0;(size_t)ipnum +static int me; + +// specifies current state +static stateenum_t state; + +// contains information passed into intermission +static wbstartstruct_t* wbs; + +static wbplayerstruct_t* plrs; // wbs->plyr[] + +// used for general timing +static int cnt; + +// used for timing of background animation +static int bcnt; + +// signals to refresh everything for one frame +static int firstrefresh; + +static int cnt_time; +static int cnt_total_time; +static int cnt_par; +static int cnt_pause; + + +// +// GRAPHICS +// + +// You Are Here graphic +static const char* yah[2] = { "WIURH0", "WIURH1" }; + +// splat +static const char* splat = "WISPLAT"; + +// %, : graphics +static const char percent[] = {"WIPCNT"}; +static const char colon[] = {"WICOLON"}; + +// 0-9 graphic +static const patch_t * num[10]; + +// minus sign +static const char wiminus[] = {"WIMINUS"}; + +// "Finished!" graphics +static const char finished[] = {"WIF"}; + +// "Entering" graphic +static const char entering[] = {"WIENTER"}; + +// "secret" +static const char sp_secret[] = {"WISCRT2"}; + +// "Kills", "Scrt", "Items", "Frags" +static const char kills[] = {"WIOSTK"}; +static const char secret[] = {"WIOSTS"}; +static const char items[] = {"WIOSTI"}; +static const char frags[] = {"WIFRGS"}; + +// Time sucks. +static const char time1[] = {"WITIME"}; +static const char par[] = {"WIPAR"}; +static const char sucks[] = {"WISUCKS"}; + +// "killers", "victims" +static const char killers[] = {"WIKILRS"}; +static const char victims[] = {"WIVCTMS"}; + +// "Total", your face, your dead face +static const char total[] = {"WIMSTT"}; +static const char star[] = {"STFST01"}; +static const char bstar[] = {"STFDEAD0"}; + +// "red P[1..MAXPLAYERS]" +static const char facebackp[] = {"STPB0"}; + + +// +// CODE +// + +static void WI_endDeathmatchStats(void); +static void WI_endNetgameStats(void); +void WI_unloadData(void); +#define WI_endStats WI_endNetgameStats + +/* ==================================================================== + * WI_levelNameLump + * Purpore: Returns the name of the graphic lump containing the name of + * the given level. + * Args: Episode and level, and buffer (must by 9 chars) to write to + * Returns: void + */ +void WI_levelNameLump(int epis, int map, char* buf, int bsize) +{ + if (gamemode == commercial) { + snprintf(buf, bsize,"CWILV%s%d",(map/10>0?"":"0"), map); //ANOTHER ROCKHACK "CWILV%2.2d" + //snprintf(buf,bsize, "CWILV%2.2d", map); + } else { + snprintf(buf,bsize, "WILV%d%d", epis, map); + } +} + +// ==================================================================== +// WI_slamBackground +// Purpose: Put the full-screen background up prior to patches +// Args: none +// Returns: void +// +static void WI_slamBackground(void) +{ + char name[9]; // limited to 8 characters + + if (gamemode == commercial || (gamemode == retail && wbs->epsd == 3)) + strcpy(name, "INTERPIC"); + else + snprintf(name, sizeof(name), "WIMAP%d", wbs->epsd); + + // background + V_DrawNamePatch(0, 0, FB, name, CR_DEFAULT, VPT_STRETCH); +} + +// ==================================================================== +// WI_Responder +// Purpose: Draw animations on intermission background screen +// Args: ev -- event pointer, not actually used here. +// Returns: False -- dummy routine +// +// The ticker is used to detect keys +// because of timing issues in netgames. +boolean WI_Responder(event_t* ev) +{ + (void)ev; + return false; +} + +// ==================================================================== +// WI_drawLF +// Purpose: Draw the "Finished" level name before showing stats +// Args: none +// Returns: void +// +void WI_drawLF(void) +{ + int y = WI_TITLEY; + char lname[9]; + + // draw + /* cph - get the graphic lump name and use it */ + WI_levelNameLump(wbs->epsd, wbs->last, lname, sizeof(lname)); + // CPhipps - patch drawing updated + V_DrawNamePatch((320 - V_NamePatchWidth(lname))/2, y, + FB, lname, CR_DEFAULT, VPT_STRETCH); + + // draw "Finished!" + y += (5*V_NamePatchHeight(lname))/4; + + // CPhipps - patch drawing updated + V_DrawNamePatch((320 - V_NamePatchWidth(finished))/2, y, + FB, finished, CR_DEFAULT, VPT_STRETCH); +} + +// ==================================================================== +// WI_drawEL +// Purpose: Draw introductory "Entering" and level name +// Args: none +// Returns: void +// +void WI_drawEL(void) +{ + int y = WI_TITLEY; + char lname[9]; + + /* cph - get the graphic lump name */ + WI_levelNameLump(wbs->epsd, wbs->next, lname, sizeof(lname)); + + // draw "Entering" + // CPhipps - patch drawing updated + V_DrawNamePatch((320 - V_NamePatchWidth(entering))/2, + y, FB, entering, CR_DEFAULT, VPT_STRETCH); + + // draw level + y += (5*V_NamePatchHeight(lname))/4; + + // CPhipps - patch drawing updated + V_DrawNamePatch((320 - V_NamePatchWidth(lname))/2, y, FB, + lname, CR_DEFAULT, VPT_STRETCH); +} + + +/* ==================================================================== + * WI_drawOnLnode + * Purpose: Draw patches at a location based on episode/map + * Args: n -- index to map# within episode + * c[] -- array of names of patches to be drawn + * Returns: void + */ +void +WI_drawOnLnode // draw stuff at a location by episode/map# +( int n, + const char* const c[] ) +{ + int i; + boolean fits = false; + + i = 0; + do + { + int left; + int top; + int right; + int bottom; + int lump = W_GetNumForName(c[i]); + const patch_t* p = W_CacheLumpNum(lump); + + left = lnodes[wbs->epsd][n].x - SHORT(p->leftoffset); + top = lnodes[wbs->epsd][n].y - SHORT(p->topoffset); + right = left + SHORT(p->width); + bottom = top + SHORT(p->height); + W_UnlockLumpNum(lump); + + if (left >= 0 + && right < 320 + && top >= 0 + && bottom < 200) + { + fits = true; + } + else + { + i++; + } + } while (!fits && i!=2); + + if (fits && i<2) + { + // CPhipps - patch drawing updated + V_DrawNamePatch(lnodes[wbs->epsd][n].x, lnodes[wbs->epsd][n].y, + FB, c[i], CR_DEFAULT, VPT_STRETCH); + } + else + { + // DEBUG + //jff 8/3/98 use logical output routine + printf("Could not place patch on level %d", n+1); + } +} + + +// ==================================================================== +// WI_initAnimatedBack +// Purpose: Initialize pointers and styles for background animation +// Args: none +// Returns: void +// +void WI_initAnimatedBack(void) +{ + int i; + anim_t* a; + + if (gamemode == commercial) // no animation for DOOM2 + return; + + if (wbs->epsd > 2) + return; + + for (i=0;iepsd];i++) + { + a = &anims[wbs->epsd][i]; + + // init variables + a->ctr = -1; + + // specify the next time to draw it + if (a->type == ANIM_ALWAYS) + a->nexttic = bcnt + 1 + (M_Random()%a->period); + else + if (a->type == ANIM_RANDOM) + a->nexttic = bcnt + 1 + a->data2+(M_Random()%a->data1); + else + if (a->type == ANIM_LEVEL) + a->nexttic = bcnt + 1; + } +} + + +// ==================================================================== +// WI_updateAnimatedBack +// Purpose: Figure out what animation we do on this iteration +// Args: none +// Returns: void +// +void WI_updateAnimatedBack(void) +{ + int i; + anim_t* a; + + if (gamemode == commercial) + return; + + if (wbs->epsd > 2) + return; + + for (i=0;iepsd];i++) + { + a = &anims[wbs->epsd][i]; + + if (bcnt == a->nexttic) + { + switch (a->type) + { + case ANIM_ALWAYS: + if (++a->ctr >= a->nanims) a->ctr = 0; + a->nexttic = bcnt + a->period; + break; + + case ANIM_RANDOM: + a->ctr++; + if (a->ctr == a->nanims) + { + a->ctr = -1; + a->nexttic = bcnt+a->data2+(M_Random()%a->data1); + } + else + a->nexttic = bcnt + a->period; + break; + + case ANIM_LEVEL: + // gawd-awful hack for level anims + if (!(state == StatCount && i == 7) + && wbs->next == a->data1) + { + a->ctr++; + if (a->ctr == a->nanims) a->ctr--; + a->nexttic = bcnt + a->period; + } + break; + } + } + } +} + + +// ==================================================================== +// WI_drawAnimatedBack +// Purpose: Actually do the animation (whew!) +// Args: none +// Returns: void +// +void WI_drawAnimatedBack(void) +{ + int i; + anim_t* a; + + if (gamemode==commercial) //jff 4/25/98 Someone forgot commercial an enum + return; + + if (wbs->epsd > 2) + return; + + for (i=0 ; iepsd] ; i++) + { + a = &anims[wbs->epsd][i]; + + if (a->ctr >= 0) + // CPhipps - patch drawing updated + V_DrawMemPatch(a->loc.x, a->loc.y, FB, a->p[a->ctr], CR_DEFAULT, VPT_STRETCH); + } +} + + +// ==================================================================== +// WI_drawNum +// Purpose: Draws a number. If digits > 0, then use that many digits +// minimum, otherwise only use as many as necessary +// Args: x, y -- location +// n -- the number to be drawn +// digits -- number of digits minimum or zero +// Returns: new x position after drawing (note we are going to the left) +// CPhipps - static +static int WI_drawNum (int x, int y, int n, int digits) +{ + int fontwidth = SHORT(num[0]->width); + int neg; + int temp; + + if (digits < 0) + { + if (!n) + { + // make variable-length zeros 1 digit long + digits = 1; + } + else + { + // figure out # of digits in # + digits = 0; + temp = n; + + while (temp) + { + temp /= 10; + digits++; + } + } + } + + neg = n < 0; + if (neg) + n = -n; + + // if non-number, do not draw it + if (n == 1994) + return 0; + + // draw the new number + while (digits--) + { + x -= fontwidth; + // CPhipps - patch drawing updated + V_DrawMemPatch(x, y, FB, num[ n % 10 ], CR_DEFAULT, VPT_STRETCH); + n /= 10; + } + + // draw a minus sign if necessary + if (neg) + // CPhipps - patch drawing updated + V_DrawNamePatch(x-=8, y, FB, wiminus, CR_DEFAULT, VPT_STRETCH); + + return x; +} + + +// ==================================================================== +// WI_drawPercent +// Purpose: Draws a percentage, really just a call to WI_drawNum +// after putting a percent sign out there +// Args: x, y -- location +// p -- the percentage value to be drawn, no negatives +// Returns: void +// CPhipps - static +static void WI_drawPercent(int x, int y, int p) +{ + if (p < 0) + return; + + // CPhipps - patch drawing updated + V_DrawNamePatch(x, y, FB, percent, CR_DEFAULT, VPT_STRETCH); + WI_drawNum(x, y, p, -1); +} + + +// ==================================================================== +// WI_drawTime +// Purpose: Draws the level completion time or par time, or "Sucks" +// if 1 hour or more +// Args: x, y -- location +// t -- the time value to be drawn +// Returns: void +// +// CPhipps - static +// - largely rewritten to display hours and use slightly better algorithm + +static void WI_drawTime(int x, int y, int t) +{ + int n; + + if (t<0) + return; + + if (t < 100*60*60) + for(;;) { + n = t % 60; + t /= 60; + x = WI_drawNum(x, y, n, (t || n>9) ? 2 : 1) - V_NamePatchWidth(colon); + + // draw + if (t) + // CPhipps - patch drawing updated + V_DrawNamePatch(x, y, FB, colon, CR_DEFAULT, VPT_STRETCH); + else break; + } + else // "sucks" (maybe should be "addicted", even I've never had a 100 hour game ;) + V_DrawNamePatch(x - V_NamePatchWidth(sucks), + y, FB, sucks, CR_DEFAULT, VPT_STRETCH); +} + + +// ==================================================================== +// WI_End +// Purpose: Unloads data structures (inverse of WI_Start) +// Args: none +// Returns: void +// +void WI_End(void) +{ + WI_unloadData(); + + if (deathmatch) + WI_endDeathmatchStats(); + else if (netgame) + WI_endNetgameStats(); + else + WI_endStats(); +} + + +// ==================================================================== +// WI_initNoState +// Purpose: Clear state, ready for end of level activity +// Args: none +// Returns: void +// +void WI_initNoState(void) +{ + state = NoState; + acceleratestage = 0; + cnt = 10; +} + + +// ==================================================================== +// WI_drawTimeStats +// Purpose: Put the times on the screen +// Args: time, total time, par time, in seconds +// Returns: void +// +// cph - pulled from WI_drawStats below + +static void WI_drawTimeStats(int cnt_time, int cnt_total_time, int cnt_par) +{ + V_DrawNamePatch(SP_TIMEX, SP_TIMEY, FB, time1, CR_DEFAULT, VPT_STRETCH); + WI_drawTime(320/2 - SP_TIMEX, SP_TIMEY, cnt_time); + + V_DrawNamePatch(SP_TIMEX, (SP_TIMEY+200)/2, FB, total, CR_DEFAULT, VPT_STRETCH); + WI_drawTime(320/2 - SP_TIMEX, (SP_TIMEY+200)/2, cnt_total_time); + + // Ty 04/11/98: redid logic: should skip only if with pwad but + // without deh patch + // killough 2/22/98: skip drawing par times on pwads + // Ty 03/17/98: unless pars changed with deh patch + + if (!(modifiedgame)) //&& !deh_pars)) + { + if (wbs->epsd < 3) + { + V_DrawNamePatch(320/2 + SP_TIMEX, SP_TIMEY, FB, par, CR_DEFAULT, VPT_STRETCH); + WI_drawTime(320 - SP_TIMEX, SP_TIMEY, cnt_par); + } + } +} + +// ==================================================================== +// WI_updateNoState +// Purpose: Cycle until end of level activity is done +// Args: none +// Returns: void +// +void WI_updateNoState(void) +{ + + WI_updateAnimatedBack(); + + if (!--cnt) + G_WorldDone(); +} + +static boolean snl_pointeron = false; + + + +// ==================================================================== +// WI_initShowNextLoc +// Purpose: Prepare to show the next level's location +// Args: none +// Returns: void +// +void WI_initShowNextLoc(void) +{ + if ((gamemode != commercial) && (gamemap == 8)) { + G_WorldDone(); + return; + } + + state = ShowNextLoc; + acceleratestage = 0; + cnt = SHOWNEXTLOCDELAY * TICRATE; + + WI_initAnimatedBack(); +} + +// ==================================================================== +// WI_updateShowNextLoc +// Purpose: Prepare to show the next level's location +// Args: none +// Returns: void +// +void WI_updateShowNextLoc(void) +{ + WI_updateAnimatedBack(); + + if (!--cnt || acceleratestage) + WI_initNoState(); + else + snl_pointeron = (cnt & 31) < 20; +} + + +// ==================================================================== +// WI_drawShowNextLoc +// Purpose: Show the next level's location on animated backgrounds +// Args: none +// Returns: void +// +void WI_drawShowNextLoc(void) +{ + int i; + int last; + + WI_slamBackground(); + + // draw animated background + WI_drawAnimatedBack(); + + if ( gamemode != commercial) + { + if (wbs->epsd > 2) + { + WI_drawEL(); // "Entering..." if not E1 or E2 + return; + } + + last = (wbs->last == 8) ? wbs->next - 1 : wbs->last; + + // draw a splat on taken cities. + for (i=0 ; i<=last ; i++) + WI_drawOnLnode(i, &splat); + + // splat the secret level? + if (wbs->didsecret) + WI_drawOnLnode(8, &splat); + + // draw flashing ptr + if (snl_pointeron) + WI_drawOnLnode(wbs->next, yah); + } + + // draws which level you are entering.. + if ( (gamemode != commercial) + || wbs->next != 30) // check for MAP30 end game + WI_drawEL(); +} + +// ==================================================================== +// WI_drawNoState +// Purpose: Draw the pointer and next location +// Args: none +// Returns: void +// +void WI_drawNoState(void) +{ + snl_pointeron = true; + WI_drawShowNextLoc(); +} + + +// ==================================================================== +// WI_fragSum +// Purpose: Calculate frags for this player based on the current totals +// of all the other players. Subtract self-frags. +// Args: playernum -- the player to be calculated +// Returns: the total frags for this player +// +int WI_fragSum(int playernum) +{ + int i; + int frags = 0; + + for (i=0 ; i 999) // Ty 03/17/98 3-digit frag count + dm_frags[i][j] = 999; + + if (dm_frags[i][j] < -999) + dm_frags[i][j] = -999; + + stillticking = true; + } + } + dm_totals[i] = WI_fragSum(i); + + if (dm_totals[i] > 999) + dm_totals[i] = 999; + + if (dm_totals[i] < -999) + dm_totals[i] = -999; // Ty 03/17/98 end 3-digit frag count + } + } + + if (!stillticking) + { + S_StartSound(0, sfx_barexp); + dm_state++; + } + } + else if (dm_state == 4) + { + if (acceleratestage) + { + S_StartSound(0, sfx_slop); + + if ( gamemode == commercial) + WI_initNoState(); + else + WI_initShowNextLoc(); + } + } + else if (dm_state & 1) + { + if (!--cnt_pause) + { + dm_state++; + cnt_pause = TICRATE; + } + } +} + + +// ==================================================================== +// WI_drawDeathmatchStats +// Purpose: Draw the stats on the screen in a matrix +// Args: none +// Returns: void +// +// proff/nicolas 09/20/98 -- changed for hi-res +// CPhipps - patch drawing updated +void WI_drawDeathmatchStats(void) +{ + int i; + int j; + int x; + int y; + int w; + + int lh; // line height + int halfface = V_NamePatchWidth(facebackp)/2; + + lh = WI_SPACINGY; + + WI_slamBackground(); + + // draw animated background + WI_drawAnimatedBack(); + WI_drawLF(); + + // draw stat titles (top line) + V_DrawNamePatch(DM_TOTALSX-V_NamePatchWidth(total)/2, + DM_MATRIXY-WI_SPACINGY+10, FB, total, CR_DEFAULT, VPT_STRETCH); + + V_DrawNamePatch(DM_KILLERSX, DM_KILLERSY, FB, killers, CR_DEFAULT, VPT_STRETCH); + V_DrawNamePatch(DM_VICTIMSX, DM_VICTIMSY, FB, victims, CR_DEFAULT, VPT_STRETCH); + + // draw P? + x = DM_MATRIXX + DM_SPACINGX; + y = DM_MATRIXY; + + for (i=0 ; iwidth); + + for (i=0 ; imaxkills; + cnt_items[i] = (plrs[i].sitems * 100) / wbs->maxitems; + + // killough 2/22/98: Make secrets = 100% if maxsecret = 0: + cnt_secret[i] = wbs->maxsecret ? + (plrs[i].ssecret * 100) / wbs->maxsecret : 100; + if (dofrags) + cnt_frags[i] = WI_fragSum(i); // we had frags + } + S_StartSound(0, sfx_barexp); // bang + ng_state = 10; + } + + if (ng_state == 2) + { + if (!(bcnt&3)) + S_StartSound(0, sfx_pistol); // pop + + stillticking = false; + + for (i=0 ; i= (plrs[i].skills * 100) / wbs->maxkills) + cnt_kills[i] = (plrs[i].skills * 100) / wbs->maxkills; + else + stillticking = true; // still got stuff to tally + } + + if (!stillticking) + { + S_StartSound(0, sfx_barexp); + ng_state++; + } + } + else if (ng_state == 4) + { + if (!(bcnt&3)) + S_StartSound(0, sfx_pistol); + + stillticking = false; + + for (i=0 ; i= (plrs[i].sitems * 100) / wbs->maxitems) + cnt_items[i] = (plrs[i].sitems * 100) / wbs->maxitems; + else + stillticking = true; + } + + if (!stillticking) + { + S_StartSound(0, sfx_barexp); + ng_state++; + } + } + else if (ng_state == 6) + { + if (!(bcnt&3)) + S_StartSound(0, sfx_pistol); + + stillticking = false; + + for (i=0 ; i= (wbs->maxsecret ? (plrs[i].ssecret * 100) / wbs->maxsecret : compatibility_level < lxdoom_1_compatibility ? 0 : 100)) + cnt_secret[i] = wbs->maxsecret ? (plrs[i].ssecret * 100) / wbs->maxsecret : 100; + else + stillticking = true; + } + + if (!stillticking) + { + S_StartSound(0, sfx_barexp); + ng_state += 1 + 2*!dofrags; + } + } + else if (ng_state == 8) + { + if (!(bcnt&3)) + S_StartSound(0, sfx_pistol); + + stillticking = false; + + for (i=0 ; i= (fsum = WI_fragSum(i))) + cnt_frags[i] = fsum; + else + stillticking = true; + } + + if (!stillticking) + { + S_StartSound(0, sfx_pldeth); + ng_state++; + } + } + else if (ng_state == 10) + { + if (acceleratestage) + { + S_StartSound(0, sfx_sgcock); + if ( gamemode == commercial ) + WI_initNoState(); + else + WI_initShowNextLoc(); + } + } + else if (ng_state & 1) + { + if (!--cnt_pause) + { + ng_state++; + cnt_pause = TICRATE; + } + } +} + + +// ==================================================================== +// WI_drawNetgameStats +// Purpose: Put the coop stats on the screen +// Args: none +// Returns: void +// +// proff/nicolas 09/20/98 -- changed for hi-res +// CPhipps - patch drawing updated +void WI_drawNetgameStats(void) +{ + int i; + int x; + int y; + int pwidth = V_NamePatchWidth(percent); + int fwidth = V_NamePatchWidth(facebackp); + + WI_slamBackground(); + + // draw animated background + WI_drawAnimatedBack(); + + WI_drawLF(); + + // draw stat titles (top line) + V_DrawNamePatch(NG_STATSX+NG_SPACINGX-V_NamePatchWidth(kills), + NG_STATSY, FB, kills, CR_DEFAULT, VPT_STRETCH); + + V_DrawNamePatch(NG_STATSX+2*NG_SPACINGX-V_NamePatchWidth(items), + NG_STATSY, FB, items, CR_DEFAULT, VPT_STRETCH); + + V_DrawNamePatch(NG_STATSX+3*NG_SPACINGX-V_NamePatchWidth(secret), + NG_STATSY, FB, secret, CR_DEFAULT, VPT_STRETCH); + + if (dofrags) + V_DrawNamePatch(NG_STATSX+4*NG_SPACINGX-V_NamePatchWidth(frags), + NG_STATSY, FB, frags, CR_DEFAULT, VPT_STRETCH); + + // draw stats + y = NG_STATSY + V_NamePatchHeight(kills); + + for (i=0 ; itotaltimes / TICRATE, wbs->partime / TICRATE); +} + +static int sp_state; + +// ==================================================================== +// WI_initStats +// Purpose: Get ready for single player stats +// Args: none +// Returns: void +// Comment: Seems like we could do all these stats in a more generic +// set of routines that weren't duplicated for dm, coop, sp +// +void WI_initStats(void) +{ + state = StatCount; + acceleratestage = 0; + sp_state = 1; + + // CPhipps - allocate (awful code, I know, but saves changing it all) and initialise + *(cnt_kills = malloc(sizeof(*cnt_kills))) = + *(cnt_items = malloc(sizeof(*cnt_items))) = + *(cnt_secret= malloc(sizeof(*cnt_secret))) = -1; + cnt_time = cnt_par = cnt_total_time = -1; + cnt_pause = TICRATE; + + WI_initAnimatedBack(); +} + +// ==================================================================== +// WI_updateStats +// Purpose: Calculate solo stats +// Args: none +// Returns: void +// +void WI_updateStats(void) +{ + WI_updateAnimatedBack(); + + if (acceleratestage && sp_state != 10) + { + acceleratestage = 0; + cnt_kills[0] = (plrs[me].skills * 100) / wbs->maxkills; + cnt_items[0] = (plrs[me].sitems * 100) / wbs->maxitems; + + // killough 2/22/98: Make secrets = 100% if maxsecret = 0: + cnt_secret[0] = (wbs->maxsecret ? + (plrs[me].ssecret * 100) / wbs->maxsecret : 100); + + cnt_total_time = wbs->totaltimes / TICRATE; + cnt_time = plrs[me].stime / TICRATE; + cnt_par = wbs->partime / TICRATE; + S_StartSound(0, sfx_barexp); + sp_state = 10; + } + + if (sp_state == 2) + { + cnt_kills[0] += 2; + + if (!(bcnt&3)) + S_StartSound(0, sfx_pistol); + + if (cnt_kills[0] >= (plrs[me].skills * 100) / wbs->maxkills) + { + cnt_kills[0] = (plrs[me].skills * 100) / wbs->maxkills; + S_StartSound(0, sfx_barexp); + sp_state++; + } + } + else if (sp_state == 4) + { + cnt_items[0] += 2; + + if (!(bcnt&3)) + S_StartSound(0, sfx_pistol); + + if (cnt_items[0] >= (plrs[me].sitems * 100) / wbs->maxitems) + { + cnt_items[0] = (plrs[me].sitems * 100) / wbs->maxitems; + S_StartSound(0, sfx_barexp); + sp_state++; + } + } + else if (sp_state == 6) + { + cnt_secret[0] += 2; + + if (!(bcnt&3)) + S_StartSound(0, sfx_pistol); + + // killough 2/22/98: Make secrets = 100% if maxsecret = 0: + if ((!wbs->maxsecret && compatibility_level < lxdoom_1_compatibility) || + cnt_secret[0] >= (wbs->maxsecret ? + (plrs[me].ssecret * 100) / wbs->maxsecret : 100)) + { + cnt_secret[0] = (wbs->maxsecret ? + (plrs[me].ssecret * 100) / wbs->maxsecret : 100); + S_StartSound(0, sfx_barexp); + sp_state++; + } + } + else if (sp_state == 8) + { + if (!(bcnt&3)) + S_StartSound(0, sfx_pistol); + + cnt_time += 3; + + if (cnt_time >= plrs[me].stime / TICRATE) + cnt_time = plrs[me].stime / TICRATE; + + cnt_total_time += 3; + + if (cnt_total_time >= wbs->totaltimes / TICRATE) + cnt_total_time = wbs->totaltimes / TICRATE; + + cnt_par += 3; + + if (cnt_par >= wbs->partime / TICRATE) + { + cnt_par = wbs->partime / TICRATE; + + if ((cnt_time >= plrs[me].stime / TICRATE) && (compatibility_level < lxdoom_1_compatibility || cnt_total_time >= wbs->totaltimes / TICRATE)) + { + S_StartSound(0, sfx_barexp); + sp_state++; + } + } + } + else if (sp_state == 10) + { + if (acceleratestage) + { + S_StartSound(0, sfx_sgcock); + + if (gamemode == commercial) + WI_initNoState(); + else + WI_initShowNextLoc(); + } + } + else if (sp_state & 1) + { + if (!--cnt_pause) + { + sp_state++; + cnt_pause = TICRATE; + } + } +} + + +// ==================================================================== +// WI_drawStats +// Purpose: Put the solo stats on the screen +// Args: none +// Returns: void +// +// proff/nicolas 09/20/98 -- changed for hi-res +// CPhipps - patch drawing updated +void WI_drawStats(void) +{ + // line height + int lh; + + lh = (3*SHORT(num[0]->height))/2; + + WI_slamBackground(); + + // draw animated background + WI_drawAnimatedBack(); + + WI_drawLF(); + + V_DrawNamePatch(SP_STATSX, SP_STATSY, FB, kills, CR_DEFAULT, VPT_STRETCH); + WI_drawPercent(320 - SP_STATSX, SP_STATSY, cnt_kills[0]); + + V_DrawNamePatch(SP_STATSX, SP_STATSY+lh, FB, items, CR_DEFAULT, VPT_STRETCH); + WI_drawPercent(320 - SP_STATSX, SP_STATSY+lh, cnt_items[0]); + + V_DrawNamePatch(SP_STATSX, SP_STATSY+2*lh, FB, sp_secret, CR_DEFAULT, VPT_STRETCH); + WI_drawPercent(320 - SP_STATSX, SP_STATSY+2*lh, cnt_secret[0]); + + WI_drawTimeStats(cnt_time, cnt_total_time, cnt_par); +} + +// ==================================================================== +// WI_checkForAccelerate +// Purpose: See if the player has hit either the attack or use key +// or mouse button. If so we set acceleratestage to 1 and +// all those display routines above jump right to the end. +// Args: none +// Returns: void +// +void WI_checkForAccelerate(void) +{ + int i; + player_t *player; + + // check for button presses to skip delays + for (i=0, player = players ; icmd.buttons & BT_ATTACK) + { + if (!player->attackdown) + acceleratestage = 1; + player->attackdown = true; + } + else + player->attackdown = false; + + if (player->cmd.buttons & BT_USE) + { + if (!player->usedown) + acceleratestage = 1; + player->usedown = true; + } + else + player->usedown = false; + } + } +} + +// ==================================================================== +// WI_Ticker +// Purpose: Do various updates every gametic, for stats, animation, +// checking that intermission music is running, etc. +// Args: none +// Returns: void +// +void WI_Ticker(void) +{ + // counter for general background animation + bcnt++; + + if (bcnt == 1) + { + // intermission music + if ( gamemode == commercial ) + S_ChangeMusic(mus_dm2int, true); + else + S_ChangeMusic(mus_inter, true); + } + + WI_checkForAccelerate(); + + switch (state) + { + case StatCount: + if (deathmatch) WI_updateDeathmatchStats(); + else if (netgame) WI_updateNetgameStats(); + else WI_updateStats(); + break; + + case ShowNextLoc: + WI_updateShowNextLoc(); + break; + + case NoState: + WI_updateNoState(); + break; + } +} + +/* ==================================================================== + * WI_loadData + * Purpose: Initialize intermission data such as background graphics, + * patches, map names, etc. + * Args: none + * Returns: void + * + * CPhipps - modified for new wad lump handling. + * - no longer preload most graphics, other funcs can use + * them by name + */ + +void WI_loadData(void) +{ + int i; + int j; + char name[9]; // limited to 8 characters + anim_t* a; + + if (gamemode != commercial) + { + if (wbs->epsd < 3) + { + for (j=0;jepsd];j++) + { + a = &anims[wbs->epsd][j]; + for (i=0;inanims;i++) + { + // MONDO HACK! + if (wbs->epsd != 1 || j != 8) + { + // animations + snprintf(name, sizeof(name),"WIA%d%s%d%s%d", wbs->epsd, (j/10>0?"":"0"), j,(i/10>0?"":"0"), i); //ANOTHER ROCKHACK + //snprintf(name, sizeof(name),"WIA%d%.2d%.2d", wbs->epsd, j, i); + a->p[i] = W_CacheLumpName(name); + } + else + { + // HACK ALERT! + a->p[i] = anims[1][4].p[i]; + } + } + } + } + } + + for (i=0;i<10;i++) + { + // numbers 0-9 + snprintf(name,sizeof(name),"WINUM%d", i); + num[i] = W_CacheLumpName(name); + } +} + +// ==================================================================== +// WI_unloadData +// Purpose: Free up the space allocated during WI_loadData +// Args: none +// Returns: void +// +// CPhipps - reverse of WI_loadData, goes through the same lumps, but unlocking +void WI_unloadData(void) +{ + int i,j; + char name[9]; // limited to 8 characters + + // cph - unlock gamemode dependent stuff here + if (gamemode != commercial) { + if (wbs->epsd < 3) { + for (j=0;jepsd];j++) { + anim_t* a = &anims[wbs->epsd][j]; + for (i=0; inanims; i++) { + // MONDO HACK! + if (wbs->epsd != 1 || j != 8) { + // animations + snprintf(name, sizeof(name),"WIA%d%s%d%s%d", wbs->epsd, (j/10>0?"":"0"), j,(i/10>0?"":"0"), i); //ANOTHER ROCKHACK + //snprintf(name,sizeof(name), "WIA%d%.2d%.2d", wbs->epsd, j, i); + W_UnlockLumpName(name); + } + } + } + } + } + + for (i=0;i<10;i++) { + // numbers 0-9 + snprintf(name, sizeof(name),"WINUM%d", i); + W_UnlockLumpName(name); + } +} + + +// ==================================================================== +// WI_Drawer +// Purpose: Call the appropriate stats drawing routine depending on +// what kind of game is being played (DM, coop, solo) +// Args: none +// Returns: void +// +void WI_Drawer (void) +{ + switch (state) + { + case StatCount: + if (deathmatch) + WI_drawDeathmatchStats(); + else if (netgame) + WI_drawNetgameStats(); + else + WI_drawStats(); + break; + + case ShowNextLoc: + WI_drawShowNextLoc(); + break; + + case NoState: + WI_drawNoState(); + break; + } +} + +// ==================================================================== +// WI_initVariables +// Purpose: Initialize the intermission information structure +// Note: wbstartstruct_t is defined in d_player.h +// Args: wbstartstruct -- pointer to the structure with the data +// Returns: void +// +void WI_initVariables(wbstartstruct_t* wbstartstruct) +{ + + wbs = wbstartstruct; + +#ifdef RANGECHECKING + if (gamemode != commercial) + { + if ( gamemode == retail ) + RNGCHECK(wbs->epsd, 0, 3); + else + RNGCHECK(wbs->epsd, 0, 2); + } + else + { + RNGCHECK(wbs->last, 0, 8); + RNGCHECK(wbs->next, 0, 8); + } + RNGCHECK(wbs->pnum, 0, MAXPLAYERS); + RNGCHECK(wbs->pnum, 0, MAXPLAYERS); +#endif + + acceleratestage = 0; + cnt = bcnt = 0; + firstrefresh = 1; + me = wbs->pnum; + plrs = wbs->plyr; + + if (!wbs->maxkills) + wbs->maxkills = 1; // probably only useful in MAP30 + + if (!wbs->maxitems) + wbs->maxitems = 1; + + if ( gamemode != retail ) + if (wbs->epsd > 2) + wbs->epsd -= 3; +} + +// ==================================================================== +// WI_Start +// Purpose: Call the various init routines +// Note: wbstartstruct_t is defined in d_player.h +// Args: wbstartstruct -- pointer to the structure with the +// intermission data +// Returns: void +// +void WI_Start(wbstartstruct_t* wbstartstruct) +{ + WI_initVariables(wbstartstruct); + WI_loadData(); + + if (deathmatch) + WI_initDeathmatchStats(); + else if (netgame) + WI_initNetgameStats(); + else + WI_initStats(); +} diff --git a/apps/plugins/doom/wi_stuff.h b/apps/plugins/doom/wi_stuff.h new file mode 100644 index 0000000000..72c1d32d07 --- /dev/null +++ b/apps/plugins/doom/wi_stuff.h @@ -0,0 +1,62 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Intermission screens. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __WI_STUFF__ +#define __WI_STUFF__ + +//#include "v_video.h" + +#include "doomdef.h" + +// States for the intermission + +typedef enum +{ + NoState = -1, + StatCount, + ShowNextLoc + +} stateenum_t; + +// Called by main loop, animate the intermission. +void WI_Ticker (void); + +// Called by main loop, +// draws the intermission directly into the screen buffer. +void WI_Drawer (void); + +// Setup for an intermission screen. +void WI_Start(wbstartstruct_t* wbstartstruct); + +// Release intermission screen memory +void WI_End(void); + +#endif diff --git a/apps/plugins/doom/z_bmalloc.c b/apps/plugins/doom/z_bmalloc.c new file mode 100644 index 0000000000..47a9b4f892 --- /dev/null +++ b/apps/plugins/doom/z_bmalloc.c @@ -0,0 +1,117 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * This is designed to be a fast allocator for small, regularly used block sizes + *----------------------------------------------------------------------------- + */ +#include "doomtype.h" +#include "z_zone.h" +#include "z_bmalloc.h" +#include "i_system.h" +#include "rockmacros.h" + +typedef struct bmalpool_s { + struct bmalpool_s *nextpool; + size_t blocks; + byte used[0]; +} bmalpool_t; + +inline static void* getelem(bmalpool_t *p, size_t size, size_t n) +{ + return (((byte*)p) + sizeof(bmalpool_t) + sizeof(byte)*(p->blocks) + size*n); +} + +inline static int iselem(const bmalpool_t *pool, size_t size, const void* p) +{ + // CPhipps - need portable # of bytes between pointers + int dif = (const char*)p - (const char*)pool; + + dif -= sizeof(bmalpool_t); + dif -= pool->blocks; + if (dif<0) return -1; + dif /= size; + return (((size_t)dif >= pool->blocks) ? -1 : dif); +} + +enum { unused_block = 0, used_block = 1}; + +void* Z_BMalloc(struct block_memory_alloc_s *pzone) +{ + register bmalpool_t **pool = (bmalpool_t **)&(pzone->firstpool); + while (*pool != NULL) { + byte *p = memchr((*pool)->used, unused_block, (*pool)->blocks); // Scan for unused marker + if (p) { + int n = p - (*pool)->used; +#ifdef SIMPLECHECKS + if ((n<0) || ((size_t)n>=(*pool)->blocks)) + I_Error("Z_BMalloc: memchr returned pointer outside of array"); +#endif + (*pool)->used[n] = used_block; + return getelem(*pool, pzone->size, n); + } else + pool = &((*pool)->nextpool); + } + { + // Nothing available, must allocate a new pool + bmalpool_t *newpool; + + // CPhipps: Allocate new memory, initialised to 0 + + *pool = newpool = Z_Calloc(sizeof(*newpool) + (sizeof(byte) + pzone->size)*(pzone->perpool), + 1, pzone->tag, NULL); + newpool->nextpool = NULL; // NULL = (void*)0 so this is redundant + + // Return element 0 from this pool to satisfy the request + newpool->used[0] = used_block; + newpool->blocks = pzone->perpool; + return getelem(newpool, pzone->size, 0); + } +} + +void Z_BFree(struct block_memory_alloc_s *pzone, void* p) +{ + register bmalpool_t **pool = (bmalpool_t**)&(pzone->firstpool); + + while (*pool != NULL) { + int n = iselem(*pool, pzone->size, p); + if (n >= 0) { +#ifdef SIMPLECHECKS + if ((*pool)->used[n] == unused_block) + I_Error("Z_BFree: Refree in zone %s", pzone->desc); +#endif + (*pool)->used[n] = unused_block; + if (memchr(((*pool)->used), used_block, (*pool)->blocks) == NULL) { + // Block is all unused, can be freed + bmalpool_t *oldpool = *pool; + *pool = (*pool)->nextpool; + Z_Free(oldpool); + } + return; + } else pool = &((*pool)->nextpool); + } + I_Error("Z_BFree: Free not in zone %s", pzone->desc); +} diff --git a/apps/plugins/doom/z_bmalloc.h b/apps/plugins/doom/z_bmalloc.h new file mode 100644 index 0000000000..0c454fcff9 --- /dev/null +++ b/apps/plugins/doom/z_bmalloc.h @@ -0,0 +1,51 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Block memory allocator + * This is designed to be a fast allocator for small, regularly used block sizes + *-----------------------------------------------------------------------------*/ +#include "rockmacros.h" + +struct block_memory_alloc_s { + void *firstpool; + size_t size; + size_t perpool; + int tag; + const char *desc; +}; + +#define DECLARE_BLOCK_MEMORY_ALLOC_ZONE(name) extern struct block_memory_alloc_s name +#define IMPLEMENT_BLOCK_MEMORY_ALLOC_ZONE(name, size, tag, num, desc) \ +struct block_memory_alloc_s name = { NULL, size, num, tag, desc} +#define NULL_BLOCK_MEMORY_ALLOC_ZONE(name) name.firstpool = NULL + +void* Z_BMalloc(struct block_memory_alloc_s *pzone); + +inline static void* Z_BCalloc(struct block_memory_alloc_s *pzone) +{ void *p = Z_BMalloc(pzone); memset(p,0,pzone->size); return p; } + +void Z_BFree(struct block_memory_alloc_s *pzone, void* p); diff --git a/apps/plugins/doom/z_zone.c b/apps/plugins/doom/z_zone.c new file mode 100644 index 0000000000..036c995743 --- /dev/null +++ b/apps/plugins/doom/z_zone.c @@ -0,0 +1,666 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Zone Memory Allocation. Neat. + * + * Neat enough to be rewritten by Lee Killough... + * + * Must not have been real neat :) + * + * Made faster and more general, and added wrappers for all of Doom's + * memory allocation functions, including malloc() and similar functions. + * Added line and file numbers, in case of error. Added performance + * statistics and tunables. + *----------------------------------------------------------------------------- + */ + +#include "z_zone.h" +#include "z_bmalloc.h" +#include "doomdef.h" +#include "i_system.h" +#include "rockmacros.h" +#include "m_argv.h" + +// Tunables + +// Alignment of zone memory (benefit may be negated by HEADER_SIZE, CHUNK_SIZE) +#define CACHE_ALIGN 32 + +// Minimum chunk size at which blocks are allocated +#define CHUNK_SIZE 32 + +// Minimum size a block must be to become part of a split +#define MIN_BLOCK_SPLIT (1024) + +// Minimum RAM machine is assumed to have +/* cph - Select zone size. 6megs is usable, but with the SDL version + * storing sounds in the zone, 8 is more sensible */ +#define MIN_RAM (8*1024*1024) + +// Amount to subtract when retrying failed attempts to allocate initial pool +#define RETRY_AMOUNT (256*1024) + +// signature for block header +#define ZONEID 0x931d4a11 + +// Number of mallocs & frees kept in history buffer (must be a power of 2) +#define ZONE_HISTORY 4 + +// End Tunables + +typedef struct memblock { + +#ifdef ZONEIDCHECK + unsigned id; +#endif + + struct memblock *next,*prev; + size_t size; + void **user; + unsigned char tag,vm; + +#ifdef INSTRUMENTED + unsigned short extra; + const char *file; + int line; +#endif + +} memblock_t; + +/* size of block header + * cph - base on sizeof(memblock_t), which can be larger than CHUNK_SIZE on + * 64bit architectures */ +static const size_t HEADER_SIZE IDATA_ATTR= (sizeof(memblock_t)+CHUNK_SIZE-1) & ~(CHUNK_SIZE-1); + +static memblock_t *rover IBSS_ATTR; // roving pointer to memory blocks +static memblock_t *zone IBSS_ATTR; // pointer to first block +static memblock_t *zonebase IBSS_ATTR; // pointer to entire zone memory +static size_t zonebase_size IBSS_ATTR; // zone memory allocated size + +#ifdef INSTRUMENTED + +// statistics for evaluating performance +static size_t free_memory; +static size_t active_memory; +static size_t purgable_memory; +static size_t inactive_memory; +static size_t virtual_memory; + +static void Z_PrintStats(void) // Print allocation statistics +{ + unsigned long total_memory = free_memory + active_memory + + purgable_memory + inactive_memory + + virtual_memory; + double s = 100.0 / total_memory; + + doom_printf("%-5u\t%6.01f%%\tstatic\n" + "%-5u\t%6.01f%%\tpurgable\n" + "%-5u\t%6.01f%%\tfree\n" + "%-5u\t%6.01f%%\tfragmentary\n" + "%-5u\t%6.01f%%\tvirtual\n" + "%-5lu\t\ttotal\n", + active_memory, + active_memory*s, + purgable_memory, + purgable_memory*s, + free_memory, + free_memory*s, + inactive_memory, + inactive_memory*s, + virtual_memory, + virtual_memory*s, + total_memory + ); +} + +#ifdef HEAPDUMP +void W_PrintLump(FILE* fp, void* p); + +void Z_DumpMemory(void) +{ + static int dump; + memblock_t* block = zone; + char buf[80]; + FILE* fp; + size_t total_cache = 0, total_free = 0, total_malloc = 0; + + sprintf(buf, "memdump.%d", dump++); + fp = fopen(buf, "w"); + do { + switch (block->tag) { + case PU_FREE: + fprintf(fp, "free %d\n", block->size); + total_free += block->size; + break; + case PU_CACHE: + fprintf(fp, "cache %s:%d:%d\n", block->file, block->line, block->size); + total_cache += block->size; + break; + case PU_LEVEL: + fprintf(fp, "level %s:%d:%d\n", block->file, block->line, block->size); + total_malloc += block->size; + break; + default: + fprintf(fp, "malloc %s:%d:%d", block->file, block->line, block->size); + total_malloc += block->size; + if (!strcmp(block->file,"w_wad.c")) W_PrintLump(fp, (char*)block + HEADER_SIZE); + fputc('\n', fp); + break; + } + block=block->next; + } while (block != zone); + fprintf(fp, "malloc %d, cache %d, free %d, total %d\n", + total_malloc, total_cache, total_free, + total_malloc + total_cache + total_free); + fclose(fp); +} +#endif +#endif + +#ifdef INSTRUMENTED + +// killough 4/26/98: Add history information + +enum {malloc_history, free_history, NUM_HISTORY_TYPES}; + +static const char *file_history[NUM_HISTORY_TYPES][ZONE_HISTORY]; +static int line_history[NUM_HISTORY_TYPES][ZONE_HISTORY]; +static int history_index[NUM_HISTORY_TYPES]; +static const char *const desc[NUM_HISTORY_TYPES] = {"malloc()'s", "free()'s"}; + +void Z_DumpHistory(char *buf) +{ + int i,j; + char s[1024]; + strcat(buf,"\n"); + for (i=0;i= sizeof(memblock_t) && MIN_RAM > LEAVE_ASIDE)) + I_Error("Z_Init: Sanity check failed"); +#endif + +// atexit(Z_Close); // exit handler + + // Allocate the memory + + zonebase=rb->plugin_get_audio_buffer(&size); + size-=2*(HEADER_SIZE + CACHE_ALIGN); // Leave space for header and CACHE_ALIGN + size = (size+CHUNK_SIZE-1) & ~(CHUNK_SIZE-1); // round to chunk size + size += HEADER_SIZE + CACHE_ALIGN; + + zonebase_size=size; + + printf("Z_Init: Allocated %dKb zone memory\n", (long unsigned)size >> 10); + + // Align on cache boundary + + zone = (memblock_t *) ((char *) zonebase + CACHE_ALIGN - + ((unsigned) zonebase & (CACHE_ALIGN-1))); + + rover = zone; // Rover points to base of zone mem + zone->next = zone->prev = zone; // Single node + zone->size = size; // All memory in one block + zone->tag = PU_FREE; // A free block + zone->vm = 0; + +#ifdef ZONEIDCHECK + zone->id = 0; +#endif + +#ifdef INSTRUMENTED + free_memory = size; + inactive_memory = zonebase_size - size; + active_memory = purgable_memory = virtual_memory = 0; +#endif +} + +/* Z_Malloc + * You can pass a NULL user if the tag is < PU_PURGELEVEL. + * + * cph - the algorithm here was a very simple first-fit round-robin + * one - just keep looping around, freeing everything we can until + * we get a large enough space + * + * This has been changed now; we still do the round-robin first-fit, + * but we only free the blocks we actually end up using; we don't + * free all the stuff we just pass on the way. + */ + +void *(Z_Malloc)(size_t size, int tag, void **user +#ifdef INSTRUMENTED + , const char *file, int line +#endif + ) +{ + register memblock_t *block; + memblock_t *start, *first_of_free; + register size_t contig_free; + +#ifdef INSTRUMENTED + size_t size_orig = size; +#ifdef CHECKHEAP + Z_CheckHeap(); +#endif + + file_history[malloc_history][history_index[malloc_history]] = file; + line_history[malloc_history][history_index[malloc_history]++] = line; + history_index[malloc_history] &= ZONE_HISTORY-1; +#endif + +#ifdef ZONEIDCHECK + if (tag >= PU_PURGELEVEL && !user) + I_Error ("Z_Malloc: An owner is required for purgable blocks" +#ifdef INSTRUMENTED + "Source: %s:%d", file, line +#endif + ); +#endif + + if (!size) + return user ? *user = NULL : NULL; // malloc(0) returns NULL + + size = (size+CHUNK_SIZE-1) & ~(CHUNK_SIZE-1); // round to chunk size + + block = rover; + + if (block->prev->tag == PU_FREE) + block = block->prev; + + start = block; + first_of_free = NULL; contig_free = 0; + + do { + /* If we just wrapped, we're not contiguous with the previous block */ + if (block == zone) contig_free = 0; + + if (block->tag < PU_PURGELEVEL && block->tag != PU_FREE) { + /* Not free(able), so no free space here */ + contig_free = 0; + } else { + /* Add to contiguous chunk of free space */ + if (!contig_free) first_of_free = block; + contig_free += block->size; + + /* First fit */ + if (contig_free >= size) + break; + } + } + while ((block = block->next) != start); // detect cycles as failure + + if (contig_free >= size) { + /* We have a block of free(able) memory on the heap which will suffice */ + block = first_of_free; + + /* If the previous block is adjacent and free, step back and include it */ + if (block != zone && block->prev->tag == PU_FREE) + block = block->prev; + + /* Free current block if needed */ + if (block->tag != PU_FREE) Z_Free((char *) block + HEADER_SIZE); + + /* Note: guaranteed that block->prev is either + * not free or not contiguous + * + * At every step, block->next must be not free, else it would + * have been merged with our block + * No range check needed because we know it works by the previous loop */ + while (block->size < size) + Z_Free((char *)(block->next) + HEADER_SIZE); + + /* Now, carve up the block */ + { + size_t extra = block->size - size; + if (extra >= MIN_BLOCK_SPLIT + HEADER_SIZE) { + memblock_t *newb = (memblock_t *)((char *) block + + HEADER_SIZE + size); + + (newb->next = block->next)->prev = newb; + (newb->prev = block)->next = newb; // Split up block + block->size = size; + newb->size = extra - HEADER_SIZE; + newb->tag = PU_FREE; + newb->vm = 0; + +#ifdef INSTRUMENTED + inactive_memory += HEADER_SIZE; + free_memory -= HEADER_SIZE; +#endif + } + + rover = block->next; // set roving pointer for next search + +#ifdef INSTRUMENTED + inactive_memory += block->extra = block->size - size_orig; + if (tag >= PU_PURGELEVEL) + purgable_memory += size_orig; + else + active_memory += size_orig; + free_memory -= block->size; +#endif + } + } else { // We don't have enough contiguous free blocks + I_Error ("Z_Malloc: Failure trying to allocate %d bytes",(unsigned long) size); + rb->sleep(300); + } + +#ifdef INSTRUMENTED + block->file = file; + block->line = line; +#endif + +#ifdef ZONEIDCHECK + block->id = ZONEID; // signature required in block header +#endif + block->tag = tag; // tag + block->user = user; // user + block = (memblock_t *)((char *) block + HEADER_SIZE); + if (user) // if there is a user + *user = block; // set user to point to new block + +#ifdef INSTRUMENTED + Z_PrintStats(); // print memory allocation stats + // scramble memory -- weed out any bugs + memset(block, gametic & 0xff, size); +#endif + return block; +} + +void (Z_Free)(void *p +#ifdef INSTRUMENTED + , const char *file, int line +#endif + ) +{ +#ifdef INSTRUMENTED +#ifdef CHECKHEAP + Z_CheckHeap(); +#endif + file_history[free_history][history_index[free_history]] = file; + line_history[free_history][history_index[free_history]++] = line; + history_index[free_history] &= ZONE_HISTORY-1; +#endif + + if (p) + { + memblock_t *other, *block = (memblock_t *)((char *) p - HEADER_SIZE); + +#ifdef ZONEIDCHECK + if (block->id != ZONEID) + I_Error("Z_Free: freed a pointer without ZONEID" +#ifdef INSTRUMENTED + "\nSource: %s:%d" + "\nSource of malloc: %s:%d" + , file, line, block->file, block->line +#endif + ); + block->id = 0; // Nullify id so another free fails +#endif + +#ifdef INSTRUMENTED + /* scramble memory -- weed out any bugs */ + memset(p, gametic & 0xff, block->size); +#endif + + if (block->user) // Nullify user if one exists + *block->user = NULL; + + { + +#ifdef INSTRUMENTED + free_memory += block->size; + inactive_memory -= block->extra; + if (block->tag >= PU_PURGELEVEL) + purgable_memory -= block->size - block->extra; + else + active_memory -= block->size - block->extra; +#endif + + block->tag = PU_FREE; // Mark block freed + + if (block != zone) + { + other = block->prev; // Possibly merge with previous block + if (other->tag == PU_FREE) + { + if (rover == block) // Move back rover if it points at block + rover = other; + (other->next = block->next)->prev = other; + other->size += block->size + HEADER_SIZE; + block = other; + +#ifdef INSTRUMENTED + inactive_memory -= HEADER_SIZE; + free_memory += HEADER_SIZE; +#endif + } + } + + other = block->next; // Possibly merge with next block + if (other->tag == PU_FREE && other != zone) + { + if (rover == other) // Move back rover if it points at next block + rover = block; + (block->next = other->next)->prev = block; + block->size += other->size + HEADER_SIZE; + +#ifdef INSTRUMENTED + inactive_memory -= HEADER_SIZE; + free_memory += HEADER_SIZE; +#endif + } + } + +#ifdef INSTRUMENTED + Z_PrintStats(); // print memory allocation stats +#endif + } +} + +void (Z_FreeTags)(int lowtag, int hightag +#ifdef INSTRUMENTED + , const char *file, int line +#endif + ) +{ + /* cph - move rover to start of zone; we like to encourage static + * data to stay in one place, at the start of the heap + */ + memblock_t *block = rover = zone; + +#ifdef HEAPDUMP + Z_DumpMemory(); +#endif + + if (lowtag <= PU_FREE) + lowtag = PU_FREE+1; + + do // Scan through list, searching for tags in range + if (block->tag >= lowtag && block->tag <= hightag) + { + memblock_t *prev = block->prev, *cur = block; +#ifdef INSTRUMENTED + (Z_Free)((char *) block + HEADER_SIZE, file, line); +#else + (Z_Free)((char *) block + HEADER_SIZE); +#endif + /* cph - be more careful here, we were skipping blocks! + * If the current block was not merged with the previous, + * cur is still a valid pointer, prev->next == cur, and cur is + * already free so skip to the next. + * If the current block was merged with the previous, + * the next block to analyse is prev->next. + * Note that the while() below does the actual step forward + */ + block = (prev->next == cur) ? cur : prev; + } + while ((block=block->next) != zone); +} + +void (Z_ChangeTag)(void *ptr, int tag +#ifdef INSTRUMENTED + , const char *file, int line +#endif + ) +{ + memblock_t *block = (memblock_t *)((char *) ptr - HEADER_SIZE); + +#ifdef INSTRUMENTED +#ifdef CHECKHEAP + Z_CheckHeap(); +#endif +#endif + +#ifdef ZONEIDCHECK + if (block->id != ZONEID) + I_Error ("Z_ChangeTag: freed a pointer without ZONEID" +#ifdef INSTRUMENTED + "\nSource: %s:%d" + "\nSource of malloc: %s:%d" + , file, line, block->file, block->line +#endif + ); + + if (tag >= PU_PURGELEVEL && !block->user) + I_Error ("Z_ChangeTag: an owner is required for purgable blocks\n" +#ifdef INSTRUMENTED + "Source: %s:%d" + "\nSource of malloc: %s:%d" + , file, line, block->file, block->line +#endif + ); + +#endif // ZONEIDCHECK + + { +#ifdef INSTRUMENTED + if (block->tag < PU_PURGELEVEL && tag >= PU_PURGELEVEL) + { + active_memory -= block->size - block->extra; + purgable_memory += block->size - block->extra; + } + else + if (block->tag >= PU_PURGELEVEL && tag < PU_PURGELEVEL) + { + active_memory += block->size - block->extra; + purgable_memory -= block->size - block->extra; + } +#endif + } + block->tag = tag; +} + +void *(Z_Realloc)(void *ptr, size_t n, int tag, void **user +#ifdef INSTRUMENTED + , const char *file, int line +#endif + ) +{ + void *p = (Z_Malloc)(n, tag, user DA(file, line)); + if (ptr) + { + memblock_t *block = (memblock_t *)((char *) ptr - HEADER_SIZE); + memcpy(p, ptr, n <= block->size ? n : block->size); + (Z_Free)(ptr DA(file, line)); + if (user) // in case Z_Free nullified same user + *user=p; + } + return p; +} + +void *(Z_Calloc)(size_t n1, size_t n2, int tag, void **user +#ifdef INSTRUMENTED + , const char *file, int line +#endif + ) +{ + return + (n1*=n2) ? memset((Z_Malloc)(n1, tag, user DA(file, line)), 0, n1) : NULL; +} + +char *(Z_Strdup)(const char *s, int tag, void **user +#ifdef INSTRUMENTED + , const char *file, int line +#endif + ) +{ + return strcpy((Z_Malloc)(strlen(s)+1, tag, user DA(file, line)), s); +} + +void (Z_CheckHeap)( +#ifdef INSTRUMENTED + const char *file, int line +#endif +) +{ + memblock_t *block = zone; // Start at base of zone mem + do // Consistency check (last node treated special) + if ((block->next != zone && + (memblock_t *)((char *) block+HEADER_SIZE+block->size) != block->next) + || block->next->prev != block || block->prev->next != block) + I_Error("Z_ChkHp: B size %d touch %d\n", block+HEADER_SIZE+block->size, block->next +#ifdef INSTRUMENTED + "Source: %s:%d" + "\nSource of offending block: %s:%d" + , file, line, block->file, block->line +#endif + ); + while ((block=block->next) != zone); +} diff --git a/apps/plugins/doom/z_zone.h b/apps/plugins/doom/z_zone.h new file mode 100644 index 0000000000..6ab9bba106 --- /dev/null +++ b/apps/plugins/doom/z_zone.h @@ -0,0 +1,117 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Zone Memory Allocation, perhaps NeXT ObjectiveC inspired. + * Remark: this was the only stuff that, according + * to John Carmack, might have been useful for + * Quake. + * + * Rewritten by Lee Killough, though, since it was not efficient enough. + * + *---------------------------------------------------------------------*/ + +#ifndef __Z_ZONE__ +#define __Z_ZONE__ + +#ifndef __GNUC__ +#define __attribute__(x) +#endif + +// Include system definitions so that prototypes become +// active before macro replacements below are in effect. + +#include "plugin.h" + +// ZONE MEMORY +// PU - purge tags. + +enum {PU_FREE, PU_STATIC, PU_SOUND, PU_MUSIC, PU_LEVEL, PU_LEVSPEC, PU_CACHE, + /* Must always be last -- killough */ PU_MAX}; + +#define PU_PURGELEVEL PU_CACHE /* First purgable tag's level */ + +#ifdef INSTRUMENTED +#define DA(x,y) ,x,y +#define DAC(x,y) x,y +#else +#define DA(x,y) +#define DAC(x,y) void +#endif + +void *(Z_Malloc)(size_t size, int tag, void **ptr DA(const char *, int)); +void (Z_Free)(void *ptr DA(const char *, int)); +void (Z_FreeTags)(int lowtag, int hightag DA(const char *, int)); +void (Z_ChangeTag)(void *ptr, int tag DA(const char *, int)); +void (Z_Init)(void); +void Z_Close(void); +void *(Z_Calloc)(size_t n, size_t n2, int tag, void **user DA(const char *, int)); +void *(Z_Realloc)(void *p, size_t n, int tag, void **user DA(const char *, int)); +char *(Z_Strdup)(const char *s, int tag, void **user DA(const char *, int)); +void (Z_CheckHeap)(DAC(const char *,int)); // killough 3/22/98: add file/line info +void Z_DumpHistory(char *); + +#ifdef INSTRUMENTED +/* cph - save space if not debugging, don't require file + * and line to memory calls */ +#define Z_Free(a) (Z_Free) (a, __FILE__,__LINE__) +#define Z_FreeTags(a,b) (Z_FreeTags) (a,b, __FILE__,__LINE__) +#define Z_ChangeTag(a,b) (Z_ChangeTag)(a,b, __FILE__,__LINE__) +#define Z_Malloc(a,b,c) (Z_Malloc) (a,b,c, __FILE__,__LINE__) +#define Z_Strdup(a,b,c) (Z_Strdup) (a,b,c, __FILE__,__LINE__) +#define Z_Calloc(a,b,c,d) (Z_Calloc) (a,b,c,d,__FILE__,__LINE__) +#define Z_Realloc(a,b,c,d) (Z_Realloc) (a,b,c,d,__FILE__,__LINE__) +#define Z_CheckHeap() (Z_CheckHeap)(__FILE__,__LINE__) +#endif + +/* cphipps 2001/11/18 - + * If we're using memory mapped file access to WADs, we won't need to maintain + * our own heap. So we *could* let "normal" malloc users use the libc malloc + * directly, for efficiency. Except we do need a wrapper to handle out of memory + * errors... damn, ok, we'll leave it for now. + */ + +#undef malloc +#undef free +#undef realloc +#undef calloc +#undef strdup + +#define malloc(n) Z_Malloc(n,PU_STATIC,0) +#define free(p) Z_Free(p) +#define realloc(p,n) Z_Realloc(p,n,PU_STATIC,0) +#define calloc(n1,n2) Z_Calloc(n1,n2,PU_STATIC,0) +#undef strdup + +char *strdup(const char *s); + +#define strdup(s) Z_Strdup(s,PU_STATIC,0) + +void Z_ZoneHistory(char *); + +extern size_t zone_size; + +#endif