summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorDave Chapman <dave@dchapman.com>2006-03-28 15:44:01 +0000
committerDave Chapman <dave@dchapman.com>2006-03-28 15:44:01 +0000
commit47f4a458d636a889e955e68f896708f1276febc0 (patch)
tree99f770c02ef606f0abbdcd332ac39e69830d8007 /apps
parentfff7d6157d56f233cad5c2003475e47a5ff809a7 (diff)
downloadrockbox-47f4a458d636a889e955e68f896708f1276febc0.zip
rockbox-47f4a458d636a889e955e68f896708f1276febc0.tar.gz
rockbox-47f4a458d636a889e955e68f896708f1276febc0.tar.bz2
rockbox-47f4a458d636a889e955e68f896708f1276febc0.tar.xz
Patch #2969 - Doom! Currently only working on the H300.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@9312 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps')
-rw-r--r--apps/plugin.c6
-rw-r--r--apps/plugin.h7
-rw-r--r--apps/plugins/Makefile5
-rw-r--r--apps/plugins/doom/Changelog47
-rw-r--r--apps/plugins/doom/Makefile145
-rw-r--r--apps/plugins/doom/am_map.c1702
-rw-r--r--apps/plugins/doom/am_map.h106
-rw-r--r--apps/plugins/doom/d_englsh.h705
-rw-r--r--apps/plugins/doom/d_event.h128
-rw-r--r--apps/plugins/doom/d_french.h437
-rw-r--r--apps/plugins/doom/d_items.c138
-rw-r--r--apps/plugins/doom/d_items.h57
-rw-r--r--apps/plugins/doom/d_main.c844
-rw-r--r--apps/plugins/doom/d_main.h74
-rw-r--r--apps/plugins/doom/d_net.c149
-rw-r--r--apps/plugins/doom/d_net.h213
-rw-r--r--apps/plugins/doom/d_player.h232
-rw-r--r--apps/plugins/doom/d_think.h92
-rw-r--r--apps/plugins/doom/d_ticcmd.h57
-rw-r--r--apps/plugins/doom/doomdata.h187
-rw-r--r--apps/plugins/doom/doomdef.c39
-rw-r--r--apps/plugins/doom/doomdef.h306
-rw-r--r--apps/plugins/doom/doomstat.c104
-rw-r--r--apps/plugins/doom/doomstat.h373
-rw-r--r--apps/plugins/doom/doomtype.h85
-rw-r--r--apps/plugins/doom/dstrings.c83
-rw-r--r--apps/plugins/doom/dstrings.h73
-rw-r--r--apps/plugins/doom/f_finale.c682
-rw-r--r--apps/plugins/doom/f_finale.h54
-rw-r--r--apps/plugins/doom/f_wipe.c193
-rw-r--r--apps/plugins/doom/f_wipe.h43
-rw-r--r--apps/plugins/doom/g_game.c2818
-rw-r--r--apps/plugins/doom/g_game.h192
-rw-r--r--apps/plugins/doom/hu_lib.c770
-rw-r--r--apps/plugins/doom/hu_lib.h264
-rw-r--r--apps/plugins/doom/hu_stuff.c1753
-rw-r--r--apps/plugins/doom/hu_stuff.h92
-rw-r--r--apps/plugins/doom/i_sound.c607
-rw-r--r--apps/plugins/doom/i_sound.h126
-rw-r--r--apps/plugins/doom/i_system.c134
-rw-r--r--apps/plugins/doom/i_system.h65
-rw-r--r--apps/plugins/doom/i_video.c454
-rw-r--r--apps/plugins/doom/i_video.h56
-rw-r--r--apps/plugins/doom/info.c5185
-rw-r--r--apps/plugins/doom/info.h1454
-rw-r--r--apps/plugins/doom/m_argv.c53
-rw-r--r--apps/plugins/doom/m_argv.h45
-rw-r--r--apps/plugins/doom/m_bbox.c58
-rw-r--r--apps/plugins/doom/m_bbox.h54
-rw-r--r--apps/plugins/doom/m_cheat.c104
-rw-r--r--apps/plugins/doom/m_cheat.h63
-rw-r--r--apps/plugins/doom/m_fixed.h94
-rw-r--r--apps/plugins/doom/m_menu.c1848
-rw-r--r--apps/plugins/doom/m_menu.h121
-rw-r--r--apps/plugins/doom/m_misc.c1077
-rw-r--r--apps/plugins/doom/m_misc.h112
-rw-r--r--apps/plugins/doom/m_random.c136
-rw-r--r--apps/plugins/doom/m_random.h148
-rw-r--r--apps/plugins/doom/m_swap.h104
-rw-r--r--apps/plugins/doom/p_ceilng.c468
-rw-r--r--apps/plugins/doom/p_doors.c672
-rw-r--r--apps/plugins/doom/p_enemy.c2623
-rw-r--r--apps/plugins/doom/p_enemy.h50
-rw-r--r--apps/plugins/doom/p_floor.c1035
-rw-r--r--apps/plugins/doom/p_genlin.c1154
-rw-r--r--apps/plugins/doom/p_inter.c904
-rw-r--r--apps/plugins/doom/p_inter.h77
-rw-r--r--apps/plugins/doom/p_lights.c437
-rw-r--r--apps/plugins/doom/p_map.c2207
-rw-r--r--apps/plugins/doom/p_map.h90
-rw-r--r--apps/plugins/doom/p_maputl.c700
-rw-r--r--apps/plugins/doom/p_maputl.h91
-rw-r--r--apps/plugins/doom/p_mobj.c1394
-rw-r--r--apps/plugins/doom/p_mobj.h409
-rw-r--r--apps/plugins/doom/p_plats.c434
-rw-r--r--apps/plugins/doom/p_pspr.c853
-rw-r--r--apps/plugins/doom/p_pspr.h93
-rw-r--r--apps/plugins/doom/p_saveg.c987
-rw-r--r--apps/plugins/doom/p_saveg.h63
-rw-r--r--apps/plugins/doom/p_setup.c1255
-rw-r--r--apps/plugins/doom/p_setup.h55
-rw-r--r--apps/plugins/doom/p_sight.c346
-rw-r--r--apps/plugins/doom/p_spec.c3255
-rw-r--r--apps/plugins/doom/p_spec.h1148
-rw-r--r--apps/plugins/doom/p_switch.c1138
-rw-r--r--apps/plugins/doom/p_telept.c322
-rw-r--r--apps/plugins/doom/p_tick.c255
-rw-r--r--apps/plugins/doom/p_tick.h66
-rw-r--r--apps/plugins/doom/p_user.c420
-rw-r--r--apps/plugins/doom/p_user.h45
-rw-r--r--apps/plugins/doom/r_bsp.c576
-rw-r--r--apps/plugins/doom/r_bsp.h78
-rw-r--r--apps/plugins/doom/r_data.c975
-rw-r--r--apps/plugins/doom/r_data.h105
-rw-r--r--apps/plugins/doom/r_defs.h422
-rw-r--r--apps/plugins/doom/r_draw.c677
-rw-r--r--apps/plugins/doom/r_draw.h99
-rw-r--r--apps/plugins/doom/r_main.c531
-rw-r--r--apps/plugins/doom/r_main.h125
-rw-r--r--apps/plugins/doom/r_plane.c434
-rw-r--r--apps/plugins/doom/r_plane.h65
-rw-r--r--apps/plugins/doom/r_segs.c843
-rw-r--r--apps/plugins/doom/r_segs.h42
-rw-r--r--apps/plugins/doom/r_sky.c53
-rw-r--r--apps/plugins/doom/r_sky.h53
-rw-r--r--apps/plugins/doom/r_state.h140
-rw-r--r--apps/plugins/doom/r_things.c976
-rw-r--r--apps/plugins/doom/r_things.h80
-rw-r--r--apps/plugins/doom/rockdoom.c706
-rw-r--r--apps/plugins/doom/rockmacros.h93
-rw-r--r--apps/plugins/doom/s_sound.c608
-rw-r--r--apps/plugins/doom/s_sound.h96
-rw-r--r--apps/plugins/doom/sounds.c240
-rw-r--r--apps/plugins/doom/sounds.h303
-rw-r--r--apps/plugins/doom/st_lib.c372
-rw-r--r--apps/plugins/doom/st_lib.h207
-rw-r--r--apps/plugins/doom/st_stuff.c1153
-rw-r--r--apps/plugins/doom/st_stuff.h101
-rw-r--r--apps/plugins/doom/tables.c2196
-rw-r--r--apps/plugins/doom/tables.h103
-rw-r--r--apps/plugins/doom/v_video.c700
-rw-r--r--apps/plugins/doom/v_video.h185
-rw-r--r--apps/plugins/doom/w_wad.c683
-rw-r--r--apps/plugins/doom/w_wad.h164
-rw-r--r--apps/plugins/doom/wi_stuff.c1989
-rw-r--r--apps/plugins/doom/wi_stuff.h62
-rw-r--r--apps/plugins/doom/z_bmalloc.c117
-rw-r--r--apps/plugins/doom/z_bmalloc.h51
-rw-r--r--apps/plugins/doom/z_zone.c666
-rw-r--r--apps/plugins/doom/z_zone.h117
130 files changed, 65584 insertions, 1 deletions
diff --git a/apps/plugin.c b/apps/plugin.c
index d69fbfc..b18ccb0 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 a2182d6..f9cca6f 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -29,6 +29,7 @@
#define MEM 2
#endif
+#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
@@ -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 586eb60..c59033a 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 0000000..2663af1
--- /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 0000000..c45ffe7
--- /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 0000000..9bdd4e4
--- /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<<FRACBITS, m_w);
+ scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
+}
+
+//
+// AM_addMark()
+//
+// Adds a marker at the current location
+// Affects global variables for marked points
+//
+// Passed nothing, returns nothing
+//
+void AM_addMark(void)
+{
+ // killough 2/22/98:
+ // remove limit on automap marks
+
+ if (markpointnum >= 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<numvertexes;i++)
+ {
+ if (vertexes[i].x < min_x)
+ min_x = vertexes[i].x;
+ else if (vertexes[i].x > 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<<FRACBITS, max_w);
+ b = FixedDiv(f_h<<FRACBITS, max_h);
+
+ min_scale_mtof = a < b ? a : b;
+ max_scale_mtof = FixedDiv(f_h<<FRACBITS, 2*PLAYERRADIUS);
+}
+
+//
+// AM_changeWindowLoc()
+//
+// Moves the map window by the global variables m_paninc.x, m_paninc.y
+//
+// Passed nothing, returns nothing
+//
+void AM_changeWindowLoc(void)
+{
+ if (m_paninc.x || m_paninc.y)
+ {
+ automapmode &= ~am_follow;
+ f_oldloc.x = INT_MAX;
+ }
+
+ m_x += m_paninc.x;
+ m_y += m_paninc.y;
+
+ if (m_x + m_w/2 > 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;pnum<MAXPLAYERS;pnum++)
+ if (playeringame[pnum])
+ break;
+
+ plr = &players[pnum];
+ m_x = plr->mo->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<<FRACBITS))
+ start += (MAPBLOCKUNITS<<FRACBITS)
+ - ((start-bmaporgx)%(MAPBLOCKUNITS<<FRACBITS));
+ end = m_x + m_w;
+
+ // draw vertical gridlines
+ ml.a.y = m_y;
+ ml.b.y = m_y+m_h;
+ for (x=start; x<end; x+=(MAPBLOCKUNITS<<FRACBITS))
+ {
+ ml.a.x = x;
+ ml.b.x = x;
+ AM_drawMline(&ml, color);
+ }
+
+ // Figure out start of horizontal gridlines
+ start = m_y;
+ if ((start-bmaporgy)%(MAPBLOCKUNITS<<FRACBITS))
+ start += (MAPBLOCKUNITS<<FRACBITS)
+ - ((start-bmaporgy)%(MAPBLOCKUNITS<<FRACBITS));
+ end = m_y + m_h;
+
+ // draw horizontal gridlines
+ ml.a.x = m_x;
+ ml.b.x = m_x + m_w;
+ for (y=start; y<end; y+=(MAPBLOCKUNITS<<FRACBITS))
+ {
+ ml.a.y = y;
+ ml.b.y = y;
+ AM_drawMline(&ml, color);
+ }
+}
+
+//
+// AM_DoorColor()
+//
+// Returns the 'color' or key needed for a door linedef type
+//
+// Passed the type of linedef, returns:
+// -1 if not a keyed door
+// 0 if a red key required
+// 1 if a blue key required
+// 2 if a yellow key required
+// 3 if a multiple keys required
+//
+// jff 4/3/98 add routine to get color of generalized keyed door
+//
+int AM_DoorColor(int type)
+{
+ if (GenLockedBase <= type && type< GenDoorBase)
+ {
+ type -= GenLockedBase;
+ type = (type & LockedKey) >> 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;i<numlines;i++)
+ {
+ l.a.x = lines[i].v1->x;
+ 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;i<lineguylines;i++)
+ {
+ l.a.x = lineguy[i].a.x;
+ l.a.y = lineguy[i].a.y;
+
+ if (scale)
+ {
+ l.a.x = FixedMul(scale, l.a.x);
+ l.a.y = FixedMul(scale, l.a.y);
+ }
+
+ if (angle)
+ AM_rotate(&l.a.x, &l.a.y, angle, 0, 0);
+
+ l.a.x += x;
+ l.a.y += y;
+
+ l.b.x = lineguy[i].b.x;
+ l.b.y = lineguy[i].b.y;
+
+ if (scale)
+ {
+ l.b.x = FixedMul(scale, l.b.x);
+ l.b.y = FixedMul(scale, l.b.y);
+ }
+
+ if (angle)
+ AM_rotate(&l.b.x, &l.b.y, angle, 0, 0);
+
+ l.b.x += x;
+ l.b.y += y;
+
+ AM_drawMline(&l, color);
+ }
+}
+
+//
+// AM_drawPlayers()
+//
+// Draws the player arrow in single player,
+// or all the player arrows in a netgame.
+//
+// Passed nothing, returns nothing
+//
+void AM_drawPlayers(void)
+{
+ int i;
+
+ if (!netgame)
+ {
+ if (ddt_cheating)
+ AM_drawLineCharacter
+ (
+ cheat_player_arrow,
+ NUMCHEATPLYRLINES,
+ 0,
+ plr->mo->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;i<MAXPLAYERS;i++) {
+ player_t* p = &players[i];
+
+ if ( (deathmatch && !singledemo) && p != plr)
+ continue;
+
+ if (playeringame[i]) {
+ fixed_t x = p->mo->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;i<numsectors;i++)
+ {
+ t = sectors[i].thinglist;
+ while (t) // for all things in that sector
+ {
+ fixed_t x = t->x, 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<<FRACBITS,
+ t->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<<FRACBITS,
+ t->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<<FRACBITS,
+ t->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<<FRACBITS,
+ t->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;i<markpointnum;i++) // killough 2/22/98: remove automap mark limit
+ if (markpoints[i].x != -1)
+ {
+ int w = 5;
+ int h = 6;
+ int fx = markpoints[i].x;
+ int fy = markpoints[i].y;
+ int j = i;
+
+ if (automapmode & am_rotate)
+ AM_rotate(&fx, &fy, ANG90-plr->mo->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 0000000..5599a3c
--- /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 0000000..596b877
--- /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 0000000..6896fd5
--- /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 0000000..6910ad0
--- /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 0000000..de4cfaa
--- /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 0000000..313fdb8
--- /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 0000000..d76779c
--- /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<myargc-1)
+ scale = atoi (myargv[p+1]);
+ if (scale < 10)
+ scale = 10;
+ if (scale > 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<myargc-1)
+ {
+ // for statistics driver
+ extern void* statcopy;
+
+ statcopy = (void*)atoi(myargv[p+1]);
+ printf ("External statistics registered.\n");
+ }
+
+ // start the apropriate game based on parms
+ p = M_CheckParm ("-record");
+ if (p && p < myargc-1)
+ {
+ G_RecordDemo (myargv[p+1]);
+ autostart = true;
+ }
+
+ p = M_CheckParm ("-loadgame");
+ if (p && p < myargc-1)
+ G_LoadGame (atoi(myargv[p+1]), false);
+
+ if ( gameaction != ga_loadgame )
+ {
+ if (!singledemo) { /* killough 12/98 */
+ if (autostart || netgame)
+ G_InitNew (startskill, startepisode, startmap);
+ else
+ D_StartTitle (); // start up intro loop
+ }
+ }
+}
+
+//
+// D_DoomMain
+//
+void D_DoomMain (void)
+{
+ D_DoomMainSetup(); // get this crap off the stack
+
+ D_DoomLoop (); // never returns
+}
diff --git a/apps/plugins/doom/d_main.h b/apps/plugins/doom/d_main.h
new file mode 100644
index 0000000..c7a861e
--- /dev/null
+++ b/apps/plugins/doom/d_main.h
@@ -0,0 +1,74 @@
+/* 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 startup and splash screenstuff.
+ *
+ *-----------------------------------------------------------------------------*/
+
+#ifndef __D_MAIN__
+#define __D_MAIN__
+
+#include "d_event.h"
+#include "w_wad.h"
+#include "doomdef.h"
+
+#ifdef __GNUG__
+#pragma interface
+#endif
+
+// jff make startskill globally visible
+extern skill_t startskill;
+
+//jff 1/24/98 make command line copies of play modes available
+extern boolean clnomonsters; // checkparm of -nomonsters
+extern boolean clrespawnparm; // checkparm of -respawn
+extern boolean clfastparm; // checkparm of -fast
+//jff end of external declaration of command line playmode
+
+extern boolean nosfxparm;
+extern boolean nomusicparm;
+extern int ffmap;
+
+// Called by IO functions when input is detected.
+void D_PostEvent(event_t* ev);
+
+// Demo stuff
+extern boolean advancedemo;
+void D_AdvanceDemo(void);
+void D_DoAdvanceDemo (void);
+
+//
+// BASE LEVEL
+//
+
+void D_PageTicker(void);
+void D_PageDrawer(void);
+void D_StartTitle(void);
+void D_DoomMain(void);
+void D_AddFile (const char *file, wad_source_t source);
+
+#endif
diff --git a/apps/plugins/doom/d_net.c b/apps/plugins/doom/d_net.c
new file mode 100644
index 0000000..f70c443
--- /dev/null
+++ b/apps/plugins/doom/d_net.c
@@ -0,0 +1,149 @@
+/* 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:
+ * Network client. Passes information to/from server, staying
+ * synchronised.
+ * Contains the main wait loop, waiting for network input or
+ * time before doing the next tic.
+ * Rewritten for LxDoom, but based around bits of the old code.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+#include "m_menu.h"
+#include "i_system.h"
+#include "i_video.h"
+#include "i_sound.h"
+#include "g_game.h"
+#include "doomdef.h"
+#include "doomstat.h"
+
+#include "rockmacros.h"
+
+#define NCMD_EXIT 0x80000000
+#define NCMD_RETRANSMIT 0x40000000
+#define NCMD_SETUP 0x20000000
+#define NCMD_KILL 0x10000000 // kill game
+#define NCMD_CHECKSUM 0x0fffffff
+
+
+doomcom_t* doomcom;
+
+static boolean server=0;
+static int remotetic; // Tic expected from the remote
+static int remotesend; // Tic expected by the remote
+
+//
+// NETWORKING
+//
+// gametic is the tic about to (or currently being) run
+// maketic is the tick that hasn't had control made for it yet
+// nettics[] has the maketics for all players
+//
+// a gametic cannot be run until nettics[] > 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; i<doomcom->numplayers; i++)
+ playeringame[i] = true;
+ for (; i<MAXPLAYERS; i++)
+ playeringame[i] = false;
+
+ consoleplayer = displayplayer = doomcom->consoleplayer;
+}
+
+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 0000000..6b586e3
--- /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 0000000..f86b68f
--- /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 0000000..55e9996
--- /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 0000000..1193a32
--- /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 0000000..f56524e
--- /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 0000000..d4ad61e
--- /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 0000000..f76b092
--- /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 0000000..75cc209
--- /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 0000000..42cd4f5
--- /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 0000000..59b3375
--- /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 0000000..104e99c
--- /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 0000000..4402c21
--- /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 <stddef.h>
+
+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 0000000..4deb3df
--- /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<MAXPLAYERS; i++)
+ if (players[i].cmd.buttons)
+ goto next_level; // go on to the next level
+
+ // advance animation
+ finalecount++;
+
+ if (finalestage == 2)
+ F_CastTicker();
+
+ if (!finalestage)
+ {
+ float speed = demo_compatibility ? TEXTSPEED : Get_TextSpeed();
+ /* killough 2/28/98: changed to allow acceleration */
+ if (finalecount > 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 0000000..63e2fbd
--- /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 0000000..a6251f2
--- /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<height;y++)
+ for(x=0;x<width;x++)
+ dest[x*height+y] = array[y*width+x];
+ memcpy(array, dest, width*height*sizeof(short));
+ Z_Free(dest);
+}
+
+static int *y;
+
+static int wipe_initMelt(int width, int height, int ticks)
+{
+ (void)ticks;
+ int i;
+
+ // copy start screen to main screen
+ memcpy(wipe_scr, wipe_scr_start, width*height);
+
+ // makes this wipe faster (in theory)
+ // to have stuff in column-major format
+ wipe_shittyColMajorXform((short*)wipe_scr_start, width/2, height);
+ wipe_shittyColMajorXform((short*)wipe_scr_end, width/2, height);
+
+ // setup initial column positions (y<0 => not ready to scroll yet)
+ y = (int *) malloc(width*sizeof(int));
+ y[0] = -(M_Random()%16);
+ for (i=1;i<width;i++)
+ {
+ int r = (M_Random()%3) - 1;
+ y[i] = y[i-1] + r;
+ if (y[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<width;i++)
+ if (y[i]<0)
+ {
+ y[i]++;
+ done = false;
+ }
+ else
+ if (y[i] < height)
+ {
+ short *s, *d;
+ int j, dy, idx;
+
+ dy = (y[i] < 16) ? y[i]+1 : 8;
+ if (y[i]+dy >= 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 0000000..ec19a81
--- /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 0000000..426ab1c
--- /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<<BT_WEAPONSHIFT;
+ }
+
+ // mouse
+ if (mousebuttons[mousebforward])
+ forward += forwardmove[speed];
+
+ // forward double click
+ if (mousebuttons[mousebforward] != dclickstate && dclicktime > 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 ; i<MAXPLAYERS ; i++)
+ {
+ if (playeringame[i] && players[i].playerstate == PST_DEAD)
+ players[i].playerstate = PST_REBORN;
+ memset (players[i].frags,0,sizeof(players[i].frags));
+ }
+
+ // initialize the msecnode_t freelist. phares 3/25/98
+ // any nodes in the freelist are gone by now, cleared
+ // by Z_FreeTags() when the previous level ended or player
+ // died.
+
+ {
+ DECLARE_BLOCK_MEMORY_ALLOC_ZONE(secnodezone);
+ NULL_BLOCK_MEMORY_ALLOC_ZONE(secnodezone);
+ //extern msecnode_t *headsecnode; // phares 3/25/98
+ //headsecnode = NULL;
+ }
+
+ P_SetupLevel (gameepisode, gamemap, 0, gameskill);
+ displayplayer = consoleplayer; // view the guy you are playing
+ gameaction = ga_nothing;
+ Z_CheckHeap ();
+
+ // clear cmd building stuff
+ memset (gamekeydown, 0, sizeof(gamekeydown));
+ joyxmove = joyymove = 0;
+ mousex = mousey = 0;
+ special_event = 0; paused = false;
+ memset (mousebuttons, 0, sizeof(mousebuttons));
+ memset (joybuttons, 0, sizeof(joybuttons));
+
+ // killough 5/13/98: in case netdemo has consoleplayer other than green
+ ST_Start();
+ HU_Start();
+
+ // killough: make -timedemo work on multilevel demos
+ // Move to end of function to minimize noise -- killough 2/22/98:
+
+ if (timingdemo)
+ {
+ static int first=1;
+ if (first)
+ {
+ starttime = I_GetTime ();
+ first=0;
+ }
+ }
+}
+
+//
+// G_Responder
+// Get info needed to make ticcmd_ts for the players.
+//
+boolean G_Responder (event_t* ev)
+{
+ // allow spy mode changes even during the demo
+ // killough 2/22/98: even during DM demo
+ //
+ // killough 11/98: don't autorepeat spy mode switch
+
+ if (ev->data1 == 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 <NUMKEYS)
+ gamekeydown[ev->data1] = true;
+ return true; // eat key down events
+
+ case ev_keyup:
+ if (ev->data1 <NUMKEYS)
+ gamekeydown[ev->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 ; i<MAXPLAYERS ; i++)
+ if (playeringame[i] && players[i].playerstate == PST_REBORN)
+ G_DoReborn (i);
+ P_MapEnd();
+
+ // do things to change the game state
+ while (gameaction != ga_nothing)
+ {
+ switch (gameaction)
+ {
+ case ga_loadlevel:
+ // force players to be initialized on level reload
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ players[i].playerstate = PST_REBORN;
+ G_DoLoadLevel ();
+ break;
+ case ga_newgame:
+ G_DoNewGame ();
+ break;
+ case ga_loadgame:
+ G_DoLoadGame ();
+ break;
+ case ga_savegame:
+ G_DoSaveGame (false);
+ break;
+ case ga_playdemo:
+ G_DoPlayDemo ();
+ break;
+ case ga_completed:
+ G_DoCompleted ();
+ break;
+ case ga_victory:
+ F_StartFinale ();
+ break;
+ case ga_worlddone:
+ G_DoWorldDone ();
+ break;
+ case ga_nothing:
+ break;
+ }
+ }
+
+ if (paused & 2 || (!demoplayback && menuactive && !netgame))
+ basetic++; // For revenant tracers and RNG -- we must maintain sync
+ else
+ {
+ // get commands, check consistancy, and build new consistancy check
+ int buf = (gametic/ticdup)%BACKUPTICS;
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ {
+ if (playeringame[i])
+ {
+ ticcmd_t *cmd = &players[i].cmd;
+
+ memcpy(cmd, &netcmds[i][buf], sizeof *cmd);
+
+ if (demoplayback)
+ G_ReadDemoTiccmd (cmd);
+ if (demorecording)
+ G_WriteDemoTiccmd (cmd);
+
+ // check for turbo cheats
+ // killough 2/14/98, 2/20/98 -- only warn in netgames and demos
+
+ if ((netgame || demoplayback) && cmd->forwardmove > 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<MAXPLAYERS ; i++)
+ {
+ if (playeringame[i])
+ {
+ if (players[i].cmd.buttons & BT_SPECIAL)
+ {
+ switch (players[i].cmd.buttons & BT_SPECIALMASK)
+ {
+ case BTS_PAUSE:
+ paused ^= 1;
+ if (paused)
+ S_PauseSound ();
+ else
+ S_ResumeSound ();
+ break;
+
+ case BTS_SAVEGAME:
+ if (!savedescription[0])
+ strcpy(savedescription, "NET GAME");
+ savegameslot =
+ (players[i].cmd.buttons & BTS_SAVEMASK)>>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; i<MAXPLAYERS; i++) {
+ if ((gamestate == GS_LEVEL) && playeringame[i] && (players[i].mo != NULL)) {
+ players[i].mo->flags &= ~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 ; i<NUMAMMO ; i++)
+ p->maxammo[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 ; i<playernum ; i++)
+ if (players[i].mo->x == 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<MAXPLAYERS ; i++)
+ {
+ if (G_CheckSpot (playernum, &playerstarts[i]) )
+ {
+ playerstarts[i].type = playernum+1; // fake as other player
+ P_SpawnPlayer (&playerstarts[i]);
+ playerstarts[i].type = i+1; // restore
+ return;
+ }
+ // he's going to be inside something. Too bad.
+ }
+ P_SpawnPlayer (&playerstarts[playernum]);
+ }
+}
+
+// DOOM Par Times
+int pars[4][10] =
+ {
+ {0},
+ {0,30,75,120,90,165,180,180,30,165},
+ {0,90,90,90,120,90,360,240,30,170},
+ {0,90,45,90,150,90,90,165,30,135}
+ };
+
+// DOOM II Par Times
+int cpars[32] =
+ {
+ 30,90,120,120,90,150,120,120,270,90, // 1-10
+ 210,150,150,150,210,150,420,150,210,150, // 11-20
+ 240,150,180,150,150,300,330,420,300,180, // 21-30
+ 120,30 // 31-32
+ };
+
+static boolean secretexit;
+
+void G_ExitLevel (void)
+{
+ secretexit = false;
+ gameaction = ga_completed;
+}
+
+// Here's for the german edition.
+// IF NO WOLF3D LEVELS, NO SECRET EXIT!
+
+void G_SecretExitLevel (void)
+{
+ if (gamemode!=commercial || haswolflevels)
+ secretexit = true;
+ else
+ secretexit = false;
+ gameaction = ga_completed;
+}
+
+//
+// G_DoCompleted
+//
+
+void G_DoCompleted (void)
+{
+ int i;
+
+ gameaction = ga_nothing;
+
+ for (i=0; i<MAXPLAYERS; i++)
+ if (playeringame[i])
+ G_PlayerFinishLevel(i); // take away cards and stuff
+
+ if (automapmode & am_active)
+ AM_Stop();
+
+ if (gamemode != commercial) // kilough 2/7/98
+ switch(gamemap)
+ {
+ // cph - Remove ExM8 special case, so it gets summary screen displayed
+ case 9:
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ players[i].didsecret = true;
+ break;
+ }
+
+ wminfo.didsecret = players[consoleplayer].didsecret;
+ wminfo.epsd = gameepisode -1;
+ wminfo.last = gamemap -1;
+
+ // wminfo.next is 0 biased, unlike gamemap
+ if (gamemode == commercial)
+ {
+ if (secretexit)
+ switch(gamemap)
+ {
+ case 15:
+ wminfo.next = 30; break;
+ case 31:
+ wminfo.next = 31; break;
+ }
+ else
+ switch(gamemap)
+ {
+ case 31:
+ case 32:
+ wminfo.next = 15; break;
+ default:
+ wminfo.next = gamemap;
+ }
+ }
+ else
+ {
+ if (secretexit)
+ wminfo.next = 8; // go to secret level
+ else
+ if (gamemap == 9)
+ {
+ // returning from secret level
+ switch (gameepisode)
+ {
+ case 1:
+ wminfo.next = 3;
+ break;
+ case 2:
+ wminfo.next = 5;
+ break;
+ case 3:
+ wminfo.next = 6;
+ break;
+ case 4:
+ wminfo.next = 2;
+ break;
+ }
+ }
+ else
+ wminfo.next = gamemap; // go to next level
+ }
+
+ wminfo.maxkills = totalkills;
+ wminfo.maxitems = totalitems;
+ wminfo.maxsecret = totalsecret;
+ wminfo.maxfrags = 0;
+
+ if ( gamemode == commercial )
+ wminfo.partime = TICRATE*cpars[gamemap-1];
+ else
+ wminfo.partime = TICRATE*pars[gameepisode][gamemap];
+
+ wminfo.pnum = consoleplayer;
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ {
+ wminfo.plyr[i].in = playeringame[i];
+ wminfo.plyr[i].skills = players[i].killcount;
+ wminfo.plyr[i].sitems = players[i].itemcount;
+ wminfo.plyr[i].ssecret = players[i].secretcount;
+ wminfo.plyr[i].stime = leveltime;
+ memcpy (wminfo.plyr[i].frags, players[i].frags,
+ sizeof(wminfo.plyr[i].frags));
+ }
+
+ /* cph - modified so that only whole seconds are added to the totalleveltimes
+ * value; so our total is compatible with the "naive" total of just adding
+ * the times in seconds shown for each level. Also means our total time
+ * will agree with Compet-n.
+ */
+ wminfo.totaltimes = (totalleveltimes += (leveltime - leveltime%35));
+
+ gamestate = GS_INTERMISSION;
+ automapmode &= ~am_active;
+
+ if (statcopy)
+ memcpy (statcopy, &wminfo, sizeof(wminfo));
+
+ WI_Start (&wminfo);
+}
+
+
+//
+// G_WorldDone
+//
+
+void G_WorldDone (void)
+{
+ gameaction = ga_worlddone;
+
+ if (secretexit)
+ players[consoleplayer].didsecret = true;
+
+ if (gamemode == commercial)
+ {
+ switch (gamemap)
+ {
+ case 15:
+ case 31:
+ if (!secretexit)
+ break;
+ case 6:
+ case 11:
+ case 20:
+ case 30:
+ F_StartFinale ();
+ break;
+ }
+ }
+ else if (gamemap == 8)
+ gameaction = ga_victory; // cph - after ExM8 summary screen, show victory stuff
+}
+
+void G_DoWorldDone (void)
+{
+ idmusnum = -1; //jff 3/17/98 allow new level's music to be loaded
+ gamestate = GS_LEVEL;
+ gamemap = wminfo.next+1;
+ G_DoLoadLevel();
+ gameaction = ga_nothing;
+ AM_clearMarks(); //jff 4/12/98 clear any marks on the automap
+}
+
+// killough 2/28/98: A ridiculously large number
+// of players, the most you'll ever need in a demo
+// or savegame. This is used to prevent problems, in
+// case more players in a game are supported later.
+
+#define MIN_MAXPLAYERS 32
+
+extern boolean setsizeneeded;
+void R_ExecuteSetViewSize(void);
+
+//CPhipps - savename variable redundant
+
+/* killough 12/98:
+ * This function returns a signature for the current wad.
+ * It is used to distinguish between wads, for the purposes
+ * of savegame compatibility warnings, and options lookups.
+ */
+
+static uint_64_t G_UpdateSignature(uint_64_t s, const char *name)
+{
+ int i, lump = W_CheckNumForName(name);
+ if (lump != -1 && (i = lump+10) < numlumps)
+ do
+ {
+ int size = W_LumpLength(i);
+ const byte *p = W_CacheLumpNum(i);
+ while (size--)
+ s <<= 1, s += *p++;
+ W_UnlockLumpNum(i);
+ }
+ while (--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<num_version_headers; i++) {
+ char vcheck[VERSIONSIZE];
+ // killough 2/22/98: "proprietary" version string :-)
+ snprintf (vcheck,sizeof(vcheck), version_headers[i].ver_printf, version_headers[i].version);
+
+ if (!strncmp(save_p, vcheck, VERSIONSIZE)) {
+ savegame_compatibility = version_headers[i].comp_level;
+ i = num_version_headers;
+ }
+ }
+ if (savegame_compatibility == -1) {
+ if (forced_loadgame) {
+ savegame_compatibility = MAX_COMPATIBILITY_LEVEL-1;
+ } else {
+ G_LoadGameErr("Unrecognised savegame version!\nAre you sure? (y/n) ");
+ return;
+ }
+ }
+
+ save_p += VERSIONSIZE;
+
+ // CPhipps - always check savegames even when forced,
+ // only print a warning if forced
+ { // killough 3/16/98: check lump name checksum (independent of order)
+ uint_64_t checksum = 0;
+
+ checksum = G_Signature();
+
+ if (memcmp(&checksum, save_p, sizeof checksum)) {
+ if (!forced_loadgame) {
+ char *msg = malloc(strlen(save_p + sizeof checksum) + 128);
+ strcpy(msg,"Incompatible Savegame!!!\n");
+ if (save_p[sizeof checksum])
+ strcat(strcat(msg,"Wads expected:\n\n"), save_p + sizeof checksum);
+ strcat(msg, "\nAre you sure?");
+ G_LoadGameErr(msg);
+ free(msg);
+ return;
+ } else
+ printf("G_DoLoadGame: Incompatible savegame\n");
+ }
+ save_p += sizeof checksum;
+ }
+
+ save_p += strlen(save_p)+1;
+
+ /* cph - FIXME - compatibility flag? */
+ compatibility_level = savegame_compatibility;
+ save_p++;
+
+ gameskill = *save_p++;
+ gameepisode = *save_p++;
+ gamemap = *save_p++;
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ playeringame[i] = *save_p++;
+ save_p += MIN_MAXPLAYERS-MAXPLAYERS; // killough 2/28/98
+
+ idmusnum = *save_p++; // jff 3/17/98 restore idmus music
+ if (idmusnum==255) idmusnum=-1; // jff 3/18/98 account for unsigned byte
+
+ /* killough 3/1/98: Read game options
+ * killough 11/98: move down to here
+ */
+ save_p = (char*)G_ReadOptions(save_p);
+
+ // load a base level
+ G_InitNew (gameskill, gameepisode, gamemap);
+
+ /* get the times - killough 11/98: save entire word */
+ memcpy(&leveltime, save_p, sizeof leveltime);
+ save_p += sizeof leveltime;
+
+ /* cph - total episode time */
+ if (compatibility_level >= 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<num_version_headers; i++)
+ if (version_headers[i].comp_level == compatibility_level) {
+ // killough 2/22/98: "proprietary" version string :-)
+ snprintf (name2,sizeof(name2),version_headers[i].ver_printf,version_headers[i].version);
+ memcpy (save_p, name2, VERSIONSIZE);
+ i = num_version_headers+1;
+ }
+
+ if ((size_t)i == num_version_headers) {
+ doom_printf("No savegame signature known for\nthis compatibility level\n"
+ "%d/%d, %d registered", compatibility_level,
+ MAX_COMPATIBILITY_LEVEL, (signed)num_version_headers);
+ free(savebuffer); // cph - free data
+ return;
+ }
+
+ save_p += VERSIONSIZE;
+
+ { /* killough 3/16/98, 12/98: store lump name checksum */
+ uint_64_t checksum = G_Signature();
+ memcpy(save_p, &checksum, sizeof checksum);
+ save_p += sizeof checksum;
+ }
+
+ // killough 3/16/98: store pwad filenames in savegame
+ {
+ // CPhipps - changed for new wadfiles handling
+ int i = 0;
+ for (*save_p = 0; (size_t)i<numwadfiles; i++)
+ {
+ const char *const w = wadfiles[i].name;
+ CheckSaveGame(strlen(w)+2);
+ strcat(strcat(save_p, w), "\n");
+ }
+ save_p += strlen(save_p)+1;
+ }
+
+ CheckSaveGame(GAME_OPTION_SIZE+MIN_MAXPLAYERS+10);
+
+ /* cph - FIXME? - Save compatibility level */
+ *save_p++ = 0;
+
+ *save_p++ = gameskill;
+ *save_p++ = gameepisode;
+ *save_p++ = gamemap;
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ *save_p++ = playeringame[i];
+
+ for (;i<MIN_MAXPLAYERS;i++) // killough 2/28/98
+ *save_p++ = 0;
+
+ *save_p++ = idmusnum; // jff 3/17/98 save idmus state
+
+ save_p = G_WriteOptions(save_p); // killough 3/1/98: save game options
+
+ /* cph - FIXME - endianness? */
+ /* killough 11/98: save entire word */
+ memcpy(save_p, &leveltime, sizeof leveltime);
+ save_p += sizeof leveltime;
+
+ /* cph - total episode time */
+ if (compatibility_level >= 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<COMP_NUM; i++)
+ comp[i] = compatibility_level < fix_levels[i];
+ for (; i<COMP_TOTAL; i++) comp[i] = 1;
+}
+
+#ifdef DOGS
+/* killough 7/19/98: Marine's best friend :) */
+static int G_GetHelpers(void)
+{
+ int j = M_CheckParm ("-dog");
+
+ if (!j)
+ j = M_CheckParm ("-dogs");
+return j ? j+1 < myargc ? atoi(myargv[j+1]) : 1 : default_dogs;
+}
+#endif
+
+
+// killough 3/1/98: function to reload all the default parameter
+// settings before a new game begins
+
+void G_ReloadDefaults(void)
+{
+ // killough 3/1/98: Initialize options based on config file
+ // (allows functions above to load different values for demos
+ // and savegames without messing up defaults).
+
+ weapon_recoil = default_weapon_recoil; // weapon recoil
+
+ player_bobbing = default_player_bobbing; // whether player bobs or not
+
+ variable_friction = allow_pushers = true;
+
+ monsters_remember = default_monsters_remember; // remember former enemies
+
+ monster_infighting = default_monster_infighting; // killough 7/19/98
+
+#ifdef DOGS
+ dogs = netgame ? 0 : G_GetHelpers(); // killough 7/19/98
+ dog_jumping = default_dog_jumping;
+#endif
+
+ distfriend = default_distfriend; // killough 8/8/98
+
+ monster_backing = default_monster_backing; // killough 9/8/98
+
+ monster_avoid_hazards = default_monster_avoid_hazards; // killough 9/9/98
+
+ monster_friction = default_monster_friction; // killough 10/98
+
+ help_friends = default_help_friends; // killough 9/9/98
+
+ monkeys = default_monkeys;
+
+ // jff 1/24/98 reset play mode to command line spec'd version
+ // killough 3/1/98: moved to here
+// respawnparm = clrespawnparm;
+// fastparm = clfastparm;
+// nomonsters = clnomonsters;
+
+ //jff 3/24/98 set startskill from defaultskill in config file, unless
+ // it has already been set by a -skill parameter
+ if (startskill==sk_none)
+ startskill = (skill_t)(defaultskill-1);
+
+ demoplayback = false;
+ singledemo = false; // killough 9/29/98: don't stop after 1 demo
+ netdemo = false;
+
+ // killough 2/21/98:
+ memset(playeringame+1, 0, sizeof(*playeringame)*(MAXPLAYERS-1));
+
+ consoleplayer = 0;
+
+ compatibility_level = default_compatibility_level;
+ {
+ int i = M_CheckParm("-complevel");
+ if (i && (1+i) < myargc) compatibility_level = atoi(myargv[i+1]);
+ }
+ if ((signed)compatibility_level == -1)
+ compatibility_level = MAX_COMPATIBILITY_LEVEL-1;
+
+ if (mbf_features)
+ memcpy(comp, default_comp, sizeof comp);
+ else
+ G_Compatibility();
+
+ // killough 3/31/98, 4/5/98: demo sync insurance
+ demo_insurance = default_demo_insurance == 1;
+
+ rngseed += 1 + gametic; // CPhipps
+// rngseed += I_GetRandomTimeSeed() + gametic; // CPhipps
+}
+
+void G_DoNewGame (void)
+{
+ G_ReloadDefaults(); // killough 3/1/98
+ netgame = false; // killough 3/1/98
+ deathmatch = false;
+ G_InitNew (d_skill, d_episode, d_map);
+ gameaction = ga_nothing;
+
+ //jff 4/26/98 wake up the status bar in case were coming out of a DM demo
+ ST_Start();
+}
+
+// killough 4/10/98: New function to fix bug which caused Doom
+// lockups when idclev was used in conjunction with -fast.
+
+void G_SetFastParms(int fast_pending)
+{
+ static int fast = 0; // remembers fast state
+ int i;
+ if (fast != fast_pending) { /* only change if necessary */
+ if ((fast = fast_pending))
+ {
+ for (i=S_SARG_RUN1; i<=S_SARG_PAIN2; i++)
+ if (states[i].tics != 1 || demo_compatibility) // killough 4/10/98
+ states[i].tics >>= 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 ; i<MAXPLAYERS ; i++)
+ players[i].playerstate = PST_REBORN;
+
+ usergame = true; // will be set false if a demo
+ paused = false;
+ automapmode &= ~am_active;
+ gameepisode = episode;
+ gamemap = map;
+ gameskill = skill;
+
+ totalleveltimes = 0; // cph
+
+ //jff 4/16/98 force marks on automap cleared every new level start
+ AM_clearMarks();
+
+ G_DoLoadLevel ();
+}
+
+
+//
+// DEMO RECORDING
+//
+
+unsigned char DEMOMARKER=0x80;
+
+void G_ReadDemoTiccmd (ticcmd_t* cmd)
+{
+ if (*demo_p == DEMOMARKER)
+ G_CheckDemoStatus(); // end of demo data stream
+ else
+ {
+ cmd->forwardmove = ((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<MAXPLAYERS ; i++)
+ *demo_p++ = playeringame[i];
+
+ // killough 2/28/98:
+ // We always store at least MIN_MAXPLAYERS bytes in demo, to
+ // support enhancements later w/o losing demo compatibility
+
+ for (; i<MIN_MAXPLAYERS; i++)
+ *demo_p++ = 0;
+
+ } else if (compatibility_level > 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<MAXPLAYERS ; i++)
+ *demo_p++ = playeringame[i];
+
+ // killough 2/28/98:
+ // We always store at least MIN_MAXPLAYERS bytes in demo, to
+ // support enhancements later w/o losing demo compatibility
+
+ for (; i<MIN_MAXPLAYERS; i++)
+ *demo_p++ = 0;
+ } else { // cph - write old v1.9 demos (might even sync)
+ longtics = M_CheckParm("-longtics");
+ *demo_p++ = longtics ? 111 : 109; // v1.9 has best chance of syncing these
+ *demo_p++ = gameskill;
+ *demo_p++ = gameepisode;
+ *demo_p++ = gamemap;
+ *demo_p++ = deathmatch;
+ *demo_p++ = respawnparm;
+ *demo_p++ = fastparm;
+ *demo_p++ = nomonsters;
+ *demo_p++ = consoleplayer;
+ for (i=0; i<4; i++) // intentionally hard-coded 4 -- killough
+ *demo_p++ = playeringame[i];
+ }
+
+ if (write(demofd, demostart, demo_p-demostart) != (signed)(size_t)(demo_p-demostart))
+ I_Error("G_BeginRecording: Error writing demo header");
+ free(demostart);
+}
+
+
+//
+// G_PlayDemo
+//
+
+static const char *defdemoname;
+
+void G_DeferedPlayDemo (const char* name)
+{
+ defdemoname = name;
+ gameaction = ga_playdemo;
+}
+
+static int demolumpnum = -1;
+
+static const byte* G_ReadDemoHeader(const byte *demo_p)
+{
+ skill_t skill;
+ int i, episode, map;
+ int demover;
+ const byte *option_p = NULL; /* killough 11/98 */
+
+ basetic = gametic; // killough 9/29/98
+
+ // killough 2/22/98, 2/28/98: autodetect old demos and act accordingly.
+ // Old demos turn on demo_compatibility => 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; i<MAXPLAYERS;i++) // killough 4/24/98
+ players[i].cheats = 0;
+
+ return demo_p;
+}
+
+void G_DoPlayDemo(void)
+{
+ char basename[9];
+
+ ExtractFileBase(defdemoname,basename); // killough
+ basename[8] = 0;
+ demobuffer = demo_p = W_CacheLumpNum(demolumpnum = W_GetNumForName(basename));
+ /* cph - store lump number for unlocking later */
+
+ demo_p = G_ReadDemoHeader(demo_p);
+
+ gameaction = ga_nothing;
+ usergame = false;
+
+ demoplayback = true;
+}
+
+//
+// G_TimeDemo
+//
+
+void G_TimeDemo(const char *name) // CPhipps - const char*
+{
+ timingdemo = true;
+ singletics = true;
+ defdemoname = name;
+ gameaction = ga_playdemo;
+}
+
+
+/* G_CheckDemoStatus
+ *
+ * Called after a death or level completion to allow demos to be cleaned up
+ * Returns true if a new demo loop action will take place
+ */
+
+boolean G_CheckDemoStatus (void)
+{
+ if (demorecording)
+ {
+ demorecording = false;
+ write(demofd, &DEMOMARKER, 1);
+ close(demofd);
+ I_Error("G_CheckDemoStatus: Demo recorded");
+ return false; // killough
+ }
+
+ if (timingdemo)
+ {
+// int endtime = I_GetTime_RealTime ();
+ int endtime = I_GetTime ();
+ // killough -- added fps information and made it work for longer demos:
+ unsigned realtics = endtime-starttime;
+ int fd=open("/games/doom/timedemo.txt",O_WRONLY | O_CREAT);
+ fprintf (fd,"Timed %d gametics in %d realtics = %d frames per second",
+ (unsigned) gametic, realtics,
+ (unsigned) gametic * (double) TICRATE / realtics);
+ close(fd);
+ I_Error ("%d gametics in %d realtics",
+ (unsigned) gametic,realtics,
+ (unsigned) gametic * (double) TICRATE / realtics);
+ return false;
+ }
+
+ if (demoplayback)
+ {
+ if (singledemo)
+ I_Error("Done Playing Demo");
+ return false;
+// exit(0); // killough
+
+ if (demolumpnum != -1) {
+ // cph - unlock the demo lump
+ W_UnlockLumpNum(demolumpnum);
+ demolumpnum = -1;
+ }
+ G_ReloadDefaults(); // killough 3/1/98
+ netgame = false; // killough 3/29/98
+ deathmatch = false;
+ D_AdvanceDemo ();
+ return true;
+ }
+ return false;
+}
+
+// killough 1/22/98: this is a "Doom printf" for messages. I've gotten
+// tired of using players->message=... 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 0000000..6a2d3dc
--- /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 0000000..2ac3d35
--- /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;i<l->len;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 (++i<l->len)
+ 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 ; y<l->y+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;i<h;i++)
+ HUlib_initTextLine
+ (
+ &s->l[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 ; i<s->h ; 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 ; i<s->h ; 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 ; i<s->h ; 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;i<HU_MAXMESSAGES;i++)
+ {
+ HUlib_initTextLine
+ (
+ &m->l[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->nl<hud_msg_lines)
+ m->nl++;
+
+ // 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;j<x+w-xs;j+=xs) // uc
+ V_DrawNumPatch(j, y, FG, bgp[1].lumpnum, CR_DEFAULT, VPT_STRETCH);
+ V_DrawNumPatch(j, y, FG, bgp[2].lumpnum, CR_DEFAULT, VPT_STRETCH); // ur
+
+ // middle rows
+ for (i=y+ys;i<y+h-ys;i+=ys)
+ {
+ V_DrawNumPatch(x, i, FG, bgp[3].lumpnum, CR_DEFAULT, VPT_STRETCH); // cl
+ for (j=x+xs;j<x+w-xs;j+=xs) // cc
+ V_DrawNumPatch(j, i, FG, bgp[4].lumpnum, CR_DEFAULT, VPT_STRETCH);
+ V_DrawNumPatch(j, i, FG, bgp[5].lumpnum, CR_DEFAULT, VPT_STRETCH); // cr
+ }
+
+ // bottom row
+ V_DrawNumPatch(x, i, FG, bgp[6].lumpnum, CR_DEFAULT, VPT_STRETCH); // ll
+ for (j=x+xs;j<x+w-xs;j+=xs) // lc
+ V_DrawNumPatch(j, i, FG, bgp[7].lumpnum, CR_DEFAULT, VPT_STRETCH);
+ V_DrawNumPatch(j, i, FG, bgp[8].lumpnum, CR_DEFAULT, VPT_STRETCH); // lr
+}
+
+//
+// HUlib_drawMText()
+//
+// Displays a hu_mtext_t widget
+//
+// Passed a hu_mtext_t
+// Returns nothing
+//
+void HUlib_drawMText(hu_mtext_t* m)
+{
+ int i, idx, y;
+ hu_textline_t *l;
+
+ if (!*m->on)
+ 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 ; i<m->nl ; 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 ; y<m->y+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 0000000..76d26bb
--- /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 0000000..fd7bd0d
--- /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;i<HU_FONTSIZE;i++,j++)
+ {
+ if ('0'<=j && j<='9')
+ {
+ snprintf(buffer, sizeof(buffer), "DIG%d",j-48);
+ 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 ('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 ; i<MAXPLAYERS ; i++)
+ HUlib_initIText
+ (
+ &w_inputbuffer[i],
+ 0,
+ 0,
+ 0,
+ 0,
+ hudcolor_chat,
+ &always_off
+ );
+
+ // now allow the heads-up display to run
+ headsupactive = true;
+}
+
+//
+// HU_MoveHud()
+//
+// Move the HUD display from distributed to compact mode or vice-versa
+//
+// Passed nothing, returns nothing
+//
+//jff 3/9/98 create this externally callable to avoid glitch
+// when menu scatter's HUD due to delay in change of position
+//
+void HU_MoveHud(void)
+{
+ static int ohud_distributed=-1;
+
+ //jff 3/4/98 move displays around on F5 changing hud_distributed
+ if (hud_distributed!=ohud_distributed)
+ {
+ w_ammo.x = hud_distributed? HU_AMMOX_D : HU_AMMOX;
+ w_ammo.y = hud_distributed? HU_AMMOY_D : HU_AMMOY;
+ w_weapon.x = hud_distributed? HU_WEAPX_D : HU_WEAPX;
+ w_weapon.y = hud_distributed? HU_WEAPY_D : HU_WEAPY;
+ w_keys.x = hud_distributed? HU_KEYSX_D : HU_KEYSX;
+ w_keys.y = hud_distributed? HU_KEYSY_D : HU_KEYSY;
+ w_gkeys.x = hud_distributed? HU_KEYSGX_D : HU_KEYSGX;
+ w_gkeys.y = hud_distributed? HU_KEYSY_D : HU_KEYSY;
+ w_monsec.x = hud_distributed? HU_MONSECX_D : HU_MONSECX;
+ w_monsec.y = hud_distributed? HU_MONSECY_D : HU_MONSECY;
+ w_health.x = hud_distributed? HU_HEALTHX_D : HU_HEALTHX;
+ w_health.y = hud_distributed? HU_HEALTHY_D : HU_HEALTHY;
+ w_armor.x = hud_distributed? HU_ARMORX_D : HU_ARMORX;
+ w_armor.y = hud_distributed? HU_ARMORY_D : HU_ARMORY;
+ }
+ ohud_distributed = hud_distributed;
+}
+
+//
+// HU_Drawer()
+//
+// Draw all the pieces of the heads-up display
+//
+// Passed nothing, returns nothing
+//
+void HU_Drawer(void)
+{
+ char *s;
+ player_t *plr;
+ char ammostr[80]; //jff 3/8/98 allow plenty room for dehacked mods
+ char healthstr[80];//jff
+ char armorstr[80]; //jff
+ int i,doit;
+
+ plr = &players[displayplayer]; // killough 3/7/98
+ // draw the automap widgets if automap is displayed
+ if (automapmode & am_active)
+ {
+ // map title
+ HUlib_drawTextLine(&w_title, false);
+
+ //jff 2/16/98 output new coord display
+ // x-coord
+ snprintf(hud_coordstrx,sizeof(hud_coordstrx),"X: %-5d", (plr->mo->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 (ammopct<ammo_red)
+ w_ammo.cm = CR_RED;
+ else if (ammopct<ammo_yellow)
+ w_ammo.cm = CR_GOLD;
+ else
+ w_ammo.cm = CR_GREEN;
+ }
+ // transfer the init string to the widget
+ s = hud_ammostr;
+ while (*s)
+ HUlib_addCharToTextLine(&w_ammo, *(s++));
+ }
+ // display the ammo widget every frame
+ HUlib_drawTextLine(&w_ammo, false);
+
+ // do the hud health display
+ if (doit)
+ {
+ int health = plr->health;
+ 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 (health<health_red)
+ w_health.cm = CR_RED;
+ else if (health<health_yellow)
+ w_health.cm = CR_GOLD;
+ else if (health<=health_green)
+ w_health.cm = CR_GREEN;
+ else
+ w_health.cm = CR_BLUE;
+
+ // transfer the init string to the widget
+ s = hud_healthstr;
+ while (*s)
+ HUlib_addCharToTextLine(&w_health, *(s++));
+ }
+ // display the health widget every frame
+ HUlib_drawTextLine(&w_health, false);
+
+ // do the hud armor display
+ if (doit)
+ {
+ int armor = plr->armorpoints;
+ 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<armor_red)
+ w_armor.cm = CR_RED;
+ else if (armor<armor_yellow)
+ w_armor.cm = CR_GOLD;
+ else if (armor<=armor_green)
+ w_armor.cm = CR_GREEN;
+ else
+ w_armor.cm = CR_BLUE;
+
+ // transfer the init string to the widget
+ s = hud_armorstr;
+ while (*s)
+ HUlib_addCharToTextLine(&w_armor, *(s++));
+ }
+ // display the armor widget every frame
+ HUlib_drawTextLine(&w_armor, false);
+
+ // do the hud weapon display
+ if (doit)
+ {
+ int w;
+ int ammo,fullammo,ammopct;
+
+ // clear the widgets internal line
+ HUlib_clearTextLine(&w_weapon);
+ i=4; hud_weapstr[i] = '\0'; //jff 3/7/98 make sure ammo goes away
+
+ // do each weapon that exists in current gamemode
+ for (w=0;w<=wp_supershotgun;w++) //jff 3/4/98 show fists too, why not?
+ {
+ int ok=1;
+ //jff avoid executing for weapons that do not exist
+ switch (gamemode)
+ {
+ case shareware:
+ if (w>=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 (ammopct<ammo_red)
+ hud_weapstr[i++] = '0'+CR_RED;
+ else if (ammopct<ammo_yellow)
+ hud_weapstr[i++] = '0'+CR_GOLD;
+ else
+ hud_weapstr[i++] = '0'+CR_GREEN;
+ hud_weapstr[i++] = '0'+w+1;
+ hud_weapstr[i++] = ' ';
+ hud_weapstr[i] = '\0';
+ }
+
+ // transfer the init string to the widget
+ s = hud_weapstr;
+ while (*s)
+ HUlib_addCharToTextLine(&w_weapon, *(s++));
+ }
+ // display the weapon widget every frame
+ HUlib_drawTextLine(&w_weapon, false);
+
+ if (doit && hud_active>1)
+ {
+ 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;k<MAXPLAYERS;k++)
+ {
+ // skip players not in game
+ if (!playeringame[k])
+ continue;
+
+ fragcount = 0;
+ // compute number of times they've fragged each player
+ // minus number of times they've been fragged by them
+ for (m=0;m<MAXPLAYERS;m++)
+ {
+ if (!playeringame[m]) continue;
+ fragcount += (m!=k)? players[k].frags[m] : -players[k].frags[m];
+ }
+
+ // very primitive sort of frags to find top four
+ if (fragcount>top1)
+ {
+ 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<MAXPLAYERS; i++)
+ {
+ if (!playeringame[i])
+ continue;
+ if (i != consoleplayer
+ && (c = players[i].cmd.chatchar))
+ {
+ if (c <= HU_BROADCAST)
+ chat_dest[i] = c;
+ else
+ {
+ if (c >= '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 ; i<MAXPLAYERS ; i++)
+ numplayers += playeringame[i];
+
+ if (ev->data1 == 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; i<MAXPLAYERS ; i++)
+ {
+ if (ev->data1 == 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 0000000..76c6a90
--- /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 0000000..471b0ee
--- /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; i<NUM_CHANNELS; i++)
+ memset(&channelinfo[i],0,sizeof(channel_info_t));
+
+ // This table provides step widths for pitch parameters.
+ for (i=-128 ; i<128 ; i++)
+ steptablemid[i]=2;
+// steptablemid[i] = (int)(pow(1.2, ((double)i/(64.0*SAMPLERATE/11025)))*65536.0);
+
+ // Generates volume lookup tables
+ // which also turn the unsigned samples
+ // into signed samples.
+ for (i=0 ; i<128 ; i++)
+ for (j=0 ; j<256 ; j++)
+ vol_lookup[i*256+j] = 3*(i*(j-128)*256)/191;
+}
+
+void I_SetSfxVolume(int volume)
+{
+ // Identical to DOS.
+ // Basically, this should propagate
+ // the menu/config file setting
+ // to the state variable used in
+ // the mixing.
+ snd_SfxVolume = volume;
+}
+
+// MUSIC API - dummy. Some code from DOS version.
+void I_SetMusicVolume(int volume)
+{
+ // Internal state variable.
+ snd_MusicVolume = volume;
+ // Now set volume on output device.
+ // Whatever( snd_MusciVolume );
+}
+
+//
+// Retrieve the raw data lump index
+// for a given SFX name.
+//
+int I_GetSfxLumpNum(sfxinfo_t* sfx)
+{
+ char namebuf[9];
+ snprintf(namebuf, sizeof(namebuf), "ds%s", sfx->name);
+ 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 ; i<NUMSFX ; i++)
+ {
+ if (!S_sfx[i].link) // Alias? Example is the chaingun sound linked to pistol.
+ S_sfx[i].data = getsfx( S_sfx[i].name); // Load data from WAD file.
+ else
+ S_sfx[i].data = S_sfx[i].link->data; // 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 0000000..2e733b1
--- /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 0000000..1e56405
--- /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 0000000..e594cb2
--- /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 0000000..b77205f
--- /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++) {
+ int r = gtable[pall[0]];
+ int g = gtable[pall[1]];
+ int b = gtable[pall[2]];
+ pall+=3;
+ paldata[i] = LCD_RGBPACK(r,g,b);
+ }
+
+ W_UnlockLumpNum(lump);
+ num_pals/=256;
+ }
+
+#ifdef RANGECHECK
+ if ((size_t)pal >= 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<LCD_HEIGHT)
+ {
+ while(wcnt<LCD_WIDTH-7)
+ {
+ if((wcnt&0x01))
+ screenptr++; // Skip every so many pixels in Doom buffer
+ *(volatile unsigned short *)0xf0000002 = palette[*screenptr];
+ screenptr++;
+ wcnt++;
+ }
+ screenptr++;
+ // move on past those 7 pixels
+ *(volatile unsigned short *) 0xf0000002 = 0;
+ *(volatile unsigned short *) 0xf0000002 = 0;
+ *(volatile unsigned short *) 0xf0000002 = 0;
+ *(volatile unsigned short *) 0xf0000002 = 0;
+ *(volatile unsigned short *) 0xf0000002 = 0;
+ *(volatile unsigned short *) 0xf0000002 = 0;
+ *(volatile unsigned short *) 0xf0000002 = 0;
+ wcnt=0;
+ hcnt++;
+ if((hcnt&0x07)==0x07)
+ screenptr+=SCREENWIDTH; // Skip every 7th line
+ }
+#else
+ // The IDOOM code for screen updates
+ unsigned char paletteIndex;
+ int x, y;
+
+ for (y = 0; y < video_h; y++)
+ {
+ for (x = 0; x < video_w; x++)
+ {
+#if LCD_HEIGHT >= 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 0000000..fd8f269
--- /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 0000000..015270f
--- /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 0000000..d6c20f0
--- /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 0000000..253fb01
--- /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 0000000..61e7a27
--- /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 0000000..916ed7a
--- /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 (x<box[BOXLEFT])
+ box[BOXLEFT] = x;
+ else if (x>box[BOXRIGHT])
+ box[BOXRIGHT] = x;
+ if (y<box[BOXBOTTOM])
+ box[BOXBOTTOM] = y;
+ else if (y>box[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 0000000..32202ec
--- /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 <limits.h>
+#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 0000000..afd68e9
--- /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 0000000..dfa916f
--- /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 0000000..3c922e8
--- /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<<FRACBITS)
+
+#define D_abs(x) ({fixed_t _t = (x), _s = _t >> (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<b
+ * (notice that the C standard for % does not guarantee this)
+ */
+
+inline static fixed_t FixedMod(fixed_t a, fixed_t b)
+{
+ if (b & (b-1)) {
+ fixed_t r = a % b;
+ return ((r<0) ? r+b : r);
+ } else
+ return (a & (b-1));
+}
+
+#endif
diff --git a/apps/plugins/doom/m_menu.c b/apps/plugins/doom/m_menu.c
new file mode 100644
index 0000000..34f3e22
--- /dev/null
+++ b/apps/plugins/doom/m_menu.c
@@ -0,0 +1,1848 @@
+// 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 selection menu, options, episode etc.
+// Sliders and icons. Kinda widget stuff.
+//
+//-----------------------------------------------------------------------------
+
+#include "doomdef.h"
+#include "dstrings.h"
+
+#include "d_main.h"
+
+#include "i_system.h"
+#include "i_video.h"
+#include "z_zone.h"
+#include "v_video.h"
+#include "w_wad.h"
+
+#include "r_main.h"
+
+#include "hu_stuff.h"
+
+#include "g_game.h"
+
+#include "m_argv.h"
+#include "m_swap.h"
+#include "s_sound.h"
+
+#include "doomstat.h"
+
+// Data.
+#include "sounds.h"
+
+#include "m_menu.h"
+#include "rockmacros.h"
+
+
+extern patchnum_t hu_font[HU_FONTSIZE];
+extern boolean message_dontfuckwithme;
+
+extern boolean chat_on; // in heads-up code
+
+//
+// defaulted values
+//
+int mouseSensitivity; // has default
+
+// Show messages has default, 0 = off, 1 = on
+int showMessages;
+
+// Blocky mode, has default, 0 = high, 1 = normal
+int screenblocks; // has default
+
+// temp for screenblocks (0-9)
+int screenSize;
+
+// -1 = no quicksave slot picked!
+int quickSaveSlot;
+
+// 1 = message to be printed
+int messageToPrint;
+// ...and here is the message string!
+char* messageString;
+
+// message x & y
+int messx;
+int messy;
+int messageLastMenuActive;
+
+// timed message = no input from user
+boolean messageNeedsInput;
+
+void (*messageRoutine)(int response);
+
+#define SAVESTRINGSIZE 24
+
+char gammamsg[5][26] =
+ {
+ GAMMALVL0,
+ GAMMALVL1,
+ GAMMALVL2,
+ GAMMALVL3,
+ GAMMALVL4
+ };
+
+// we are going to be entering a savegame string
+int saveStringEnter;
+int saveSlot; // which slot to save in
+int saveCharIndex; // which char we're editing
+// old save description before edit
+char saveOldString[SAVESTRINGSIZE];
+
+boolean inhelpscreens;
+boolean menuactive;
+
+#define SKULLXOFF -32
+#define LINEHEIGHT 16
+
+extern boolean sendpause;
+char savegamestrings[10][SAVESTRINGSIZE];
+
+char endstring[170];
+
+
+//
+// MENU TYPEDEFS
+//
+typedef struct
+{
+ // 0 = no cursor here, 1 = ok, 2 = arrows ok
+ short status;
+
+ char name[10];
+
+ // choice = menu item #.
+ // if status = 2,
+ // choice=0:leftarrow,1:rightarrow
+ void (*routine)(int choice);
+
+ // hotkey in menu
+ char alphaKey;
+}
+menuitem_t;
+
+
+
+typedef struct menu_s
+{
+ short numitems; // # of menu items
+ struct menu_s* prevMenu; // previous menu
+ menuitem_t* menuitems; // menu items
+ void (*routine)(void); // draw routine ROCKBOX
+ short x;
+ short y; // x,y of menu
+ short lastOn; // last item user was on in menu
+}
+menu_t;
+
+short itemOn; // menu item skull is on
+short skullAnimCounter; // skull animation counter
+short whichSkull; // which skull to draw
+int systemvol;
+
+// graphic name of skulls
+// warning: initializer-string for array of chars is too long
+char skullName[2][/*8*/9] = {"M_SKULL1","M_SKULL2"};
+
+// current menudef
+menu_t* currentMenu;
+
+//
+// PROTOTYPES
+//
+void M_NewGame(int choice);
+void M_Episode(int choice);
+void M_ChooseSkill(int choice);
+void M_LoadGame(int choice);
+void M_SaveGame(int choice);
+void M_Options(int choice);
+void M_EndGame(int choice);
+void M_ReadThis(int choice);
+void M_ReadThis2(int choice);
+void M_QuitDOOM(int choice);
+
+void M_ChangeMessages(int choice);
+void M_ChangeSensitivity(int choice);
+void M_SfxVol(int choice);
+void M_MusicVol(int choice);
+void M_SystemVol(int choice);
+void M_SizeDisplay(int choice);
+void M_StartGame(int choice);
+void M_Sound(int choice);
+
+void M_FinishReadThis(int choice);
+void M_LoadSelect(int choice);
+void M_SaveSelect(int choice);
+void M_ReadSaveStrings(void);
+void M_QuickSave(void);
+void M_QuickLoad(void);
+
+void M_DrawMainMenu(void);
+void M_DrawReadThis1(void);
+void M_DrawReadThis2(void);
+void M_DrawNewGame(void);
+void M_DrawEpisode(void);
+void M_DrawOptions(void);
+void M_DrawSound(void);
+void M_DrawLoad(void);
+void M_DrawSave(void);
+
+void M_DrawSaveLoadBorder(int x,int y);
+void M_SetupNextMenu(menu_t *menudef);
+void M_DrawThermo(int x,int y,int thermWidth,int thermDot);
+void M_DrawEmptyCell(menu_t *menu,int item);
+void M_DrawSelCell(menu_t *menu,int item);
+void M_WriteText(int x, int y, char *string);
+int M_StringWidth(const char* string);
+int M_StringHeight(const char* string);
+void M_StartControlPanel(void);
+void M_StartMessage(char *string,void *routine,boolean input);
+void M_StopMessage(void);
+void M_ClearMenus (void);
+
+
+
+
+//
+// DOOM MENU
+//
+enum
+{
+ newgame = 0,
+ options,
+ loadgame,
+ savegame,
+ readthis,
+ quitdoom,
+ main_end
+} main_e;
+
+menuitem_t MainMenu[]=
+ {
+ {1,"M_NGAME",M_NewGame,'n'},
+ {1,"M_OPTION",M_Options,'o'},
+ {1,"M_LOADG",M_LoadGame,'l'},
+ {1,"M_SAVEG",M_SaveGame,'s'},
+ // Another hickup with Special edition.
+ {1,"M_RDTHIS",M_ReadThis,'r'},
+ {1,"M_QUITG",M_QuitDOOM,'q'}
+ };
+
+menu_t MainDef =
+ {
+ main_end,
+ NULL,
+ MainMenu,
+ M_DrawMainMenu,
+ 97,64,
+ 0
+ };
+
+
+//
+// EPISODE SELECT
+//
+enum
+{
+ ep1,
+ ep2,
+ ep3,
+ ep4,
+ ep_end
+} episodes_e;
+
+menuitem_t EpisodeMenu[]=
+ {
+ {1,"M_EPI1", M_Episode,'k'},
+ {1,"M_EPI2", M_Episode,'t'},
+ {1,"M_EPI3", M_Episode,'i'},
+ {1,"M_EPI4", M_Episode,'t'}
+ };
+
+menu_t EpiDef =
+ {
+ ep_end, // # of menu items
+ &MainDef, // previous menu
+ EpisodeMenu, // menuitem_t ->
+ 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+5<rb->sound_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;i<thermWidth;i++)
+ {
+ V_DrawNamePatch(xx, y, 0, "M_THERMM", CR_DEFAULT, VPT_STRETCH);
+ xx += 8;
+ }
+ V_DrawNamePatch(xx, y, 0, "M_THERMR", CR_DEFAULT, VPT_STRETCH);
+ V_DrawNamePatch((x+8)+thermDot*8,y,0,"M_THERMO",CR_DEFAULT,VPT_STRETCH);
+}
+
+
+
+void
+M_DrawEmptyCell
+( menu_t* menu,
+ int item )
+{
+ // CPhipps - patch drawing updated
+ V_DrawNamePatch(menu->x - 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;i<max;i++)
+ {
+ if (currentMenu->menuitems[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 0000000..8444b72
--- /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 0000000..2cde210
--- /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<numdefaults ; i++)
+ if(defaults[i].location.pi)
+ write(fd,defaults[i].location.pi, sizeof(int));
+
+ close (fd);
+}
+
+/*
+ * M_LookupDefault
+ *
+ * cph - mimic MBF function for now. Yes it's crap.
+ */
+
+struct default_s *M_LookupDefault(const char *name)
+{
+ int i;
+ for (i = 0 ; i < numdefaults ; i++)
+ if ((defaults[i].type != def_none) && !strcmp(name, defaults[i].name))
+ return &defaults[i];
+ I_Error("M_LookupDefault: %s not found",name);
+ return NULL;
+}
+
+//
+// M_LoadDefaults
+//
+
+#define NUMCHATSTRINGS 10 // phares 4/13/98
+
+void M_LoadDefaults (void)
+{
+ int i;
+ int fd;
+ // set everything to base values
+
+ numdefaults = sizeof(defaults)/sizeof(defaults[0]);
+ for (i = 0 ; i < numdefaults ; i++) {
+ if (defaults[i].location.ppsz)
+ *defaults[i].location.ppsz = strdup(defaults[i].defaultvalue.psz);
+ if (defaults[i].location.pi)
+ *defaults[i].location.pi = defaults[i].defaultvalue.i;
+ }
+
+ fd = open (GAMEBASE"default.dfg", O_RDONLY);
+ if (fd<0)
+ return; // don't have anything to read
+
+ for (i=0 ; i<numdefaults ; i++)
+ if(defaults[i].location.pi)
+ read(fd,defaults[i].location.pi, sizeof(int));
+
+ close (fd);
+}
+
+
+//
+// SCREEN SHOTS
+//
+
+// CPhipps - nasty but better than nothing
+static boolean screenshot_write_error;
+
+// jff 3/30/98 types and data structures for BMP output of screenshots
+//
+// killough 5/2/98:
+// Changed type names to avoid conflicts with endianess functions
+
+#define BI_RGB 0L
+
+typedef unsigned long dword_t;
+typedef long long_t;
+typedef unsigned char ubyte_t;
+
+typedef struct tagBITMAPFILEHEADER
+{
+ unsigned short bfType;
+ dword_t bfSize;
+ unsigned short bfReserved1;
+ unsigned short bfReserved2;
+ dword_t bfOffBits;
+} PACKEDATTR BITMAPFILEHEADER;
+
+typedef struct tagBITMAPINFOHEADER
+{
+ dword_t biSize;
+ long_t biWidth;
+ long_t biHeight;
+ unsigned short biPlanes;
+ unsigned short biBitCount;
+ dword_t biCompression;
+ dword_t biSizeImage;
+ long_t biXPelsPerMeter;
+ long_t biYPelsPerMeter;
+ dword_t biClrUsed;
+ dword_t biClrImportant;
+} PACKEDATTR BITMAPINFOHEADER;
+#if 0
+// jff 3/30/98 binary file write with error detection
+// CPhipps - static, const on parameter
+static void SafeWrite(const void *data, size_t size, size_t number, int st)
+{
+ /* if (write(data,size,number,st)<number)
+ screenshot_write_error = true; // CPhipps - made non-fatal*/
+}
+#endif
+//
+// WriteBMPfile
+// jff 3/30/98 Add capability to write a .BMP file (256 color uncompressed)
+//
+
+// CPhipps - static, const on parameters
+static void WriteBMPfile(const char* filename, const byte* data,
+ const int width, const int height, const byte* palette)
+{
+ (void)filename;
+ (void)data;
+ (void)width;
+ (void)height;
+ (void)palette;
+ /* int i,wid;
+ BITMAPFILEHEADER bmfh;
+ BITMAPINFOHEADER bmih;
+ int fhsiz,ihsiz;
+ FILE *st;
+ char zero=0;
+ ubyte_t c;
+
+ fhsiz = sizeof(BITMAPFILEHEADER);
+ ihsiz = sizeof(BITMAPINFOHEADER);
+ wid = 4*((width+3)/4);
+ //jff 4/22/98 add endian macros
+ bmfh.bfType = SHORT(19778);
+ bmfh.bfSize = LONG(fhsiz+ihsiz+256L*4+width*height);
+ bmfh.bfReserved1 = SHORT(0);
+ bmfh.bfReserved2 = SHORT(0);
+ bmfh.bfOffBits = LONG(fhsiz+ihsiz+256L*4);
+
+ bmih.biSize = LONG(ihsiz);
+ bmih.biWidth = LONG(width);
+ bmih.biHeight = LONG(height);
+ bmih.biPlanes = SHORT(1);
+ bmih.biBitCount = SHORT(8);
+ bmih.biCompression = LONG(BI_RGB);
+ bmih.biSizeImage = LONG(wid*height);
+ bmih.biXPelsPerMeter = LONG(0);
+ bmih.biYPelsPerMeter = LONG(0);
+ bmih.biClrUsed = LONG(256);
+ bmih.biClrImportant = LONG(256);
+
+ st = fopen(filename,"wb");
+ if (st!=NULL) {
+ // write the header
+ SafeWrite(&bmfh.bfType,sizeof(bmfh.bfType),1,st);
+ SafeWrite(&bmfh.bfSize,sizeof(bmfh.bfSize),1,st);
+ SafeWrite(&bmfh.bfReserved1,sizeof(bmfh.bfReserved1),1,st);
+ SafeWrite(&bmfh.bfReserved2,sizeof(bmfh.bfReserved2),1,st);
+ SafeWrite(&bmfh.bfOffBits,sizeof(bmfh.bfOffBits),1,st);
+
+ SafeWrite(&bmih.biSize,sizeof(bmih.biSize),1,st);
+ SafeWrite(&bmih.biWidth,sizeof(bmih.biWidth),1,st);
+ SafeWrite(&bmih.biHeight,sizeof(bmih.biHeight),1,st);
+ SafeWrite(&bmih.biPlanes,sizeof(bmih.biPlanes),1,st);
+ SafeWrite(&bmih.biBitCount,sizeof(bmih.biBitCount),1,st);
+ SafeWrite(&bmih.biCompression,sizeof(bmih.biCompression),1,st);
+ SafeWrite(&bmih.biSizeImage,sizeof(bmih.biSizeImage),1,st);
+ SafeWrite(&bmih.biXPelsPerMeter,sizeof(bmih.biXPelsPerMeter),1,st);
+ SafeWrite(&bmih.biYPelsPerMeter,sizeof(bmih.biYPelsPerMeter),1,st);
+ SafeWrite(&bmih.biClrUsed,sizeof(bmih.biClrUsed),1,st);
+ SafeWrite(&bmih.biClrImportant,sizeof(bmih.biClrImportant),1,st);
+
+ // write the palette, in blue-green-red order, gamma corrected
+ for (i=0;i<768;i+=3) {
+ c=gammatable[usegamma][palette[i+2]];
+ SafeWrite(&c,sizeof(char),1,st);
+ c=gammatable[usegamma][palette[i+1]];
+ SafeWrite(&c,sizeof(char),1,st);
+ c=gammatable[usegamma][palette[i+0]];
+ SafeWrite(&c,sizeof(char),1,st);
+ SafeWrite(&zero,sizeof(char),1,st);
+ }
+
+ for (i = 0 ; i < height ; i++)
+ SafeWrite(data+(height-1-i)*width,sizeof(byte),wid,st);
+
+ fclose(st);
+ }*/
+}
+
+//
+// M_ScreenShot
+//
+// Modified by Lee Killough so that any number of shots can be taken,
+// the code is faster, and no annoying "screenshot" message appears.
+
+// CPhipps - modified to use its own buffer for the image
+// - checks for the case where no file can be created (doesn't occur on POSIX systems, would on DOS)
+// - track errors better
+// - split into 2 functions
+
+//
+// M_DoScreenShot
+// Takes a screenshot into the names file
+
+void M_DoScreenShot (const char* fname)
+{
+ byte *linear;
+#ifndef GL_DOOM
+ const byte *pal;
+ int pplump = W_GetNumForName("PLAYPAL");
+#endif
+
+ screenshot_write_error = false;
+
+#ifdef GL_DOOM
+ // munge planar buffer to linear
+ // CPhipps - use a malloc()ed buffer instead of screens[2]
+ gld_ReadScreen(linear = malloc(SCREENWIDTH * SCREENHEIGHT * 3));
+
+ // save the bmp file
+
+ WriteTGAfile
+ (fname, linear, SCREENWIDTH, SCREENHEIGHT);
+#else
+ // munge planar buffer to linear
+ // CPhipps - use a malloc()ed buffer instead of screens[2]
+ I_ReadScreen(linear = malloc(SCREENWIDTH * SCREENHEIGHT));
+
+ // killough 4/18/98: make palette stay around (PU_CACHE could cause crash)
+ pal = W_CacheLumpNum (pplump);
+
+ // save the bmp file
+
+ WriteBMPfile
+ (fname, linear, SCREENWIDTH, SCREENHEIGHT, pal);
+
+ // cph - free the palette
+ W_UnlockLumpNum(pplump);
+#endif
+ free(linear);
+ // 1/18/98 killough: replace "SCREEN SHOT" acknowledgement with sfx
+
+ if (screenshot_write_error)
+ doom_printf("M_ScreenShot: Error writing screenshot");
+}
+
+void M_ScreenShot(void)
+{
+ static int shot;
+ char lbmname[32];
+ int startshot;
+
+ screenshot_write_error = false;
+
+ if (fileexists(".")) screenshot_write_error = true;
+
+ startshot = shot; // CPhipps - prevent infinite loop
+
+ do
+ snprintf(lbmname,sizeof(lbmname),"DOOM%d.BMP", shot++);
+ while (!fileexists(lbmname) && (shot != startshot) && (shot < 10000));
+
+ if (!fileexists(lbmname)) screenshot_write_error = true;
+
+ if (screenshot_write_error) {
+ doom_printf ("M_ScreenShot: Couldn't create a BMP");
+ // killough 4/18/98
+ return;
+ }
+
+ M_DoScreenShot(lbmname); // cph
+
+ S_StartSound(NULL,gamemode==commercial ? sfx_radio : sfx_tink);
+}
diff --git a/apps/plugins/doom/m_misc.h b/apps/plugins/doom/m_misc.h
new file mode 100644
index 0000000..25eb854
--- /dev/null
+++ b/apps/plugins/doom/m_misc.h
@@ -0,0 +1,112 @@
+/* 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:
+ * External non-system-specific stuff, like storing config settings,
+ * simple file handling, and saving screnshots.
+ *
+ *-----------------------------------------------------------------------------*/
+
+
+#ifndef __M_MISC__
+#define __M_MISC__
+
+
+#include "doomtype.h"
+//
+// MISC
+//
+
+boolean M_WriteFile (char const* name,void* source,int length);
+
+int M_ReadFile (char const* name,byte** buffer);
+
+void M_ScreenShot (void);
+void M_DoScreenShot (const char*); // cph
+
+void M_LoadDefaults (void);
+
+void M_SaveDefaults (void);
+
+
+int M_DrawText (int x,int y,boolean direct,char* string);
+
+struct default_s *M_LookupDefault(const char *name); /* killough 11/98 */
+
+// phares 4/21/98:
+// Moved from m_misc.c so m_menu.c could see it.
+
+// CPhipps - struct to hold a value in a config file
+// Cannot be a union, as it must be initialised
+typedef struct default_s
+{
+ const char* name;
+ /* cph -
+ * The location struct holds the pointer to the variable holding the
+ * setting. For int's we do nothing special.
+ * For strings, the string is actually stored on our heap with Z_Strdup()
+ * BUT we don't want the rest of the program to be able to modify them,
+ * so we declare it const. It's not really const though, and m_misc.c and
+ * m_menu.c cast it back when they need to change it. Possibly this is
+ * more trouble than it's worth.
+ */
+ struct {
+ int* pi;
+ const char** ppsz;
+ } location;
+ struct {
+ int i;
+ const char* psz;
+ } defaultvalue; // CPhipps - default value
+ // Limits (for an int)
+ int minvalue; // jff 3/3/98 minimum allowed value
+ int maxvalue; // jff 3/3/98 maximum allowed value
+ enum {
+ def_none, // Dummy entry
+ def_str, // A string
+ def_int, // Integer
+ def_hex, // Integer (write in hex)
+ def_bool = def_int, // Boolean
+ def_key = def_hex, // Key code (byte)
+ def_mouseb = def_int,// Mouse button
+ def_colour = def_hex // Colour (256 colour palette entry)
+ } type; // CPhipps - type of entry
+ int setupscreen; // phares 4/19/98: setup screen where this appears
+ int *current; /* cph - MBF-like pointer to current value */
+ // cph - removed the help strings from the config file
+ // const char* help; // jff 3/3/98 description of parameter
+ // CPhipps - remove unused "lousy hack" code
+ struct setup_menu_s *setup_menu; /* Xref to setup menu item, if any */
+} default_t;
+
+#define IS_STRING(dv) ((dv).type == def_str)
+// CPhipps - What is the max. key code that X will send us?
+#define MAX_KEY 65536
+#define MAX_MOUSEB 2
+
+#define UL (-123456789) /* magic number for no min or max for parameter */
+
+#endif
diff --git a/apps/plugins/doom/m_random.c b/apps/plugins/doom/m_random.c
new file mode 100644
index 0000000..2c43aaf
--- /dev/null
+++ b/apps/plugins/doom/m_random.c
@@ -0,0 +1,136 @@
+/* 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:
+ * Random number LUT.
+ *
+ * 1/19/98 killough: Rewrote random number generator for better randomness,
+ * while at the same time maintaining demo sync and backward compatibility.
+ *
+ * 2/16/98 killough: Made each RNG local to each control-equivalent block,
+ * to reduce the chances of demo sync problems.
+ *
+ *-----------------------------------------------------------------------------*/
+
+
+#include "doomstat.h"
+#include "m_random.h"
+
+//
+// M_Random
+// Returns a 0-255 number
+//
+static const unsigned char rndtable[256] = { // 1/19/98 killough -- made const
+ 0, 8, 109, 220, 222, 241, 149, 107, 75, 248, 254, 140, 16, 66 ,
+ 74, 21, 211, 47, 80, 242, 154, 27, 205, 128, 161, 89, 77, 36 ,
+ 95, 110, 85, 48, 212, 140, 211, 249, 22, 79, 200, 50, 28, 188 ,
+ 52, 140, 202, 120, 68, 145, 62, 70, 184, 190, 91, 197, 152, 224 ,
+ 149, 104, 25, 178, 252, 182, 202, 182, 141, 197, 4, 81, 181, 242 ,
+ 145, 42, 39, 227, 156, 198, 225, 193, 219, 93, 122, 175, 249, 0 ,
+ 175, 143, 70, 239, 46, 246, 163, 53, 163, 109, 168, 135, 2, 235 ,
+ 25, 92, 20, 145, 138, 77, 69, 166, 78, 176, 173, 212, 166, 113 ,
+ 94, 161, 41, 50, 239, 49, 111, 164, 70, 60, 2, 37, 171, 75 ,
+ 136, 156, 11, 56, 42, 146, 138, 229, 73, 146, 77, 61, 98, 196 ,
+ 135, 106, 63, 197, 195, 86, 96, 203, 113, 101, 170, 247, 181, 113 ,
+ 80, 250, 108, 7, 255, 237, 129, 226, 79, 107, 112, 166, 103, 241 ,
+ 24, 223, 239, 120, 198, 58, 60, 82, 128, 3, 184, 66, 143, 224 ,
+ 145, 224, 81, 206, 163, 45, 63, 90, 168, 114, 59, 33, 159, 95 ,
+ 28, 139, 123, 98, 125, 196, 15, 70, 194, 253, 54, 14, 109, 226 ,
+ 71, 17, 161, 93, 186, 87, 244, 138, 20, 52, 123, 251, 26, 36 ,
+ 17, 46, 52, 231, 232, 76, 31, 221, 84, 37, 216, 165, 212, 106 ,
+ 197, 242, 98, 43, 39, 175, 254, 145, 190, 84, 118, 222, 187, 136 ,
+ 120, 163, 236, 249
+ };
+
+rng_t rng; // the random number state
+
+unsigned long rngseed = 1993; // killough 3/26/98: The seed
+
+int P_Random(pr_class_t pr_class)
+{
+ // killough 2/16/98: We always update both sets of random number
+ // generators, to ensure repeatability if the demo_compatibility
+ // flag is changed while the program is running. Changing the
+ // demo_compatibility flag does not change the sequences generated,
+ // only which one is selected from.
+ //
+ // All of this RNG stuff is tricky as far as demo sync goes --
+ // it's like playing with explosives :) Lee
+
+ int compat = pr_class == pr_misc ?
+ (rng.prndindex = (rng.prndindex + 1) & 255) :
+ (rng. rndindex = (rng. rndindex + 1) & 255) ;
+
+ unsigned long boom;
+
+ // killough 3/31/98:
+ // If demo sync insurance is not requested, use
+ // much more unstable method by putting everything
+ // except pr_misc into pr_all_in_one
+
+ if (pr_class != pr_misc && !demo_insurance) // killough 3/31/98
+ pr_class = pr_all_in_one;
+
+ boom = rng.seed[pr_class];
+
+ // killough 3/26/98: add pr_class*2 to addend
+
+ rng.seed[pr_class] = boom * 1664525ul + 221297ul + pr_class*2;
+
+ if (demo_compatibility)
+ return rndtable[compat];
+
+ boom >>= 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<NUMPRCLASS; i++) // go through each pr_class and set
+ rng.seed[i] = seed *= 69069ul; // each starting seed differently
+ rng.prndindex = rng.rndindex = 0; // clear two compatibility indices
+}
diff --git a/apps/plugins/doom/m_random.h b/apps/plugins/doom/m_random.h
new file mode 100644
index 0000000..67c1a3b
--- /dev/null
+++ b/apps/plugins/doom/m_random.h
@@ -0,0 +1,148 @@
+/* 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:
+ * Functions to return random numbers.
+ *
+ *-----------------------------------------------------------------------------*/
+
+
+#ifndef __M_RANDOM__
+#define __M_RANDOM__
+
+#include "doomtype.h"
+
+// killough 1/19/98: rewritten to use to use a better random number generator
+// in the new engine, although the old one is available for compatibility.
+
+// killough 2/16/98:
+//
+// Make every random number generator local to each control-equivalent block.
+// Critical for demo sync. Changing the order of this list breaks all previous
+// versions' demos. The random number generators are made local to reduce the
+// chances of sync problems. In Doom, if a single random number generator call
+// was off, it would mess up all random number generators. This reduces the
+// chances of it happening by making each RNG local to a control flow block.
+//
+// Notes to developers: if you want to reduce your demo sync hassles, follow
+// this rule: for each call to P_Random you add, add a new class to the enum
+// type below for each block of code which calls P_Random. If two calls to
+// P_Random are not in "control-equivalent blocks", i.e. there are any cases
+// where one is executed, and the other is not, put them in separate classes.
+//
+// Keep all current entries in this list the same, and in the order
+// indicated by the #'s, because they're critical for preserving demo
+// sync. Do not remove entries simply because they become unused later.
+
+typedef enum {
+ pr_skullfly, // #1
+ pr_damage, // #2
+ pr_crush, // #3
+ pr_genlift, // #4
+ pr_killtics, // #5
+ pr_damagemobj, // #6
+ pr_painchance, // #7
+ pr_lights, // #8
+ pr_explode, // #9
+ pr_respawn, // #10
+ pr_lastlook, // #11
+ pr_spawnthing, // #12
+ pr_spawnpuff, // #13
+ pr_spawnblood, // #14
+ pr_missile, // #15
+ pr_shadow, // #16
+ pr_plats, // #17
+ pr_punch, // #18
+ pr_punchangle, // #19
+ pr_saw, // #20
+ pr_plasma, // #21
+ pr_gunshot, // #22
+ pr_misfire, // #23
+ pr_shotgun, // #24
+ pr_bfg, // #25
+ pr_slimehurt, // #26
+ pr_dmspawn, // #27
+ pr_missrange, // #28
+ pr_trywalk, // #29
+ pr_newchase, // #30
+ pr_newchasedir, // #31
+ pr_see, // #32
+ pr_facetarget, // #33
+ pr_posattack, // #34
+ pr_sposattack, // #35
+ pr_cposattack, // #36
+ pr_spidrefire, // #37
+ pr_troopattack, // #38
+ pr_sargattack, // #39
+ pr_headattack, // #40
+ pr_bruisattack, // #41
+ pr_tracer, // #42
+ pr_skelfist, // #43
+ pr_scream, // #44
+ pr_brainscream, // #45
+ pr_cposrefire, // #46
+ pr_brainexp, // #47
+ pr_spawnfly, // #48
+ pr_misc, // #49
+ pr_all_in_one, // #50
+ /* CPhipps - new entries from MBF, mostly unused for now */
+ pr_opendoor, // #51
+ pr_targetsearch, // #52
+ pr_friends, // #53
+ pr_threshold, // #54
+ pr_skiptarget, // #55
+ pr_enemystrafe, // #56
+ pr_avoidcrush, // #57
+ pr_stayonlift, // #58
+ pr_helpfriend, // #59
+ pr_dropoff, // #60
+ pr_randomjump, // #61
+ pr_defect, // #62 // Start new entries -- add new entries below
+
+ // End of new entries
+ NUMPRCLASS // MUST be last item in list
+} pr_class_t;
+
+// The random number generator's state.
+typedef struct {
+ unsigned long seed[NUMPRCLASS]; // Each block's random seed
+ int rndindex, prndindex; // For compatibility support
+} rng_t;
+
+extern rng_t rng; // The rng's state
+
+extern unsigned long rngseed; // The starting seed (not part of state)
+
+// Returns a number from 0 to 255,
+#define M_Random() P_Random(pr_misc)
+
+// As M_Random, but used by the play simulation.
+int P_Random(pr_class_t);
+
+// Fix randoms for demos.
+void M_ClearRandom(void);
+
+#endif
diff --git a/apps/plugins/doom/m_swap.h b/apps/plugins/doom/m_swap.h
new file mode 100644
index 0000000..fdf2b92
--- /dev/null
+++ b/apps/plugins/doom/m_swap.h
@@ -0,0 +1,104 @@
+/* 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:
+ * Endianess handling, swapping 16bit and 32bit.
+ *
+ *-----------------------------------------------------------------------------*/
+
+
+#ifndef __M_SWAP__
+#define __M_SWAP__
+
+#ifdef __GNUG__
+#pragma interface
+#endif
+
+/* Endianess handling. */
+
+/* cph - First the macros to do the actual byte swapping */
+
+/* leban
+ * rather than continue the confusing tradition of redefining the
+ * stardard macro, we now present the doom_ntoh and doom_hton macros....
+ * might as well use the xdoom macros.
+ */
+
+#ifndef doom_swap_l
+#define doom_swap_l(x) \
+ ((long int)((((unsigned long int)(x) & 0x000000ffU) << 24) | \
+ (((unsigned long int)(x) & 0x0000ff00U) << 8) | \
+ (((unsigned long int)(x) & 0x00ff0000U) >> 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 0000000..db5a701
--- /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->oldspeed<CEILSPEED*3)
+ ceiling->speed = 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 = &sectors[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 0000000..9d8f28c
--- /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 = &sectors[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 0000000..b1f40bc
--- /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; i<sec->linecount; 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; c<MAXPLAYERS; c++)
+ if (playeringame[c] && players[c].playerstate==PST_LIVE &&
+ (anyone || P_IsVisible(actor, players[c].mo, allaround)))
+ {
+ P_SetTarget(&actor->target, 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<MAXPLAYERS; i++)
+ if (playeringame[i] && players[i].health > 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 0000000..edf59af
--- /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 0000000..bbcf2bc
--- /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] || dest<sector->ceilingheight)?
+ 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 = &sectors[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 = &sectors[sec->nextsec];
+ if (sec->nextsec==-1) // if all thinkers ahead are done too
+ {
+ while (sec->prevsec!=-1) // clear all locks
+ {
+ sec->stairlock = 0;
+ sec = &sectors[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 = &sectors[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<<FRACBITS;
+ floor->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 = &sectors[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 = &sectors[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 = &sectors[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 = &sectors[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 0000000..a521210
--- /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 = &sectors[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 = &sectors[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 <type> 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 = &sectors[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 = &sectors[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 = &sectors[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 = &sectors[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 = &sectors[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 0000000..f4a0f80
--- /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 ; i<NUMAMMO ; i++)
+ player->maxammo[i] *= 2;
+ player->backpack = true;
+ }
+ for (i=0 ; i<NUMAMMO ; i++)
+ P_GiveAmmo (player, i, 1);
+ player->message = 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; player<MAXPLAYERS; player++)
+ if (playeringame[player])
+ activeplayers++;
+
+ if (activeplayers) {
+ player = P_Random(pr_friends) % activeplayers;
+
+ for (i=0; i<MAXPLAYERS; i++)
+ if (playeringame[i])
+ if (!player--)
+ players[i].killcount++;
+ }
+ }
+ }
+ }
+
+ if (target->player)
+ {
+ // 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 0000000..669a958
--- /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 0000000..44d151b
--- /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 = &sectors[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 0000000..35194de
--- /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)<<FRACBITS;
+ yh = (spot->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 0000000..6985cc1
--- /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 0000000..a2ef132
--- /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 0000000..a000bf0
--- /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 0000000..3aaaf45
--- /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; i<NUMMOBJTYPES; i++)
+ hash[i].first = NUMMOBJTYPES;
+ for (i=0; i<NUMMOBJTYPES; i++)
+ if (mobjinfo[i].doomednum != -1)
+ {
+ unsigned h = (unsigned) mobjinfo[i].doomednum % NUMMOBJTYPES;
+ hash[i].next = hash[h].first;
+ hash[h].first = i;
+ }
+ }
+
+ i = hash[type % NUMMOBJTYPES].first;
+ while ((i < NUMMOBJTYPES) && ((unsigned)mobjinfo[i].doomednum != type))
+ i = hash[i].next;
+ return i;
+}
+
+//
+// P_RespawnSpecials
+//
+
+void P_RespawnSpecials (void)
+{
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+ subsector_t* ss;
+ mobj_t* mo;
+ mapthing_t* mthing;
+ int i;
+
+ // only respawn items in deathmatch
+
+ if (deathmatch != 2)
+ return;
+
+ // nothing left to respawn?
+
+ if (iquehead == iquetail)
+ return;
+
+ // wait at least 30 seconds
+
+ if (leveltime - itemrespawntime[iquetail] < 30*35)
+ return;
+
+ mthing = &itemrespawnque[iquetail];
+
+ x = mthing->x << 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]<<MF_TRANSSHIFT;
+
+ mobj->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 0000000..bdd863a
--- /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 0000000..4a5c28b
--- /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 <type> 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 = &sectors[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 0000000..9ef9e73
--- /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; i<NUMPSPRITES; i++)
+ player->psprites[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; i<NUMPSPRITES; i++, psp++)
+ if (psp->state && 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 0000000..bb6517c
--- /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 0000000..bf1a2ed
--- /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 ; i<MAXPLAYERS ; i++)
+ if (playeringame[i])
+ {
+ int j;
+ player_t *dest;
+
+ PADSAVEP();
+ dest = (player_t *) save_p;
+ memcpy(dest, &players[i], sizeof(player_t));
+ save_p += sizeof(player_t);
+ for (j=0; j<NUMPSPRITES; j++)
+ if (dest->psprites[j].state)
+ dest->psprites[j].state =
+ (state_t *)(dest->psprites[j].state-states);
+ }
+}
+
+//
+// P_UnArchivePlayers
+//
+void P_UnArchivePlayers (void)
+{
+ int i;
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ if (playeringame[i])
+ {
+ int j;
+
+ PADSAVEP();
+
+ memcpy(&players[i], save_p, sizeof(player_t));
+ save_p += sizeof(player_t);
+
+ // will be set when unarc thinker
+ players[i].mo = NULL;
+ players[i].message = NULL;
+ players[i].attacker = NULL;
+
+ for (j=0 ; j<NUMPSPRITES ; j++)
+ if (players[i]. psprites[j].state)
+ players[i]. psprites[j].state =
+ &states[ (int)players[i].psprites[j].state ];
+ }
+}
+
+
+//
+// P_ArchiveWorld
+//
+void P_ArchiveWorld (void)
+{
+ int i;
+ const sector_t *sec;
+ const line_t *li;
+ const side_t *si;
+ short *put;
+
+ // killough 3/22/98: fix bug caused by hoisting save_p too early
+ // killough 10/98: adjust size for changes below
+ size_t size =
+ (sizeof(short)*5 + sizeof sec->floorheight + sizeof sec->ceilingheight)
+ * numsectors + sizeof(short)*3*numlines + 4;
+
+ for (i=0; i<numlines; i++)
+ {
+ if (lines[i].sidenum[0] != -1)
+ size +=
+ sizeof(short)*3 + sizeof si->textureoffset + 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 ; i<numsectors ; i++,sec++)
+ {
+ // killough 10/98: save full floor & ceiling heights, including fraction
+ memcpy(put, &sec->floorheight, 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 ; i<numlines ; i++,li++)
+ {
+ int j;
+
+ *put++ = li->flags;
+ *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 ; i<numsectors ; i++,sec++)
+ {
+ // killough 10/98: load full floor & ceiling heights, including fractions
+
+ memcpy(&sec->floorheight, 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 ; i<numlines ; i++,li++)
+ {
+ int j;
+
+ li->flags = *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(&sectors[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 = &sectors[(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 = &sectors[(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 = &sectors[(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 = &sectors[(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 = &sectors[(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 = &sectors[(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 = &sectors[(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 = &sectors[(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 = &sectors[(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 0000000..1bfe1d4
--- /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 0000000..d40372d
--- /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 <math.h>
+
+#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; i<numvertexes; i++)
+ {
+ vertexes[i].x = SHORT(((mapvertex_t *) data)[i].x)<<FRACBITS;
+ vertexes[i].y = SHORT(((mapvertex_t *) data)[i].y)<<FRACBITS;
+ }
+
+ // Free buffer memory.
+ W_UnlockLumpNum(lump);
+}
+
+//
+// P_LoadSegs
+//
+// killough 5/3/98: reformatted, cleaned up
+
+static void P_LoadSegs (int lump)
+{
+ int i;
+ const byte *data; // cph - const
+
+ numsegs = W_LumpLength(lump) / sizeof(mapseg_t);
+ segs = Z_Calloc(numsegs,sizeof(seg_t),PU_LEVEL,0);
+ data = W_CacheLumpNum(lump); // cph - wad lump handling updated
+
+ for (i=0; i<numsegs; i++)
+ {
+ seg_t *li = segs+i;
+ mapseg_t *ml = (mapseg_t *) data + i;
+
+ int side, linedef;
+ line_t *ldef;
+
+ li->v1 = &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; i<numsubsectors; i++)
+ {
+ subsectors[i].numlines = (unsigned short)SHORT(((mapsubsector_t *) data)[i].numsegs );
+ subsectors[i].firstline = (unsigned short)SHORT(((mapsubsector_t *) data)[i].firstseg);
+ }
+
+ W_UnlockLumpNum(lump); // cph - release the data
+}
+
+//
+// P_LoadSectors
+//
+// killough 5/3/98: reformatted, cleaned up
+
+static void P_LoadSectors (int lump)
+{
+ const byte *data; // cph - const*
+ int i;
+
+ numsectors = W_LumpLength (lump) / sizeof(mapsector_t);
+ sectors = Z_Calloc (numsectors,sizeof(sector_t),PU_LEVEL,0);
+ data = W_CacheLumpNum (lump); // cph - wad lump handling updated
+
+ for (i=0; i<numsectors; i++)
+ {
+ sector_t *ss = sectors + i;
+ const mapsector_t *ms = (mapsector_t *) data + i;
+
+ ss->floorheight = SHORT(ms->floorheight)<<FRACBITS;
+ ss->ceilingheight = SHORT(ms->ceilingheight)<<FRACBITS;
+ ss->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; i<numnodes; i++)
+ {
+ node_t *no = nodes + i;
+ mapnode_t *mn = (mapnode_t *) data + i;
+ int j;
+
+ no->x = SHORT(mn->x)<<FRACBITS;
+ no->y = SHORT(mn->y)<<FRACBITS;
+ no->dx = SHORT(mn->dx)<<FRACBITS;
+ no->dy = SHORT(mn->dy)<<FRACBITS;
+
+ for (j=0 ; j<2 ; j++)
+ {
+ int k;
+ no->children[j] = SHORT(mn->children[j]);
+ for (k=0 ; k<4 ; k++)
+ no->bbox[j][k] = SHORT(mn->bbox[j][k])<<FRACBITS;
+ }
+ }
+
+ W_UnlockLumpNum(lump); // cph - release the data
+}
+
+
+//
+// P_LoadThings
+//
+// killough 5/3/98: reformatted, cleaned up
+
+static void P_LoadThings (int lump)
+{
+ mapthing_t tempthing; // this needed to be added as the SHORT calls were overwriting eachother on reload
+ int i, numthings = W_LumpLength (lump) / sizeof(mapthing_t);
+ const byte *data = W_CacheLumpNum (lump); // cph - wad lump handling updated, const*
+
+ for (i=0; i<numthings; i++)
+ {
+ mapthing_t *mt = (mapthing_t *) data + i;
+
+ // Do not spawn cool, new monsters if !commercial
+ if (gamemode != commercial)
+ switch(mt->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; i<numlines; i++)
+ {
+ maplinedef_t *mld = (maplinedef_t *) data + i;
+ line_t *ld = lines+i;
+ vertex_t *v1, *v2;
+
+ ld->flags = 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;j<numlines;j++) // if tag!=0,
+ if (lines[j].tag == ld->tag) // 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; i<numsides; i++)
+ {
+ register mapsidedef_t *msd = (mapsidedef_t *) data + i;
+ register side_t *sd = sides + i;
+ register sector_t *sec;
+
+ sd->textureoffset = SHORT(msd->textureoffset)<<FRACBITS;
+ sd->rowoffset = SHORT(msd->rowoffset)<<FRACBITS;
+
+ // killough 4/4/98: allow sidedef texture names to be overloaded
+ // killough 4/11/98: refined to allow colormaps to work as wall
+ // textures if invalid as colormaps but valid as textures.
+
+ sd->sector = sec = &sectors[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<<blkshift)-1)/* mask for rel position within cell */
+#define blkmargin 0 /* size guardband around map used */
+// jff 10/8/98 use guardband>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<numvertexes;i++)
+ {
+ fixed_t t;
+
+ if ((t=vertexes[i].x) < map_minx)
+ map_minx = t;
+ else if (t > 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;i<NBlocks;i++)
+ {
+ blocklists[i] = malloc(sizeof(linelist_t));
+ blocklists[i]->num = -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;i<numlines;i++)
+ {
+ int x1 = lines[i].v1->x>>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<ncols;j++)
+ {
+ // intersection of Linedef with x=xorg+(j<<blkshift)
+ // (y-y1)*dx = dy*(x-x1)
+ // y = dy*(x-x1)+y1*dx;
+
+ int x = xorg+(j<<blkshift); // (x,y) is intersection
+ int y = (dy*(x-x1))/dx+y1;
+ int yb = (y-yorg)>>blkshift; // block row number
+ int yp = (y-yorg)&blkmask; // y position within block
+
+ if (yb<0 || yb>nrows-1) // outside blockmap, continue
+ continue;
+
+ if (x<minx || x>maxx) // 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 && miny<y)
+ AddBlockLine(blocklists,blockcount,blockdone,ncols*(yb-1)+j,i);
+ if (j>0 && minx<x)
+ AddBlockLine(blocklists,blockcount,blockdone,ncols*yb+j-1,i);
+ }
+ else if (spos) // / - block x-,y-
+ {
+ if (yb>0 && j>0 && minx<x)
+ AddBlockLine(blocklists,blockcount,blockdone,ncols*(yb-1)+j-1,i);
+ }
+ else if (horiz) // - - block x-,y
+ {
+ if (j>0 && minx<x)
+ AddBlockLine(blocklists,blockcount,blockdone,ncols*yb+j-1,i);
+ }
+ }
+ else if (j>0 && minx<x) // else not at corner: x-,y
+ AddBlockLine(blocklists,blockcount,blockdone,ncols*yb+j-1,i);
+ }
+ }
+
+ // For each row, see where the line along its bottom edge, which
+ // it contains, intersects the Linedef i. Add i to all the corresponding
+ // blocklists.
+
+ if (!horiz)
+ {
+ for (j=0;j<nrows;j++)
+ {
+ // intersection of Linedef with y=yorg+(j<<blkshift)
+ // (x,y) on Linedef i satisfies: (y-y1)*dx = dy*(x-x1)
+ // x = dx*(y-y1)/dy+x1;
+
+ int y = yorg+(j<<blkshift); // (x,y) is intersection
+ int x = (dx*(y-y1))/dy+x1;
+ int xb = (x-xorg)>>blkshift; // block column number
+ int xp = (x-xorg)&blkmask; // x position within block
+
+ if (xb<0 || xb>ncols-1) // outside blockmap, continue
+ continue;
+
+ if (y<miny || y>maxy) // 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 && miny<y)
+ AddBlockLine(blocklists,blockcount,blockdone,ncols*(j-1)+xb,i);
+ if (xb>0 && minx<x)
+ AddBlockLine(blocklists,blockcount,blockdone,ncols*j+xb-1,i);
+ }
+ else if (vert) // | - block x,y-
+ {
+ if (j>0 && miny<y)
+ AddBlockLine(blocklists,blockcount,blockdone,ncols*(j-1)+xb,i);
+ }
+ else if (spos) // / - block x-,y-
+ {
+ if (xb>0 && j>0 && miny<y)
+ AddBlockLine(blocklists,blockcount,blockdone,ncols*(j-1)+xb-1,i);
+ }
+ }
+ else if (j>0 && miny<y) // else not on a corner: x,y-
+ AddBlockLine(blocklists,blockcount,blockdone,ncols*(j-1)+xb,i);
+ }
+ }
+ }
+
+ // Add initial 0 to all blocklists
+ // count the total number of lines (and 0's and -1's)
+
+ memset(blockdone,0,NBlocks*sizeof(int));
+ for (i=0,linetotal=0;i<NBlocks;i++)
+ {
+ AddBlockLine(blocklists,blockcount,blockdone,i,0);
+ linetotal += blockcount[i];
+ }
+
+ // Create the blockmap lump
+
+ blockmaplump = Z_Malloc(sizeof(*blockmaplump) * (4+NBlocks+linetotal),
+ PU_LEVEL, 0);
+ // blockmap header
+
+ blockmaplump[0] = bmaporgx = xorg << FRACBITS;
+ blockmaplump[1] = bmaporgy = yorg << FRACBITS;
+ blockmaplump[2] = bmapwidth = ncols;
+ blockmaplump[3] = bmapheight = nrows;
+
+ // offsets to lists and block lists
+
+ for (i=0;i<NBlocks;i++)
+ {
+ linelist_t *bl = blocklists[i];
+ long offs = blockmaplump[4+i] = // set offset to block's list
+ (i? blockmaplump[4+i-1] : 4+NBlocks) + (i? blockcount[i-1] : 0);
+
+ // add the lines in each block's list to the blockmaplump
+ // delete each list node as we go
+
+ while (bl)
+ {
+ linelist_t *tmp = bl->next;
+ 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 ; i<count ; i++)
+ {
+ short t = SHORT(wadblockmaplump[i]); // killough 3/1/98
+ blockmaplump[i] = t == -1 ? -1l : (long) t & 0xffff;
+ }
+
+ W_UnlockLumpNum(lump); // cph - unlock the lump
+
+ bmaporgx = blockmaplump[0]<<FRACBITS;
+ bmaporgy = blockmaplump[1]<<FRACBITS;
+ bmapwidth = blockmaplump[2];
+ bmapheight = blockmaplump[3];
+ }
+
+ // clear out mobj chains - CPhipps - use calloc
+ blocklinks = Z_Calloc (bmapwidth*bmapheight,sizeof(*blocklinks),PU_LEVEL,0);
+ blockmap = blockmaplump+4;
+}
+
+//
+// P_GroupLines
+// Builds sector line lists and subsector sector numbers.
+// Finds block bounding boxes for sectors.
+//
+// killough 5/3/98: reformatted, cleaned up
+// cph 18/8/99: rewritten to avoid O(numlines * numsectors) section
+// It makes things more complicated, but saves seconds on big levels
+// figgi 09/18/00 -- adapted for gl-nodes
+
+// cph - convenient sub-function
+static void P_AddLineToSector(line_t* li, sector_t* sector)
+{
+ fixed_t *bbox = (void*)sector->blockbox;
+
+ 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 ; i<numsubsectors ; i++)
+ {
+ seg_t *seg = &segs[subsectors[i].firstline];
+ subsectors[i].sector = NULL;
+ for(j=0; j<subsectors[i].numlines; j++)
+ {
+ if(seg->sidedef)
+ {
+ 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; i<numlines; i++, li++)
+ {
+ li->frontsector->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; i<numsectors; i++, sector++)
+ {
+ sector->lines = linebuffer;
+ linebuffer += sector->linecount;
+ sector->linecount = 0;
+ M_ClearBox(sector->blockbox);
+ }
+ }
+
+ // Enter those lines
+ for (i=0,li=lines; i<numlines; i++, li++)
+ {
+ P_AddLineToSector(li, li->frontsector);
+ if (li->backsector && li->backsector != li->frontsector)
+ P_AddLineToSector(li, li->backsector);
+ }
+
+ for (i=0, sector = sectors; i<numsectors; i++, sector++)
+ {
+ fixed_t *bbox = (void*)sector->blockbox; // 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; i<numsegs; i++) // Go through each seg
+ {
+ const line_t *l;
+
+ if (segs[i].miniseg == true) //figgi -- skip minisegs
+ return;
+
+ l = segs[i].linedef; // The parent linedef
+ if (l->dx && 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; i<MAXPLAYERS; i++)
+ players[i].killcount = players[i].secretcount = players[i].itemcount = 0;
+
+ // Initial height of PointOfView will be set by player think.
+ players[consoleplayer].viewz = 1;
+
+ // Make sure all sounds are stopped before Z_FreeTags.
+ S_Start();
+
+ Z_FreeTags(PU_LEVEL, PU_PURGELEVEL-1);
+ if (rejectlump != -1) { // cph - unlock the reject table
+ W_UnlockLumpNum(rejectlump);
+ rejectlump = -1;
+ }
+
+ P_InitThinkers();
+
+ // if working with a devlopment map, reload it
+ // W_Reload (); killough 1/31/98: W_Reload obsolete
+
+ // find map name
+ if (gamemode == commercial)
+ {
+ if (map<10)
+ snprintf (lumpname,sizeof(lumpname),"map0%d", map);
+ else
+ snprintf (lumpname,sizeof(lumpname),"map%d", map);
+ }
+ else
+ {
+ snprintf(lumpname,sizeof(lumpname), "E%dM%d", episode, map); // killough 1/24/98: simplify
+ }
+
+ lumpnum = W_GetNumForName(lumpname);
+
+ leveltime = 0;
+
+ // note: most of this ordering is important
+
+ // killough 3/1/98: P_LoadBlockMap call moved down to below
+ // killough 4/4/98: split load of sidedefs into two parts,
+ // to allow texture names to be used in special linedefs
+
+ usingGLNodes = false;
+ P_LoadVertexes (lumpnum+ML_VERTEXES);
+ P_LoadSectors (lumpnum+ML_SECTORS);
+ P_LoadSideDefs (lumpnum+ML_SIDEDEFS);
+ P_LoadLineDefs (lumpnum+ML_LINEDEFS);
+ P_LoadSideDefs2 (lumpnum+ML_SIDEDEFS);
+ P_LoadLineDefs2 (lumpnum+ML_LINEDEFS);
+ P_LoadBlockMap (lumpnum+ML_BLOCKMAP);
+
+ P_LoadSubsectors(lumpnum + ML_SSECTORS);
+ P_LoadNodes(lumpnum + ML_NODES);
+ P_LoadSegs(lumpnum + ML_SEGS);
+
+ if (rejectlump != -1)
+ W_UnlockLumpNum(rejectlump);
+ rejectlump = lumpnum+ML_REJECT;
+ {
+ int rjlen = W_LumpLength(rejectlump);
+ int rjreq = (numsectors*numsectors+7)/8;
+ if (rjlen < rjreq) {
+ printf("P_SetupLevel: REJECT too short (%d<%d) - padded\n",rjlen,rjreq);
+ rejectmatrix = W_CacheLumpNumPadded(rejectlump,rjreq,0xff);
+ } else {
+ rejectmatrix = W_CacheLumpNum(rejectlump);
+ }
+ }
+ P_GroupLines();
+
+ P_RemoveSlimeTrails(); // killough 10/98: remove slime trails from wad
+
+ // Note: you don't need to clear player queue slots --
+ // a much simpler fix is in g_game.c -- killough 10/98
+
+ bodyqueslot = 0;
+ deathmatch_p = deathmatchstarts;
+ P_MapStart();
+ P_LoadThings(lumpnum+ML_THINGS);
+
+ // if deathmatch, randomly spawn the active players
+ if (deathmatch)
+ for (i=0; i<MAXPLAYERS; i++)
+ if (playeringame[i])
+ {
+ players[i].mo = NULL;
+ G_DeathMatchSpawnPlayer(i);
+ }
+
+ // killough 3/26/98: Spawn icon landings:
+ if (gamemode==commercial)
+ P_SpawnBrainTargets();
+
+ // clear special respawning que
+ iquehead = iquetail = 0;
+
+ // set up world state
+ P_SpawnSpecials();
+
+ P_MapEnd();
+
+ // preload graphics
+ if (precache)
+ R_PrecacheLevel();
+}
+
+//
+// P_Init
+//
+void P_Init (void)
+{
+ P_InitSwitchList();
+ P_InitPicAnims();
+ R_InitSprites(sprnames);
+}
diff --git a/apps/plugins/doom/p_setup.h b/apps/plugins/doom/p_setup.h
new file mode 100644
index 0000000..7d33457
--- /dev/null
+++ b/apps/plugins/doom/p_setup.h
@@ -0,0 +1,55 @@
+/* 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:
+ * Setup a game, startup stuff.
+ *
+ *-----------------------------------------------------------------------------*/
+
+#ifndef __P_SETUP__
+#define __P_SETUP__
+
+#include "p_mobj.h"
+
+#ifdef __GNUG__
+#pragma interface
+#endif
+
+void P_SetupLevel(int episode, int map, int playermask, skill_t skill);
+void P_Init(void); /* Called by startup code. */
+
+extern const byte *rejectmatrix; /* for fast sight rejection - cph - const* */
+
+/* killough 3/1/98: change blockmap from "short" to "long" offsets: */
+extern long *blockmaplump; /* offsets in blockmap are from here */
+extern long *blockmap;
+extern int bmapwidth;
+extern int bmapheight; /* in mapblocks */
+extern fixed_t bmaporgx;
+extern fixed_t bmaporgy; /* origin of block map */
+extern mobj_t **blocklinks; /* for thing chains */
+
+#endif
diff --git a/apps/plugins/doom/p_sight.c b/apps/plugins/doom/p_sight.c
new file mode 100644
index 0000000..737fcf6
--- /dev/null
+++ b/apps/plugins/doom/p_sight.c
@@ -0,0 +1,346 @@
+/* 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:
+ * LineOfSight/Visibility checks, uses REJECT Lookup Table.
+ *
+ *-----------------------------------------------------------------------------*/
+
+#include "doomstat.h"
+#include "r_main.h"
+#include "p_maputl.h"
+#include "p_setup.h"
+#include "m_bbox.h"
+#include "rockmacros.h"
+//
+// P_CheckSight
+//
+// killough 4/19/98:
+// Convert LOS info to struct for reentrancy and efficiency of data locality
+
+typedef struct {
+ fixed_t sightzstart, t2x, t2y; // eye z of looker
+ divline_t strace; // from t1 to t2
+ fixed_t topslope, bottomslope; // slopes to top and bottom of target
+ fixed_t bbox[4];
+ fixed_t maxz,minz; // cph - z optimisations for 2sided lines
+} los_t;
+
+static los_t los; // cph - made static
+
+//
+// P_DivlineSide
+// Returns side 0 (front), 1 (back), or 2 (on).
+//
+// killough 4/19/98: made static, cleaned up
+
+inline static int P_DivlineSide(fixed_t x, fixed_t y, const divline_t *node)
+{
+ fixed_t left, right;
+ return
+ !node->dx ? 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 0000000..2876b7f
--- /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 = &sectors[secnum];
+
+ if (!comp[comp_model])
+ minsize = 32000<<FRACBITS; //jff 3/13/98 prevent overflow in height calcs
+
+ for (i = 0; i < sec->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 = &sectors[secnum];
+
+ if (!comp[comp_model])
+ minsize = 32000<<FRACBITS; //jff 3/13/98 prevent overflow
+ // in height calcs
+ for (i = 0; i < sec->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 = &sectors[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->linecount<linecount?
+ sec->linecount : 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 = &sectors[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->linecount<linecount?
+ sec->linecount : 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<MAXPLAYERS;k++)
+ {
+ if (!playeringame[k]) continue;
+ fragcount = 0;
+ for (m=0;m<MAXPLAYERS;m++)
+ {
+ if (!playeringame[m]) continue;
+ fragcount += (m!=k)? players[k].frags[m] : -players[k].frags[m];
+ }
+ if (fragcount >= 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 ; i<anim->basepic+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 ; i<numsectors ; i++, sector++)
+ {
+ if (!sector->special)
+ 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<<DAMAGE_SHIFT; //jff 3/14/98 put damage bits in
+ break;
+
+ case 8:
+ // glowing light
+ P_SpawnGlowingLight(sector);
+ break;
+ case 9:
+ // secret sector
+ if (sector->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<numlines; i++)
+ switch (lines[i].special)
+ {
+ int s, sec;
+
+ // killough 3/7/98:
+ // support for drawn heights coming from different sector
+ case 242:
+ sec = sides[*lines[i].sidenum].sector-sectors;
+ for (s = -1; (s = P_FindSectorFromLineTag(lines+i,s)) >= 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;i<numlines;i++,l++)
+ {
+ fixed_t dx = l->dx >> 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 0000000..7a13ad8
--- /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 0000000..698c4c8
--- /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 0000000..9282e9f
--- /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 0000000..4bf8fea
--- /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; i<NUMTHCLASS; i++) // killough 8/29/98: initialize threaded lists
+ thinkerclasscap[i].cprev = thinkerclasscap[i].cnext = &thinkerclasscap[i];
+
+ thinkercap.prev = thinkercap.next = &thinkercap;
+}
+
+//
+// killough 8/29/98:
+//
+// We maintain separate threads of friends and enemies, to permit more
+// efficient searches.
+//
+
+void P_UpdateThinker(thinker_t *thinker)
+{
+ // find the class the thinker belongs to
+
+ int class = thinker->function == 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<MAXPLAYERS; i++)
+ if (playeringame[i])
+ P_PlayerThink(&players[i]);
+
+ P_RunThinkers();
+ P_UpdateSpecials();
+ P_RespawnSpecials();
+ P_MapEnd();
+ leveltime++; // for par times
+}
+
diff --git a/apps/plugins/doom/p_tick.h b/apps/plugins/doom/p_tick.h
new file mode 100644
index 0000000..5a49516
--- /dev/null
+++ b/apps/plugins/doom/p_tick.h
@@ -0,0 +1,66 @@
+/* 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:
+ * Core thinker processing prototypes.
+ *-----------------------------------------------------------------------------*/
+
+#ifndef __P_TICK__
+#define __P_TICK__
+
+#include "d_think.h"
+
+#ifdef __GNUG__
+#pragma interface
+#endif
+
+/* Called by C_Ticker, can call G_PlayerExited.
+ * Carries out all thinking of monsters and players. */
+
+void P_Ticker(void);
+
+extern thinker_t thinkercap; // Both the head and tail of the thinker list
+
+void P_InitThinkers(void);
+void P_AddThinker(thinker_t *thinker);
+void P_RemoveThinker(thinker_t *thinker);
+void P_RemoveThinkerDelayed(thinker_t *thinker); // killough 4/25/98
+
+void P_UpdateThinker(thinker_t *thinker); // killough 8/29/98
+
+void P_SetTarget(mobj_t **mo, mobj_t *target); // killough 11/98
+
+// killough 8/29/98: threads of thinkers, for more efficient searches
+typedef enum {
+ th_misc,
+ th_friends,
+ th_enemies,
+ NUMTHCLASS
+} th_class;
+
+extern thinker_t thinkerclasscap[];
+
+#endif
diff --git a/apps/plugins/doom/p_user.c b/apps/plugins/doom/p_user.c
new file mode 100644
index 0000000..abbe36b
--- /dev/null
+++ b/apps/plugins/doom/p_user.c
@@ -0,0 +1,420 @@
+/* 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.
+ *
+ *-----------------------------------------------------------------------------*/
+
+#include "doomstat.h"
+#include "d_event.h"
+#include "r_main.h"
+#include "p_map.h"
+#include "p_spec.h"
+#include "p_user.h"
+#include "rockmacros.h"
+// Index of the special effects (INVUL inverse) map.
+
+#define INVERSECOLORMAP 32
+
+//
+// Movement.
+//
+
+// 16 pixels of bob
+
+#define MAXBOB 0x100000
+
+boolean onground; // whether player is on ground or in air
+
+//
+// P_Thrust
+// Moves the given origin along a given angle.
+//
+
+void P_Thrust(player_t* player,angle_t angle,fixed_t move)
+{
+ angle >>= 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 0000000..a236b2a
--- /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 0000000..358787d
--- /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 = &sectors[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 0000000..2ea6538
--- /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 0000000..aad16e4
--- /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 (; x1<x2 ; x1++)
+ if (collump[x1] == -1) // Column has multiple patches?
+ // killough 1/25/98, 4/9/98: Fix medusa bug.
+ R_DrawColumnInCache((column_t*)((byte*)realpatch+LONG(cofs[x1])),
+ block+colofs[x1],patch->originy,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 ( ; x<x2 ; x++)
+ {
+ // killough 4/9/98: keep a count of the number of posts in column,
+ // to fix Medusa bug while allowing for transparent multipatches.
+
+ const column_t *col = (column_t*)((byte*)realpatch+LONG(cofs[x]));
+ for (;col->topdelta != 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<nummappatches ; i++)
+ {
+ strncpy (name,name_p+i*8, 8);
+ patchlookup[i] = W_CheckNumForName(name);
+ if (patchlookup[i] == -1)
+ {
+ // killough 4/17/98:
+ // Some wads use sprites as wall patches, so repeat check and
+ // look for sprites this time, but only if there were no wall
+ // patches found. This is the same as allowing for both, except
+ // that wall patches always win over sprites, even when they
+ // appear first in a wad. This is a kludgy solution to the wad
+ // lump namespace problem.
+
+ patchlookup[i] = (W_CheckNumForName)(name, ns_sprites);
+
+ if (patchlookup[i] == -1 && devparm)
+ //jff 8/3/98 use logical output routine
+ printf("\nWarning: patch %.8s, index %d does not exist",name,i);
+ }
+ }
+ W_UnlockLumpNum(names_lump); // cph - release the lump
+
+ // Load the map texture definitions from textures.lmp.
+ // The data is contained in one or two lumps,
+ // TEXTURE1 for shareware, plus TEXTURE2 for commercial.
+
+ maptex = maptex1 = W_CacheLumpNum(maptex_lump[0] = W_GetNumForName("TEXTURE1"));
+ numtextures1 = LONG(*maptex);
+ maxoff = W_LumpLength(maptex_lump[0]);
+ directory = maptex+1;
+
+ if (W_CheckNumForName("TEXTURE2") != -1)
+ {
+ maptex2 = W_CacheLumpNum(maptex_lump[1] = W_GetNumForName("TEXTURE2"));
+ numtextures2 = LONG(*maptex2);
+ maxoff2 = W_LumpLength(maptex_lump[1]);
+ }
+ else
+ {
+ maptex2 = NULL;
+ numtextures2 = 0;
+ maxoff2 = 0;
+ }
+ numtextures = numtextures1 + numtextures2;
+
+ // killough 4/9/98: make column offsets 32-bit;
+ // clean up malloc-ing to use sizeof
+
+ textures = Z_Malloc(numtextures*sizeof*textures, PU_STATIC, 0);
+ textureheight = Z_Malloc(numtextures*sizeof*textureheight, PU_STATIC, 0);
+
+ totalwidth = 0;
+
+ for (i=0 ; i<numtextures ; i++, directory++)
+ {
+ if (i == numtextures1)
+ {
+ // Start looking in second texture file.
+ maptex = maptex2;
+ maxoff = maxoff2;
+ directory = maptex+1;
+ }
+
+ offset = LONG(*directory);
+
+ if (offset > 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 <PuteraJF@Npt.NUWC.Navy.Mil> 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;j<sizeof(texture->name);j++)
+ texture->name[j]=mtexture->name[j];
+ }
+ /* #endif */
+
+ mpatch = mtexture->patches;
+ patch = texture->patches;
+
+ for (j=0 ; j<texture->patchcount ; 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<<FRACBITS;
+
+ totalwidth += texture->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 ; i<numtextures ; i++)
+ R_GenerateLookup(i, &errors);
+
+ if (errors)
+ I_Error("R_InitTextures: %d errors", errors);
+
+ // Create translation table for global animation.
+ // killough 4/9/98: make column offsets 32-bit;
+ // clean up malloc-ing to use sizeof
+
+ texturetranslation =
+ Z_Malloc((numtextures+1)*sizeof*texturetranslation, PU_STATIC, 0);
+
+ for (i=0 ; i<numtextures ; i++)
+ texturetranslation[i] = i;
+
+ // killough 1/31/98: Initialize texture hash table
+ for (i = 0; i<numtextures; i++)
+ textures[i]->index = -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 ; i<numflats ; i++)
+ flattranslation[i] = i;
+}
+
+//
+// R_InitSpriteLumps
+// Finds the width and hoffset of all sprites in the wad,
+// so the sprite does not need to be cached completely
+// just for having the header info ready during rendering.
+//
+void R_InitSpriteLumps(void)
+{
+ int i;
+ const patch_t *patch;
+
+ firstspritelump = W_GetNumForName("S_START") + 1;
+ lastspritelump = W_GetNumForName("S_END") - 1;
+ numspritelumps = lastspritelump - firstspritelump + 1;
+
+ // killough 4/9/98: make columnd offsets 32-bit;
+ // clean up malloc-ing to use sizeof
+
+ spritewidth = Z_Malloc(numspritelumps*sizeof*spritewidth, PU_STATIC, 0);
+ spriteoffset = Z_Malloc(numspritelumps*sizeof*spriteoffset, PU_STATIC, 0);
+ spritetopoffset =
+ Z_Malloc(numspritelumps*sizeof*spritetopoffset, PU_STATIC, 0);
+
+ for (i=0 ; i< numspritelumps ; i++)
+ {
+ patch = W_CacheLumpNum(firstspritelump+i);
+ spritewidth[i] = SHORT(patch->width)<<FRACBITS;
+ spriteoffset[i] = SHORT(patch->leftoffset)<<FRACBITS;
+ spritetopoffset[i] = SHORT(patch->topoffset)<<FRACBITS;
+ W_UnlockLumpNum(firstspritelump+i);
+ }
+}
+
+//
+// R_InitColormaps
+//
+// killough 3/20/98: rewritten to allow dynamic colormaps
+// and to remove unnecessary 256-byte alignment
+//
+// killough 4/4/98: Add support for C_START/C_END markers
+//
+
+void R_InitColormaps(void)
+{
+ int i;
+ firstcolormaplump = W_GetNumForName("C_START");
+ lastcolormaplump = W_GetNumForName("C_END");
+ numcolormaps = lastcolormaplump - firstcolormaplump;
+ colormaps = Z_Malloc(sizeof(*colormaps) * numcolormaps, PU_STATIC, 0);
+ colormaps[0] = (lighttable_t *)W_CacheLumpName("COLORMAP");
+ for (i=1; i<numcolormaps; i++)
+ colormaps[i] = (lighttable_t *)W_CacheLumpNum(i+firstcolormaplump);
+ // cph - always lock
+}
+
+// killough 4/4/98: get colormap number from name
+// killough 4/11/98: changed to return -1 for illegal names
+// killough 4/17/98: changed to use ns_colormaps tag
+
+int R_ColormapNumForName(const char *name)
+{
+ register int i = 0;
+ if (strncasecmp(name,"COLORMAP",8)) // COLORMAP predefined to return 0
+ if ((i = (W_CheckNumForName)(name, ns_colormaps)) != -1)
+ i -= firstcolormaplump;
+ return i;
+}
+
+//
+// R_InitTranMap
+//
+// Initialize translucency filter map
+//
+// By Lee Killough 2/21/98
+//
+
+struct _cache {
+ unsigned char pct;
+ unsigned char playpal[256];
+} cache;
+
+int tran_filter_pct = 66; // filter percent
+
+#define TSC 12 /* number of fixed point digits in filter percent */
+
+void R_InitTranMap(int progress)
+{
+ int lump = W_CheckNumForName("TRANMAP");
+
+ // If a tranlucency filter map lump is present, use it
+ if (lump != -1) // Set a pointer to the translucency filter maps.
+ main_tranmap = W_CacheLumpNum(lump); // killough 4/11/98
+ else
+ { // Compose a default transparent filter map based on PLAYPAL.
+ const byte *playpal = W_CacheLumpName("PLAYPAL");
+ byte *my_tranmap;
+
+ int cachefd = open(GAMEBASE"tranmap.dat",O_RDONLY);
+
+ main_tranmap = my_tranmap = Z_Malloc(256*256, PU_STATIC, 0); // killough 4/11/98
+
+ // Use cached translucency filter if it's available
+
+ if ((cachefd<0) ? cachefd = open(GAMEBASE"tranmap.dat",O_WRONLY | O_CREAT) , 1 :
+ read(cachefd, &cache, sizeof(cache)) != sizeof(cache) ||
+ cache.pct != tran_filter_pct ||
+ memcmp(cache.playpal, playpal, sizeof cache.playpal) ||
+ read(cachefd, my_tranmap, 256*256) != 256*256 ) // killough 4/11/98
+ {
+
+ long *stackdeath=malloc(256*7*sizeof(long)); // This was a bunch of static varibles, way too big for rockbox
+ long *pal[3], *tot, *pal_w1[3];
+ pal[0]=&stackdeath[0];
+ pal[1]=&stackdeath[256];
+ pal[2]=&stackdeath[256*2];
+ tot=&stackdeath[256*3];
+ pal_w1[0]=&stackdeath[256*4];
+ pal_w1[1]=&stackdeath[256*5];
+ pal_w1[2]=&stackdeath[256*6];
+ long w1 = ((unsigned long) tran_filter_pct<<TSC)/100;
+ long w2 = (1l<<TSC)-w1;
+
+ if (progress)
+ printf("Please wait: Tranmap build");
+ // First, convert playpal into long int type, and transpose array,
+ // for fast inner-loop calculations. Precompute tot array.
+
+ {
+ register int i = 255;
+ register const unsigned char *p = playpal+255*3;
+ do
+ {
+ register long t,d;
+ pal_w1[0][i] = (pal[0][i] = t = p[0]) * w1;
+ d = t*t;
+ pal_w1[1][i] = (pal[1][i] = t = p[1]) * w1;
+ d += t*t;
+ pal_w1[2][i] = (pal[2][i] = t = p[2]) * w1;
+ d += t*t;
+ p -= 3;
+ tot[i] = d << (TSC-1);
+ } while (--i>=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 0000000..12c9eb7
--- /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 0000000..a3bd5cd
--- /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 0000000..df68277
--- /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<MAXTRANS; i++) transtocolour[i] = 255;
+
+ for (i=0; i<MAXPLAYERS; i++) {
+ byte wantcolour = mapcolor_plyr[i];
+ playernumtotrans[i] = 0;
+ if (wantcolour != 0x70) // Not green, would like translation
+ for (j=0; j<MAXTRANS; j++)
+ if (transtocolour[j] == 255) {
+ transtocolour[j] = wantcolour; playernumtotrans[i] = j+1; break;
+ }
+ }
+
+ // translate just the 16 green colors
+ for (i=0; i<256; i++)
+ if (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<FUZZTABLE; i++)
+ fuzzoffset[i] = fuzzoffset_org[i]*SCREENWIDTH;
+}
+
+
+//
+// R_FillBackScreen
+// Fills the back screen with a pattern
+// for variable screen sizes
+// Also draws a beveled edge.
+//
+// CPhipps - patch drawing updated
+
+void R_FillBackScreen (void)
+{
+ int x,y;
+
+ if (scaledviewwidth == SCREENWIDTH)
+ return;
+
+ V_DrawBackground(gamemode == commercial ? "GRNROCK" : "FLOOR7_2", 1);
+
+ for (x=0 ; x<scaledviewwidth ; x+=8)
+ V_DrawNamePatch(viewwindowx+x,viewwindowy-8,1,"brdr_t", CR_DEFAULT, VPT_NONE);
+
+ for (x=0 ; x<scaledviewwidth ; x+=8)
+ V_DrawNamePatch(viewwindowx+x,viewwindowy+viewheight,1,"brdr_b", CR_DEFAULT, VPT_NONE);
+
+ for (y=0 ; y<viewheight ; y+=8)
+ V_DrawNamePatch(viewwindowx-8,viewwindowy+y,1,"brdr_l", CR_DEFAULT, VPT_NONE);
+
+ for (y=0 ; y<viewheight ; y+=8)
+ V_DrawNamePatch(viewwindowx+scaledviewwidth,viewwindowy+y,1,"brdr_r", CR_DEFAULT, VPT_NONE);
+
+ // Draw beveled edge.
+ V_DrawNamePatch(viewwindowx-8,viewwindowy-8,1,"brdr_tl", CR_DEFAULT, VPT_NONE);
+
+ V_DrawNamePatch(viewwindowx+scaledviewwidth,viewwindowy-8,1,"brdr_tr", CR_DEFAULT, VPT_NONE);
+
+ V_DrawNamePatch(viewwindowx-8,viewwindowy+viewheight,1,"brdr_bl", CR_DEFAULT, VPT_NONE);
+
+ V_DrawNamePatch(viewwindowx+scaledviewwidth,viewwindowy+viewheight,1,"brdr_br", CR_DEFAULT, VPT_NONE);
+}
+
+//
+// Copy a screen buffer.
+//
+
+void R_VideoErase(unsigned ofs, int count)
+{
+ memcpy(screens[0]+ofs, screens[1]+ofs, count); // LFB copy.
+}
+
+
+//
+// R_DrawViewBorder
+// Draws the border around the view
+// for different size windows?
+//
+
+void R_DrawViewBorder(void)
+{
+ int top, side, ofs, i;
+ // proff/nicolas 09/20/98: Added for high-res (inspired by DosDOOM)
+ int side2;
+
+ // proff/nicolas 09/20/98: Removed for high-res
+ // if (scaledviewwidth == SCREENWIDTH)
+ // return;
+
+ // proff/nicolas 09/20/98: Added for high-res (inspired by DosDOOM)
+ if ((SCREENHEIGHT != viewheight) ||
+ ((automapmode & am_active) && ! (automapmode & am_overlay)))
+ {
+ ofs = ( SCREENHEIGHT - ST_SCALED_HEIGHT ) * SCREENWIDTH;
+ side= ( SCREENWIDTH - ST_SCALED_WIDTH ) / 2;
+ side2 = side * 2;
+
+ R_VideoErase ( ofs, side );
+
+ ofs += ( SCREENWIDTH - side );
+ for ( i = 1; i < ST_SCALED_HEIGHT; i++ )
+ {
+ R_VideoErase ( ofs, side2 );
+ ofs += SCREENWIDTH;
+ }
+
+ R_VideoErase ( ofs, side );
+ }
+
+ if ( viewheight >= ( 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 ; i<viewheight ; i++)
+ {
+ R_VideoErase (ofs, side);
+ ofs += SCREENWIDTH;
+ }
+}
diff --git a/apps/plugins/doom/r_draw.h b/apps/plugins/doom/r_draw.h
new file mode 100644
index 0000000..3b43135
--- /dev/null
+++ b/apps/plugins/doom/r_draw.h
@@ -0,0 +1,99 @@
+/* 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 __R_DRAW__
+#define __R_DRAW__
+
+#include "r_defs.h"
+
+#ifdef __GNUG__
+#pragma interface
+#endif
+
+extern lighttable_t *dc_colormap;
+extern int dc_x;
+extern int dc_yl;
+extern int dc_yh;
+extern fixed_t dc_iscale;
+extern fixed_t dc_texturemid;
+extern int dc_texheight; // killough
+
+// first pixel in a column
+extern const byte *dc_source;
+
+// The span blitting interface.
+// Hook in assembler or system specific BLT here.
+
+void R_DrawColumn(void) ICODE_ATTR;
+void R_DrawTLColumn(void) ICODE_ATTR; // drawing translucent textures // phares
+void R_DrawFuzzColumn(void) ICODE_ATTR; // The Spectre/Invisibility effect.
+
+// Draw with color translation tables, for player sprite rendering,
+// Green/Red/Blue/Indigo shirts.
+
+void R_DrawTranslatedColumn(void);
+
+void R_VideoErase(unsigned ofs, int count);
+
+extern lighttable_t *ds_colormap;
+
+extern int ds_y;
+extern int ds_x1;
+extern int ds_x2;
+extern fixed_t ds_xfrac;
+extern fixed_t ds_yfrac;
+extern fixed_t ds_xstep;
+extern fixed_t ds_ystep;
+
+// start of a 64*64 tile image
+extern byte *ds_source;
+extern byte playernumtotrans[MAXPLAYERS]; // CPhipps - what translation table for what player
+extern byte *translationtables;
+extern byte *dc_translation;
+
+// Span blitting for rows, floor/ceiling. No Spectre effect needed.
+void R_DrawSpan(void) ICODE_ATTR;
+
+void R_InitBuffer(int width, int height);
+
+// Initialize color translation tables, for player rendering etc.
+void R_InitTranslationTables(void);
+
+// Rendering function.
+void R_FillBackScreen(void);
+
+// If the view size is not full screen, draws a border around it.
+void R_DrawViewBorder(void);
+
+extern const byte *tranmap; // translucency filter maps 256x256 // phares
+extern const byte *main_tranmap; // killough 4/11/98
+
+#endif
diff --git a/apps/plugins/doom/r_main.c b/apps/plugins/doom/r_main.c
new file mode 100644
index 0000000..f79097a
--- /dev/null
+++ b/apps/plugins/doom/r_main.c
@@ -0,0 +1,531 @@
+/* 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:
+ * Rendering main loop and setup functions,
+ * utility functions (BSP, geometry, trigonometry).
+ * See tables.c, too.
+ *
+ *-----------------------------------------------------------------------------*/
+
+#include "doomstat.h"
+#include "w_wad.h"
+#include "r_main.h"
+#include "r_things.h"
+#include "r_plane.h"
+#include "r_bsp.h"
+#include "r_draw.h"
+#include "m_bbox.h"
+#include "r_sky.h"
+#include "v_video.h"
+#include "i_system.h"
+//#include "lprintf.h"
+#include "st_stuff.h"
+#include "rockmacros.h"
+
+// Fineangles in the SCREENWIDTH wide window.
+#define FIELDOFVIEW 2048
+
+// killough: viewangleoffset is a legacy from the pre-v1.2 days, when Doom
+// had Left/Mid/Right viewing. +/-ANG90 offsets were placed here on each
+// node, by d_net.c, to set up a L/M/R session.
+
+int viewangleoffset;
+
+int validcount = 1; // increment every time a check is made
+lighttable_t *fixedcolormap;
+int centerx IBSS_ATTR;
+int centery IBSS_ATTR;
+fixed_t centerxfrac, centeryfrac;
+fixed_t projection;
+fixed_t viewx, viewy, viewz;
+angle_t viewangle;
+fixed_t viewcos, viewsin;
+player_t *viewplayer;
+extern lighttable_t **walllights;
+
+//
+// precalculated math tables
+//
+
+angle_t clipangle;
+
+// The viewangletox[viewangle + FINEANGLES/4] lookup
+// maps the visible view angles to screen X coordinates,
+// flattening the arc to a flat projection plane.
+// There will be many angles mapped to the same X.
+
+int viewangletox[FINEANGLES/2];
+
+// The xtoviewangleangle[] table maps a screen pixel
+// to the lowest viewangle that maps back to x ranges
+// from clipangle to -clipangle.
+
+angle_t xtoviewangle[SCREENWIDTH+1]; // killough 2/8/98
+
+// killough 3/20/98: Support dynamic colormaps, e.g. deep water
+// killough 4/4/98: support dynamic number of them as well
+
+int numcolormaps;
+lighttable_t *(*c_scalelight)[LIGHTLEVELS][MAXLIGHTSCALE];
+lighttable_t *(*c_zlight)[LIGHTLEVELS][MAXLIGHTZ];
+lighttable_t *(*scalelight)[MAXLIGHTSCALE];
+lighttable_t *(*zlight)[MAXLIGHTZ];
+lighttable_t *fullcolormap;
+lighttable_t **colormaps;
+
+// killough 3/20/98, 4/4/98: end dynamic colormaps
+
+int extralight; // bumped light from gun blasts
+
+void (*colfunc)(void);
+
+//
+// R_PointOnSide
+// Traverse BSP (sub) tree,
+// check point against partition plane.
+// Returns side 0 (front) or 1 (back).
+//
+// killough 5/2/98: reformatted
+//
+
+int R_PointOnSide(fixed_t x, fixed_t y, const node_t *node)
+{
+ if (!node->dx)
+ 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<FINEANGLES/2 ; i++)
+ {
+ int t;
+ if (finetangent[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<<ANGLETOFINESHIFT)-ANG90;
+ }
+
+ // Take out the fencepost cases from viewangletox.
+ for (i=0; i<FINEANGLES/2; i++)
+ if (viewangletox[i] == -1)
+ viewangletox[i] = 0;
+ else
+ if (viewangletox[i] == viewwidth+1)
+ viewangletox[i] = viewwidth;
+
+ clipangle = xtoviewangle[0];
+}
+
+//
+// R_InitLightTables
+// Only inits the zlight table,
+// because the scalelight table changes with view size.
+//
+
+#define DISTMAP 2
+
+void R_InitLightTables (void)
+{
+ int i;
+
+ // killough 4/4/98: dynamic colormaps
+ c_zlight = malloc(sizeof(*c_zlight) * numcolormaps);
+ c_scalelight = malloc(sizeof(*c_scalelight) * numcolormaps);
+
+ // Calculate the light levels to use
+ // for each level / distance combination.
+ for (i=0; i< LIGHTLEVELS; i++)
+ {
+ int j, startmap = ((LIGHTLEVELS-1-i)*2)*NUMCOLORMAPS/LIGHTLEVELS;
+ for (j=0; j<MAXLIGHTZ; j++)
+ {
+ // CPhipps - use 320 here instead of SCREENWIDTH, otherwise hires is
+ // brighter than normal res
+ int scale = FixedDiv ((320/2*FRACUNIT), (j+1)<<LIGHTZSHIFT);
+ int t, level = startmap - (scale >>= 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<numcolormaps; t++) // killough 4/4/98
+ c_zlight[t][i][j] = colormaps[t] + level;
+ }
+ }
+}
+
+//
+// R_SetViewSize
+// Do not really change anything here,
+// because it might be in the middle of a refresh.
+// The change will take effect next refresh.
+//
+
+boolean setsizeneeded;
+int setblocks;
+
+void R_SetViewSize(int blocks)
+{
+ setsizeneeded = true;
+ setblocks = blocks;
+}
+
+//
+// R_ExecuteSetViewSize
+//
+
+void R_ExecuteSetViewSize (void)
+{
+ int i;
+
+ setsizeneeded = false;
+
+ if (setblocks == 11)
+ {
+ scaledviewwidth = SCREENWIDTH;
+ viewheight = SCREENHEIGHT;
+ }
+ else
+ {
+ scaledviewwidth = setblocks*32;
+ viewheight = (setblocks*168/10)&~7;
+ }
+
+ viewwidth = scaledviewwidth;
+
+ centery = viewheight/2;
+ centerx = viewwidth/2;
+ centerxfrac = centerx<<FRACBITS;
+ centeryfrac = centery<<FRACBITS;
+ projection = centerxfrac;
+
+ R_InitBuffer (scaledviewwidth, viewheight);
+
+ R_InitTextureMapping();
+
+ // psprite scales
+ pspritescale = FRACUNIT*viewwidth/SCREENWIDTH;
+ pspriteiscale = FRACUNIT*SCREENWIDTH/viewwidth;
+
+ // thing clipping
+ for (i=0 ; i<viewwidth ; i++)
+ screenheightarray[i] = viewheight;
+
+ // planes
+ for (i=0 ; i<viewheight ; i++)
+ { // killough 5/2/98: reformatted
+ fixed_t dy = D_abs(((i-viewheight/2)<<FRACBITS)+FRACUNIT/2);
+ yslope[i] = FixedDiv ( (viewwidth)/2*FRACUNIT, dy);
+ }
+
+ for (i=0 ; i<viewwidth ; i++)
+ {
+ fixed_t cosadj = D_abs(finecosine[xtoviewangle[i]>>ANGLETOFINESHIFT]);
+ distscale[i] = FixedDiv(FRACUNIT,cosadj);
+ }
+
+ // Calculate the light levels to use
+ // for each level / scale combination.
+ for (i=0; i<LIGHTLEVELS; i++)
+ {
+ int j, startmap = ((LIGHTLEVELS-1-i)*2)*NUMCOLORMAPS/LIGHTLEVELS;
+ for (j=0 ; j<MAXLIGHTSCALE ; j++)
+ {
+ // CPhipps - use 320 here instead of SCREENWIDTH, otherwise hires is
+ // brighter than normal res
+ int scale = FixedDiv ((320/2*FRACUNIT), (j+1)<<LIGHTZSHIFT);
+ int t, level = startmap - (scale >>= 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; t<numcolormaps; t++) // killough 4/4/98
+ c_scalelight[t][i][j] = colormaps[t] + level;
+ }
+ }
+}
+
+//
+// R_Init
+//
+
+extern int screenblocks;
+
+void R_Init (void)
+{
+ // CPhipps - R_DrawColumn isn't constant anymore, so must
+ // initialise in code
+ colfunc = R_DrawColumn; // current column draw function
+ if (SCREENWIDTH<320)
+ I_Error("R_Init: Screenwidth(%d) < 320",SCREENWIDTH);
+#if 1
+ printf("\nR_LoadTrigTables: ");
+ R_LoadTrigTables();
+#endif
+ printf("\nR_InitData: ");
+ R_InitData();
+ R_SetViewSize(screenblocks);
+ printf("\nR_Init: R_InitPlanes ");
+ R_InitPlanes();
+ printf("R_InitLightTables ");
+ R_InitLightTables();
+ printf("R_InitSkyMap ");
+ R_InitSkyMap();
+ printf("R_InitTranslationsTables ");
+ R_InitTranslationTables();
+}
+
+//
+// R_PointInSubsector
+//
+// killough 5/2/98: reformatted, cleaned up
+
+subsector_t *R_PointInSubsector(fixed_t x, fixed_t y)
+{
+ int nodenum = numnodes-1;
+ while (!(nodenum & NF_SUBSECTOR))
+ nodenum = nodes[nodenum].children[R_PointOnSide(x, y, nodes+nodenum)];
+ return &subsectors[nodenum & ~NF_SUBSECTOR];
+}
+
+//
+// R_SetupFrame
+//
+
+void R_SetupFrame (player_t *player)
+{
+ int i, cm;
+
+ viewplayer = player;
+ viewx = player->mo->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<MAXLIGHTSCALE ; i++)
+ scalelightfixed[i] = fixedcolormap;
+ }
+ else
+ fixedcolormap = 0;
+
+ validcount++;
+}
+
+//
+// R_RenderView
+//
+void R_RenderPlayerView (player_t* player)
+{
+ R_SetupFrame (player);
+
+ // Clear buffers.
+ R_ClearClipSegs ();
+ R_ClearDrawSegs ();
+ R_ClearPlanes ();
+ R_ClearSprites ();
+
+ // check for new console commands.
+ // NetUpdate ();
+
+ // The head node is the last node output.
+ R_RenderBSPNode (numnodes-1);
+
+ // Check for new console commands.
+ // NetUpdate ();
+
+ R_DrawPlanes ();
+
+ // Check for new console commands.
+ // NetUpdate ();
+
+ R_DrawMasked ();
+
+ // Check for new console commands.
+ // NetUpdate ();
+}
diff --git a/apps/plugins/doom/r_main.h b/apps/plugins/doom/r_main.h
new file mode 100644
index 0000000..10978b3
--- /dev/null
+++ b/apps/plugins/doom/r_main.h
@@ -0,0 +1,125 @@
+/* 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:
+ * Renderer main interface.
+ *
+ *-----------------------------------------------------------------------------*/
+
+#ifndef __R_MAIN__
+#define __R_MAIN__
+
+#include "d_player.h"
+#include "r_data.h"
+
+#ifdef __GNUG__
+#pragma interface
+#endif
+
+//
+// POV related.
+//
+
+extern fixed_t viewcos;
+extern fixed_t viewsin;
+extern int viewwidth;
+extern int viewheight;
+extern int viewwindowx;
+extern int viewwindowy;
+extern int centerx;
+extern int centery;
+extern fixed_t centerxfrac;
+extern fixed_t centeryfrac;
+extern fixed_t projection;
+extern int validcount;
+extern int linecount;
+extern int loopcount;
+
+//
+// Rendering stats
+//
+
+extern int rendered_visplanes, rendered_segs, rendered_vissprites;
+extern boolean rendering_stats;
+
+//
+// Lighting LUT.
+// Used for z-depth cuing per column/row,
+// and other lighting effects (sector ambient, flash).
+//
+
+// Lighting constants.
+
+#define LIGHTLEVELS 16
+#define LIGHTSEGSHIFT 4
+#define MAXLIGHTSCALE 48
+#define LIGHTSCALESHIFT 12
+#define MAXLIGHTZ 128
+#define LIGHTZSHIFT 20
+
+// killough 3/20/98: Allow colormaps to be dynamic (e.g. underwater)
+extern lighttable_t *(*scalelight)[MAXLIGHTSCALE];
+extern lighttable_t *(*zlight)[MAXLIGHTZ];
+extern lighttable_t *fullcolormap;
+extern int numcolormaps; // killough 4/4/98: dynamic number of maps
+extern lighttable_t **colormaps;
+// killough 3/20/98, 4/4/98: end dynamic colormaps
+
+extern int extralight;
+extern lighttable_t *fixedcolormap;
+
+// Number of diminishing brightness levels.
+// There a 0-31, i.e. 32 LUT in the COLORMAP lump.
+
+#define NUMCOLORMAPS 32
+
+//
+// Function pointers to switch refresh/drawing functions.
+// Used to select shadow mode etc.
+//
+
+extern void (*colfunc)(void);
+
+//
+// Utility functions.
+//
+
+int R_PointOnSide(fixed_t x, fixed_t y, const node_t *node);
+int R_PointOnSegSide(fixed_t x, fixed_t y, const seg_t *line);
+angle_t R_PointToAngle(fixed_t x, fixed_t y);
+angle_t R_PointToAngle2(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2);
+subsector_t *R_PointInSubsector(fixed_t x, fixed_t y);
+
+//
+// REFRESH - the actual rendering functions.
+//
+
+void R_RenderPlayerView(player_t *player); // Called by G_Drawer.
+void R_Init(void); // Called by startup code.
+void R_SetViewSize(int blocks); // Called by M_Responder.
+void R_ExecuteSetViewSize(void); // cph - called by D_Display to complete a view resize
+
+#endif
diff --git a/apps/plugins/doom/r_plane.c b/apps/plugins/doom/r_plane.c
new file mode 100644
index 0000000..60d37f8
--- /dev/null
+++ b/apps/plugins/doom/r_plane.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:
+ * Here is a core component: drawing the floors and ceilings,
+ * while maintaining a per column clipping list only.
+ * Moreover, the sky areas have to be determined.
+ *
+ * MAXVISPLANES is no longer a limit on the number of visplanes,
+ * but a limit on the number of hash slots; larger numbers mean
+ * better performance usually but after a point they are wasted,
+ * and memory and time overheads creep in.
+ *
+ * For more information on visplanes, see:
+ *
+ * http://classicgaming.com/doom/editing/
+ *
+ * Lee Killough
+ *
+ *-----------------------------------------------------------------------------*/
+
+#include "z_zone.h" /* memory allocation wrappers -- killough */
+
+#include "doomstat.h"
+#include "w_wad.h"
+#include "r_main.h"
+#include "r_draw.h"
+#include "r_things.h"
+#include "r_sky.h"
+#include "r_plane.h"
+#include "rockmacros.h"
+
+#define MAXVISPLANES 128 /* must be a power of 2 */
+
+static visplane_t *visplanes[MAXVISPLANES] IBSS_ATTR; // killough
+static visplane_t *freetail; // killough
+static visplane_t **freehead = &freetail; // killough
+visplane_t *floorplane, *ceilingplane;
+
+// killough -- hash function for visplanes
+// Empirically verified to be fairly uniform:
+
+#define visplane_hash(picnum,lightlevel,height) \
+ ((unsigned)((picnum)*3+(lightlevel)+(height)*7) & (MAXVISPLANES-1))
+
+size_t maxopenings;
+short *openings,*lastopening;
+
+// Clip values are the solid pixel bounding the range.
+// floorclip starts out SCREENHEIGHT
+// ceilingclip starts out -1
+
+short floorclip[SCREENWIDTH], ceilingclip[SCREENWIDTH];
+
+// spanstart holds the start of a plane span; initialized to 0 at start
+
+static int spanstart[SCREENHEIGHT]; // killough 2/8/98
+
+//
+// texture mapping
+//
+
+static lighttable_t **planezlight;
+static fixed_t planeheight;
+
+// killough 2/8/98: make variables static
+
+static fixed_t basexscale, baseyscale;
+static fixed_t cachedheight[SCREENHEIGHT];
+static fixed_t cacheddistance[SCREENHEIGHT];
+static fixed_t cachedxstep[SCREENHEIGHT];
+static fixed_t cachedystep[SCREENHEIGHT];
+static fixed_t xoffs, yoffs; // killough 2/28/98: flat offsets
+
+fixed_t yslope[SCREENHEIGHT], distscale[SCREENWIDTH];
+
+//
+// R_InitPlanes
+// Only at game startup.
+//
+void R_InitPlanes (void)
+{
+}
+
+//
+// R_MapPlane
+//
+// Uses global vars:
+// planeheight
+// ds_source
+// basexscale
+// baseyscale
+// viewx
+// viewy
+// xoffs
+// yoffs
+//
+// BASIC PRIMITIVE
+//
+
+static void R_MapPlane(int y, int x1, int x2)
+{
+ angle_t angle;
+ fixed_t distance, length;
+ unsigned index;
+
+#ifdef RANGECHECK
+ if (x2 < x1 || x1<0 || x2>=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 ; i<viewwidth ; i++)
+ floorclip[i] = viewheight, ceilingclip[i] = -1;
+
+ for (i=0;i<MAXVISPLANES;i++) // new code -- killough
+ for (*freehead = visplanes[i], visplanes[i] = NULL; *freehead; )
+ freehead = &(*freehead)->next;
+
+ 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;i<MAXVISPLANES;i++)
+ for (pl=visplanes[i]; pl; pl=pl->next)
+ R_DoDrawPlane(pl);
+}
diff --git a/apps/plugins/doom/r_plane.h b/apps/plugins/doom/r_plane.h
new file mode 100644
index 0000000..9696ea2
--- /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 0000000..4771132
--- /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->ceilingheight<backsector->ceilingheight
+ ? 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)
+static int didsolidcol; /* True if at least one column was marked solid */
+
+static void R_RenderSegLoop (void)
+{
+ fixed_t texturecolumn = 0; // shut up compiler warning
+ for ( ; rw_x < rw_stopx ; rw_x++)
+ {
+
+ // mark floor / ceiling areas
+
+ int yh = bottomfrac>>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 0000000..bbf56b6
--- /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 0000000..2ec2603
--- /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 0000000..1b817c1
--- /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 0000000..2e11bb5
--- /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 0000000..2e1f72e
--- /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<numentries; i++) // initialize hash table as empty
+ hash[i].index = -1;
+
+ for (i=0; (size_t)i<numentries; i++) // Prepend each sprite to hash chain
+ { // prepend so that later ones win
+ int j = R_SpriteNameHash(lumpinfo[i+firstspritelump].name) % numentries;
+ hash[i].next = hash[j].index;
+ hash[j].index = i;
+ }
+
+ // scan all the lump names for each of the names,
+ // noting the highest frame letter.
+
+ for (i=0 ; i<numsprites ; i++)
+ {
+ const char *spritename = namelist[i];
+ int j = hash[R_SpriteNameHash(spritename) % numentries].index;
+
+ if (j >= 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<SCREENWIDTH ; i++)
+ negonearray[i] = -1;
+ R_InitSpriteDefs (namelist);
+}
+
+void R_ClearSprites (void)
+{
+ num_vissprite = 0; // killough
+}
+
+//
+// R_NewVisSprite
+//
+
+vissprite_t *R_NewVisSprite(void)
+{
+ if (num_vissprite >= 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<<FRACBITS);
+
+ // Drawn by either R_DrawColumn
+ // or (SHADOW) R_DrawFuzzColumn.
+ colfunc ();
+ }
+ column = (const column_t *)( (byte *)column + column->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<<FRACBITS) /* + FRACUNIT/2 */ -
+ (psp->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; i<NUMPSPRITES; i++,psp++)
+ if (psp->state)
+ 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 0000000..dc93e30
--- /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 0000000..ae994c1
--- /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(; i<fpoint-1; i++)
+ filearray[i]=filearray[i+1];
+
+ fpoint--;
+ return 0;
+}
+#endif
+struct plugin_api* rb;
+#define MAXARGVS 100
+
+// Here is a hacked up printf command to get the output from the game.
+int printf(const char *fmt, ...)
+{
+ static int p_xtpt;
+ char p_buf[50];
+ bool ok;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ok = vsnprintf(p_buf,sizeof(p_buf), fmt, ap);
+ va_end(ap);
+
+ rb->lcd_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 0000000..6caeb2a
--- /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 0000000..c8ed7b2
--- /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)
+
+// Distance tp origin when sounds should be maxed out.
+// This should relate to movement clipping resolution
+// (see BLOCKMAP handling).
+// Originally: (200*0x10000).
+
+#define S_CLOSE_DIST (160*0x10000)
+#define S_ATTENUATOR ((S_CLIPPING_DIST-S_CLOSE_DIST)>>FRACBITS)
+
+// Adjustable by menu.
+#define NORM_PITCH 128
+#define NORM_PRIORITY 64
+#define NORM_SEP 128
+#define S_STEREO_SWING (96<<FRACBITS)
+
+typedef struct
+{
+ sfxinfo_t *sfxinfo; // sound information (if null, channel avail.)
+ void *origin; // origin of sound
+ int handle; // handle of the sound being played
+ int is_pickup; // killough 4/25/98: whether sound is a player's weapon
+} channel_t;
+
+// the set of channels available
+static channel_t* channels;
+
+// These are not used, but should be (menu).
+// Maximum volume of a sound effect.
+// Internal default is max out of 0-15.
+int snd_SfxVolume = 15;
+
+// Maximum volume of music. Useless so far.
+int snd_MusicVolume = 15;
+
+// whether songs are mus_paused
+static boolean mus_paused;
+
+// music currently being played
+static musicinfo_t* mus_playing=0;
+
+// following is set
+// by the defaults code in M_misc:
+// number of channels available
+int default_numChannels;
+int numChannels;
+
+//jff 3/17/98 to keep track of last IDMUS specified music num
+int idmusnum;
+
+//
+// Internals.
+//
+
+void S_StopChannel(int cnum);
+
+int S_AdjustSoundParams(mobj_t *listener, mobj_t *source,
+ int *vol, int *sep, int *pitch);
+
+static int S_getChannel(void *origin, sfxinfo_t *sfxinfo, int is_pickup);
+
+//
+// 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 )
+{
+ //jff 1/22/98 skip sound init if sound not enabled
+ numChannels = default_numChannels;
+ if (!nosfxparm)
+ {
+ int i;
+
+ printf("S_Init: default sfx volume %d\n", sfxVolume);
+
+ // Whatever these did with DMX, these are rather dummies now.
+ I_SetChannels();
+
+ S_SetSfxVolume(sfxVolume);
+
+ S_SetMusicVolume(musicVolume);
+
+ // Allocating the internal channels for mixing
+ // (the maximum numer of sounds rendered
+ // simultaneously) within zone memory.
+ // CPhipps - calloc
+ channels = (channel_t *) calloc(numChannels,sizeof(channel_t));
+
+ // no sounds are playing, and they are not mus_paused
+ mus_paused = 0;
+
+ // Note that sounds have not been cached (yet).
+ for (i=1 ; i<NUMSFX ; i++)
+ S_sfx[i].lumpnum = S_sfx[i].usefulness = -1;
+ }
+}
+
+//
+// Per level startup code.
+// Kills playing sounds at start of level,
+// determines music if any, changes music.
+//
+void S_Start(void)
+{
+ int cnum, mnum;
+
+ if (!nosfxparm)
+ {
+ // kill all playing sounds at start of level
+ // (trust me - a good idea)
+ for (cnum=0 ; cnum<numChannels ; cnum++)
+ if (channels[cnum].sfxinfo)
+ S_StopChannel(cnum);
+
+ // start new music for the level
+ mus_paused = 0;
+
+ if (gamemode == commercial)
+ mnum = mus_runnin + gamemap - 1;
+ else
+ {
+ int spmus[]= // Song - Who? - Where?
+ {
+ mus_e3m4, // American e4m1
+ mus_e3m2, // Romero e4m2
+ mus_e3m3, // Shawn e4m3
+ mus_e1m5, // American e4m4
+ mus_e2m7, // Tim e4m5
+ mus_e2m4, // Romero e4m6
+ mus_e2m6, // J.Anderson e4m7 CHIRON.WAD
+ mus_e2m5, // Shawn e4m8
+ mus_e1m9 // Tim e4m9
+ };
+
+ if (gameepisode < 4)
+ mnum = mus_e1m1 + (gameepisode-1)*9 + gamemap-1;
+ else
+ mnum = spmus[gamemap-1];
+ }
+
+ S_ChangeMusic(mnum, true);
+ }
+}
+
+void S_StartSoundAtVolume(void *origin_p, int sfx_id, int volume)
+{
+ int sep, pitch, priority, cnum, is_pickup;
+ sfxinfo_t* sfx;
+ mobj_t* origin = (mobj_t *) origin_p;
+
+ if (nosfxparm)
+ return;
+
+ is_pickup = sfx_id & PICKUP_SOUND || sfx_id == sfx_oof || (compatibility_level >= 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 ; cnum<numChannels ; cnum++)
+ if (channels[cnum].sfxinfo && channels[cnum].origin == origin &&
+ (comp[comp_sound] || channels[cnum].is_pickup == is_pickup))
+ {
+ S_StopChannel(cnum);
+ break;
+ }
+
+ // try to find a channel
+ cnum = S_getChannel(origin, sfx, is_pickup);
+
+ if (cnum<0)
+ return;
+
+ // get lumpnum if necessary
+ // killough 2/28/98: make missing sounds non-fatal
+ if (sfx->lumpnum < 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 ; cnum<numChannels ; cnum++)
+ if (channels[cnum].sfxinfo && channels[cnum].origin == origin)
+ {
+ S_StopChannel(cnum);
+ break;
+ }
+}
+
+//
+// Stop and resume music, during game PAUSE.
+//
+void S_PauseSound(void)
+{
+ if (nosfxparm)
+ return;
+
+ if (mus_playing && !mus_paused)
+ {
+ I_PauseSong(mus_playing->handle);
+ 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 ; cnum<numChannels ; cnum++)
+ {
+ sfxinfo_t* sfx;
+ channel_t* c = &channels[cnum];
+
+ if ((sfx = c->sfxinfo))
+ {
+ 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 ; i<numChannels ; i++)
+ if (cnum != i && c->sfxinfo == 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; cnum<numChannels && channels[cnum].sfxinfo; cnum++)
+ if (origin && channels[cnum].origin == origin &&
+ channels[cnum].is_pickup == is_pickup)
+ {
+ S_StopChannel(cnum);
+ break;
+ }
+
+ // None available
+ if (cnum == numChannels)
+ { // Look for lower priority
+ for (cnum=0 ; cnum<numChannels ; cnum++)
+ if (channels[cnum].sfxinfo->priority >= 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 0000000..0a4857e
--- /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 <origin>
+// using <sound_id> 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 <origin>
+void S_StopSound(void* origin);
+
+// Start music using <music_id> from sounds.h
+void S_StartMusic(int music_id);
+
+// Start music using <music_id> 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 0000000..200a402
--- /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 0000000..887a8e7
--- /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 0000000..adcd0e6
--- /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 0000000..09e5faa
--- /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 0000000..5d9244d
--- /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;i<NUMWEAPONS;i++)
+ {
+ if (oldweaponsowned[i] != plyr->weaponowned[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 ; i<MAXPLAYERS ; i++)
+ {
+ if (i != displayplayer) // killough 3/7/98
+ st_fragscount += plyr->frags[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.num<health_red)
+ STlib_updatePercent(&w_health, CR_RED, refresh);
+ else if (*w_health.n.num<health_yellow)
+ STlib_updatePercent(&w_health, CR_GOLD, refresh);
+ else if (*w_health.n.num<=health_green)
+ STlib_updatePercent(&w_health, CR_GREEN, refresh);
+ else
+ STlib_updatePercent(&w_health, CR_BLUE2, refresh); //killough 2/28/98
+
+ //jff 2/16/98 make color of armor depend on amount
+ if (*w_armor.n.num<armor_red)
+ STlib_updatePercent(&w_armor, CR_RED, refresh);
+ else if (*w_armor.n.num<armor_yellow)
+ STlib_updatePercent(&w_armor, CR_GOLD, refresh);
+ else if (*w_armor.n.num<=armor_green)
+ STlib_updatePercent(&w_armor, CR_GREEN, refresh);
+ else
+ STlib_updatePercent(&w_armor, CR_BLUE2, refresh); //killough 2/28/98
+
+ STlib_updateBinIcon(&w_armsbg, refresh);
+
+ for (i=0;i<6;i++)
+ STlib_updateMultIcon(&w_arms[i], refresh);
+
+ STlib_updateMultIcon(&w_faces, refresh);
+
+ for (i=0;i<3;i++)
+ STlib_updateMultIcon(&w_keyboxes[i], refresh);
+
+ STlib_updateNum(&w_frags, CR_DEFAULT, refresh);
+
+}
+
+void ST_doRefresh(void)
+{
+
+ st_firsttime = false;
+
+ // draw status bar background to off-screen buff
+ ST_refreshBackground();
+
+ // and refresh all widgets
+ ST_drawWidgets(true);
+
+}
+
+void ST_diffDraw(void)
+{
+ // update all widgets
+ ST_drawWidgets(false);
+}
+
+void ST_Drawer(boolean st_statusbaron, boolean refresh)
+{
+ /* cph - let status bar on be controlled
+ * completely by the call from D_Display
+ * proff - really do it
+ */
+ st_firsttime = st_firsttime || refresh;
+
+ ST_doPaletteStuff(); // Do red-/gold-shifts from damage/items
+
+ if (st_statusbaron) {
+ if (st_firsttime)
+ ST_doRefresh(); /* If just after ST_Start(), refresh all */
+ else
+ ST_diffDraw(); /* Otherwise, update as little as possible */
+ }
+}
+
+//
+// ST_loadGraphics
+//
+// CPhipps - Loads graphics needed for status bar if doload is true,
+// unloads them otherwise
+//
+static void ST_loadGraphics(boolean doload)
+{
+
+ int i,facenum;
+
+ char namebuf[9];
+ // cph - macro that either acquires a pointer and lock for a lump, or
+ // unlocks it. var is referenced exactly once in either case, so ++ in arg works
+ /*
+ #define LOADORFREE(var,name) \
+ if (!doload) { W_UnlockLumpName(name); var = NULL; } \
+ else var = (const patch_t*)W_CacheLumpName(name)
+ */
+
+ // Load the numbers, tall and short
+ for (i=0;i<10;i++)
+ {
+ snprintf(namebuf, sizeof(namebuf),"STTNUM%d", i);
+ R_SetPatchNum(&tallnum[i],namebuf);
+
+ snprintf(namebuf, sizeof(namebuf),"STYSNUM%d", i);
+ R_SetPatchNum(&shortnum[i],namebuf);
+ }
+
+ // Load percent key.
+ R_SetPatchNum(&tallpercent,"STTPRCNT");
+
+ // key cards
+ for (i=0;i<NUMCARDS+3;i++) //jff 2/23/98 show both keys too
+ {
+ snprintf(namebuf, sizeof(namebuf), "STKEYS%d", i);
+ R_SetPatchNum(&keys[i], namebuf);
+ }
+
+ // arms background
+ R_SetPatchNum(&armsbg, "STARMS");
+
+ // arms ownership widgets
+ for (i=0;i<6;i++)
+ {
+ snprintf(namebuf, sizeof(namebuf),"STGNUM%d", i+2);
+ // gray #
+ R_SetPatchNum(&arms[i][0], namebuf);
+
+ // yellow #
+ arms[i][1] = shortnum[i+2];
+ }
+
+ // face backgrounds for different color players
+ // killough 3/7/98: add better support for spy mode by loading all
+ // player face backgrounds and using displayplayer to choose them:
+ R_SetPatchNum(&faceback, "STFB0");
+
+ // status bar background bits
+ if (doload)
+ sbar = V_PatchToBlock("STBAR", CR_DEFAULT, VPT_NONE,
+ &sbar_width, &sbar_height);
+ else {
+ free(sbar); sbar=NULL;
+ }
+
+ // face states
+ facenum = 0;
+ for (i=0;i<ST_NUMPAINFACES;i++)
+ {
+ int j;
+ for (j=0;j<ST_NUMSTRAIGHTFACES;j++)
+ {
+ snprintf(namebuf, sizeof(namebuf), "STFST%d%d", i, j);
+ R_SetPatchNum(&faces[facenum++], namebuf);
+ }
+ snprintf(namebuf, sizeof(namebuf), "STFTR%d0", i); // turn right
+ R_SetPatchNum(&faces[facenum++], namebuf);
+ snprintf(namebuf, sizeof(namebuf), "STFTL%d0", i); // turn left
+ R_SetPatchNum(&faces[facenum++], namebuf);
+ snprintf(namebuf, sizeof(namebuf), "STFOUCH%d", i); // ouch!
+ R_SetPatchNum(&faces[facenum++], namebuf);
+ snprintf(namebuf, sizeof(namebuf), "STFEVL%d", i); // evil grin ;)
+ R_SetPatchNum(&faces[facenum++], namebuf);
+ snprintf(namebuf, sizeof(namebuf), "STFKILL%d", i); // pissed off
+ R_SetPatchNum(&faces[facenum++], namebuf);
+ }
+ R_SetPatchNum(&faces[facenum++], "STFGOD0");
+ R_SetPatchNum(&faces[facenum++], "STFDEAD0");
+}
+
+void ST_loadData(void)
+{
+ ST_loadGraphics(true);
+}
+
+void ST_unloadData(void)
+{
+ ST_loadGraphics(false);
+}
+
+void ST_initData(void)
+{
+ int i;
+
+ st_firsttime = true;
+ plyr = &players[displayplayer]; // killough 3/7/98
+
+ st_clock = 0;
+ st_chatstate = StartChatState;
+ st_gamestate = FirstPersonState;
+
+ st_statusbaron = true;
+ st_oldchat = st_chat = false;
+ st_cursoron = false;
+
+ st_faceindex = 0;
+ st_palette = -1;
+
+ st_oldhealth = -1;
+
+ for (i=0;i<NUMWEAPONS;i++)
+ oldweaponsowned[i] = plyr->weaponowned[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 0000000..d65b01e
--- /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 0000000..dfb2376
--- /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; n<size; n++) tbl[n] = doom_swap_l(tbl[n])
+
+ CORRECT_TABLE_ENDIAN(finesine, 10240);
+ CORRECT_TABLE_ENDIAN(finetangent, 4096);
+ CORRECT_TABLE_ENDIAN(tantoangle, 2049);
+ printf("corrected.");
+ }
+}
+#endif
diff --git a/apps/plugins/doom/tables.h b/apps/plugins/doom/tables.h
new file mode 100644
index 0000000..f9ec438
--- /dev/null
+++ b/apps/plugins/doom/tables.h
@@ -0,0 +1,103 @@
+/* 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.
+ *
+ *-----------------------------------------------------------------------------*/
+
+#ifndef __TABLES__
+#define __TABLES__
+
+#include "m_fixed.h"
+#include "rockmacros.h"
+
+#define FINEANGLES 8192
+#define FINEMASK (FINEANGLES-1)
+
+// 0x100000000 to 0x2000
+#define ANGLETOFINESHIFT 19
+
+#ifndef ALL_IN_ONE
+
+// TABLES_AS_LUMPS causes the tables to be loaded from a wad lump, and the normal
+// data to be stored as a predefined lump.
+// Only really useful for dumping the trig tables or with NO_PREDEFINED_LUMPS
+#define TABLES_AS_LUMPS
+#endif
+
+// Binary Angle Measument, BAM.
+#define ANG45 0x20000000
+#define ANG90 0x40000000
+#define ANG180 0x80000000
+#define ANG270 0xc0000000
+
+#define SLOPERANGE 2048
+#define SLOPEBITS 11
+#define DBITS (FRACBITS-SLOPEBITS)
+
+typedef unsigned angle_t;
+
+// Load trig tables if needed
+#ifdef TABLES_AS_LUMPS
+void R_LoadTrigTables(void);
+#define TRIG_CONST
+#else
+#define TRIG_CONST const
+#endif
+
+// Effective size is 10240.
+extern TRIG_CONST fixed_t *finesine;
+
+// Re-use data, is just PI/2 phase shift.
+extern TRIG_CONST fixed_t *finecosine;
+
+// Effective size is 4096.
+extern TRIG_CONST fixed_t *finetangent;
+
+// Effective size is 2049;
+// The +1 size is to handle the case when x==y without additional checking.
+
+extern TRIG_CONST angle_t *tantoangle;
+
+// Utility function, called by R_PointToAngle.
+int SlopeDiv(unsigned num, unsigned den);
+
+#undef TRIG_CONST
+#endif
diff --git a/apps/plugins/doom/v_video.c b/apps/plugins/doom/v_video.c
new file mode 100644
index 0000000..a7dbe84
--- /dev/null
+++ b/apps/plugins/doom/v_video.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:
+ * Gamma correction LUT stuff.
+ * Color range translation support
+ * Functions to draw patches (by post) directly to screen.
+ * Functions to blit a block to the screen.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+#include "doomdef.h"
+#include "r_main.h"
+#include "r_draw.h"
+#include "m_bbox.h"
+#include "w_wad.h" /* needed for color translation lump lookup */
+#include "v_video.h"
+#include "i_video.h"
+#include "i_system.h"
+#include "m_swap.h"
+#include "rockmacros.h"
+// Each screen is [SCREENWIDTH*SCREENHEIGHT];
+byte *screens[6];
+int dirtybox[4];
+
+/* jff 4/24/98 initialize this at runtime */
+const byte *colrngs[CR_LIMIT];
+
+// Now where did these came from?
+const byte gammatable[5][256] = // CPhipps - const
+ {
+ {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,32,
+ 33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,
+ 49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,
+ 65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,
+ 81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,
+ 97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,
+ 113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,
+ 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
+ 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
+ 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
+ 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
+ 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
+ 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
+ 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
+ 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255},
+
+ {2,4,5,7,8,10,11,12,14,15,16,18,19,20,21,23,24,25,26,27,29,30,31,
+ 32,33,34,36,37,38,39,40,41,42,44,45,46,47,48,49,50,51,52,54,55,
+ 56,57,58,59,60,61,62,63,64,65,66,67,69,70,71,72,73,74,75,76,77,
+ 78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,
+ 99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,
+ 115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,129,
+ 130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,
+ 146,147,148,148,149,150,151,152,153,154,155,156,157,158,159,160,
+ 161,162,163,163,164,165,166,167,168,169,170,171,172,173,174,175,
+ 175,176,177,178,179,180,181,182,183,184,185,186,186,187,188,189,
+ 190,191,192,193,194,195,196,196,197,198,199,200,201,202,203,204,
+ 205,205,206,207,208,209,210,211,212,213,214,214,215,216,217,218,
+ 219,220,221,222,222,223,224,225,226,227,228,229,230,230,231,232,
+ 233,234,235,236,237,237,238,239,240,241,242,243,244,245,245,246,
+ 247,248,249,250,251,252,252,253,254,255},
+
+ {4,7,9,11,13,15,17,19,21,22,24,26,27,29,30,32,33,35,36,38,39,40,42,
+ 43,45,46,47,48,50,51,52,54,55,56,57,59,60,61,62,63,65,66,67,68,69,
+ 70,72,73,74,75,76,77,78,79,80,82,83,84,85,86,87,88,89,90,91,92,93,
+ 94,95,96,97,98,100,101,102,103,104,105,106,107,108,109,110,111,112,
+ 113,114,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,
+ 129,130,131,132,133,133,134,135,136,137,138,139,140,141,142,143,144,
+ 144,145,146,147,148,149,150,151,152,153,153,154,155,156,157,158,159,
+ 160,160,161,162,163,164,165,166,166,167,168,169,170,171,172,172,173,
+ 174,175,176,177,178,178,179,180,181,182,183,183,184,185,186,187,188,
+ 188,189,190,191,192,193,193,194,195,196,197,197,198,199,200,201,201,
+ 202,203,204,205,206,206,207,208,209,210,210,211,212,213,213,214,215,
+ 216,217,217,218,219,220,221,221,222,223,224,224,225,226,227,228,228,
+ 229,230,231,231,232,233,234,235,235,236,237,238,238,239,240,241,241,
+ 242,243,244,244,245,246,247,247,248,249,250,251,251,252,253,254,254,
+ 255},
+
+ {8,12,16,19,22,24,27,29,31,34,36,38,40,41,43,45,47,49,50,52,53,55,
+ 57,58,60,61,63,64,65,67,68,70,71,72,74,75,76,77,79,80,81,82,84,85,
+ 86,87,88,90,91,92,93,94,95,96,98,99,100,101,102,103,104,105,106,107,
+ 108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,
+ 125,126,127,128,129,130,131,132,133,134,135,135,136,137,138,139,140,
+ 141,142,143,143,144,145,146,147,148,149,150,150,151,152,153,154,155,
+ 155,156,157,158,159,160,160,161,162,163,164,165,165,166,167,168,169,
+ 169,170,171,172,173,173,174,175,176,176,177,178,179,180,180,181,182,
+ 183,183,184,185,186,186,187,188,189,189,190,191,192,192,193,194,195,
+ 195,196,197,197,198,199,200,200,201,202,202,203,204,205,205,206,207,
+ 207,208,209,210,210,211,212,212,213,214,214,215,216,216,217,218,219,
+ 219,220,221,221,222,223,223,224,225,225,226,227,227,228,229,229,230,
+ 231,231,232,233,233,234,235,235,236,237,237,238,238,239,240,240,241,
+ 242,242,243,244,244,245,246,246,247,247,248,249,249,250,251,251,252,
+ 253,253,254,254,255},
+
+ {16,23,28,32,36,39,42,45,48,50,53,55,57,60,62,64,66,68,69,71,73,75,76,
+ 78,80,81,83,84,86,87,89,90,92,93,94,96,97,98,100,101,102,103,105,106,
+ 107,108,109,110,112,113,114,115,116,117,118,119,120,121,122,123,124,
+ 125,126,128,128,129,130,131,132,133,134,135,136,137,138,139,140,141,
+ 142,143,143,144,145,146,147,148,149,150,150,151,152,153,154,155,155,
+ 156,157,158,159,159,160,161,162,163,163,164,165,166,166,167,168,169,
+ 169,170,171,172,172,173,174,175,175,176,177,177,178,179,180,180,181,
+ 182,182,183,184,184,185,186,187,187,188,189,189,190,191,191,192,193,
+ 193,194,195,195,196,196,197,198,198,199,200,200,201,202,202,203,203,
+ 204,205,205,206,207,207,208,208,209,210,210,211,211,212,213,213,214,
+ 214,215,216,216,217,217,218,219,219,220,220,221,221,222,223,223,224,
+ 224,225,225,226,227,227,228,228,229,229,230,230,231,232,232,233,233,
+ 234,234,235,235,236,236,237,237,238,239,239,240,240,241,241,242,242,
+ 243,243,244,244,245,245,246,246,247,247,248,248,249,249,250,250,251,
+ 251,252,252,253,254,254,255,255}
+ };
+
+int usegamma;
+
+/*
+ * V_InitColorTranslation
+ *
+ * Loads the color translation tables from predefined lumps at game start
+ * No return
+ *
+ * Used for translating text colors from the red palette range
+ * to other colors. The first nine entries can be used to dynamically
+ * switch the output of text color thru the HUlib_drawText routine
+ * by embedding ESCn in the text to obtain color n. Symbols for n are
+ * provided in v_video.h.
+ *
+ * cphipps - constness of crdef_t stuff fixed
+ */
+
+typedef struct {
+ const char *name;
+ const byte **map;
+} crdef_t;
+
+// killough 5/2/98: table-driven approach
+static const crdef_t crdefs[] = {
+ {"CRBRICK", &colrngs[CR_BRICK ]},
+ {"CRTAN", &colrngs[CR_TAN ]},
+ {"CRGRAY", &colrngs[CR_GRAY ]},
+ {"CRGREEN", &colrngs[CR_GREEN ]},
+ {"CRBROWN", &colrngs[CR_BROWN ]},
+ {"CRGOLD", &colrngs[CR_GOLD ]},
+ {"CRRED", &colrngs[CR_RED ]},
+ {"CRBLUE", &colrngs[CR_BLUE ]},
+ {"CRORANGE", &colrngs[CR_ORANGE]},
+ {"CRYELLOW", &colrngs[CR_YELLOW]},
+ {"CRBLUE2", &colrngs[CR_BLUE2]},
+ {NULL, NULL}
+ };
+
+// killough 5/2/98: tiny engine driven by table above
+void V_InitColorTranslation(void)
+{
+ register const crdef_t *p;
+ for (p=crdefs; p->name; 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<s_width; x++, tx+=dx)
+ dst_row[x] = src_row[tx >> 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 ; y<SCREENHEIGHT ; y+=64)
+ for (x=y ? 0 : 64; x<SCREENWIDTH ; x+=64)
+ V_CopyRect(0, 0, scrn, ((SCREENWIDTH-x) < 64) ? (SCREENWIDTH-x) : 64,
+ ((SCREENHEIGHT-y) < 64) ? (SCREENHEIGHT-y) : 64, x, y, scrn, VPT_NONE);
+ W_UnlockLumpNum(lump);
+}
+#endif
+
+//
+// V_GetBlock
+//
+// Gets a linear block of pixels from the view buffer.
+//
+// The pixels in the rectangle at x,y in screenbuffer scrn with size
+// width by height are linearly packed into the buffer dest.
+// No return
+//
+
+#ifndef GL_DOOM
+void V_GetBlock(int x, int y, int scrn, int width, int height, byte *dest)
+{
+ byte *src;
+
+#ifdef RANGECHECK
+ if (x<0
+ ||x+width >SCREENWIDTH
+ || 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 ; i<PREALLOCED_SCREENS ; i++)
+ screens[i] = calloc(SCREENWIDTH*SCREENHEIGHT, 1);
+ for (; i<4; i++) // Clear the rest (paranoia)
+ screens[i] = NULL;
+}
+
+//
+// V_DrawMemPatch
+//
+// CPhipps - unifying patch drawing routine, handles all cases and combinations
+// of stretching, flipping and translating
+//
+// This function is big, hopefully not too big that gcc can't optimise it well.
+// In fact it packs pretty well, there is no big performance lose for all this merging;
+// the inner loops themselves are just the same as they always were
+// (indeed, laziness of the people who wrote the 'clones' of the original V_DrawPatch
+// means that their inner loops weren't so well optimised, so merging code may even speed them).
+//
+#ifndef GL_DOOM
+void V_DrawMemPatch(int x, int y, int scrn, const patch_t *patch,
+ int cm, enum patch_translation_e flags)
+{
+ const byte *trans;
+
+ if (cm<CR_LIMIT)
+ trans=colrngs[cm];
+ else
+ trans=translationtables + 256*((cm-CR_LIMIT)-1);
+ y -= SHORT(patch->topoffset);
+ 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 0000000..c9926e8
--- /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 0000000..4bd3807
--- /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; i<numlumps; i++) {
+ if (lumpinfo[i].locks)
+ printf("%8.8s %6u %2d %6d\n", lumpinfo[i].name,
+ W_LumpLength(i), lumpinfo[i].locks, gametic - locktic[i]);
+ }
+}
+#endif
+
+#ifdef HEAPDUMP
+void W_PrintLump(FILE* fp, void* p) {
+ int i;
+ for (i=0; i<numlumps; i++)
+ if (lumpcache[i] == p) {
+ fdprintf(fp, " %8.8s %6u %2d %6d", lumpinfo[i].name,
+ W_LumpLength(i), lumpinfo[i].locks, gametic - locktic[i]);
+ return;
+ }
+ fprintf(fp, " not found");
+}
+#endif
+
+
+
+static int W_Filelength(int handle)
+{
+ /*
+ struct stat fileinfo;
+ if (fstat(handle,&fileinfo) == -1)
+ I_Error("W_Filelength: Error fstating");
+ return fileinfo.st_size;
+ */
+ return filesize(handle);
+}
+
+void ExtractFileBase (const char *path, char *dest)
+{
+ const char *src = path + strlen(path) - 1;
+ int length;
+
+ // back up until a \ or the start
+ while (src != path && src[-1] != ':' // killough 3/22/98: allow c:filename
+ && *(src-1) != '\\'
+ && *(src-1) != '/')
+ src--;
+
+ // copy up to eight characters
+ memset(dest,0,8);
+ length = 0;
+
+ while (*src && *src != '.' && ++length<9)
+ *dest++ = toupper(*src++);
+ /* cph - length check removed, just truncate at 8 chars.
+ * If there are 8 or more chars, we'll copy 8, and no zero termination
+ */
+}
+
+//
+// 1/18/98 killough: adds a default extension to a path
+// Note: Backslashes are treated specially, for MS-DOS.
+//
+
+char *AddDefaultExtension(char *path, const char *ext)
+{
+ char *p = path;
+ while (*p++);
+ while (p-->path && *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)i<numlumps ; i++,lump_p++, fileinfo++)
+ {
+ lump_p->handle = 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++)
+ lumpinfo[i].index = -1; // mark slots empty
+
+ // Insert nodes to the beginning of each chain, in first-to-last
+ // lump order, so that the last lump of a given name appears first
+ // in any chain, observing pwad ordering rules. killough
+
+ for (i=0; i<numlumps; i++)
+ { // hash function:
+ int j = W_LumpNameHash(lumpinfo[i].name) % (unsigned) numlumps;
+ lumpinfo[i].next = lumpinfo[j].index; // Prepend to list
+ lumpinfo[j].index = i;
+ }
+}
+
+// End of lump hashing -- killough 1/31/98
+
+
+
+// W_GetNumForName
+// Calls W_CheckNumForName, but bombs out if not found.
+//
+int W_GetNumForName (const char* name) // killough -- const added
+{
+ int i = W_CheckNumForName (name);
+ if (i == -1)
+ I_Error("W_GetNumForName: %s not found", name);
+ return i;
+}
+
+// W_Init
+// Loads each of the files in the wadfiles array.
+// All files are optional, but at least one file
+// must be found.
+// Files with a .wad extension are idlink files
+// with multiple lumps.
+// Other files are single lumps with the base filename
+// for the lump name.
+// Lump names can appear multiple times.
+// The name searcher looks backwards, so a later file
+// does override all earlier ones.
+//
+// CPhipps - modified to use the new wadfiles array
+//
+struct wadfile_info *wadfiles=NULL;
+
+size_t numwadfiles = 0; // CPhipps - size of the wadfiles array (dynamic, no limit)
+
+void W_Init(void)
+{
+#ifndef NO_PREDEFINED_LUMPS
+ // killough 1/31/98: add predefined lumps first
+
+ numlumps = num_predefined_lumps;
+
+ // lumpinfo will be realloced as lumps are added
+ lumpinfo = malloc(numlumps*sizeof(*lumpinfo));
+
+ memcpy(lumpinfo, predefined_lumps, numlumps*sizeof(*lumpinfo));
+ // Ty 08/29/98 - add source flag to the predefined lumps
+ {
+ int i;
+ for (i=0;i<numlumps;i++)
+ lumpinfo[i].source = source_pre;
+ }
+#else
+ // CPhipps - start with nothing
+
+ numlumps = 0; lumpinfo = malloc(0);
+#endif
+
+ { // CPhipps - new wadfiles array used
+ // open all the files, load headers, and count lumps
+ int i;
+ for (i=0; (size_t)i<numwadfiles; i++)
+ W_AddFile(wadfiles[i].name, wadfiles[i].src);
+ }
+ if (!numlumps)
+ I_Error ("W_Init: No files found");
+
+ //jff 1/23/98
+ // get all the sprites and flats into one marked block each
+ // killough 1/24/98: change interface to use M_START/M_END explicitly
+ // killough 4/17/98: Add namespace tags to each entry
+
+ W_CoalesceMarkedResource("S_START", "S_END", ns_sprites);
+ W_CoalesceMarkedResource("F_START", "F_END", ns_flats);
+
+ // killough 4/4/98: add colormap markers
+ W_CoalesceMarkedResource("C_START", "C_END", ns_colormaps);
+
+ // set up caching
+ lumpcache = calloc(sizeof *lumpcache, numlumps); // killough
+
+ if (!lumpcache)
+ I_Error ("W_Init: Couldn't allocate lumpcache");
+
+ // killough 1/31/98: initialize lump hash table
+ W_InitLumpHash();
+
+#ifdef TIMEDIAG
+ // cph - allocate space for lock time diagnostics
+ locktic = malloc(sizeof(*locktic)*numlumps);
+ atexit(W_ReportLocks);
+#endif
+}
+
+//
+// W_LumpLength
+// Returns the buffer size needed to load the given lump.
+//
+int W_LumpLength (int lump)
+{
+ if (lump >= 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)i<num_predefined_lumps;i++)
+ {
+ filelump_t fileinfo = {0};
+ fileinfo.filepos = LONG(filepos);
+ fileinfo.size = LONG(predefined_lumps[i].size);
+ strncpy(fileinfo.name, predefined_lumps[i].name, 8);
+ write(handle, &fileinfo, sizeof(fileinfo));
+ filepos += predefined_lumps[i].size;
+ }
+
+ // write lumps
+ for (i=0;(size_t)i<num_predefined_lumps;i++)
+ write(handle, predefined_lumps[i].data, predefined_lumps[i].size);
+
+ close(handle);
+ I_Error("WritePredefinedLumpWad: Predefined lumps wad, %s written", filename);
+ }
+ I_Error("WritePredefinedLumpWad: Can't open predefined lumps wad %s for output", filename);
+}
+#endif
diff --git a/apps/plugins/doom/w_wad.h b/apps/plugins/doom/w_wad.h
new file mode 100644
index 0000000..f505f42
--- /dev/null
+++ b/apps/plugins/doom/w_wad.h
@@ -0,0 +1,164 @@
+/* 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:
+ * WAD I/O functions.
+ *
+ *-----------------------------------------------------------------------------*/
+
+
+#ifndef __W_WAD__
+#define __W_WAD__
+
+#ifdef __GNUG__
+#pragma interface
+#endif
+
+#include "m_fixed.h"
+
+//
+// TYPES
+//
+
+typedef struct
+{
+ char identification[4]; // Should be "IWAD" or "PWAD".
+ int numlumps;
+ int infotableofs;
+} wadinfo_t;
+
+typedef struct
+{
+ int filepos;
+ int size;
+ char name[8];
+} filelump_t;
+
+#ifndef ALL_IN_ONE
+
+// NO_PREDEFINED_LUMPS causes none of the predefined lumps in info.c to be
+// included, and removes all extra code which is only there for them
+// Saves a little memory normally, lots if any were overridden, and makes
+// the executable smaller
+#define NO_PREDEFINED_LUMPS
+
+#endif
+
+//
+// WADFILE I/O related stuff.
+//
+
+// CPhipps - defined enum in wider scope
+// Ty 08/29/98 - add source field to identify where this lump came from
+typedef enum {
+ // CPhipps - define elements in order of 'how new/unusual'
+ source_iwad=0, // iwad file load
+ source_pre, // predefined lump
+ source_auto_load, // lump auto-loaded by config file
+ source_pwad, // pwad file load
+ source_lmp, // lmp file load
+ source_net // CPhipps
+} wad_source_t;
+
+typedef struct
+{
+ // WARNING: order of some fields important (see info.c).
+
+ char name[8];
+ int size;
+#ifndef NO_PREDEFINED_LUMPS
+ const void *data; // killough 1/31/98: points to predefined lump data
+#endif
+
+ // killough 1/31/98: hash table fields, used for ultra-fast hash table lookup
+ int index, next;
+
+ // killough 4/17/98: namespace tags, to prevent conflicts between resources
+ enum {
+ ns_global=0,
+ ns_sprites,
+ ns_flats,
+ ns_colormaps
+ } namespace;
+
+ int handle;
+ int position;
+ unsigned int locks; // CPhipps - wad lump locking
+ wad_source_t source;
+} lumpinfo_t;
+
+// killough 1/31/98: predefined lumps
+extern const size_t num_predefined_lumps;
+extern const lumpinfo_t predefined_lumps[];
+
+extern void **lumpcache;
+extern lumpinfo_t *lumpinfo;
+extern int numlumps;
+
+// CPhipps - changed wad init
+// We _must_ have the wadfiles[] the same as those actually loaded, so there
+// is no point having these separate entities. This belongs here.
+struct wadfile_info {
+ const char* name;
+ wad_source_t src;
+};
+
+extern struct wadfile_info *wadfiles;
+
+extern size_t numwadfiles; // CPhipps - size of the wadfiles array
+
+void W_Init(void); // CPhipps - uses the above array
+
+// killough 4/17/98: if W_CheckNumForName() called with only
+// one argument, pass ns_global as the default namespace
+
+#define W_CheckNumForName(name) (W_CheckNumForName)(name, ns_global)
+int (W_CheckNumForName)(const char* name, int); // killough 4/17/98
+int W_GetNumForName (const char* name);
+int W_LumpLength (int lump);
+void W_ReadLump (int lump, void *dest);
+// CPhipps - modified for 'new' lump locking
+void* W_CacheLumpNum (int lump, unsigned short locks);
+void W_UnlockLumpNum(int lump, signed short unlocks);
+
+/* cph - special version to return lump with padding, for sound lumps */
+void * W_CacheLumpNumPadded(int lump, size_t len, unsigned char pad);
+
+// CPhipps - convenience macros
+#define W_CacheLumpNum(num) (W_CacheLumpNum)((num),1)
+#define W_CacheLumpName(name) W_CacheLumpNum (W_GetNumForName(name))
+
+#define W_UnlockLumpNum(num) (W_UnlockLumpNum)((num),1)
+#define W_UnlockLumpName(name) W_UnlockLumpNum (W_GetNumForName(name))
+
+char *AddDefaultExtension(char *, const char *); // killough 1/18/98
+void ExtractFileBase(const char *, char *); // killough
+unsigned W_LumpNameHash(const char *s); // killough 1/31/98
+
+// Function to write all predefined lumps to a PWAD if requested
+extern void WritePredefinedLumpWad(const char *filename); // jff 5/6/98
+
+#endif
diff --git a/apps/plugins/doom/wi_stuff.c b/apps/plugins/doom/wi_stuff.c
new file mode 100644
index 0000000..3d14d08
--- /dev/null
+++ b/apps/plugins/doom/wi_stuff.c
@@ -0,0 +1,1989 @@
+/* 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.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+#include "doomstat.h"
+#include "m_random.h"
+#include "w_wad.h"
+#include "g_game.h"
+#include "r_main.h"
+#include "v_video.h"
+#include "wi_stuff.h"
+#include "s_sound.h"
+#include "sounds.h"
+#include "m_swap.h"
+#include "r_draw.h"
+
+//
+// Data needed to add patches to full screen intermission pics.
+// Patches are statistics messages, and animations.
+// Loads of by-pixel layout and placement, offsets etc.
+//
+
+//
+// Different vetween registered DOOM (1994) and
+// Ultimate DOOM - Final edition (retail, 1995?).
+// This is supposedly ignored for commercial
+// release (aka DOOM II), which had 34 maps
+// in one episode. So there.
+#define NUMEPISODES 4
+#define NUMMAPS 9
+
+
+// Not used
+// in tics
+//U #define PAUSELEN (TICRATE*2)
+//U #define SCORESTEP 100
+//U #define ANIMPERIOD 32
+// pixel distance from "(YOU)" to "PLAYER N"
+//U #define STARDIST 10
+//U #define WK 1
+
+
+// GLOBAL LOCATIONS
+#define WI_TITLEY 2
+#define WI_SPACINGY 33
+
+// SINGLE-PLAYER STUFF
+#define SP_STATSX 50
+#define SP_STATSY 50
+
+#define SP_TIMEX 8
+// proff/nicolas 09/20/98 -- changed for hi-res
+#define SP_TIMEY 160
+//#define SP_TIMEY (SCREENHEIGHT-32)
+
+
+// NET GAME STUFF
+#define NG_STATSY 50
+#define NG_STATSX (32 + V_NamePatchWidth(star)/2 + 32*!dofrags)
+
+#define NG_SPACINGX 64
+
+
+// Used to display the frags matrix at endgame
+// DEATHMATCH STUFF
+#define DM_MATRIXX 42
+#define DM_MATRIXY 68
+
+#define DM_SPACINGX 40
+
+#define DM_TOTALSX 269
+
+#define DM_KILLERSX 10
+#define DM_KILLERSY 100
+#define DM_VICTIMSX 5
+#define DM_VICTIMSY 50
+
+
+// These animation variables, structures, etc. are used for the
+// DOOM/Ultimate DOOM intermission screen animations. This is
+// totally different from any sprite or texture/flat animations
+typedef enum
+{
+ ANIM_ALWAYS, // determined by patch entry
+ ANIM_RANDOM, // occasional
+ ANIM_LEVEL // continuous
+} animenum_t;
+
+typedef struct
+{
+ int x; // x/y coordinate pair structure
+ int y;
+} point_t;
+
+
+//
+// Animation.
+// There is another anim_t used in p_spec.
+//
+typedef struct
+{
+ animenum_t type;
+
+ // period in tics between animations
+ int period;
+
+ // number of animation frames
+ int nanims;
+
+ // location of animation
+ point_t loc;
+
+ // ALWAYS: n/a,
+ // RANDOM: period deviation (<256),
+ // LEVEL: level
+ int data1;
+
+ // ALWAYS: n/a,
+ // RANDOM: random base period,
+ // LEVEL: n/a
+ int data2;
+
+ /* actual graphics for frames of animations
+ * cphipps - const
+ */
+ const patch_t* p[3];
+
+ // following must be initialized to zero before use!
+
+ // next value of bcnt (used in conjunction with period)
+ int nexttic;
+
+ // last drawn animation frame
+ int lastdrawn;
+
+ // next frame number to animate
+ int ctr;
+
+ // used by RANDOM and LEVEL when animating
+ int state;
+} anim_t;
+
+
+static point_t lnodes[NUMEPISODES][NUMMAPS] =
+ {
+ // Episode 0 World Map
+ {
+ { 185, 164 }, // location of level 0 (CJ)
+ { 148, 143 }, // location of level 1 (CJ)
+ { 69, 122 }, // location of level 2 (CJ)
+ { 209, 102 }, // location of level 3 (CJ)
+ { 116, 89 }, // location of level 4 (CJ)
+ { 166, 55 }, // location of level 5 (CJ)
+ { 71, 56 }, // location of level 6 (CJ)
+ { 135, 29 }, // location of level 7 (CJ)
+ { 71, 24 } // location of level 8 (CJ)
+ },
+
+ // Episode 1 World Map should go here
+ {
+ { 254, 25 }, // location of level 0 (CJ)
+ { 97, 50 }, // location of level 1 (CJ)
+ { 188, 64 }, // location of level 2 (CJ)
+ { 128, 78 }, // location of level 3 (CJ)
+ { 214, 92 }, // location of level 4 (CJ)
+ { 133, 130 }, // location of level 5 (CJ)
+ { 208, 136 }, // location of level 6 (CJ)
+ { 148, 140 }, // location of level 7 (CJ)
+ { 235, 158 } // location of level 8 (CJ)
+ },
+
+ // Episode 2 World Map should go here
+ {
+ { 156, 168 }, // location of level 0 (CJ)
+ { 48, 154 }, // location of level 1 (CJ)
+ { 174, 95 }, // location of level 2 (CJ)
+ { 265, 75 }, // location of level 3 (CJ)
+ { 130, 48 }, // location of level 4 (CJ)
+ { 279, 23 }, // location of level 5 (CJ)
+ { 198, 48 }, // location of level 6 (CJ)
+ { 140, 25 }, // location of level 7 (CJ)
+ { 281, 136 } // location of level 8 (CJ)
+ }
+
+ };
+
+
+//
+// Animation locations for episode 0 (1).
+// Using patches saves a lot of space,
+// as they replace 320x200 full screen frames.
+//
+static anim_t epsd0animinfo[] =
+ {
+ { ANIM_ALWAYS, TICRATE/3, 3, { 224, 104 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
+ { ANIM_ALWAYS, TICRATE/3, 3, { 184, 160 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
+ { ANIM_ALWAYS, TICRATE/3, 3, { 112, 136 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
+ { ANIM_ALWAYS, TICRATE/3, 3, { 72, 112 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
+ { ANIM_ALWAYS, TICRATE/3, 3, { 88, 96 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
+ { ANIM_ALWAYS, TICRATE/3, 3, { 64, 48 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
+ { ANIM_ALWAYS, TICRATE/3, 3, { 192, 40 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
+ { ANIM_ALWAYS, TICRATE/3, 3, { 136, 16 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
+ { ANIM_ALWAYS, TICRATE/3, 3, { 80, 16 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
+ { ANIM_ALWAYS, TICRATE/3, 3, { 64, 24 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 }
+ };
+
+static anim_t epsd1animinfo[] =
+ {
+ { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 1, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
+ { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 2, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
+ { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 3, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
+ { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 4, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
+ { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 5, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
+ { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 6, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
+ { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 7, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
+ { ANIM_LEVEL, TICRATE/3, 3, { 192, 144 }, 8, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
+ { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 8, 0, { 0, 0, 0 }, 0, 0, 0, 0 }
+ };
+
+static anim_t epsd2animinfo[] =
+ {
+ { ANIM_ALWAYS, TICRATE/3, 3, { 104, 168 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
+ { ANIM_ALWAYS, TICRATE/3, 3, { 40, 136 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
+ { ANIM_ALWAYS, TICRATE/3, 3, { 160, 96 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
+ { ANIM_ALWAYS, TICRATE/3, 3, { 104, 80 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
+ { ANIM_ALWAYS, TICRATE/3, 3, { 120, 32 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
+ { ANIM_ALWAYS, TICRATE/4, 3, { 40, 0 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 }
+ };
+
+static int NUMANIMS[NUMEPISODES] =
+ {
+ sizeof(epsd0animinfo)/sizeof(anim_t),
+ sizeof(epsd1animinfo)/sizeof(anim_t),
+ sizeof(epsd2animinfo)/sizeof(anim_t)
+ };
+
+static anim_t *anims[NUMEPISODES] =
+ {
+ epsd0animinfo,
+ epsd1animinfo,
+ epsd2animinfo
+ };
+
+
+//
+// GENERAL DATA
+//
+
+//
+// Locally used stuff.
+//
+#define FB 0
+
+
+// States for single-player
+#define SP_KILLS 0
+#define SP_ITEMS 2
+#define SP_SECRET 4
+#define SP_FRAGS 6
+#define SP_TIME 8
+#define SP_PAR ST_TIME
+
+#define SP_PAUSE 1
+
+// in seconds
+#define SHOWNEXTLOCDELAY 4
+//#define SHOWLASTLOCDELAY SHOWNEXTLOCDELAY
+
+
+// used to accelerate or skip a stage
+int acceleratestage; // killough 3/28/98: made global
+
+// wbs->pnum
+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 <LevelName>
+ /* 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;i<NUMANIMS[wbs->epsd];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;i<NUMANIMS[wbs->epsd];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 ; i<NUMANIMS[wbs->epsd] ; 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<MAXPLAYERS ; i++)
+ {
+ if (playeringame[i] // is this player playing?
+ && i!=playernum) // and it's not the player we're calculating
+ {
+ frags += plrs[playernum].frags[i];
+ }
+ }
+
+
+ // JDC hack - negative frags.
+ frags -= plrs[playernum].frags[playernum];
+
+ return frags;
+}
+
+
+static int dm_state;
+// CPhipps - short, dynamically allocated
+static short int **dm_frags; // frags matrix
+static short int *dm_totals; // totals by player
+
+// ====================================================================
+// WI_initDeathmatchStats
+// Purpose: Set up to display DM stats at end of level. Calculate
+// frags for all players.
+// Args: none
+// Returns: void
+//
+void WI_initDeathmatchStats(void)
+{
+ int i; // looping variables
+
+ // CPhipps - allocate data structures needed
+ dm_frags = calloc(MAXPLAYERS, sizeof(*dm_frags));
+ dm_totals = calloc(MAXPLAYERS, sizeof(*dm_totals));
+
+ state = StatCount; // We're doing stats
+ acceleratestage = 0;
+ dm_state = 1; // count how many times we've done a complete stat
+
+ cnt_pause = TICRATE;
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ {
+ if (playeringame[i])
+ {
+ // CPhipps - allocate frags line
+ dm_frags[i] = calloc(MAXPLAYERS, sizeof(**dm_frags)); // set all counts to zero
+
+ dm_totals[i] = 0;
+ }
+ }
+ WI_initAnimatedBack();
+}
+
+
+// ====================================================================
+// CPhipps - WI_endDeathmatchStats
+// Purpose: Deallocate dynamically allocated DM stats data
+// Args: none
+// Returns: void
+//
+
+void WI_endDeathmatchStats(void)
+{
+ int i;
+ for (i=0; i<MAXPLAYERS; i++)
+ free(dm_frags[i]);
+
+ free(dm_frags); free(dm_totals);
+}
+
+// ====================================================================
+// WI_updateDeathmatchStats
+// Purpose: Advance Deathmatch stats screen animation. Calculate
+// frags for all players. Lots of noise and drama around
+// the presentation.
+// Args: none
+// Returns: void
+//
+void WI_updateDeathmatchStats(void)
+{
+ int i;
+ int j;
+
+ boolean stillticking;
+
+ WI_updateAnimatedBack();
+
+ if (acceleratestage && dm_state != 4) // still ticking
+ {
+ acceleratestage = 0;
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ {
+ if (playeringame[i])
+ {
+ for (j=0 ; j<MAXPLAYERS ; j++)
+ if (playeringame[j])
+ dm_frags[i][j] = plrs[i].frags[j];
+
+ dm_totals[i] = WI_fragSum(i);
+ }
+ }
+
+
+ S_StartSound(0, sfx_barexp); // bang
+ dm_state = 4; // we're done with all 4 (or all we have to do)
+ }
+
+
+ if (dm_state == 2)
+ {
+ if (!(bcnt&3))
+ S_StartSound(0, sfx_pistol); // noise while counting
+
+ stillticking = false;
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ {
+ if (playeringame[i])
+ {
+ for (j=0 ; j<MAXPLAYERS ; j++)
+ {
+ if (playeringame[j]
+ && dm_frags[i][j] != plrs[i].frags[j])
+ {
+ if (plrs[i].frags[j] < 0)
+ dm_frags[i][j]--;
+ else
+ dm_frags[i][j]++;
+
+ if (dm_frags[i][j] > 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 ; i<MAXPLAYERS ; i++)
+ {
+ if (playeringame[i]) {
+ //int trans = playernumtotrans[i];
+ V_DrawNamePatch(x-halfface, DM_MATRIXY - WI_SPACINGY,
+ FB, facebackp, i ? CR_LIMIT+i : CR_DEFAULT,
+ VPT_STRETCH | (i ? VPT_TRANS : 0));
+ V_DrawNamePatch(DM_MATRIXX-halfface, y,
+ FB, facebackp, i ? CR_LIMIT+i : CR_DEFAULT,
+ VPT_STRETCH | (i ? VPT_TRANS : 0));
+
+ if (i == me)
+ {
+ V_DrawNamePatch(x-halfface, DM_MATRIXY - WI_SPACINGY,
+ FB, bstar, CR_DEFAULT, VPT_STRETCH);
+ V_DrawNamePatch(DM_MATRIXX-halfface, y,
+ FB, star, CR_DEFAULT, VPT_STRETCH);
+ }
+ }
+ x += DM_SPACINGX;
+ y += WI_SPACINGY;
+ }
+
+ // draw stats
+ y = DM_MATRIXY+10;
+ w = SHORT(num[0]->width);
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ {
+ x = DM_MATRIXX + DM_SPACINGX;
+
+ if (playeringame[i])
+ {
+ for (j=0 ; j<MAXPLAYERS ; j++)
+ {
+ if (playeringame[j])
+ WI_drawNum(x+w, y, dm_frags[i][j], 2);
+
+ x += DM_SPACINGX;
+ }
+ WI_drawNum(DM_TOTALSX+w, y, dm_totals[i], 2);
+ }
+ y += WI_SPACINGY;
+ }
+}
+
+
+//
+// Note: The term "Netgame" means a coop game
+//
+static short *cnt_kills;
+static short *cnt_items;
+static short *cnt_secret;
+static short *cnt_frags;
+static int dofrags;
+static int ng_state;
+
+// ====================================================================
+// CPhipps - WI_endNetgameStats
+// Purpose: Clean up coop game stats
+// Args: none
+// Returns: void
+//
+static void WI_endNetgameStats(void)
+{
+ free(cnt_frags);
+ free(cnt_secret);
+ free(cnt_items);
+ free(cnt_kills);
+}
+
+// ====================================================================
+// WI_initNetgameStats
+// Purpose: Prepare for coop game stats
+// Args: none
+// Returns: void
+//
+void WI_initNetgameStats(void)
+{
+ int i;
+
+ state = StatCount;
+ acceleratestage = 0;
+ ng_state = 1;
+
+ cnt_pause = TICRATE;
+
+ // CPhipps - allocate these dynamically, blank with calloc
+ cnt_kills = calloc(MAXPLAYERS, sizeof(*cnt_kills));
+ cnt_items = calloc(MAXPLAYERS, sizeof(*cnt_items));
+ cnt_secret= calloc(MAXPLAYERS, sizeof(*cnt_secret));
+ cnt_frags = calloc(MAXPLAYERS, sizeof(*cnt_frags));
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ if (playeringame[i])
+ dofrags += WI_fragSum(i);
+
+ dofrags = !!dofrags; // set to true or false - did we have frags?
+
+ WI_initAnimatedBack();
+}
+
+
+// ====================================================================
+// WI_updateNetgameStats
+// Purpose: Calculate coop stats as we display them with noise and fury
+// Args: none
+// Returns: void
+// Comment: This stuff sure is complicated for what it does
+//
+void WI_updateNetgameStats(void)
+{
+ int i;
+ int fsum;
+
+ boolean stillticking;
+
+ WI_updateAnimatedBack();
+
+ if (acceleratestage && ng_state != 10)
+ {
+ acceleratestage = 0;
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ {
+ if (!playeringame[i])
+ continue;
+
+ cnt_kills[i] = (plrs[i].skills * 100) / wbs->maxkills;
+ 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<MAXPLAYERS ; i++)
+ {
+ if (!playeringame[i])
+ continue;
+
+ cnt_kills[i] += 2;
+
+ if (cnt_kills[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<MAXPLAYERS ; i++)
+ {
+ if (!playeringame[i])
+ continue;
+
+ cnt_items[i] += 2;
+ if (cnt_items[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<MAXPLAYERS ; i++)
+ {
+ if (!playeringame[i])
+ continue;
+
+ cnt_secret[i] += 2;
+
+ // killough 2/22/98: Make secrets = 100% if maxsecret = 0:
+
+ if (cnt_secret[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<MAXPLAYERS ; i++)
+ {
+ if (!playeringame[i])
+ continue;
+
+ cnt_frags[i] += 1;
+
+ if (cnt_frags[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 ; i<MAXPLAYERS ; i++)
+ {
+ //int trans = playernumtotrans[i];
+ if (!playeringame[i])
+ continue;
+
+ x = NG_STATSX;
+ V_DrawNamePatch(x-fwidth, y, FB, facebackp,
+ i ? CR_LIMIT+i : CR_DEFAULT,
+ VPT_STRETCH | (i ? VPT_TRANS : 0));
+
+ if (i == me)
+ V_DrawNamePatch(x-fwidth, y, FB, star, CR_DEFAULT, VPT_STRETCH);
+
+ x += NG_SPACINGX;
+ WI_drawPercent(x-pwidth, y+10, cnt_kills[i]); x += NG_SPACINGX;
+ WI_drawPercent(x-pwidth, y+10, cnt_items[i]); x += NG_SPACINGX;
+ WI_drawPercent(x-pwidth, y+10, cnt_secret[i]); x += NG_SPACINGX;
+
+ if (dofrags)
+ WI_drawNum(x, y+10, cnt_frags[i], -1);
+
+ y += WI_SPACINGY;
+ }
+
+ if (y <= SP_TIMEY)
+ // cph - show times in coop on the entering screen
+ WI_drawTimeStats(plrs[me].stime / TICRATE, wbs->totaltimes / 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 ; i<MAXPLAYERS ; i++, player++)
+ {
+ if (playeringame[i])
+ {
+ if (player->cmd.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;j<NUMANIMS[wbs->epsd];j++)
+ {
+ a = &anims[wbs->epsd][j];
+ for (i=0;i<a->nanims;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;j<NUMANIMS[wbs->epsd];j++) {
+ anim_t* a = &anims[wbs->epsd][j];
+ for (i=0; i<a->nanims; 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 0000000..72c1d32
--- /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 0000000..47a9b4f
--- /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 0000000..0c454fc
--- /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 0000000..036c995
--- /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<NUM_HISTORY_TYPES;i++)
+ {
+ sprintf(s,"\nLast several %s:\n\n", desc[i]);
+ strcat(buf,s);
+ for (j=0; j<ZONE_HISTORY; j++)
+ {
+ int k = (history_index[i]-j-1) & (ZONE_HISTORY-1);
+ if (file_history[i][k])
+ {
+ sprintf(s, "File: %s, Line: %d\n", file_history[i][k],
+ line_history[i][k]);
+ strcat(buf,s);
+ }
+ }
+ }
+}
+#else
+
+void Z_DumpHistory(char *buf)
+{
+ (void)buf;
+}
+
+#endif
+
+void Z_Close(void)
+{
+// (free)(zonebase);
+ zone = rover = zonebase = NULL;
+}
+
+void Z_Init(void)
+{
+ unsigned int size;
+#ifdef INSTRUMENTED
+ if (!(HEADER_SIZE >= 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 0000000..6ab9bba
--- /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